8
votes

GCC avec -fno-intégré ne semble pas fonctionner

Je voudrais comparer la fonction GCC intégrée memcpy code> contre celui de libc. Cependant, toutes les itérations de -fno-intégrées code> ou -fno-intégrées-memcpy code> semblent être ignorées.

//g++ -O3 foo.cpp -S or
//g++ -O3 -fno-builtin foo.cpp -S
#include <string.h>
int main() {
    volatile int n = 1000;
    //int n = 1000;
    float *x = new float[1000];
    float *y = new float[1000];
    memcpy(y,x,sizeof(float)*n);
    //__builtin_memcpy(y,x,sizeof(float)*n);    
}


3 commentaires

Je viens de remarquer que dans cette question et vos commentaires, vous avez mal orthographié -fno-intégré plusieurs façons différentes. Vérifiez que cela ne jette pas vos résultats. L'orthographe correcte est "b u je suis je n".


@Zack, merci d'avoir trouvé les orthographes. J'espère que je les ai tous réparés. J'ai vraiment été un peu trop bâclé (j'ai aussi utilisé nouveau quand j'aurais dû utiliser Malloc dans mon exemple de test - dans mon propre code, j'utilise _mm_malloc quand même). Mais GCC se plaint si j'utilise l'une des distinctions. Mais si vous souhaitez vérifier vous-même, déposez-vous le code ci-dessus (Supprimer le volatil) dans gcc.godbolt.org et Changer de GCC 4.8 ou 4.9, ajoutez -fno-intégré et regardez le code de montage.


@Zack, assurez-vous d'ajouter -O3 aussi.


3 Réponses :


1
votes

REMARQUE: parce que vous compilez le code C ++, je ne suis pas sûr à 100% si cela s'applique si cela s'applique.

La norme C nécessite toutes les fonctions de la bibliothèque (sauf indication contraire explicite) avoir une adresse et peut être l'opérande de la & Opérateur d'adresse. En effet, il permet de mettre en œuvre certaines fonctions / la plupart des fonctions en tant que macro fonctionnelle, mais devraient toujours se comporter comme une variable / fonction réelle dans certains cas. Pour éviter la version macro de celui-ci, vous avez juste besoin de quelque chose entre le jeton memcpy et le jeton ( (comme @ZACH a fait remarquer, WhitSpace est insuffisant): xxx

Cela force l'utilisation de la fonction réelle, qui doit éviter tout type de définition macro intégrée.


C'est aussi possible (Lire: probablement) que le -O3 optimisation analyse pour certains appels de fonction (tels que memcpy ) et les remplace par des appels intégrés, quel que soit le -fno-in-inseditin .


11 commentaires

Une version macro de memcpy sera toujours étendue avec WhitSpace entre Memcpy et (. Mettre des parenthèses autour du jeton memcpy Cependant, cependant, se comporte comme vous le décrivez.


De plus, je peux dire autorité que -fno-intégré est supposé pour faire ce que l'OP attend, à tous les niveaux d'optimisation. GCC.GNU. org / onlinedocs / GCC-4.8.1 / GCC / ...


J'ai essayé vos deux suggestions avec GCC et G ++ (ce code compile tout simplement bien en C, donc je ne suis pas sûr que la balise C ++ est meilleure) et ils n'ont pas fait de différence. C'est comme si -O3 l'emporte sur tout.


@Zboson Nouveau est C ++, pas c; Ce programme devrait vous donner une erreur de compilation si elle est placée dans un fichier avec une extension de code et compilée avec la commande gcc au lieu de < Code> g ++ .


@Zack, oui, tu es correct. J'aurais dû utiliser Malloc pour éviter toute confusion.


@Zack uniquement si c'est une macro d'objet, pas une macro de fonction. La norme C indique explicitement qu'une invocation macro fonctionnelle nécessite non espace entre le nom de la macro et la parenthèse d'ouverture


@Trewmcgowen Vous envisagez de macro fonctionnelle Définition , pas d'utilisation. N1570 (approximation la plus proche de C2011 disponible sans Payer pour cela): 6.10.3p3 Plus les règles de la grammaire en 6.10.3p {9,10} exigent que les macros fonctionnelles sont définies sans espace entre le nom de la macro et la parenthèse ouverte. (1/2)


@Trewmcgowen Toutefois, la prose en 6.10.3p10 (en particulier la phrase commençant par chaque instance ultérieure du nom de macro de type fonction suivie d'un ( comme le prochain jeton de prétraitement "(Accenseignement mine: WhitSpace n'est pas un jeton de prétraitement)) clairement (Eh bien, si vous êtes habitué à la normale) indique que les macros fonctionnelles sont développés même s'il y a une quantité de blancheur de quelque nature que ce soit entre le nom de la macro et le (. (2/2)


Temps de confession: j'ai écrit environ 40% du préprocesseur actuel de GCC. C'était il y a plus de dix ans, mais je suppose que j'ai toujours à peu près la section 6.10 mémorisée.


@Zack impressionnant! Je travaille sur mon propre compilateur C - alors maintenant je suppose que je sais qui se déranger quand je suis coincé;)


