IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Problème de compilation avec l'option O3


Sujet :

Langage C++

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 82
    Par défaut Problème de compilation avec l'option O3
    Bonjour

    Suite à des discutions sur ce forum, j'ai voulu tester l'option O3 sur un programme qui fonctionnait bien sans. Comme cela ne fonctionnait plus très bien, j'ai fini par cerner le noeud du problème : il semble y avoir un problème quand on introduit une fonction écrite en assembleur. Voila ce que cela donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    #include <iostream>
     
    using namespace std;
    #define uint64_t unsigned long long
    #define uint32_t unsigned long
    //------------------------------------------
     
    void print(uint64_t A[], uint32_t N)
    {
    	cout <<"{";
    	for (int k = 0; k < N; ++k){
    		cout<<A[k] <<", ";
    	}
    	cout <<'\b'<<'\b'<<"}"<<endl ;
    }
    ;
    // new T = T + k*A
    // dim A = 2; dim T = 4;
    // T[j] + k*A[j] = u[j] + b*v[j]
    void mul_add(uint64_t k, uint64_t A[], uint64_t T[])
    {
       uint64_t c ;
       __asm__ __volatile__(
          " mov %[A], %%rsi ;"
          " mov %[T], %%rdi ;"
          " mov $0, %[c] ;"           // carry = 0
          " mov $2, %%rcx ;"          // loop counter (j = 2 - rcx)
       " 0: ;"
          " mov (%%rsi), %%rax ;"     // rax = A[j]
          " mul %[k] ;"               // k*A[j] = rax + rdx*b
          " add (%%rdi), %%rax ;"     // rax = rax + T[j] = u[j]
          " adc $0, %%rdx ;"          // rdx = rdx + CF = v[j]
          " add %[c], %%rax ;"        // rax = u[j] + carry -> new T[j]
          " adc $0, %%rdx ;"          // rdx = v[j] + CF -> new carry
          " mov %%rax, (%%rdi) ;"     // new T[j] = rax
          " mov %%rdx, %[c] ;"        // new carry = rdx
          " add $8, %%rsi ;"
          " add $8, %%rdi ;"
       " loop 0b ;"
          " add %[c], (%%rdi) ;"      // new T[2] = T[2] + carry
          :
          : [A] "r" (A)
          , [T] "r" (T)
          , [k] "r" (k)
          , [c] "r" (c)                // carry
          : "cc", "memory", "%rax", "%rcx", "%rdx"
       );
    }
     
    //-----------------------------------
    int main(void)
    {
      uint64_t x = 2;
      uint64_t y = 3755218545365861964ULL;
      uint64_t n = 10203806521854051703ULL;
      uint64_t q = 17966832521566772153ULL;
      uint64_t X[2] = {x,0}, Y[2] = {y,0}, N[2] = {n,0}, T[4] = {0};
     
     //  cout<<endl<<"X = ";print(X,2);
     //  cout<<endl<<"Y = ";print(Y,2);
     //  cout<<endl<<"N = ";print(N,2);
     //  cout<<endl<<"T = ";print(T,4);
     //  cout<<endl<<"------------"<<endl;
       mul_add(x,Y,T);
       cout<<endl<<"T = ";   print(T,4);
     
       return 0;
    }
    Je travaille sous Windows avec Code::Blocks (dernière version) et MinGW_w64 comme compilateur (mais j'ai aussi testé avec Clang).
    Avec ces données, mul_add calcule 2*3755218545365861964 et place le résultat dans T
    Sans O3 le résultat est correct (aussi bien avec Clang qu'avec MinGW_w64.) On obtient
    T = {7510437090731723928, 0, 0, 0}

    Process returned 0 (0x0) execution time : 0.042 s
    Press any key to continue.
    Les problème surviennent avec O3

    ----------- Avec MinGW_w64 -----------------------
    Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est correct. On obtient
    T = {7510437090731723928, 0, 0, 0}

    Process returned 0 (0x0) execution time : 0.013 s
    Press any key to continue.
    Mais si on décommente une des lignes (ou plusieurs), on obtient
    Process returned -1073741819 (0xC0000005) execution time : 0.838 s
    Press any key to continue.
    ---------- Avec Clang -------------

    Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est faux. On obtient
    T = {15020874181463447856, 0, 0, 0}

    Process returned 0 (0x0) execution time : 0.042 s
    Press any key to continue.
    De plus, si on décommente une ou plusieurs lignes, on obtient, suivant les cas
    Process returned -1073741819 (0xC0000005) execution time : 0.509 s
    Press any key to continue.
    ou bien
    terminate called after throwing an instance of 'std::bad_cast'
    what(): std::bad_cast

    Process returned -1073740791 (0xC0000409) execution time : 0.489 s
    Press any key to continue.
    Cela est juste un exemple. J'ai obtenu d'autres situations tout aussi bizarres
    • une erreur (0xC0000005) si on place un 'exit()' quelque part mais qui disparaît si on place cet 'exit()' un peu plus loin.

    • une variable de boucle réinitialisée, ce qui donne une boucle infinie

    • la modification de la valeur d'un constante, etc.



    Merci pour vos lumières.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 162
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par serge17 Voir le message
    De plus, si on décommente une ou plusieurs lignes, on obtient, suivant les cas
    Process returned -1073741819 (0xC0000005) execution time : 0.509 s
    Press any key to continue.
    ou bien
    terminate called after throwing an instance of 'std::bad_cast'
    what(): std::bad_cast

    Process returned -1073740791 (0xC0000409) execution time : 0.489 s
    Press any key to continue.
    Ça s'appelle un crash, utilise le debugger pour voir où ça crash.
    M'enfin quelle idée de faire de l'asm dans un code C ? Pourquoi ne pas faire juste du C++ ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 708
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 708
    Par défaut
    Bonjour,

    Cela ressemble à un débordement mémoire. Si c'est le cas, il provient certainement du code assembleur qui peut faire ce qu'il veut. Si cette hypothèse est correcte un agrandissement de X et Y à 4 pourrait être intéressant.

    Que le débordement apparaisse sous des formes diverses (voire pas du tout) selon les options de compilation n'est pas des plus surprenant.

    Par ailleurs, le code assembleur ne sera jamais optimisé par le compilateur, d'une part parce que __volatile__ lui dit "pas touche !", et d'autre part parce que les registres de travail sont rigidifiés ne laissant pas le compilateur les redistribuer à son gré. On se demande ce qui reste à optimiser : les affichages ?

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 82
    Par défaut
    Merci à tous pour vos réponses

    #Bousk
    Ça s'appelle un crash, utilise le debugger pour voir où ça crash.
    Je vais essayer de voir. Ma question initiale était << Comment le fait de faire 'cout<<endl;' ou pas peut changer quelque chose ? >>
    M'enfin quelle idée de faire de l'asm dans un code C ?
    Je ne sait pas si cela change quelque chose mais c'est de l'asm dans un code C++.
    Pourquoi ne pas faire juste du C++ ?
    En C++, c'est un calcul en multi-précision ; Boost par exemple peut faire le travail mais avec un temps d'exécution bien trop grand. Evidemment, je ne peut pas tester les temps d'exécutions avec l'option O3 !

    # Guesset
    Par ailleurs, le code assembleur ne sera jamais optimisé par le compilateur, d'une part parce que __volatile__ lui dit "pas touche !", et d'autre part parce que les registres de travail sont rigidifiés ne laissant pas le compilateur les redistribuer à son gré. On se demande ce qui reste à optimiser : les affichages ?
    Mon code asm été testé directement et indirectement ne nombreuses fois : il marche parfaitement. D'autre part il est suffisamment commenté pour se rendre compte qu'il fait exactement ce pour quoi il est fait (mais je ne suis pas un expert -- loin s'en faut ! -- et si on peut l'améliorer en quoi que ce soit, je suis preneur).
    Comme tu le fait remarquer, quelle peut bien être l'optimisation ? Il n'empêche quelle détraque tout.
    Cela ressemble à un débordement mémoire. Si c'est le cas, il provient certainement du code assembleur qui peut faire ce qu'il veut. Si cette hypothèse est correcte un agrandissement de X et Y à 4 pourrait être intéressant.
    Effectivement l'erreur 0xC0000005 correspond à une violation de l'espace mémoire. C'est forcément le code asm qui est en cause parce que c'est le seul à faire quelque chose ! Suivant ton conseil j'ai effectué un agrandissement (j'en ai profité pour simplifier l'exemple)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(void)
    {
      uint64_t x = 5;
      uint64_t y = 3755218545365861964ULL;
      uint64_t X[10] = {x,0}, Y[10] = {y,0}, T[10] = {0};
     //  cout<<endl;
       mul_add(x,Y,T);
       cout<<endl<<"T = ";   print(T,4);
       return 0;
    Avec le '//' cela donne toujours le bon résultat. Petite curiosité supplémentaire : dans le main ci-dessus, si on remplace T(10] par T(12], on obtient un résultat faux.
    Hélas, si on effectue 'cout<<endl;' l'erreur 0xC0000005 est toujours là ...

    # tous : quelqu'un a-t-il essayé d'exécuter ce nano-programme ? (copier-coller = 1s + exécution = 0.5 s)

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 306
    Par défaut
    Soyons clair. Ce que tu décris est une corruption mémoire.
    Et il y a tout à parier qu'elle vient de l'asm.

    Et comme dit par mes VDD, mettre de l'O3 par dessus de l'asm ne vas pas l'optimiser. a contrario de le mettre sur du C++.

    > Evidemment, je ne peux pas tester les temps d'exécutions avec l'option O3 !

    Tu veux dire que tu n'as pas testé les temps d'exécution d'un code pur C++ en O3?? Tu peux le comparer directement à ton asm en O0, car il ne seras jamais optimisé en O3 comme on te le disait.

    Donne-nous le code C++ équivalent à ton asm et on verra à l'optimiser.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Réponses: 8
    Dernier message: 13/05/2011, 20h29
  2. Réponses: 1
    Dernier message: 16/07/2008, 03h34
  3. Réponses: 3
    Dernier message: 04/11/2007, 20h55
  4. [JB9][EJB]Compiler avec Make ou javac ?
    Par _gtm_ dans le forum JBuilder
    Réponses: 4
    Dernier message: 11/07/2003, 16h59
  5. Compilation avec un Makefile
    Par Mau dans le forum GTK+ avec C & C++
    Réponses: 3
    Dernier message: 28/02/2003, 12h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo