This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: reload displacement optimization


> While looking into some problems in reload this evening (which I could
> not reproduce, annoyingly), I noticed that reload would produce, when
> a displacement off of a base register is out of range,
> 
>         lda $6,-31856
>         ldah $6,1($6)
>         addq $6,$30,$6
>         ldq $12,0($6)
> 
> when
> 
> 	ldah $6,1($30)
> 	ldq $12,-31856($6)
> 
> is sufficient.
> 
> The solution, I believe, is to teach find_reloads_address about
> this new way to break up an address.  The following patch does this,
> but in a blatently machine dependent way.
> 
> Can anyone think of a way to properly conditionalize this, and
> to break up the address?

I made a new macro LEGITIMIZE_RELOAD_ADDRESS for the SH and i386 some time
ago, but since Kenner doesn't care enough about embedded targets and the
i386 didn't make a convincing case, it never got submitted.
Could you fit your optimization into this framework?


 ------------------- old patch follows ----------------------------------
The text size of the i386 stage1 cc1 minus the size of reload.o
(reload.c was changed) shrank by 208 bytes, or 0.018% .
Nice, but I think we need some better RISC workstation results to make a
convincing case.

diff -p -r ss-961031/config/i386/i386.h ss-961031-leg-rel/config/i386/i386.h
*** ss-961031/config/i386/i386.h	Tue Oct 15 16:21:03 1996
--- ss-961031-leg-rel/config/i386/i386.h	Tue Nov  5 23:18:09 1996
*************** do {						\
*** 1638,1643 ****
--- 1638,1704 ----
      goto WIN;								\
  }
  
