------- Comment #6 from jakub at gcc dot gnu dot org 2008-07-10 13:34 ------- More self-contained testcase: register unsigned long *r14 asm ("r14"); extern void abort (void);
__attribute__ ((noinline)) void test (void) { *++r14 = 31337; } int main () { unsigned long stack[2]; stack[0] = 0; stack[1] = 0; r14 = stack; test (); if (r14 != stack + 1 || *r14 != 31337) abort (); return 0; } We have: (insn 5 2 6 2 pr36753.c:7 (parallel [ (set (reg/f:DI 58 [ r14.1 ]) (plus:DI (reg/v:DI 43 r14 [ r14 ]) (const_int 8 [0x8]))) (clobber (reg:CC 17 flags)) ]) 279 {*adddi_1_rex64} (expr_list:REG_DEAD (reg/v:DI 43 r14 [ r14 ]) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil)))) (insn 6 5 7 2 pr36753.c:7 (set (reg/v:DI 43 r14 [ r14 ]) (reg/f:DI 58 [ r14.1 ])) 89 {*movdi_1_rex64} (nil)) (insn 7 6 0 2 pr36753.c:7 (set (mem:DI (reg/f:DI 58 [ r14.1 ]) [2 S8 A64]) (const_int 31337 [0x7a69])) 89 {*movdi_1_rex64} (expr_list:REG_DEAD (reg/f:DI 58 [ r14.1 ]) (nil))) before fwprop2, and: In insn 7, replacing (mem:DI (reg/f:DI 58 [ r14.1 ]) [2 S8 A64]) with (mem:DI (plus:DI (reg/v:DI 43 r14 [ r14 ]) (const_int 8 [0x8])) [2 S8 A64]) Changed insn 7 Wonder why nothing in fwprop.c checks modified_between_p, that would clearly say that reg:DI 43 r14 has been modified between the setter and use and thus the propagation is invalid. To Andrew: many ABIs have one or more fixed registers reserved, so you can use those as global register vars, or you can e.g. build with -ffixed-* to make sure even when you don't have the global register var declaration in some CU, it isn't randomly clobbered. Many projects rely heavily on global register vars, including the Linux kernel or e.g. glibc (in the latter it is used in libpthread for all thread specific stuff). From what I see, this fwprop bug isn't specific to global register vars, any REG, be it hard or pseudo, can be modified between the setter and user... -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36753