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,