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