rfc: eliminate some reload copies

Richard Henderson rth@redhat.com
Fri Jan 11 14:18:00 GMT 2002


We've noticed reload doing silly copies before, but today I was
looking at some x86 DImode code and barfed.  Consider

	/* -O -mmmx -ffixed-mm0 -fomit-frame-pointer */
	register long long mm0 __asm__("mm0");
	long long foo(void) { return mm0; }

foo:
        subl    $12, %esp
        movl    %ebx, 8(%esp)
        movq    %mm0, (%esp)
        movl    (%esp), %ecx
        movl    4(%esp), %ebx
        movl    %ecx, %eax
        movl    %ebx, %edx
        movl    8(%esp), %ebx
        addl    $12, %esp
        ret

A couple of things to note.  One, we reload

	(set (reg:DI eax) (reg:DI mm0))
as
	(set (reg:DI ecx) (mem:DI sp))
	(set (reg:DI eax) (reg:DI ecx))

We have only three SImode call-clobbered registers, so handling two
DImode values simultaneously requires that we use a call-saved register.

I hacked up reload to notice simple moves of this form and try to
use the destination register as the reload register when possible.
This results in reloads like

	(set (reg:DI eax) (mem:DI sp))
	(set (reg:DI eax) (reg:DI eax))

which is trivially corrected later, resulting in

        subl    $12, %esp
        movq    %mm0, (%esp)
        movl    (%esp), %eax
        movl    4(%esp), %edx
        addl    $12, %esp
        ret

I admit that the placement of the following code is less than ideal,
but I couldn't figure out where else to do this in which we have
enough context.  As it is, we have to put this in two places.  The
change in choose_reload_regs makes the change actually happen, and
the change in find_reload_regs prevents us from thinking we'll need
ebx and spilling it in the prologue.

Is this sort of hackery likely to get me in trouble?  Any ideas how
to place this sort of thing to avoid duplicating code?



r~


	* reload1.c (find_reload_regs): Try to use the destination of a
	simple set as the reload register.
	(choose_reload_regs): Likewise.

Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.320
diff -c -p -d -r1.320 reload1.c
*** reload1.c	2002/01/11 02:44:48	1.320
--- reload1.c	2002/01/11 20:39:17
*************** find_reload_regs (chain)
*** 1788,1803 ****
       that provided the reload registers.  */
    for (i = 0; i < chain->n_reloads; i++)
      {
        /* Show whether this reload already has a hard reg.  */
!       if (chain->rld[i].reg_rtx)
  	{
! 	  int regno = REGNO (chain->rld[i].reg_rtx);
! 	  chain->rld[i].regno = regno;
! 	  chain->rld[i].nregs
! 	    = HARD_REGNO_NREGS (regno, GET_MODE (chain->rld[i].reg_rtx));
  	}
        else
! 	chain->rld[i].regno = -1;
        reload_order[i] = i;
      }
  
--- 1788,1820 ----
       that provided the reload registers.  */
    for (i = 0; i < chain->n_reloads; i++)
      {
+       struct reload *rld = &chain->rld[i];
+ 
+       /* Special case a simple move with an input reload and a destination
+ 	 of a hard reg, if the hard reg is ok, use it.  */
+       if (rld->when_needed == RELOAD_FOR_INPUT
+ 	  && GET_CODE (PATTERN (chain->insn)) == SET
+ 	  && GET_CODE (SET_DEST (PATTERN (chain->insn))) == REG
+ 	  && SET_SRC (PATTERN (chain->insn)) == rld->in)
+ 	{
+ 	  rtx dest = SET_DEST (PATTERN (chain->insn));
+ 	  unsigned int regno = REGNO (dest);
+ 
+ 	  if (regno < FIRST_PSEUDO_REGISTER
+ 	      && TEST_HARD_REG_BIT (reg_class_contents[rld->class], regno)
+ 	      && HARD_REGNO_MODE_OK (regno, rld->mode))
+ 	    rld->reg_rtx = dest;
+ 	}
+ 
        /* Show whether this reload already has a hard reg.  */
!       if (rld->reg_rtx)
  	{
! 	  int regno = REGNO (rld->reg_rtx);
! 	  rld->regno = regno;
! 	  rld->nregs = HARD_REGNO_NREGS (regno, GET_MODE (rld->reg_rtx));
  	}
        else
! 	rld->regno = -1;
        reload_order[i] = i;
      }
  
*************** choose_reload_regs (chain)
*** 5813,5818 ****
--- 5830,5855 ----
  	     optional.  */
  	  if (rld[r].reg_rtx != 0 || rld[r].optional)
  	    continue;
+ 
+ 	  /* Special case a simple move with an input reload and a
+ 	     destination of a hard reg, if the hard reg is ok, use it.  */
+ 	  if (rld[r].when_needed == RELOAD_FOR_INPUT
+ 	      && GET_CODE (PATTERN (chain->insn)) == SET
+ 	      && GET_CODE (SET_DEST (PATTERN (chain->insn))) == REG
+ 	      && SET_SRC (PATTERN (chain->insn)) == rld[r].in)
+ 	    {
+ 	      rtx dest = SET_DEST (PATTERN (chain->insn));
+ 	      unsigned int regno = REGNO (dest);
+ 
+ 	      if (regno < FIRST_PSEUDO_REGISTER
+ 		  && TEST_HARD_REG_BIT (reg_class_contents[rld[r].class],
+ 					regno)
+ 		  && HARD_REGNO_MODE_OK (regno, rld[r].mode))
+ 		{
+ 		  rld[r].reg_rtx = dest;
+ 		  continue;
+ 		}
+ 	    }
  
  	  if (! allocate_reload_reg (chain, r, j == n_reloads - 1))
  	    break;



More information about the Gcc-patches mailing list