problem with flow and caller_save
Herman ten Brugge
Haj.Ten.Brugge@net.HCC.nl
Tue Oct 27 22:02:00 GMT 1998
Hello,
I discovered a bug in flow.c that caused caller_save to generate bad code.
I will try to explain what happens. Suppose we have the following insns at
the start of a function:
(call_insn 5 4 7 (parallel[
(call (mem:QI (symbol_ref:QI ("__main")) 0)
(const_int 0))
(clobber (reg:QI 31 r11))
] ) -1 (nil)
(expr_list:REG_UNUSED (reg:QI 31 r11)
(nil))
(nil))
(insn 10 7 13 (set (subreg:QI (reg/v:HI 37) 0)
(mem/u:QI (symbol_ref/u:QI ("*LC4")) 0)) 5 {movqi_noclobber} (nil)
(nil))
(insn 13 10 16 (set (subreg:QI (reg/v:HI 37) 1)
(const_int 21845)) 5 {movqi_noclobber} (insn_list 10 (nil))
(nil))
This will call __main and load pseudo_reg 37 (long long) with a value.
The flowanalyses will now mark reg 37 as a caller_save reg in
propagate_block at line 1886 (REG_N_CALLS_CROSSED (i)++;). This is
because it does not detect correctly that reg 37 becomes life after the call
to __main.
Now global alloc assigns a caller save register (r0,r1) to reg 37. The code
now looks like:
call __main
load r0,...
load r1,...
Now caller save is done (save_call_clobbered_regs). This results in the
following code.
save r0
save r1
call __main
load r0,...
load r1,...
restore r0
restore r1
The restore is done after the load is done because only referenced regs
are checked and not set regs.
Now the next passes will optimise this into:
save r0
save r1
call __main
restore r0
restore r1
Oops, the load insns are gone.
I made a temporary fix to solve the caller save problem. I restore the
registers when I see a set is done. But I think we should modify flow to
generate correct life info. I don't know how to do this so perhaps some
one else should have a look at it.
Herman.
--- caller-save.c.org Wed Oct 28 06:48:08 1998
+++ caller-save.c Wed Oct 28 06:48:36 1998
@@ -363,6 +363,12 @@ save_call_clobbered_regs ()
CLEAR_HARD_REG_SET (referenced_regs);
mark_referenced_regs (PATTERN (insn));
AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
+
+ /* Set bits for registers set. */
+ CLEAR_HARD_REG_SET (this_insn_sets);
+ note_stores (PATTERN (insn), mark_set_regs);
+ AND_HARD_REG_SET (this_insn_sets, hard_regs_saved);
+ IOR_HARD_REG_SET (referenced_regs, this_insn_sets);
}
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
--
-------------------------------------------------------------------------
Herman ten Brugge Email: Haj.Ten.Brugge@net.HCC.nl
More information about the Gcc-bugs
mailing list