Je ne comprends pas pourquoi le compilateur GCC coupe une partie de mon code alors qu'il conserve absolument le même dans le quartier?
Le code C:
#define setb_SYNCO do{(PORTA|= (1<<0));} while(0);
ISR(INT0_vect){
unsigned char i;
i = 10;
while(i>0)i--; // first pause - omitted
setb_SYNCO;
setb_GATE;
i=30;
clrb_SYNCO;
while(i>0)i--; // second pause - preserved
clrb_GATE;
}
La partie correspondante de LSS (fichier assembleur, créé par le compilateur):
ISR(INT0_vect){
a4: 1f 92 push r1
a6: 0f 92 push r0
a8: 0f b6 in r0, 0x3f ; 63
aa: 0f 92 push r0
ac: 11 24 eor r1, r1
ae: 8f 93 push r24
unsigned char i;
i = 10;
while(i>0)i--;
setb_SYNCO;
b0: d8 9a sbi 0x1b, 0 ; 27
setb_GATE;
b2: d9 9a sbi 0x1b, 1 ; 27
i=30;
clrb_SYNCO;
b4: d8 98 cbi 0x1b, 0 ; 27
b6: 8e e1 ldi r24, 0x1E ; 30
b8: 81 50 subi r24, 0x01 ; 1
while(i>0)i--;
ba: f1 f7 brne .-4 ; 0xb8 <__vector_1+0x14>
clrb_GATE;
bc: d9 98 cbi 0x1b, 1 ; 27
}
be: 8f 91 pop r24
c0: 0f 90 pop r0
c2: 0f be out 0x3f, r0 ; 63
c4: 0f 90 pop r0
c6: 1f 90 pop r1
c8: 18 95 reti
Je pourrais supposer que le compilateur a compris qu'un tel code est factice et qu'il le supprime, mais pourquoi conserve-t-il le même à la fin du code?
Existe-t-il des instructions du compilateur pour empêcher une telle optimisation?
Réponses:
Étant donné que dans un commentaire, vous dites que "chaque coche de CPU est digne", je suggère d'utiliser un assemblage en ligne pour faire votre boucle de retards comme vous le souhaitez. Cette solution est supérieure aux différentes
volatile
ou-O0
parce qu'elle indique clairement votre intention.Cela devrait faire l'affaire. La chose volatile est là pour dire au compilateur "Je sais que cela ne fait rien, gardez-le et faites-moi confiance". Les trois "instructions" asm sont assez explicites, vous pouvez utiliser n'importe quel registre au lieu de r24, je crois que le compilateur aime les registres inférieurs, donc vous voudrez peut-être utiliser un registre élevé. Après la première,
:
vous devez répertorier les variables c en sortie (en lecture et en écriture), et il n'y en a pas, après la seconde,:
vous devez répertorier les variables c en entrée (uniquement), encore une fois, il n'y en a pas, et le troisième paramètre est une liste séparée par des virgules de registres modifiés , dans ce cas r24. Je ne sais pas si vous devez également inclure le registre d'état puisque leZERO
drapeau change bien sûr, je ne l'ai pas inclus.éditez la réponse éditée comme OP demandé. Quelques notes.
Le
"+rm"
avant(i)
signifie que vous laisser le compilateur décident de placer i en m Emory ou dans un r egistrecanadiendesins. C'est une bonne chose dans la plupart des cas, car le compilateur peut mieux optimiser s'il est gratuit. Dans votre cas, je pense que vous ne souhaitez conserver que la contrainte r pour forcer i à être un registre.la source
c
variable au lieu du littéral que10
j'ai mentionné dans la réponse d'origine? J'essaie de lire les manuels du GCC concernant l'utilisation correcte de la construction asm mais c'est un peu obscurci pour moi maintenant. J'apprécierais beaucoup!Vous pouvez essayer de faire en sorte que la boucle fasse quelque chose. En l'état, le compilateur dit à juste titre "Cette boucle ne fait rien - je m'en débarrasserai".
Vous pouvez donc essayer une construction que j'utilise fréquemment:
Remarque: toutes les cibles du compilateur gcc n'utilisent pas la même syntaxe d'assemblage en ligne - vous devrez peut-être la modifier pour votre cible.
la source
Oui, vous pouvez supposer cela. Si vous déclarez la variable i comme volatile, vous dites au compilateur de ne pas optimiser sur i.
la source
register unsigned char volatile i __asm__("r1");
peut-être?i
volatile résout tout. Ceci est garanti par la norme C 5.1.2.3. Un compilateur conforme ne doit pas optimiser ces boucles s'ili
est volatil. Heureusement, GCC est un compilateur conforme. Il existe malheureusement de nombreux compilateurs C potentiels qui ne sont pas conformes à la norme, mais ce n'est pas pertinent pour cette question particulière. Il n'y a absolument aucun besoin d'assembleur en ligne.Après la première boucle
i
est une constante. L'initialisation dei
et la boucle ne font que produire une valeur constante. Rien dans la norme ne spécifie que cette boucle doit être compilée telle quelle. La norme ne dit rien non plus sur le timing. Le code compilé doit se comporter comme si la boucle était présente et c'est le cas. Vous ne pouvez pas dire de manière fiable que cette optimisation a été effectuée sous la norme (le timing ne compte pas).La deuxième boucle doit également être supprimée. Je considère que c'est un bug (ou une optimisation manquante) que ce n'est pas le cas. Après la boucle
i
est zéro constant. Le code doit être remplacé par une misei
à zéro.Je pense que GCC reste
i
purement pour la raison que vous effectuez un accès au port (opaque) pourrait affecteri
.Utilisation
pour faire croire à GCC que la boucle fait quelque chose.
la source