commit 034bf089f69d13ebab4765439163824a946913bb Author: Richard Henderson 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