Questo codice (braccio):GCC genera codice differente a seconda schiera di valori di indice
void blinkRed(void)
{
for(;;)
{
bb[0x0008646B] ^= 1;
sys.Delay_ms(14);
}
}
... viene compilato in folowing asm-codice:
08000470: ldr r4, [pc, #20] ; (0x8000488 <blinkRed()+24>) // r4 = 0x422191ac
08000472: ldr r6, [pc, #24] ; (0x800048c <blinkRed()+28>)
08000474: movs r5, #14
08000476: ldr r3, [r4, #0]
08000478: eor.w r3, r3, #1
0800047c: str r3, [r4, #0]
0800047e: mov r0, r6
08000480: mov r1, r5
08000482: bl 0x80001ac <CSTM32F100C6::Delay_ms(unsigned int)>
08000486: b.n 0x8000476 <blinkRed()+6>
È ok.
Ma, se mi limito a cambiare indice di array (-0x400
) ....
void blinkRed(void)
{
for(;;)
{
bb[0x0008606B] ^= 1;
sys.Delay_ms(14);
}
}
... Ho codice non ottimizzato così:
08000470: ldr r4, [pc, #24] ; (0x800048c <blinkRed()+28>) // r4 = 0x42218000
08000472: ldr r6, [pc, #28] ; (0x8000490 <blinkRed()+32>)
08000474: movs r5, #14
08000476: ldr.w r3, [r4, #428] ; 0x1ac
0800047a: eor.w r3, r3, #1
0800047e: str.w r3, [r4, #428] ; 0x1ac
08000482: mov r0, r6
08000484: mov r1, r5
08000486: bl 0x80001ac <CSTM32F100C6::Delay_ms(unsigned int)>
0800048a: b.n 0x8000476 <blinkRed()+6>
La differenza è che in il primo caso r4
viene caricato con l'indirizzo di destinazione immediatamente (0x422191ac
) e quindi l'accesso alla memoria viene eseguito con istruzioni a 2 byte, ma nel secondo caso lo r4
viene caricato con un indirizzo intermedio (0x42218000
) e quindi l'accesso alla memoria viene eseguito con l'istruzione di 4 byte con offset (+0x1ac
) all'indirizzo di destinazione (0x422181ac
).
Perché il compilatore lo fa?
che uso: arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -g2 -Wall -O1 -std=gnu++14 -fno-exceptions -fno-use-cxa-atexit -fstrict-volatile-bitfields -c -DSTM32F100C6T6B -DSTM32F10X_LD_VL
bb
è:
__attribute__ ((section(".bitband"))) volatile u32 bb[0x00800000];
In .ld
esso è definito come: in MEMORY
sezione:
BITBAND(rwx): ORIGIN = 0x42000000, LENGTH = 0x02000000
in SECTIONS
sezione:
.bitband (NOLOAD) :
SUBALIGN(0x02000000)
{
KEEP(*(.bitband))
} > BITBAND
Ummm ... non sono sicuro se questo è rilevante, ma ... anche la versione ottimizzata funzionerà? Forse ci sono alcune condizioni preliminari per il carico più veloce.Queste informazioni indicano se si tratta del problema dell'ottimizzatore o dell'architettura. – luk32
Entrambe le versioni funzionano. Non riesco a immaginare alcun presupposto disponibile in uno dei due casi e non disponibile in altri. Ho modificato l'indice passo dopo passo e ho scoperto che la seconda versione viene compilata se l'indice di array è compreso nell'intervallo da 0x00086020 a 0x000863FF. Se l'indice dell'array è fuori da questo intervallo, viene compilata la prima versione (ottimizzata). – Woodoo
Che tipo di ARM? Probabilmente un problema di allineamento della memoria. – Unimportant