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