http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56476
Bug #: 56476 Summary: ARM volatile writes/str creates superfluous and uncalled for read/ldr with -Os Classification: Unclassified Product: gcc Version: 4.7.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassig...@gcc.gnu.org ReportedBy: j...@embeddedarm.com Gcc 4.7.1 crosscompiler ARM EABI target, x86 Linux host. In the below code, there are only writes to the "regs" volatile unsigned int *. Yet, compiling with "-Os", "-O2", or "-O -ftree-vrp" yields code that will do an uncalled for ldrne in the assembler output. This is bad as this volatile unsigned int * represents hardware registers where bus reads have side-effects and reading a value and then writing the same value back to the same location is not an equivalent operation to doing nothing at all. Several gcc versions have been tested and all but some really old 3.3.4 gcc toolchain exhibited this. (4.6.1 and a 4.4.4 were tested also and had the bug) //Jesse Off volatile unsigned int * regs; void test(void) { int i, x; regs[0x708 / 4] = 0xdeadbeef; for (i = 0xbad; i >= 0; i--) { if (i == 1) regs[0x708 / 4] = 0xbeefdead; for (x = 1; x >= 0; x--) { regs[0x708 / 4] = 0xbadcab; regs[0x704 / 4] = x; } } } /* BROKEN ASM!!!! (Compiled with -Os) 00000000 <test>: 0: e59f3048 ldr r3, [pc, #72] ; 50 <test+0x50> 4: e59f2048 ldr r2, [pc, #72] ; 54 <test+0x54> 8: e5933000 ldr r3, [r3] c: e92d4010 push {r4, lr} 10: e59f1040 ldr r1, [pc, #64] ; 58 <test+0x58> 14: e5832708 str r2, [r3, #1800] ; 0x708 18: e59f203c ldr r2, [pc, #60] ; 5c <test+0x5c> 1c: e3a04001 mov r4, #1 20: e3a0c000 mov ip, #0 24: e3520001 cmp r2, #1 28: 15930708 ldrne r0, [r3, #1800] ; 0x708 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- NOT SAFE! 2c: 059f002c ldreq r0, [pc, #44] ; 60 <test+0x60> 30: e2522001 subs r2, r2, #1 34: e5830708 str r0, [r3, #1800] ; 0x708 38: e5831708 str r1, [r3, #1800] ; 0x708 3c: e5834704 str r4, [r3, #1796] ; 0x704 40: e5831708 str r1, [r3, #1800] ; 0x708 44: e583c704 str ip, [r3, #1796] ; 0x704 48: 2afffff5 bcs 24 <test+0x24> 4c: e8bd8010 pop {r4, pc} 50: 00000000 .word 0x00000000 54: deadbeef .word 0xdeadbeef 58: 00badcab .word 0x00badcab 5c: 00000bad .word 0x00000bad 60: beefdead .word 0xbeefdead RIGHT AND WORKING (Compiled with -O) (no superfluous ldr on a volatile) 00000000 <test>: 0: e52d4004 push {r4} ; (str r4, [sp, #-4]!) 4: e59f304c ldr r3, [pc, #76] ; 58 <test+0x58> 8: e5933000 ldr r3, [r3] c: e59f2048 ldr r2, [pc, #72] ; 5c <test+0x5c> 10: e5832708 str r2, [r3, #1800] ; 0x708 14: e59f2044 ldr r2, [pc, #68] ; 60 <test+0x60> 18: e59f1044 ldr r1, [pc, #68] ; 64 <test+0x64> 1c: e3a0c001 mov ip, #1 20: e3a00000 mov r0, #0 24: e59f403c ldr r4, [pc, #60] ; 68 <test+0x68> 28: ea000001 b 34 <test+0x34> 2c: e3520001 cmp r2, #1 30: 05834708 streq r4, [r3, #1800] ; 0x708 34: e5831708 str r1, [r3, #1800] ; 0x708 38: e583c704 str ip, [r3, #1796] ; 0x704 3c: e5831708 str r1, [r3, #1800] ; 0x708 40: e5830704 str r0, [r3, #1796] ; 0x704 44: e2422001 sub r2, r2, #1 48: e3720001 cmn r2, #1 4c: 1afffff6 bne 2c <test+0x2c> 50: e8bd0010 pop {r4} 54: e12fff1e bx lr 58: 00000000 .word 0x00000000 5c: deadbeef .word 0xdeadbeef 60: 00000bad .word 0x00000bad 64: 00badcab .word 0x00badcab 68: beefdead .word 0xbeefdead */