Perché il compilatore non utilizza direttamente LSR


10

Ciao, ho lavorato su un progetto usando un Arduino Uno (quindi ATmega328p) in cui il tempismo è piuttosto importante e quindi volevo vedere in quali istruzioni il compilatore stava convertendo il mio codice. E lì ho un uint8_tche sposto un po 'a destra su ogni iterazione usando data >>= 1e sembra che il compilatore abbia tradotto questo in 5 istruzioni ( dataè in r24):

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

Ma se guardo nella documentazione del set di istruzioni vedo un'istruzione che fa esattamente questo: lsr r24

Trascuro qualcosa o perché il compilatore non usa anche questo? I registri r18e r19non vengono utilizzati altrove.

Sto usando un Ardunio ma se ho ragione usa solo il normale avr-gcccompilatore. Questo è il codice (tagliato) che genera la sequenza:

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;
}

Per quanto posso vedere, l'IDE di Ardunino sta usando il compilatore gcc AVR fornito dal sistema che è la versione 6.2.0-1.fc24. Entrambi sono installati tramite il gestore dei pacchetti, quindi dovrebbe essere aggiornato.


1
L'assembly non sembra corrispondere al codice C.
Eugene Sh.

Bene, l'ho compilato usando l'IDE di Ardunio e poi l'ho usato avr-objdumpsul file elf ... Cosa sembra non corrispondere?
xZise

1
@Eugene Sh .: Si fa corrisponde al codice C. Corrisponde solo alla rigadata >>= 1;
Curd

1
Questo è uno dei casi in cui "usare i turni anziché la divisione" è un consiglio sbagliato. Se lo fai / = 2 invece il compilatore genererà lsr r24; (consiglio: prova il gcc explorer a giocare con la generazione del codice asm)
PlasmaHH

Quale compilatore? Quale processore? Dovrebbe essere ovvio che si tratta di informazioni necessarie affinché la domanda abbia un senso.
Olin Lathrop,

Risposte:


18

Secondo le specifiche del linguaggio C, qualsiasi valore la cui dimensione è inferiore alla dimensione di int(dipende dal particolare compilatore; nel tuo caso intè largo 16 bit) coinvolto in qualsiasi operazione (nel tuo caso >>) viene trasmesso a intprima dell'operazione.
Questo comportamento del compilatore è chiamato promozione di numeri interi .

Ed è esattamente quello che ha fatto il compilatore:

  • r19 = 0 è l'MSByte del valore intero promosso di data.
  • (r19, r18) rappresenta il valore intero intero promosso datache viene quindi spostato a destra di un bit di asr r19e ror 18.
  • Il risultato è quindi implicitamente gettato di nuovo al vostro uint8_tvariabile data:
    mov r24, r18, vale a dire il MSByte in r19 viene gettato via.

Modifica:
ovviamente il complier potrebbe ottimizzare il codice.
Cercando di riprodurre il problema, ho scoperto che almeno con avr-gcc versione 4.9.2 il problema non si verifica. Crea un codice molto efficiente, ovvero la linea C data >>= 1;viene compilata in una sola lsr r24istruzione. Quindi forse stai usando una versione del compilatore molto vecchia.


2
Non è uno spreco totale perché a volte è necessario il codice non ottimizzato per il debug a livello di assemblatore. Quindi sei molto contento se hai un codice non ottimizzato.
Cagliata

3
Se ricordo bene, -mint8 è il flag per creare numeri interi a 8 bit. Tuttavia, questo ha molti effetti collaterali indesiderati. Mi dispiace, non riesco proprio a ricordare cosa fossero adesso, ma non ho mai usato la bandiera a causa loro. Ho trascorso molto tempo a confrontare avr-gcc con un compilatore commerciale molti anni fa.
Jon

1
Oh, è vero, lo standard C richiede che gli interi siano almeno a 16 bit, quindi l'uso di -mint8 interrompe tutte le librerie.
Jon

9
Nigel Jones ha detto nel "Codice C efficiente per i microcontrollori a 8 bit" qualcosa del tipo: "... Le regole di promozione dei numeri interi di C sono probabilmente il crimine più atroce commesso contro quelli di noi che lavorano nel mondo a 8 bit" ...
Dirceu Rodrigues Jr

1
@Jonas Wielicki: la migliore soluzione al problema è usare un compilatore migliore. Ad esempio con avr-gcc versione 4.9.2 non riesco a riprodurre il problema: per la riga di codice C d >>= 1;ottengo solo una singola lsr r24istruzione. Forse xZise sta usando una versione del compilatore molto vecchia.
Cagliata
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.