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 <r...@redhat.com>
Date:   Wed Jun 15 15:35:57 2011 -0700

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

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
 

Reply via email to