This case looks like this: typedef struct { unsigned char a : 2; unsigned char b : 3; unsigned char c : 1; unsigned char d : 1; unsigned char e : 1; } a_struct;
foo (flags) a_struct *flags; { return (flags->c != 0 || flags->d != 1 || flags->e != 1 || flags->a != 2 || flags->b != 3); } main () { a_struct flags; flags.c = 0; flags.d = 1; flags.e = 1; flags.a = 2; flags.b = 3; if (foo (&flags) != 0) abort (); else exit (0); } at Os, foo gets inlined into main, so after tree opts, we have: ;; Function main (main) main () { struct a_struct flags; <bb 0>: flags.c = 0; flags.d = 1; flags.e = 1; flags.a = 2; flags.b = 3; if (BIT_FIELD_REF <flags, 8, 0> != 206) goto <L0>; else goto <L1>; <L0>:; abort (); <L1>:; exit (0); } The *initial* RTL (ie from 00.expand), looks like this: ;; ;; Full RTL generated for this function: ;; (note 2 0 5 NOTE_INSN_DELETED) ;; Start of basic block 0, registers live: (nil) (note 5 2 3 0 [bb 0] NOTE_INSN_BASIC_BLOCK) (note 3 5 4 0 NOTE_INSN_FUNCTION_BEG) (note 4 3 6 0 NOTE_INSN_DELETED) ;; End of basic block 0, registers live: (nil) ;; Start of basic block 1, registers live: (nil) (note 6 4 8 1 [bb 1] NOTE_INSN_BASIC_BLOCK) (insn 8 6 10 1 (parallel [ (set (reg/v:QI 58 [ flags ]) (and:QI (reg/v:QI 58 [ flags ]) (const_int -33 [0xffffffdf]))) (clobber (reg:CC 17 flags)) ]) -1 (nil) (nil)) (insn 10 8 12 1 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int 64 [0x40]))) (clobber (reg:CC 17 flags)) This is *already* wrong, AFAICT, because reg:QI 58 is uninitialized, and we are trying to use it's value. Why do we do this? This causes problems on the dataflow branch (or will RSN when kenny commits the latest upates). We don't mark 58 as live at the beginning of block 0 (because it isn't special in any way, isn't set in entry, and isn't a hard reg, so there is no reason to mark it live incoming to bb 0). Marking uninitialized registers live everywhere gives you very imprecise dataflow information when they are only initialized along some paths (which is why things like "make_accurate_live_analysis" compute liveness without them. Dataflow-branch does the equivalent of make_accurate_live_analysis *all the time*). Liveness on mainline looks like ;; Start of basic block 0, registers live: 7 [sp] 16 [argp] 20 [frame] 58 (note 6 3 8 0 [bb 0] NOTE_INSN_BASIC_BLOCK) (insn 8 6 10 0 (parallel [ (set (reg/v:QI 58 [ flags ]) (and:QI (reg/v:QI 58 [ flags ]) (const_int -33 [0xffffffdf]))) (clobber (reg:CC 17 flags)) ]) 212 {*andqi_1} (nil) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) (insn 10 8 12 0 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int 64 [0x40]))) (clobber (reg:CC 17 flags)) ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 8 (nil)) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) (insn 12 10 15 0 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int -64 [0xffffffc0]))) (clobber (reg:CC 17 flags)) ]) 227 {*iorqi_1} (nil) (Note 58 ends up live because the dataflow isn't smart enough to know that it isn't *set anywhere*) On dataflow, we have (note bbs are renumbered so exit and entry are no longer negative, a patch is forthcoming for this): ;; Start of basic block 2, registers live: 7 [sp] 16 [argp] 20 [frame] (note 6 3 8 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (insn 8 6 10 2 (parallel [ (set (reg/v:QI 58 [ flags ]) (and:QI (reg/v:QI 58 [ flags ]) (const_int -33 [0xffffffdf]))) (clobber (reg:CC 17 flags)) ]) 212 {*andqi_1} (nil) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) (insn 10 8 12 2 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int 64 [0x40]))) (clobber (reg:CC 17 flags)) ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 8 (nil)) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) (insn 12 10 15 2 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int -128 [0xffffff80]))) (clobber (reg:CC 17 flags)) ]) 227 {*iorqi_1} (insn_list:REG_DEP_TRUE 10 (nil)) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) Combine, now freed of its shackles, does this: (note 8 6 10 2 NOTE_INSN_DELETED) (note 10 8 12 2 NOTE_INSN_DELETED) (insn 12 10 15 2 (parallel [ (set (reg/v:QI 58 [ flags ]) (ior:QI (reg/v:QI 58 [ flags ]) (const_int -64 [0xffffffc0]))) (clobber (reg:CC 17 flags)) ]) 227 {*iorqi_1} (nil) (expr_list:REG_UNUSED (reg:CC 17 flags) (nil))) and then the test program crashes depending on what value eax ends up getting at the start of main (IE if you run it 10 times, it will abort probably twice).