Ich kann nicht verstehen, warum der GCC-Compiler einen Teil meines Codes ausschneidet, während er absolut denselben in der Nachbarschaft beibehält?
Der C-Code:
#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;
}
Der entsprechende Teil von LSS (Assembler-Datei, erstellt vom Compiler):
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
Ich könnte davon ausgehen, dass der Compiler herausfindet, dass ein solcher Code ein Dummy ist, und ihn ausschneidet, aber warum wird am Ende des Codes derselbe beibehalten?
Gibt es Compiler-Anweisungen, um eine solche Optimierung zu verhindern?
Da Sie in einem Kommentar angeben, dass "jeder CPU-Tick wertvoll ist", schlage ich vor, eine Inline-Assemblierung zu verwenden, um Ihre Verzögerungsschleife so zu gestalten, wie Sie es möchten. volatile
Diese Lösung ist den verschiedenen oder überlegen, -O0
weil sie deutlich macht, was Ihre Absicht ist.
unsigned char i = 10;
__asm__ volatile ( "loop: subi %0, 0x01\n\t"
" brne loop"
: "+rm" (i)
: /* no inputs */
: /* no dirty registers to decleare*/);
Das sollte reichen. Das flüchtige Ding ist da, um dem Compiler zu sagen: "Ich weiß, dass das nichts bringt, behalte es einfach und vertraue mir". Die drei asm "Anweisungen" sind ziemlich selbsterklärend, Sie können jedes Register anstelle von r24 verwenden, ich glaube, der Compiler mag niedrigere Register, also sollten Sie vielleicht ein hohes verwenden. Nach dem ersten :
sollten Sie c-Variablen für die Ausgabe (Lesen und Schreiben) auflisten, und es gibt keine, nach dem zweiten :
sollten Sie c-Variablen für die Eingabe (nur) auflisten, wieder gibt es keine, und der dritte Parameter ist eine durch Kommas getrennte Liste geänderter Register , in diesem Fall r24. Ich bin mir nicht sicher, ob Sie auch das Statusregister einbeziehen sollten, da sich das ZERO
Flag natürlich ändert, ich habe es nicht eingeschlossen.
Bearbeiten Sie die bearbeitete Antwort wie von OP angefordert. Einige Notizen.
Das "+rm"
Before (i)
bedeutet, dass Sie den Compiler entscheiden lassen, i in den Speicher oder in ein Register zu stellen. Das ist in den meisten Fällen eine gute Sache, da der Compiler besser optimieren kann, wenn er kostenlos ist. In Ihrem Fall glaube ich, dass Sie nur die r-Einschränkung beibehalten möchten, um i zu zwingen, ein Register zu sein.
c
Variable anstelle des Literals zu akzeptieren, 10
das ich in der ursprünglichen Antwort erwähnt habe? Ich versuche, die GCC-Handbücher bezüglich der richtigen Verwendung der Asm -Konstruktion zu lesen, aber das ist mir jetzt etwas unklar. Ich wäre sehr dankbar!Sie könnten versuchen, die Schleife tatsächlich etwas tun zu lassen. So wie es aussieht, sagt der Compiler zu Recht "Diese Schleife macht nichts - ich werde sie los".
Sie könnten also ein Konstrukt ausprobieren, das ich häufig verwende:
int i;
for (i = 0; i < 10; i++) {
asm volatile ("nop");
}
Hinweis: Nicht alle Ziele für den gcc-Compiler verwenden dieselbe Inline-Assembly-Syntax – Sie müssen sie möglicherweise für Ihr Ziel anpassen.
Ja, davon könnte man ausgehen. Wenn Sie die Variable i als flüchtig deklarieren, teilen Sie dem Compiler mit, auf i nicht zu optimieren.
i
Leider sagt dies dem Compiler nicht nur etwas über die Optimierung, sondern zwingt einen auch dazu, die Variable im RAM
zuzuweisen, sodass mein Code erheblich größer und langsamer wird. In meinem Fall ist jeder CPU-Tick wert, daher möchte ich einen Weg finden, die Optimierung möglichst inline zu steuern.i
Einfügen eines Registers bereits eine Optimierung ist, daher ist der erste Kommentar von @Roman ein Missverständnis.register unsigned char volatile i __asm__("r1");
vielleicht?i
als flüchtig löst alles. Dies wird durch den C-Standard 5.1.2.3 garantiert. Ein konformer Compiler darf diese Schleifen nicht wegoptimieren, wenn sie i
flüchtig ist. Glücklicherweise ist GCC ein konformer Compiler. Leider gibt es viele Möchtegern-C-Compiler, die nicht dem Standard entsprechen, aber das ist für diese spezielle Frage irrelevant. Es ist absolut kein Inline-Assembler erforderlich.Nach der ersten Schleife i
ist eine Konstante. Die Initialisierung von i
und der Schleife bewirkt nichts anderes, als einen konstanten Wert zu erzeugen. Nichts im Standard legt fest, dass diese Schleife unverändert kompiliert werden muss. Auch über das Timing sagt die Norm nichts aus. Der kompilierte Code muss sich so verhalten, als wäre die Schleife vorhanden, und dies ist der Fall. Sie können nicht zuverlässig sagen, dass diese Optimierung unter dem Standard durchgeführt wurde (Timing zählt nicht).
Die zweite Schleife sollte ebenfalls gelöscht werden. Ich halte es für einen Fehler (oder eine fehlende Optimierung), was es nicht ist. Nach der Schleife i
ist konstant Null. Der Code sollte durch Setzen i
auf Null ersetzt werden.
Ich denke GCC hält i
rein aus dem Grund rum, dass man einen (undurchsichtigen) Portzugriff beeinflussen könnte i
.
Verwenden
asm volatile ("nop");
um GCC dazu zu bringen zu glauben, dass die Schleife etwas tut.
Wladimir Cravero
Roman Matwejew
i
im RAM zugewiesen wurdeWladimir Cravero
Wladimir Cravero
Roman Matwejew
Cort Ammon
Ilmari Karonen
Roman Matwejew
Zufällig832
Roman Matwejew
Marc Glisse
Stefano Sanfilippo
i
von10
bis0
, aber der aktualisierte Wert wird nie verwendet: Nach der Schleife gibt es ein define (i = 30
), aber keine Verwendung (wiey = i + 1
). Was auch immer der Werti
vor demi = 30
Teil hatte, ist also nicht relevant. Diewhile
Schleife wird als sinnlos markiert und der entsprechende Code wird nicht ausgegeben.Wladimir Cravero