ARM Cortex-M Broken Binaries with -O2 and -O3 (-fschedule-insns)

Timo Sintonen via D.gnu d.gnu at puremagic.com
Sat Jul 22 00:07:33 PDT 2017


On Saturday, 22 July 2017 at 01:11:02 UTC, Mike wrote:
> On Friday, 21 July 2017 at 23:44:53 UTC, Mike wrote:
>
>> I'm getting broken binaries with -O2 and -O3.  I've nailed the 
>> culprit down to -fschedule-insns (i.e. if I add 
>> -fno-schedule-insns to -O2 or -O3, the binary works fine).
>>
>> I disassembled '-O2' and '-O2 -fno-schedule-insns' and 
>> compared them, but they were quite different all the way 
>> through.  No only because of address locations, but also 
>> different registers and even different opcodes.  (e.g. 'str 
>> r2, [sp, #12]' vs 'strd r1, r2, [sp, #8]')
>
> Interestingly, I added a stategically placed `asm { "nop"; }` 
> and my binary was able to execute further.  Comparing the 
> disassembly of the function I modified still showed quite a 
> significant difference.
>
> Working Binary
> -------------
> ldr	r2, [pc, #188]	; (8000c50 <hardwareInit+0x104>)
> ldr	r1, [pc, #188]	; (8000c54 <hardwareInit+0x108>)
> ldr	r3, [r2, #0]
> and.w	r3, r3, #780	; 0x30c
> orr.w	r3, r3, #37888	; 0x9400
> movs	r0, #0
> str	r3, [r2, #0]
> strb	r0, [r1, #0]
> ;-------------------------------------------------------
> nop                     ; My stategically placed nop
> ;-------------------------------------------------------
> ldr	r3, [pc, #172]	; (8000c58 <hardwareInit+0x10c>)
> ldr	r0, [pc, #176]	; (8000c5c <hardwareInit+0x110>)
> ldr	r4, [pc, #176]	; (8000c60 <hardwareInit+0x114>)
> ldr	r2, [pc, #180]	; (8000c64 <hardwareInit+0x118>)
> movs	r1, #1
> strb	r1, [r3, #0]
> ldr	r3, [r0, #0]
> orr.w	r3, r3, #49152	; 0xc000
> str	r3, [r0, #0]
> strb	r1, [r4, #0]
>
> Not Working Binary
> ------------------
> ldr	r0, [pc, #184]	; (8000c4c <hardwareInit+0x100>)
> ldr	r1, [pc, #184]	; (8000c50 <hardwareInit+0x104>)
> ldr	r2, [pc, #188]	; (8000c54 <hardwareInit+0x108>)
> ldr	r3, [r1, #0]
> ldr	r4, [pc, #188]	; (8000c58 <hardwareInit+0x10c>)
> movs	r5, #0
> strb	r5, [r0, #0]
> movs	r0, #1
> strb	r0, [r2, #0]
> ldr	r2, [r4, #0]
> ldr	r5, [pc, #180]	; (8000c5c <hardwareInit+0x110>)
> orr.w	r2, r2, #49152	; 0xc000
> and.w	r3, r3, #780	; 0x30c
> str	r2, [r4, #0]
> orr.w	r3, r3, #37888	; 0x9400
> ldr	r2, [pc, #168]	; (8000c60 <hardwareInit+0x114>)
> strb	r0, [r5, #0]
> str	r3, [r1, #0]
>
> By "Not Working" I mean this code gets stuck in the while loop
>
> PWR.CR.ODEN.value = true;
> while(!PWR.CSR.ODRDY.value) { }
>
> This is simply setting the "Overdrive Enable" register on the 
> power control peripheral of my hardware.  The documentation 
> states:
>
> To set or reset the ODEN bit, the HSI or HSE must be selected 
> as system clock.
>
> I'm setting the HSI prior to setting ODEN, but it appears that 
> maybe the compiler is reordering the instructions.  I still 
> need to investigate that further, but hopefully that provides a 
> little more insight.
>
> Mike

A quick answer without looking your code: this never worked 
properly because the compiler thinks the value is not changing 
and may be optimized out of the loop. After this the test inside 
while may also be optimized outside. Then the whole while thing 
which now has nothing to test and nothing inside the body can be 
optimized out.

I got this working because 'shared' meant 'volatile' in gdc but 
this is not true any more.
I did not yet look how you define your data type and how you 
access the data but it seems the compiler thinks it is an 
ordinary variable.

I made custom Volatile data type that uses those new compiler 
intrinsics and my sample program seems to work with gdc 7.
The only thing that does not work is exceptions. The exception 
code in runtime has changed a lot so I do not know whether it 
should work or not.



More information about the D.gnu mailing list