9
votes

Comment aligner la pile à 32 limites d'octets dans GCC?

J'utilise MINGW64 Build basé sur GCC 4.6.1 pour la cible Windows 64bit. Je joue avec les nouvelles instructions d'AVX d'Intel. Mes arguments de ligne de commande sont -March = CineI7-AVX -MTUNE = COREI7-AVX -MAVX .

Mais j'ai commencé à courir dans des erreurs de défaut de segmentation lors de l'allocation de variables locales sur la pile. GCC utilise les mouvements alignés vmovaps et vmovapd pour déplacer __ m256 et __ m256d autour et ces instructions nécessitent 32 octets alignement. Cependant, la pile pour Windows 64bit n'a que 16 alignements d'octets.

Comment puis-je modifier l'alignement de la pile de GCC à 32 octets?

J'ai essayé d'utiliser -msttackrealign mais en vain, car cela aligne seulement 16 octets. Je ne pouvais pas faire __ attribut __ ((forcer_align_arg_pointer)) Travailler soit, il aligne à 16 octets de toute façon. Je n'ai pas pu trouver d'autres options de compilateur qui répondraient à cela. Toute aide est grandement appréciée.

éditer: J'ai essayé d'utiliser -mpreferred-pile-stack-limite = 5 , mais GCC dit que 5 n'est pas pris en charge pour cette cible. Je suis à court d'idées.


2 commentaires

Est-ce que cela signifie __ attribut__ ((aligné (32))) n'est pas honoré aussi? par exemple. Si vous utilisez __ m256 x __attribute__ ((aligné (32)))


Linux n'allonge pas la pile de 32 non plus. GCC ciblant Linux utilise et -32 $,% RSP (ou tout alignement supérieur) pour aligner la pile dans les fonctions qui doivent renverser un __ m256 , __ m512 ou tous les objets que vous avez déclarés avec alignas (32) ou quelque chose de plus élevé que 16. Il semble qu'un bogue étrange que Mingw GCC n'utilise pas la même séquence pour enregistrer l'original RSP et l'aligner.


3 Réponses :


16
votes

J'ai exploré la question, a déposé un rapport de bogue GCC et a découvert qu'il s'agit d'un problème connexe MINGW64. Voir Bug de GCC # 49001 . Apparemment, GCC ne prend pas en charge l'alignement de la pile de 32 octets sur Windows. Cela empêche efficacement l'utilisation d'instructions AVX 256 bits.

J'ai enquêté sur la manière de faire face à ce problème. La solution la plus simple et la plus blunte est de remplacer les accès à la mémoire alignée VMOVAPS / PD / DQA par des alternatives non alignées VMOVUPUPS, etc. Alors j'ai appris Python la nuit dernière (très bel outil, en passant) et retiré le script suivant qui fait le travail avec un Fichier d'assembleur d'entrée Produit par GCC: P>

import re
import fileinput
import sys

# fix aligned stack access
# replace aligned vmov* by unaligned vmov* with 32-byte aligned operands 
# see Intel's AVX programming guide, page 39
vmova = re.compile(r"\s*?vmov(\w+).*?((\(%r.*?%ymm)|(%ymm.*?\(%r))")
aligndict = {"aps" : "ups", "apd" : "upd", "dqa" : "dqu"};
for line in fileinput.FileInput(sys.argv[1:],inplace=1):
    m = vmova.match(line)
    if m and m.group(1) in aligndict:
        s = m.group(1)
        print line.replace("vmov"+s, "vmov"+aligndict[s]),
    else:
        print line,


3 commentaires

Pourriez-vous partager votre script de ré-rétrécissement de Prolog? En outre, comment obtenir du fichier d'assemblage (généré par -s) à un exécutable? Merci


@NobertP. La situation est-elle meilleure avec des versions ultérieures de Mingw64?


Parce que GCC semble être balayer ce bug sous le tapis (il a 6 ans!), Nous avons décidé d'aller un autre itinéraire. Une bonne pétition à l'ancienne, veuillez le signer. Changer.org/p/gnu-project-gcc- Compiler-Fix-Bug-54412



1
votes

Vous pouvez obtenir l'effet que vous voulez par

  1. Déclarant vos variables pas comme variables, mais comme champs dans une structure
  2. Déclarant un tableau plus grand que la structure par une quantité appropriée de remplissage
  3. faire du pointeur / adresse arithmétique pour trouver une adresse alignée de 32 octets à la côte de la matrice
  4. casting qui adresse à un pointeur à votre structure
  5. Enfin en utilisant les membres de données de votre structure

    Vous pouvez utiliser la même technique lorsque MALLOC () ne correspond pas de substance sur le tas de manière appropriée.

    par exemple xxx

    xxx


0 commentaires

1
votes

Je viens de courir dans le même problème d'avoir des défauts de segmentation lors de l'utilisation d'AVX à l'intérieur de mes fonctions. Et c'était également dû au désalignement de la pile. Compte tenu du fait qu'il s'agit d'un problème de compilateur (et des options pouvant aider ne sont pas disponibles dans Windows), j'ai travaillé autour de l'utilisation de la pile par:

  1. à l'aide de variables statiques (voir cette problème ). Compte tenu du fait qu'ils ne sont pas stockés dans la pile, vous pouvez forcer leur alignement en utilisant __ attribut __ ((alignement (32))) dans votre déclaration. Par exemple: statique __m256i r __attribute __ ((aligné (32))) .

  2. Inlinge des fonctions / méthodes recevant / renvoyer les données AVX . Vous pouvez forcer GCC à la configuration de votre fonction / méthode en ajoutant inline et __ ((toujours_inline)) à votre prototype / déclaration de fonction. L'amélioration de vos fonctions augmente la taille de votre programme, mais elles empêchent également la fonction d'utiliser la pile (et donc, évite la question de la pile-alignement). Exemple: inline __m256i myavxfonction (vide) __attribute __ ((toujours_inline)); .

    Sachez que l'utilisation de variables statiques n'est pas une sécurité du thread, comme indiqué dans la référence. Si vous écrivez une application multi-threadée, vous devrez peut-être ajouter une certaine protection pour vos chemins critiques.


3 commentaires

Dans MacOS, le compilateur alignez tout tableau à 16 octets. GCC fait-il cela aussi sur 64 bits?


Salut. Après avoir effectué une expérience dans une machine Windows de 64B, à l'aide de GCC, j'ai constaté que le premier élément d'un tableau est aligné de 16 octets par défaut. Les autres éléments de la matrice sont alignés en fonction du type de données des éléments de la matrice. Par exemple, un tableau A de N caractères (1 octet large) aurait et a [ n ] = & a [0] + n , Être & a [ n ] 16 octets aligné.


Est-ce que les versions ultérieures de Mingw64 avec GCC 7.x résolvent ce problème?