+ #define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)\
+ do {									\
+   if (GET_CODE (X) == PLUS						\
+       && GET_CODE (XEXP (X, 0)) == REG && GET_CODE (XEXP (X, 1)) == REG	\
+       && REGNO (XEXP (X, 0)) >= FIRST_PSEUDO_REGISTER			\
+       && REGNO (XEXP (X, 1)) >= FIRST_PSEUDO_REGISTER)			\
+     {									\
+       int reg0 = REGNO (XEXP (X, 0));					\
+       int reg1 = REGNO (XEXP (X, 1));					\
+ 									\
+       /* pic handling isn't implemented for this macro yet, so		\
+ 	 bail out if one of the operands might require it.  */		\
+       if (flag_pic							\
+ 	  && ((reg_equiv_constant[reg0]					\
+ 	       && SYMBOLIC_CONST (reg_equiv_constant[reg0]))		\
+ 	      || (reg_equiv_constant[reg1]				\
+ 		  && SYMBOLIC_CONST (reg_equiv_constant[reg1]))		\
+ 	      || reg_equiv_memory_loc[reg0]				\
+ 	      || reg_equiv_memory_loc[reg1]))				\
+ 	break;								\
+ 									\
+       if (reg_equiv_memory_loc[reg0])					\
+ 	X = gen_rtx (PLUS, Pmode,					\
+ 		     eliminate_regs (reg_equiv_memory_loc[reg0], Pmode,	\
+ 				     NULL_RTX),				\
+ 		     XEXP (X, 1));					\
+       if (reg_equiv_memory_loc[reg1])					\
+ 	X = gen_rtx (PLUS, Pmode, XEXP (X, 0),				\
+ 		     eliminate_regs (reg_equiv_memory_loc[reg1], Pmode,	\
+ 				     NULL_RTX));			\
+       if (reg_equiv_constant[reg0])					\
+ 	{								\
+ 	  X = gen_rtx (PLUS, Pmode, XEXP (X, 1), reg_equiv_constant[reg0]);\
+ 	  push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR,	\
+ 		       INDEX_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM),	\
+ 		       (TYPE));						\
+ 	  goto win;							\
+ 	}								\
+       if (reg_equiv_constant[reg1])					\
+ 	{								\
+ 	  X = gen_rtx (PLUS, Pmode, XEXP (X, 0), reg_equiv_constant[reg1]);\
+ 	  push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR,	\
+ 		       INDEX_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM),	\
+ 		       (TYPE));						\
+ 	  goto win;							\
+ 	}								\
+       push_reload (X, NULL_RTX, &X, NULL_PTR, INDEX_REG_CLASS, Pmode,	\
+ 		   VOIDmode, 0, 0, (OPNUM), (TYPE));			\
+       goto win;								\
+     }									\
+   if (GET_CODE (X) == PLUS						\
+       && (GET_CODE (XEXP (X, 0)) == MEM					\
+ 	  || GET_CODE (XEXP (X, 1)) == MEM))				\
+     {									\
+       /* We created this before from reg_equiv_memory_loc.  */		\
+       push_reload (X, NULL_RTX, &X, NULL_PTR, INDEX_REG_CLASS, Pmode,	\
+ 		   VOIDmode, 0, 0, (OPNUM), (TYPE));			\
+       goto win;								\
+     }									\
+ } while (0);
+ 
  #define REWRITE_ADDRESS(x) rewrite_address(x)
  
  /* Nonzero if the constant value X is a legitimate general operand
diff -p -r ss-961031/config/sh/sh.h ss-961031-leg-rel/config/sh/sh.h
*** ss-961031/config/sh/sh.h	Fri Nov  1 20:22:33 1996
--- ss-961031-leg-rel/config/sh/sh.h	Tue Nov  5 23:19:10 1996
*************** extern struct rtx_def *sh_builtin_savere
*** 1119,1124 ****
--- 1119,1177 ----
      }								\
  }
  
+ #define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN)	\
+ {									\
+   if (GET_CODE (X) == PLUS						\
+       && (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8)	\
+       && GET_CODE (XEXP (X, 1)) == CONST_INT				\
+       && BASE_REGISTER_RTX_P (XEXP (X, 0))				\
+       && ! (TARGET_SH3E && MODE == SFmode))				\
+     {									\
+       rtx index_rtx = XEXP (X, 1);					\
+       HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base;		\
+       rtx sum;								\
+ 									\
+       /* Instead of offset_base 128..131 use 124..127, so that		\
+ 	 simple add suffices.  */					\
+       if (offset > 127)							\
+ 	{								\
+ 	  offset_base = ((offset + 4) & ~60) - 4;			\
+ 	}								\
+       else								\
+ 	offset_base = offset & ~60;					\
+       /* Sometimes the normal form does not suit DImode.  We		\
+ 	 could avoid that by using smaller ranges, but that		\
+ 	 would give less optimized code when SImode is			\
+ 	 prevalent.  */							\
+       if (GET_MODE_SIZE (MODE) + offset - offset_base <= 64)		\
+ 	{								\
+ 	  sum = gen_rtx (PLUS, Pmode, XEXP (X, 0),			\
+ 			 GEN_INT (offset_base));			\
+ 	  X = gen_rtx (PLUS, Pmode, sum, GEN_INT (offset - offset_base));\
+ 	  push_reload (sum, NULL_RTX, &XEXP (X, 0), NULL_PTR,	\
+ 		       BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM),	\
+ 		       (TYPE));						\
+ 	  goto WIN;							\
+ 	}								\
+     }									\
+   /* We must re-recognize what we created before.  */			\
+   else if (GET_CODE (X) == PLUS						\
+ 	   && (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8)	\
+ 	   && GET_CODE (XEXP (X, 0)) == PLUS				\
+ 	   && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT		\
+ 	   && BASE_REGISTER_RTX_P (XEXP (XEXP (X, 0), 0))		\
+ 	   && GET_CODE (XEXP (X, 1)) == CONST_INT			\
+ 	   && ! (TARGET_SH3E && MODE == SFmode))			\
+     {									\
+       /* Because this address is so complex, we know it must have	\
+ 	 been created by LEGITIMIZE_RELOAD_ADDRESS before; thus,	\
+ 	 it is already unshared, and needs no further unsharing.  */	\
+       push_reload (XEXP ((X), 0), NULL_RTX, &XEXP ((X), 0), NULL_PTR,	\
+ 		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), (TYPE));\
+       goto WIN;								\
+     }									\
+ }
+ 
  /* Go to LABEL if ADDR (a legitimate address expression)
     has an effect that depends on the machine mode it is used for.  */
  #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)			\
diff -p -r ss-961031/reload.c ss-961031-leg-rel/reload.c
*** ss-961031/reload.c	Fri Nov  1 20:22:40 1996
--- ss-961031-leg-rel/reload.c	Tue Nov  5 23:19:53 1996
*************** find_reloads_address (mode, memrefloc, a
*** 4253,4258 ****
--- 4253,4272 ----
  	return 0;
      }
  
