9
votes

Optimisation de la division dans GCC

Voici un code (programme complet suit plus tard dans la question): xxx

maintenant, si j'appelle cette fonction de modèle avec int , puis je reçois un facteur de 6 différences de performance en fonction de la définition de la const ou non de: xxx

examinant le démontage montre que dans le cas rapide (const), le modulo a été transformé en une multiplication et chose de type décalage, alors que dans le cas lent (non-const), il utilise idiovisl .

Peu pire, si j'essaie d'envelopper mon entier dans une classe, l'optimisation n'a pas "t arrive si j'utilise const ou non. Le code utilise toujours idiovisl et exécute lentement: xxx

mes questions sont les suivantes:

1) est-ce un principe simple de C ++ elle-même, ou l'optimisation de GCC, qui explique pourquoi cela se produit, ou est-ce simplement un cas de "diverses heuristiques exécutées, c'est le code que vous obtenez"?

2) Y a-t-il un moyen de faire le compilateur Récupérez-vous que mon const-enracial déclaré localement et jamais référencé peut être traité comme une valeur de Const de compilation? Je veux que cette chose soit un remplacement droit pour INT dans les modèles.

3) est-il un moyen connu d'envelopper un INT tel que le compilateur puisse jeter l'emballage lors de l'optimisation? L'objectif est que Wrackint sera un modèle basé sur des stratégies. Mais si une politique "sans rien" entraîne essentiellement des pénalités de vitesse 6x 6x arbitraires sur Int, je ferai mieux à désordre la situation de la situation et de l'utiliser directement.


1 commentaires

Au cas où il provoque une confusion - j'aurais probablement dû renommé ma fonction "Fizz" lorsque j'ai supprimé le "|| i% 5" ;-)


4 Réponses :


1
votes

Essayez de combiner const int V dans votre classe wraffoint avec const t dans votre fonction FIZZBUZZ et voyez si le compilateur peut optimiser cela.

En déclarant const int Vous avez créé un cas spécial - une constante de temps de compilation. Le compilateur sait quelle est la valeur, et peut l'optimiser plus lourdement qu'une valeur qui pourrait éventuellement changer pendant la course du programme.


3 commentaires

Malheureusement, enveloppé a deux opérateurs qui modifient v . Mais introduisant une nouvelle classe, enveloppé avec eux supprimé, ajoutant un opérateur approprié% et apportant div A const enveloppé osselsint , ne déclenche pas l'optimisation. Il court lentement.


Et je comprends que "const int" est spécial. Cependant, même lorsque le non-const, le compilateur tire la valeur dans un registre et le registre n'est jamais modifié dans la boucle. Donc, j'espérais plutôt (a) que certains DFA lui permettraient de constater qu'un INT local qui n'est jamais modifié et aucune référence prise, est aussi bonne que la const et lui donnez le traitement, et / ou (b) qu'un const La structure contenant un int est tout comme Const comme un const int .


Donc, je suppose que la question devient "" Y a-t-il une forte raison pour laquelle ni (a) ni (b) ne se passe, ou n'est-ce pas que le GCC ne le gère pas? "



0
votes

Y a-t-il un moyen connu d'envelopper un INT tel que le compilateur puisse jeter l'emballage lors de l'optimisation?

Essayez de passer enveloppé par valeur. Ensuite, enveloppé S peut être transmis dans des registres. Pass-By-Const-Référence force parfois GCC de revenir à la pile pour le passage de l'argument.

À propos du INT vs Const int Le ralentissement, je ne peux que spéculer que GCC tente de le jouer en sécurité face à un aliasing. Fondamentalement, s'il ne peut pas prouver que div n'est pas un alias pour une autre variable plus accessible, il ne peut pas la transformer en une constante. Si vous le déclarez const, GCC suppose qu'il n'est pas aliasé et effectue la conversion en une constante. Outre le idiovisl , vous devez également voir une mémoire de récupération de la mémoire, une fois, lors de la saisie de la fonction, par opposition à des valeurs immédiates utilisées pour le boîtier const .


1 commentaires

Dans les cas d'intensément enveloppés et non constitutifs, DIV est initialisé avec " MOVL 3 $,% EDI " et ne touche jamais la mémoire. Et la modification de tous les opérateurs de enveloppe (ainsi que le constructeur) à passer par la valeur ne permet pas l'optimisation.



7
votes

Je suppose que c'est juste la version sévère de GCC que vous utilisez. Le plus ancien compilateur que j'ai sur ma machine - GCC-4.1.2, effectue la manière rapide avec les versions non constituées et les versions d'enveloppe (et le fait uniquement à -0 -O1).


2 commentaires

Une raison particulière que vous n'avez pas améliorée dans 4 ans?


Cygwin par défaut à 3.4. Je suppose qu'ils l'utilisent toujours pour construire une cygwin elle-même, ou quelque chose. Il a un paquet GCC-4, cependant, je vais donc essayer cela. Pas aussi mauvais que les 12 mois + que la version de Gnupg de Cygwin contenait une faille de sécurité critique fixée en amont.



0
votes

La différence de vitesse est causée par le compilateur ne sachant pas si "div" changera de valeur. Quand c'est non-const, il le traite comme une variable étant transmis. Cela pourrait être n'importe quoi, et le compilateur utilisera donc une instruction qui divise deux variables - IDIVL. Lorsque vous dites que c'est Const, le compilateur est libre de le traiter exactement comme si vous avez saisi:

if (i  % 3 == 0)


1 commentaires

Seul le modulo des pouvoirs de deux peut être exprimé en utilisant et.