Bon, alors j'ai fait quelques tests et je conclus à ma troisième possibilité : il y a un bug. Kevin ?
En fait -Os déconne complètement, la preuve, ça optimise mieux avec -O :
j'ai compilé ce code :
extern int flag, machin, truc;
void bouclecomplexe () {
int i;
asm ("|for de base");
for (i = 0; i < 42; i++) {
if (flag) machin |= truc;
else machin &= truc;
}
asm ("|for à l'envers");
for (i = 42; i--; ) {
if (flag) machin |= truc;
else machin &= truc;
}
asm ("|do-while avec --i");
i = 42; do {
if (flag) machin |= truc;
else machin &= truc;
} while (--i);
asm ("|do-while avec i--");
i = 41; do {
if (flag) machin |= truc;
else machin &= truc;
} while (i--);
}
Voici ce que donne -Os :
bouclecomplexe:
link.w %a6,#0
movm.l #0x1c00,-(%sp)
#APP
|for de base
#NO_APP
clr.w %d3
move.w flag,%d5
move.w machin,%d2
move.w truc,%d4
jbra .L2
.even
.L8:
move.w %d2,%d1
addq.w #1,%d3
or.w %d4,%d2
tst.w %d5
jbne .L2
move.w %d1,%d2
and.w %d4,%d2
.L2:
cmp.w #41,%d3
jble .L8
move.w %d2,machin
#APP
|for à l'envers
#NO_APP
moveq.l #42,%d3
move.w flag,%d4
move.w truc,%a0
jbra .L32
.even
.L15:
move.w %d2,%d1
move.w %a0,%d0
or.w %d0,%d2
tst.w %d4
jbne .L32
move.w %d1,%d2
and.w %d0,%d2
.L32:
dbra %d3,.L15
move.w %d2,machin
#APP
|do-while avec --i
#NO_APP
moveq.l #42,%d3
move.w flag,%a1
move.w truc,%d4
.L16:
move.w %a1,%d5
move.w %d2,%d1
move.w %d3,%a0
subq.w #1,%a0
or.w %d4,%d2
tst.w %d5
jbne .L18
move.w %d1,%d2
and.w %d4,%d2
.L18:
move.w %a0,%d3
jbne .L16
move.w %d2,machin
#APP
|do-while avec i--
#NO_APP
moveq.l #41,%d3
move.w %d2,%d1
move.w truc,%d2
.L22:
move.w %d3,%a0
subq.w #1,%a0
tst.w %d5
jbeq .L25
or.w %d2,%d1
jbra .L24
.even
.L25:
and.w %d2,%d1
.L24:
move.w %a0,%d3
cmp.w #-1,%d3
jbne .L22
move.w %d1,machin
movm.l (%sp)+,#0x38
unlk %a6
rts
Non seulement il pessimise les boucles comme un gros taré, mais en plus il fait des manipulations de registres totalement ésotériques...
Par contre, avec -O on a ce à quoi on s'attend : les solutions de BiHi et Pollux donnent toutes deux exactement le même résultat (initialisation à 41 et dbra à la fin) (dbra = dbf ??), mais celle de PpHd donne un subq suivi de bne.
Avec -O2, c'est encore mieux car il retourne la première boucle (tout de même !) mais il ne la finit pas par un dbra : il met subq suivi de jbpl (c'est quoi jbpl ?) À part ça il ne change pas grand-chose, sauf qu'il modifie les if pour que dans un cas ça branche deux fois et dans l'autre pas du tout, au lieu de une fois dans chaque (je ne comprends pas l'intérêt, mais au moins ça ne change pas la taille...)
Alors j'ai cherché s'il y avait un flag spécifique activé par -Os et pas par -O2 qui faisait tout merder, mais je n'en ai pas trouvé dans la doc (d'ailleurs la doc est fausse par endroits, elle dit que -fomit-frame-pointer est activé par -Os, or ce n'est pas le cas...)