diff mbox

[AVR] : Fix PR46779

Message ID 4DFA48FA.8010904@redhat.com
State New
Headers show

Commit Message

Richard Henderson June 16, 2011, 6:18 p.m. UTC
On 06/16/2011 11:09 AM, Denis Chertykov wrote:
> Only one question why you removed avr_legitimize_address ?

It doesn't actually do anything useful.

All it does is, for a subset of inputs, force the address into
a register.  This is the same as the fallback action.  That is,
any non-legitimate address is forced into a register.

A more useful version of legitimize_address would be to split
a large offset into two pieces, the large one to be CSE'd and
the small one that fits into a memory offset.

E.g. the following with which I was experimenting.


r~
commit 034bf089f69d13ebab4765439163824a946913bb
Author: Richard Henderson <rth@redhat.com>
Date:   Wed Jun 15 15:35:57 2011 -0700

    avr: Split address offsets in legitimize{_reload,}_address.

Comments

Denis Chertykov June 16, 2011, 7:17 p.m. UTC | #1
2011/6/16 Richard Henderson <rth@redhat.com>:
> On 06/16/2011 11:09 AM, Denis Chertykov wrote:
>> Only one question why you removed avr_legitimize_address ?
>
> It doesn't actually do anything useful.
>
> All it does is, for a subset of inputs, force the address into
> a register.  This is the same as the fallback action.  That is,
> any non-legitimate address is forced into a register.
>
> A more useful version of legitimize_address would be to split
> a large offset into two pieces, the large one to be CSE'd and
> the small one that fits into a memory offset.
>
> E.g. the following with which I was experimenting.

Are you working in public git repository ?
Can I chekout it ?

If not then may be you can drop a full patch against svn.

Denis.
Richard Henderson June 16, 2011, 7:32 p.m. UTC | #2
On 06/16/2011 12:17 PM, Denis Chertykov wrote:
> Are you working in public git repository ?
> Can I chekout it ?
> 
> If not then may be you can drop a full patch against svn.

I've pushed it to 

  git://gcc.gnu.org/git/gcc.git rth/avr-addressing

As I said yesterday, there's still a crash in libgcc, so
we've merely exchanged one crash for another from G-J's
patch.


r~
Denis Chertykov June 16, 2011, 7:49 p.m. UTC | #3
2011/6/16 Richard Henderson <rth@redhat.com>:
> On 06/16/2011 12:17 PM, Denis Chertykov wrote:
>> Are you working in public git repository ?
>> Can I chekout it ?
>>
>> If not then may be you can drop a full patch against svn.
>
> I've pushed it to
>
>  git://gcc.gnu.org/git/gcc.git rth/avr-addressing

Thank you.

> As I said yesterday, there's still a crash in libgcc, so
> we've merely exchanged one crash for another from G-J's
> patch.

It's not a problem for experiments with new addressing code.

Denis.
diff mbox

Patch

diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 5c60e2e..3045587 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -110,6 +110,8 @@  extern void out_shift_with_cnt (const char *templ, rtx insn,
 extern reg_class_t avr_mode_code_base_reg_class (enum machine_mode, RTX_CODE, RTX_CODE);
 extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, RTX_CODE, RTX_CODE);
 extern rtx avr_incoming_return_addr_rtx (void);
+extern rtx avr_legitimize_reload_address (rtx, enum machine_mode,
+					  int, int, int, int);
 #endif /* RTX_CODE */
 
 #ifdef HAVE_MACHINE_MODES
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 045da63..78c2467 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -1160,7 +1160,7 @@  static inline int
 avr_reg_ok_for_addr (rtx reg, int strict)
 {
   return (REG_P (reg)
-          && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, MEM, SCRATCH)
+          && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, MEM, UNKNOWN)
               || (!strict && REGNO (reg) >= FIRST_PSEUDO_REGISTER)));
 }
 
@@ -1226,12 +1226,88 @@  avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 /* Attempts to replace X with a valid
    memory address for an operand of mode MODE  */
 
-rtx
-avr_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED)
+static rtx
+avr_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+                        enum machine_mode mode)
 {
+  if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)))
+    {
+      HOST_WIDE_INT addend = INTVAL (XEXP (x, 1));
+
+      if (addend > MAX_LD_OFFSET (mode))
+	{
+	  HOST_WIDE_INT hi, lo;
+
+	  x = XEXP (x, 0);
+	  if (!REG_P (x)
+	      || !avr_regno_mode_code_ok_for_base_p (REGNO (x), mode,
+						     PLUS, UNKNOWN))
+	    x = force_reg (Pmode, x);
+
+	  lo = addend & 63;
+	  hi = addend - lo;
+	  x = force_reg (Pmode, plus_constant (x, hi));
+	  return plus_constant (x, lo);
+	}
+    }
+
   return x;
 }
 
