Pourquoi le compilateur n'utilise pas directement LSR

10

Salut, je travaille sur un projet utilisant un Arduino Uno (donc ATmega328p) où le timing est assez important et je voulais donc voir dans quelles instructions le compilateur convertissait mon code. Et là, j'en ai un uint8_tque je décale d'un bit vers la droite à chaque itération en utilisant data >>= 1et il semble que le compilateur ait traduit cela en 5 instructions ( dataen r24):

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

Mais si je regarde dans la documentation du jeu d'instructions, je vois une instruction qui fait exactement ceci: lsr r24

Dois-je ignorer quelque chose ou pourquoi le compilateur ne l'utilise-t-il pas également? Les registres r18et r19ne sont utilisés nulle part ailleurs.

J'utilise un Ardunio mais si j'ai raison, il utilise simplement le avr-gcccompilateur normal . C'est le code (découpé) qui génère la séquence:

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

Autant que je puisse voir, l'IDE Ardunino utilise le compilateur AVR gcc fourni par le système qui est la version 6.2.0-1.fc24. Les deux sont installés via le gestionnaire de packages et doivent donc être à jour.

xZise
la source
1
L'assemblage ne semble pas correspondre au code C.
Eugene Sh.
Eh bien, je l'ai compilé en utilisant l'IDE Ardunio et ensuite utilisé avr-objdumpsur le fichier elf… Qu'est-ce qui ne semble pas correspondre?
xZise
1
@Eugene Sh .: Il ne correspond au code C. Cela correspond juste à la lignedata >>= 1;
Curd
1
C'est l'un des cas où "utiliser les décalages au lieu de la division" n'est pas le bon conseil. Si vous faites / = 2 à la place, le compilateur générera lsr r24; (Astuce: essayez l'explorateur gcc pour jouer avec la génération de code asm)
PlasmaHH
Quel compilateur? Quel processeur? Il devrait vraiment être évident que ces informations sont nécessaires pour que la question ait un sens.
Olin Lathrop

Réponses:

18

Selon la spécification du langage C, toute valeur dont la taille est inférieure à la taille de int(dépend du compilateur particulier; dans votre cas, a une intlargeur de 16 bits) impliquée dans une opération (dans votre cas >>) est convertie en un intavant l'opération.
Ce comportement du compilateur est appelé promotion d'entiers .

Et c'est exactement ce que le compilateur a fait:

  • r19 = 0 est le MSByte de la valeur promue entière de data.
  • (r19, r18) représente la valeur totale promue entière dataqui est ensuite décalée d'un bit vers la droite par asr r19et ror 18.
  • Le résultat est ensuite coulé à votre implicitement la uint8_tvariable data:
    mov r24, r18, à savoir le MSByte à R19 est jeté.

Edit:
Bien sûr, le complice pourrait optimiser le code.
En essayant de reproduire le problème, j'ai trouvé qu'au moins avec la version avr-gcc 4.9.2, le problème ne se produit pas. Il crée un code très efficace, c'est-à-dire que la ligne C data >>= 1;est compilée en une seule lsr r24instruction. Alors peut-être que vous utilisez une très ancienne version du compilateur.

fromage blanc
la source
2
Ce n'est pas un gaspillage total car parfois vous avez besoin du code non optimisé pour le débogage au niveau assembleur. Ensuite, vous êtes très heureux si vous avez du code non optimisé.
Curd
3
Si je me souviens bien, -mint8 est le drapeau pour faire des entiers 8 bits. Cependant, cela a beaucoup d'effets secondaires indésirables. Désolé, je ne me souviens plus vraiment de ce qu'ils étaient maintenant, mais je n'ai jamais utilisé le drapeau à cause d'eux. J'ai passé beaucoup de temps à comparer avr-gcc à un compilateur commercial il y a plusieurs années.
Jon
1
Oh c'est vrai, la norme C exige que les entiers soient au moins 16 bits, donc l'utilisation de -mint8 casse toutes les bibliothèques.
Jon
9
Nigel Jones a dit dans "Code C efficace pour les microcontrôleurs 8 bits" quelque chose comme: "... Les règles de promotion des nombres entiers de C sont probablement le crime le plus odieux commis contre ceux d'entre nous qui travaillent dans le monde 8 bits" ...
Dirceu Rodrigues Jr
1
@Jonas Wielicki: la meilleure solution au problème est d'utiliser un meilleur compilateur. Par exemple, avec avr-gcc version 4.9.2, je ne peux pas reproduire le problème: pour la ligne de code C, d >>= 1;je reçois une seule lsr r24instruction. Peut-être que xZise utilise une très ancienne version du compilateur.
Curd