csmith@convex.uucp (Chris Smith) (02/06/89)
gcc generates bad code for this program when compiled -O with 1.33:
/usr/local/lib/gcc-cc1 /tmp/cc010022.cpp -quiet -dumpbase t.c -dl -g -O -version -o t.s
GNU C version 1.33 (convex) compiled by GNU C version 1.33.
getdec()
{
int n = 0;
int c = getch();
while (c) {
n = n * 10 + (c - '0');
c = getch();
}
return n;
}
.stabd 68,0,6
ld.w -4(fp),s0 <-- computing n * 10
shf.w #2,s0
ld.w -4(fp),s2 (s2 is the spill register)
add.w s2,s0
add.w s0,s0
st.w s0,-4(fp) <-- it's in s0
add.w #-48,s2 <-- suddenly shifts to s2
st.w s2,-4(fp)
add.w s1,s2
L5:
st.w s2,-4(fp)
Here is an annotated lreg dump, look for <-- below
;; Function getdec
20 registers.
Register 16 used 16 times across 17 insns; dies in 2 places; crosses calls.
Register 17 used 8 times across 11 insns.
Register 18 used 4 times across 2 insns in block 1.
Register 19 used 4 times across 2 insns in block 1.
3 basic blocks.
Basic block 0: first insn 5, last 42.
Registers live at start: 8
Basic block 1: first insn 24, last 13.
Registers live at start: 8 16 17
Basic block 2: first insn 41, last 34.
Registers live at start: 16
;; Register 18 in 0.
;; Register 19 in 0.
(note 1 0 2 ("t.c") 2)
(note 2 1 3 "" -1)
(note 3 2 4 "" -2)
(note 4 3 5 ("t.c") 3)
(insn 5 4 6 (set (reg/v:SI 16)
(const_int 0)) 15 (nil)
(nil))
(note 6 5 7 ("t.c") 4)
(call_insn 7 6 8 (set (reg:SI 0)
(call (mem:QI (symbol_ref:SI ("getch")))
(const_int 0))) 130 (nil)
(nil))
(insn 8 7 9 (set (reg/v:SI 17)
(reg:SI 0)) 15 (nil)
(expr_list:QI (reg:SI 0)
(nil)))
(note 9 8 40 ("t.c") 5)
(insn 40 9 42 (set (cc0)
(reg/v:SI 17)) 0 (insn_list 8 (nil))
(nil))
(jump_insn 42 40 10 (set (pc)
(if_then_else (ne (cc0)
(const_int 0))
(pc)
(label_ref 41))) 120 (nil)
(nil))
(note 10 42 24 "" -4)
(code_label 24 10 14 3)
(note 14 24 15 "" -1)
(note 15 14 16 ("t.c") 6)
(insn 16 15 17 (set (reg:SI 18)
(ashift:SI (reg/v:SI 16)
(const_int 2))) 95 (nil)
(nil))
(insn 17 16 18 (set (reg:SI 19)
(plus:SI (reg:SI 18)
(reg/v:SI 16))) 50 (insn_list 16 (nil))
(expr_list:QI (reg:SI 18)
(expr_list:QI (reg/v:SI 16)
(nil))))
(insn 18 17 19 (set (reg/v:SI 16)
(ashift:SI (reg:SI 19)
(const_int 1))) 95 (insn_list 17 (nil))
(expr_list:QI (reg:SI 19)
(nil))) <---- at choose_reload_targets, this insn is
(insn:QI 18 17 19 (set (reg/v:SI 16)
(ashift:SI (reg:SI 0)
(const_int 1))) 95 (insn_list 17 (nil))
(expr_list:QI (reg:SI 0)
(nil)))
reload_in (reg:SI 0)
reload_out (reg:SI 16)
reg_reloaded_contents[2] = 16
reg_last_reload_reg[16] = (reg:SI 2)
picks reload_reg_rtx (reg:SI 0)
generates output reload
(insn 46 18 19 (set (reg/v:SI 16)
(reg:SI 0)) -1 (nil)
(nil))
(insn 19 18 20 (set (reg/v:SI 16)
(plus:SI (reg/v:SI 16)
(const_int -48))) 50 (insn_list 18 (nil))
(nil))
reload_in (reg:SI 16)
reload_out (reg:SI 16)
reg_reloaded_contents[2] = 16
reg_last_reload_reg[16] = (reg:SI 2)
picks reload_reg_rtx (reg:SI 2)
generates output reload
(insn 47 19 20 (set (reg/v:SI 16)
(reg:SI 2)) -1 (nil)
(nil))
The output reload for insn 18 clobbers reg 16, which is then used in
the following insn. I have no slightest idea what ought to be happening
here, but here is a brute-force fix: (in choose_reload_targets)
/* Output the reload insn. */
store_insn = emit_insn_after (gen_move_insn (old, reloadreg), insn);
+ /* Output reload might have written into a reg
+ whose contents we were remembering */
+ forget_old_reloads (PATTERN (store_insn));
/* If final will look at death notes for this reg,