@@ -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
@@ -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. */
@@ -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
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.