+rtx
+avr_legitimize_reload_address (rtx x, enum machine_mode mode,
+			       int opnum, int type, int addr_type,
+			       int ind_levels ATTRIBUTE_UNUSED)
+{
+  /* We must recognize output that we have already generated ourselves.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && REG_P (XEXP (XEXP (x, 0), 0))
+      && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+      && CONST_INT_P (XEXP (x, 1)))
+    {
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+		   BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+		   opnum, (enum reload_type) addr_type);
+      return x;
+    }
+
+  /* We wish to handle large displacements off a register by splitting
+     the addend into two parts.  This may allow some sharing.  */
+  if (GET_CODE (x) == PLUS
+      && REG_P (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1)))
+    {
+      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+      HOST_WIDE_INT hi, lo;
+
+      lo = val & 63;
+      hi = val - lo;
+
+      if (val > MAX_LD_OFFSET (mode) && hi && lo)
+	{
+          /* Reload the high part into a base reg; leave the low part
+	     in the mem directly.  */
+          x = plus_constant (XEXP (x, 0), hi);
+          x = gen_rtx_PLUS (Pmode, x, GEN_INT (lo));
+
+          push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+		       BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+		       opnum, (enum reload_type) addr_type);
+          return x;
+	}
+    }
+
+  if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
+    {
+      push_reload (XEXP (x, 0), NULL, &XEXP (x,0), NULL,
+	           POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0,
+		   opnum, (enum reload_type) type);
+      return x;
+    }
+
+  return NULL_RTX;
+}
 
 /* Return a pointer register name as a string.  */
 
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 426ddec..9cb19d1 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -367,50 +367,20 @@  extern int avr_reg_order[];
 
 #define MAX_REGS_PER_ADDRESS 1
 
-/* LEGITIMIZE_RELOAD_ADDRESS will allow register R26/27 to be used, where it
-   is no worse than normal base pointers R28/29 and R30/31. For example:
-   If base offset is greater than 63 bytes or for R++ or --R addressing.  */
-   
-#define _LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)    \
-do {									    \
-  if (1&&(GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC))	    \
-    {									    \
-      push_reload (XEXP (X,0), XEXP (X,0), &XEXP (X,0), &XEXP (X,0),	    \
-	           POINTER_REGS, GET_MODE (X),GET_MODE (X) , 0, 0,	    \
-		   OPNUM, RELOAD_OTHER);				    \
-      goto WIN;								    \
-    }									    \
-  if (GET_CODE (X) == PLUS						    \
-      && REG_P (XEXP (X, 0))						    \
-      && (reg_equiv_constant (REGNO (XEXP (X, 0))) == 0)		    \
-      && GET_CODE (XEXP (X, 1)) == CONST_INT				    \
-      && INTVAL (XEXP (X, 1)) >= 1)					    \
-    {									    \
-      int fit = INTVAL (XEXP (X, 1)) <= (64 - GET_MODE_SIZE (MODE));	    \
-      if (fit)								    \
-	{								    \
-          if (reg_equiv_address (REGNO (XEXP (X, 0))) != 0)		    \
-	    {								    \
-	      int regno = REGNO (XEXP (X, 0));				    \
-	      rtx mem = make_memloc (X, regno);				    \
-	      push_reload (XEXP (mem,0), NULL, &XEXP (mem,0), NULL,         \
-		           POINTER_REGS, Pmode, VOIDmode, 0, 0,		    \
-		           1, ADDR_TYPE (TYPE));			    \
-	      push_reload (mem, NULL_RTX, &XEXP (X, 0), NULL,		    \
-		           BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
-		           OPNUM, TYPE);				    \
-	      goto WIN;							    \
-	    }								    \
-	}								    \
-      else if (! (frame_pointer_needed && XEXP (X,0) == frame_pointer_rtx)) \
-	{								    \
-	  push_reload (X, NULL_RTX, &X, NULL,				    \
-		       POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0,	    \
-		       OPNUM, TYPE);					    \
-          goto WIN;							    \
-	}								    \
-    }									    \
-} while(0)
+/* Try a machine-dependent way of reloading an illegitimate address
+   operand.  If we find one, push the reload and jump to WIN.  This
+   macro is used in only one place: `find_reloads_address' in reload.c.  */
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN)		     \
+do {									     \
+  rtx new_x = avr_legitimize_reload_address (X, MODE, OPNUM,                 \
+					     TYPE, ADDR_TYPE (TYPE), IND_L); \
+  if (new_x)								     \
+    {									     \
+      X = new_x;							     \
+      goto WIN;								     \
+    }									     \
+} while (0)
 
 #define BRANCH_COST(speed_p, predictable_p) 0