+ #ifdef LEGITIMIZE_RELOAD_ADDRESS
+   if (memrefloc)
+     LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
+ 			       ind_levels, win);
+   if (0)
+     {
+      win:
+       *memrefloc = copy_rtx (*memrefloc);
+       XEXP (*memrefloc, 0) = ad;
+       move_replacements (&ad, &XEXP (*memrefloc, 0));
+       return 1;
+     }
+ #endif
+ 
    /* The address is not valid.  We have to figure out why.  One possibility
       is that it is itself a MEM.  This can happen when the frame pointer is
       being eliminated, a pseudo is not allocated to a hard register, and the
*************** copy_replacements (x, y)
*** 5124,5129 ****
--- 5138,5162 ----
  	      r->mode = replacements[j].mode;
  	    }
  	}
+ }
+ 
+ /* Change any replacements being done to *X to be done to *Y */
+ 
+ void
+ move_replacements (x, y)
+      rtx *x;
+      rtx *y;
+ {
+   int i;
+ 
+   for (i = 0; i < n_replacements; i++)
+     if (replacements[i].subreg_loc == x)
+       replacements[i].subreg_loc = y;
+     else if (replacements[i].where == x)
+       {
+ 	replacements[i].where = y;
+ 	replacements[i].subreg_loc = 0;
+       }
  }
  
  /* If LOC was scheduled to be replaced by something, return the replacement.
diff -p -r ss-961031/reload.h ss-961031-leg-rel/reload.h
*** ss-961031/reload.h	Thu Jun 15 13:00:35 1995
--- ss-961031-leg-rel/reload.h	Tue Nov  5 23:19:53 1996
*************** extern void subst_reloads PROTO((void));
*** 176,181 ****
--- 176,185 ----
     the RTL.  */
  extern void copy_replacements PROTO((rtx, rtx));
  
+ /* Change any replacements being done to *X to be done to *Y */
+ 
+ extern void move_replacements PROTO((rtx *x, rtx *y));
+ 
  /* If LOC was scheduled to be replaced by something, return the replacement.
     Otherwise, return *LOC.  */
  extern rtx find_replacement PROTO((rtx *));
diff -p -r ss-961031/tm.texi ss-961031-leg-rel/tm.texi
*** ss-961031/tm.texi	Tue Oct 15 16:21:16 1996
--- ss-961031-leg-rel/tm.texi	Wed Nov  6 02:57:28 1996
*************** address.  The compiler has standard ways
*** 4026,4031 ****
--- 4026,4075 ----
  fact, it is safe for this macro to do nothing.  But often a
  machine-dependent strategy can generate better code.
  
+ @findex LEGITIMIZE_RELOAD_ADDRESS
+ @item LEGITIMIZE_RELOAD_ADDRESS (@var{x}, @var{mode}, @var{opnum}, @var{type},
+ @var{ind_levels}, @var{win})
+ A C compound statement that attempts to replace @var{x}, which is an address
+ that needs reloading, with a valid memory address for an operand of mode
+ @var{mode}.  @var{win} will be a C statement label elsewhere in the code.
+ It is not necessary to define this macro, but it might be useful for
+ performance reasons.  For example, on the i386, it is sometimes possible to
+ use a single reload register instead of two by reloading a sum of two pseudo
+ registers into a register.
+ Another example: For a number of RISC processors, offsets are
+ limited so that often an intermediate address needs to be generated in
+ order to address a stack slot.  By defining LEGITIMIZE_RELOAD_ADDRESS 
+ appropriately, the intermediate addresses generated for adjactend some stack
+ slots can be made identical, and thus be shared.
+ 
+ The macro definition may use
+ 
+ @example
+ strict_memory_address_p (@var{mode}, @var{x});
+ @end example
+ 
+ @noindent
+ to test if the address has become legitimate.
+ 
+ @findex push_reload
+ It may use @code{push_reload} to indicate parts that need reloading.
+ @var{opnum}, @var{type} and @var{ind_levels} are usually suitable to be
+ passed unaltered to push_reload.
+ 
+ The code generated by this macro should not alter the substructure of
+ @var{x}.  If it transforms @var{x} into a more legitimate form, it
+ should assign @var{x} (which will always be a C variable) a new value.
+ This also applies to parts that you change indirectly by calling
+ @code{push_reload}.
+ 
+ @findex copy_rtx
+ If you want to change only a part of @var{x}, one standard way of doing
+ this is to use @code{copy_rtx}.  Note, however, that is unshares only a
+ single level of rtl.  Thus, if the part to be changed is not at the
+ top level, you'll need to replace first the top leve
+ It is not necessary for this macro to come up with a legitimate
+ address;  but often a machine-dependent strategy can generate better code.
+ 
  @findex GO_IF_MODE_DEPENDENT_ADDRESS
  @item GO_IF_MODE_DEPENDENT_ADDRESS (@var{addr}, @var{label})
  A C statement or compound statement with a conditional @code{goto



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]