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]