J'ai changé de nouveau à Malloc et j'ai modifié le nom du fichier en .C et j'ai essayé vos suggestions. Ils n'ont pas fait de différence. Étrangement sans -Fno-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-intuitin, produit un montage simple sans memcpy et avec celui-ci, il produisit un résultat similaire à g ++ sans -Fno-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-in-nodal. Donc, l'interrupteur a un effet, mais il a toujours produit du code intégré qui n'appelle pas MEMCY.



4
votes

-fno-intégré code> et -fno-intégré-memcpy code> Les deux ont l'effet que vous attendiez avec GCC 4.9.1. Ceci est probablement juste un bogue dans la GCC 4.8.2; Cette combinaison particulière d'options n'est pas largement utilisée. -ffreestanding code> est un interrupteur associé qui peut avoir l'effet que vous souhaitez avec 4.8.2.

Notez que le compilateur est dans ses droits pour optimiser votre programme vers P>

int main() { return 0; }


12 commentaires

J'ai essayé -ffreestanding . Cela n'a fait aucune différence. Je vais devoir installer GCC 4.9.1 pour vérifier votre réponse.


J'ai regardé la sortie de l'assembly à http://gcc.godbolt.org/ et je peux confirmer que -fno-intégré fonctionne comme prévu dans GCC 4.9 et non dans GCC 4.8.1.


J'ai vérifié GCC 4.4 à 4.9 et 4.9 est le seul qui le convient correct.


La CPI le fait-elle correctement aussi. Lorsque je passe -fno-intégré utilise memcpy et sans qu'elle utilise _intel_fast_memcpy .


Juste pour être clair, le compilateur n'a pas optimisé le code de code. Il est clair de regarder le code de l'assembleur.


@Zboson oui. Je disais juste que c'est aurait pu avoir . De plus, Clang fait . J'ai déposé un bug sur GCC: gcc.gnu.org/bugzilla/show_bug.cgi ? id = 62112


BTW, je ne sais toujours pas comment supprimer le code intégré dans GCC 4.8. Est-ce que ma seule option de mise à niveau vers GCC 4.9?


@Zboson il ressemble à ça. Je doute que les personnes du GCC considèrent que cela soit un bogue assez important pour corriger la série 4.8.x, bien que vous puissiez certainement essayer de le signaler ( GCC.GNU.ORG/BUGZILLA ).


Si vous voulez savoir pourquoi je me soucie de cela, il s'agit de Optimisation du manuel C ++ . Voir la section 2.6 "Comparaison des bibliothèques de fonction". Il affirme que MemCy de GCC de GCC intégré et de glibc sous-performance (et que ce sont les pires). En utilisant son asmlib, je peux le voir fonctionner beaucoup mieux que MemCy de Glibc. Je n'ai pas encore comparé à la fonction intégrée. Il recommande d'utiliser -fno-intégré .


@Zboson Dans la mesure où ce document est correct, signaler que comme un bogue dans GCC et / ou glibc et c'est sera pris au sérieux. Cependant, des travaux substantiels sont entrés dans une optimisation des fonctions de chaîne dans GCC 4.9 et GLIBC 2.19; Je ne serais pas surpris si ce document était maintenant inexact.


J'ai comparé le memcpy intégré de GCC 4.8 et 4.9 (que j'ai installé aujourd'hui) et ils semblent l'efficacité maintenant. Cependant, Glibc 2.19 est toujours assez lent que l'asmlib. Je pense que l'asmlib utilise des magasins non temporels ( _mm_stream_ps ) pour les grandes tailles. Mais le code intégré doit être une constante de temps de compilation et inférieure ou égale à 8192. Donc, j'ai donc loin autour du bogue -Fno-in-in-in-in-in-in-in-in-in-in-in-in-in (code> pour GCC 4.8.


Désolé de Belabor Ce point, mais je viens de télécharger glibc 2.19, l'a compilée et l'a installée et il est maintenant aussi rapide que l'asmlib que vous avez dit. Ce que j'ai comparé au début, c'était Eglibc 2.19 qui est la valeur par défaut sur Ubuntu / Debian (jusqu'à la prochaine version). Cela fait une énorme différence.



1
votes

Une partie probable de votre problème est avec GLIBC, pas GCC. Vous n'avez pas spécifié, mais vous utilisez probablement Ubuntu, qui définit -d_fortify_source = 2 par défaut. Ceci invite les en-têtes GLIBC à fournir une définition inline de memcpy qui transmet à __ memcpy_chk . .


0 commentaires