The r8c/m16c family cannot shift by more than 16 bits at a time ever, or 8 bits at a time with constant shifts. So, to do a variable number of shift on a 32 bit value, it needs to emit a conditional, turning the attached example into this:
i = 0xfffff; if (j >= 16) { i >>= 8; i >>= 8; j -= 16; } ... Combine (rightfully) knows that i becomes the constant 0xf and replaces the two constant shifts with it. However, it doesn't update the life information. So, we have a basic block (#3 below) which has register 28 live, but being assigned (i.e. it's really dead). GCC notices this later, and dies. Ideas? -------------------- int foo(int j) { long i = 0xfffff; return i >> j; } -------------------- $ ./cc1 -quiet -Os dj.c Register 28 died unexpectedly. ;; basic block 3, loop depth 0, count 0 ;; prev block 2, next block 4 ;; pred: 2 [50.0%] (fallthru) ;; succ: 4 [100.0%] (fallthru) ;; Registers live at start: 7 [fb] 8 [sp] 11 [argp] 28 30 (note 34 13 14 3 [bb 3] NOTE_INSN_BASIC_BLOCK) (note 14 34 15 3 NOTE_INSN_DELETED) (insn 15 14 16 3 (set (reg:SI 28) (const_int 15 [0xf])) 173 {movsi_splittable} (nil) (nil)) (insn 16 15 17 3 (set (reg:QI 30) (plus:QI (reg:QI 30) (const_int 16 [0x10]))) 2 {addqi3} (nil) (nil)) ;; Registers live at end: 7 [fb] 8 [sp] 11 [argp] 28 30 dj.c: In function 'foo': dj.c:5: internal compiler error: internal consistency failure -------------------- #0 internal_error (gmsgid=0x868f18 "internal consistency failure") at ../../gcc/gcc/diagnostic.c:582 #1 0x00000000005e6da9 in verify_local_live_at_start (new_live_at_start=0xbce5f8, bb=0x2a95599480) at ../../gcc/gcc/flow.c:544 #2 0x00000000005e71a2 in update_life_info (blocks=0x0, extent=UPDATE_LIFE_LOCAL, prop_flags=5) at ../../gcc/gcc/flow.c:698 #3 0x00000000005ede09 in recompute_reg_usage () at ../../gcc/gcc/flow.c:4476 #4 0x00000000006ef93e in execute_one_pass (pass=0xb1bda0) at ../../gcc/gcc/passes.c:872 #5 0x00000000006efaac in execute_pass_list (pass=0xb1bda0) at ../../gcc/gcc/passes.c:919 #6 0x00000000006efabe in execute_pass_list (pass=0xb1cc20) at ../../gcc/gcc/passes.c:920 -------------------- ;; Function foo (foo) insn_cost 6: 4 insn_cost 11: 4 insn_cost 12: 4 insn_cost 13: 0 insn_cost 14: 8 insn_cost 15: 8 insn_cost 16: 8 insn_cost 18: 8 insn_cost 26: 4 insn_cost 32: 0 (note 2 0 8 NOTE_INSN_DELETED) ;; Start of basic block 2, registers live: 2 [r1] 7 [fb] 8 [sp] 11 [argp] (note 8 2 6 2 [bb 2] NOTE_INSN_BASIC_BLOCK) (insn 6 8 7 2 (set (reg/v:HI 26 [ j ]) (reg:HI 2 r1 [ j ])) 171 {movhi_op} (nil) (expr_list:REG_DEAD (reg:HI 2 r1 [ j ]) (nil))) (note 7 6 11 2 NOTE_INSN_FUNCTION_BEG) (insn 11 7 12 2 (set (reg:QI 30) (neg:QI (subreg:QI (reg/v:HI 26 [ j ]) 0))) 12 {negqi2} (insn_list:REG_DEP_TRUE 6 (nil)) (expr_list:REG_DEAD (reg/v:HI 26 [ j ]) (nil))) (insn 12 11 13 2 (set (reg:SI 28) (const_int 1048575 [0xfffff])) 173 {movsi_splittable} (nil) (expr_list:REG_EQUAL (const_int 1048575 [0xfffff]) (nil))) (jump_insn 13 12 34 2 (set (pc) (if_then_else (ge (reg:QI 30) (const_int -16 [0xfffffffffffffff0])) (label_ref 17) (pc))) 47 {cbranchqi4} (insn_list:REG_DEP_TRUE 11 (nil)) (expr_list:REG_BR_PROB (const_int 5000 [0x1388]) (nil))) ;; End of basic block 2, registers live: 7 [fb] 8 [sp] 11 [argp] 28 30 ;; Start of basic block 3, registers live: 7 [fb] 8 [sp] 11 [argp] 28 30 (note 34 13 14 3 [bb 3] NOTE_INSN_BASIC_BLOCK) (note 14 34 15 3 NOTE_INSN_DELETED) (insn 15 14 16 3 (set (reg:SI 28) (const_int 15 [0xf])) 173 {movsi_splittable} (nil) (nil)) (insn 16 15 17 3 (set (reg:QI 30) (plus:QI (reg:QI 30) (const_int 16 [0x10]))) 2 {addqi3} (nil) (nil)) ;; End of basic block 3, registers live: 7 [fb] 8 [sp] 11 [argp] 28 30 ;; Start of basic block 4, registers live: 7 [fb] 8 [sp] 11 [argp] 28 30 (code_label 17 16 35 4 2 "" [1 uses]) (note 35 17 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK) (insn 18 35 23 4 (parallel [ (set (reg:SI 28) (ashiftrt:SI (reg:SI 28) (neg:QI (reg:QI 30)))) (clobber (scratch:HI)) ]) 225 {ashrsi3_16} (nil) (expr_list:REG_DEAD (reg:QI 30) (expr_list:REG_UNUSED (scratch:HI) (expr_list:REG_EQUAL (ashiftrt:SI (const_int 1048575 [0xfffff]) (subreg:QI (reg/v:HI 26 [ j ]) 0)) (nil))))) (note 23 18 26 4 NOTE_INSN_FUNCTION_END) (insn 26 23 32 4 (set (reg/i:HI 0 r0 [ <result> ]) (subreg:HI (reg:SI 28) 0)) 171 {movhi_op} (insn_list:REG_DEP_TRUE 18 (nil)) (expr_list:REG_DEAD (reg:SI 28) (nil))) (insn 32 26 0 4 (use (reg/i:HI 0 r0 [ <result> ])) -1 (insn_list:REG_DEP_TRUE 26 (nil)) (nil)) ;; End of basic block 4, registers live: 0 [r0] 7 [fb] 8 [sp] 11 [argp]