Warum verwendet der Compiler nicht direkt LSR?

10

Hallo, ich habe an einem Projekt mit einem Arduino Uno (also ATmega328p) gearbeitet, bei dem das Timing sehr wichtig ist, und wollte wissen, in welche Anweisungen der Compiler meinen Code konvertiert. Und da drin habe ich eine, uint8_tdie ich bei jeder Iteration mit ein Bit nach rechts verschiebe, data >>= 1und es scheint, dass der Compiler dies in 5 Anweisungen übersetzt hat ( dataist in r24):

mov     r18, r24
ldi     r19, 0x00
asr     r19
ror     r18
mov     r24, r18

Wenn ich mir aber die Dokumentation zum Befehlssatz ansehe, sehe ich eine Anweisung, die genau dies tut: lsr r24

Übersehe ich etwas oder warum verwendet der Compiler dies nicht auch? Die Register r18und r19werden nirgendwo anders verwendet.

Ich benutze ein Ardunio, aber wenn ich richtig bin, benutzt es nur den normalen avr-gccCompiler. Dies ist der Code (getrimmt), der die Sequenz generiert:

ISR(PCINT0_vect) {
    uint8_t data = 0;
    for (uint8_t i = 8; i > 0; --i) {
//        asm volatile ("lsr %0": "+w" (data));
        data >>= 1;
        if (PINB & (1 << PB0))
            data |= 0x80;
    }
    host_data = data;
}

Soweit ich sehen kann, verwendet die Ardunino-IDE den vom System bereitgestellten AVR-gcc-Compiler, der Version 6.2.0-1.fc24 ist. Beide werden über die Paketverwaltung installiert und sollten daher auf dem neuesten Stand sein.

xZise
quelle
1
Die Assembly scheint nicht dem C-Code zu entsprechen.
Eugene Sh.
Nun, ich habe es mit der Ardunio-IDE kompiliert und dann avr-objdumpfür die Elf-Datei verwendet. Was scheint nicht zu entsprechen?
xZise
1
@Eugene Sh .: Es tut entspricht den C - Code. Es entspricht nur der Liniedata >>= 1;
Curd
1
Dies ist einer der Fälle, in denen "Verschiebungen anstelle von Teilung verwenden" der falsche Rat ist. Wenn Sie stattdessen / = 2 ausführen, generiert der Compiler lsr r24. (Tipp: Versuchen Sie den GCC-Explorer, um mit der Asm-Code-Generierung
herumzuspielen.
Welcher Compiler? Welcher Prozessor? Es sollte wirklich offensichtlich sein, dass dies notwendige Informationen sind, damit die Frage Sinn ergibt.
Olin Lathrop

Antworten:

18

Gemäß der C-Sprachspezifikation wird jeder Wert, dessen Größe kleiner als die Größe von int(abhängig vom jeweiligen Compiler; in Ihrem Fall int16 Bit breit) ist, der an einer Operation (in Ihrem Fall >>) beteiligt ist, auf einen Wert intvor der Operation übertragen.
Dieses Verhalten des Compilers wird als Integer-Promotion bezeichnet .

Und genau das hat der Compiler getan:

  • r19 = 0 ist der MSByte des ganzzahligen heraufgestuften Werts von data.
  • (r19, r18) repräsentiert die Gesamt ganzzahligen Wert gefördert , datadaß dann nach rechts um ein Bit verschoben wird asr r19und ror 18.
  • Das Ergebnis wird dann implizit auf Ihre uint8_tVariable zurückgesetzt data:
    mov r24, r18dh der MSByte in r19 wird weggeworfen.

Bearbeiten:
Natürlich könnte der Complier den Code optimieren.
Beim Versuch, das Problem zu reproduzieren, stellte ich fest, dass das Problem zumindest mit avr-gcc Version 4.9.2 nicht auftritt. Es wird sehr effizienter Code erstellt, dh die C-Zeile data >>= 1;wird zu nur einer einzigen lsr r24Anweisung kompiliert . Vielleicht verwenden Sie eine sehr alte Compilerversion.

Quark
quelle
2
Es ist keine völlige Verschwendung, da Sie manchmal den nicht optimierten Code zum Debuggen auf Assembler-Ebene benötigen. Dann freuen Sie sich sehr, wenn Sie nicht optimierten Code haben.
Curd
3
Wenn ich mich richtig erinnere, ist -mint8 das Flag, um ganze Zahlen 8-Bit zu machen. Dies hat jedoch viele unerwünschte Nebenwirkungen. Entschuldigung, ich kann mich nicht genau erinnern, was sie jetzt waren, aber ich habe die Flagge wegen ihnen nie benutzt. Ich habe vor vielen Jahren viel Zeit damit verbracht, avr-gcc mit einem kommerziellen Compiler zu vergleichen.
Jon
1
Oh, das stimmt, der C-Standard verlangt, dass Ganzzahlen mindestens 16-Bit sind, sodass die Verwendung von -mint8 alle Bibliotheken zerstört.
Jon
9
Nigel Jones sagte in "Effizienter C-Code für 8-Bit-Mikrocontroller" so etwas wie: "... Die Regeln für die ganzzahlige Werbung von C sind wahrscheinlich das abscheulichste Verbrechen gegen diejenigen von uns, die in der 8-Bit-Welt arbeiten" ...
Dirceu Rodrigues Jr
1
@ Jonas Wielicki: Die beste Lösung für das Problem ist die Verwendung eines besseren Compilers. ZB mit avr-gcc Version 4.9.2 kann ich das Problem nicht reproduzieren: Für die C-Codezeile d >>= 1;bekomme ich nur eine einzige lsr r24Anweisung. Möglicherweise verwendet xZise eine sehr alte Compilerversion.
Curd