RFC: reloading sums

Joern Rennecke joern.rennecke@superh.com
Thu Jun 19 19:03:00 GMT 2003


For gcc/20020426-2.c I see a reload failure for sh5-compact -ml .
find_reload is faced with this instruction:

(gdb) call debug_rtx(insn)
(insn:HI 1007 1006 1008 57 /swbuild/build/srcw/gcc/testsuite/gcc.dg/20020426-2.c:156 (set (reg:SI 2 r2 [467])
        (mem:SI (plus:SI (plus:SI (reg:SI 13 r13 [471])
                    (const_int 136 [0x88]))
                (reg/f:SI 14 r14)) [3 x S4 A32])) 123 {movsi_ie} (nil)
    (expr_list:REG_DEAD (reg:SI 13 r13 [471])
        (nil)))

And it records the following reloads:

(gdb) call debug_reload()
Reload 0: reload_in (SI) = (plus:SI (reg:SI 13 r13 [471])
                                                    (const_int 136 [0x88]))
        GENERAL_REGS, RELOAD_FOR_INPUT_ADDRESS (opnum = 1)
        reload_in_reg: (plus:SI (reg:SI 13 r13 [471])
                                                    (const_int 136 [0x88]))
        reload_reg_rtx: (reg:SI 13 r13)
Reload 1: reload_in (SI) = (reg/f:SI 14 r14)
        R0_REGS, RELOAD_FOR_INPUT_ADDRESS (opnum = 1)
        reload_in_reg: (reg/f:SI 14 r14)

For reload 0, the constant 136 has to be loaded into a register first.
But find_reloads has already assigned the reload register 13, which is
also an input for the reload.  Oops, we end up with:

(insn 1481 1006 1482 57 (set (reg:SI 13 r13)
        (const_int 136 [0x88])) -1 (nil)
    (nil))

(insn 1482 1481 1483 57 (set (reg:SI 13 r13)
        (plus:SI (reg:SI 13 r13)
            (reg:SI 13 r13 [471]))) 23 {*addsi3_compact} (nil)
    (expr_list:REG_EQUIV (plus:SI (reg:SI 13 r13 [471])
            (const_int 136 [0x88]))
        (nil)))

(insn 1483 1482 1007 57 (set (reg:SI 0 r0)
        (reg/f:SI 14 r14)) -1 (nil)
    (nil))

(insn:HI 1007 1483 1008 57 /swbuild/build/srcw/gcc/testsuite/gcc.dg/20020426-2.c:156 (set (reg:SI 2 r2 [467])
        (mem:SI (plus:SI (reg:SI 13 r13)
                (reg:SI 0 r0)) [3 x S4 A32])) 123 {movsi_ie} (nil)
    (expr_list:REG_DEAD (reg:SI 13 r13 [471])
        (nil)))

This is actually a problem for all RISC processors that have an indexed
addressing mode - if you have a memory reference using the indexed addressing
mode, and the base address is a pseudo containing an address in the frame
and this pseudo fails to get a hard register, we end up with a double PLUS,
so the frame address gets reloaded.  Now, when the index got a hard register,
and it dies in this insn, push_reload will consider that hard register as
a reload register, and disregrad overlaps with rld[n_reloads].in .  That is
fine as long as the add can be done with a single insn, but when the constant
is so large that it has to be reloaded into a register first, that clobbers
the index.

Now, we could add another target macro to the zoo we already have, but that
would really be duplicating information that is already represented somewhere
else, although not easy to get at.

I'm currently experimenting with the attached patch.
The #if 1 section is there for debug purposes only - this code should not
be triggered too often, as copying recog_data around and generating garbage
rtl doesn't come cheap.
Moreover, I want to verify that there are no unreasonable false negatives.

I'm currently testing this on i686-pc-linux-gnu X sh64-elf and
i686-pc-linux-gnu native.
	
-- 
--------------------------
SuperH (UK) Ltd.
2410 Aztec West / Almondsbury / BRISTOL / BS32 4QX
T:+44 1454 465658
-------------- next part --------------
2003-06-19  J"orn Rennecke <joern.rennecke@superh.com>

	* reload.c (can_reload_into): New function.
	(push_reload): Use it.

Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.214
diff -p -r1.214 reload.c
*** reload.c	12 Jun 2003 19:01:08 -0000	1.214
--- reload.c	19 Jun 2003 18:39:14 -0000
*************** reload_inner_reg_of_subreg (x, mode, out
*** 840,845 ****
--- 840,894 ----
  	      != (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner))));
  }
  
+ /* Return nonzero if IN can be reloaded into REGNO with mode MODE without
+    requiring an extra reload register.  The caller has already found that
+    IN contains some reference to REGNO, so check that we can produce the
+    new value in a single step.  E.g. if we have
+    (set (reg r13) (plus (reg r13) (const int 1))), and there is an
+    instruction that adds one to a register, this should succeed.
+    However, if we have something like
+    (set (reg r13) (plus (reg r13) (const int 999))), and the constant 999
+    needs to be loaded into a register first, we need a separate reload
+    register.  */
+ static int
+ can_reload_into (rtx in, int regno, enum machine_mode mode)
+ {
+   rtx dst, test_insn;
+   int r;
+   struct recog_data save_recog_data;
+ 
+   /* For matching constraints, we often get notional input reloads where
+      we want to use the original register as the reload register.  Speed
+      this up, since it trivially works.  */
+   if (in->code == REG)
+     return 1;
+ 
+   /* To test MEMs properly, we'd have to take into account all the reloads
+      that are already scheduled, which can become quite complicated.
+      And since we've already handled addres reloads for this MEM, it
+      should always succeed anyway.  */
+   if (in->code == MEM)
+     return 1;
+ 
+   /* If we can make a simple SET insn that does the job, everything should
+      be fine.  */
+   dst =  gen_rtx_REG (mode, regno);
+   test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, dst, in));
+   save_recog_data = recog_data;
+   r = recog_memoized (test_insn) >= 0 && constrain_operands (1);
+   recog_data = save_recog_data;
+ #if 1
+ {
+   int c = -1;
+   if (GET_CODE (in) == PLUS && GET_CODE (XEXP (in, 1)) == CONST_INT)
+     c = INTVAL (XEXP (in, 1));
+   debug_rtx(PATTERN (test_insn));
+   printf ("can_reload_into returns %d (constant %d)\n", r, c);
+ }
+ #endif
+   return r;
+ }
+ 
  /* Record one reload that needs to be performed.
     IN is an rtx saying where the data are to be found before this instruction.
     OUT says where they must be stored after the instruction.
*************** push_reload (in, out, inloc, outloc, cla
*** 1532,1538 ****
  					  regno + offs))
  		break;
  
! 	    if (offs == nregs)
  	      {
  		rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
  		break;
--- 1581,1591 ----
  					  regno + offs))
  		break;
  
! 	    if (offs == nregs
! 		&& (! (refers_to_regno_for_reload_p
! 		       (regno, (regno + HARD_REGNO_NREGS (regno, inmode)),
! 				in, (rtx *)0))
! 		    || can_reload_into (in, regno, inmode)))
  	      {
  		rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
  		break;


More information about the Gcc-patches mailing list