diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2a217347921..cb8074fdf64 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2009-05-12 Kaz Kojima + + * config/sh/sh-protos.h (sh_legitimate_index_p): Declare. + (sh_legitimate_address_p): Likewise. + * config/sh/sh.c (sh_legitimate_index_p): New. + (sh_legitimate_address_p): Likewise. + * config/sh/sh.h (REG_OK_FOR_BASE_P): Add STRICT parameter. + (REG_OK_FOR_INDEX_P, SUBREG_OK_FOR_INDEX_P): Likewise. + (MODE_DISP_OK_4, MODE_DISP_OK_8): Remove. + (MAYBE_BASE_REGISTER_RTX_P): New macro. + (MAYBE_INDEX_REGISTER_RTX_P): Likewise. + (BASE_REGISTER_RTX_P): Use MAYBE_BASE_REGISTER_RTX_P. + (INDEX_REGISTER_RTX_P): Use MAYBE_INDEX_REGISTER_RTX_P. + (GO_IF_LEGITIMATE_INDEX): Use sh_legitimate_index_p. + (GO_IF_LEGITIMATE_ADDRESS): Use sh_legitimate_address_p. + 2009-05-12 Jan Hubicka * tree-inline.c (estimate_operator_cost): Add operands; diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 0c89f17b15d..fb896819b34 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -58,6 +58,8 @@ extern int fp_zero_operand (rtx); extern int fp_one_operand (rtx); extern int fp_int_operand (rtx); extern rtx get_fpscr_rtx (void); +extern bool sh_legitimate_index_p (enum machine_mode, rtx); +extern bool sh_legitimate_address_p (enum machine_mode, rtx, bool); extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); extern int nonpic_symbol_mentioned_p (rtx); extern void emit_sf_insn (rtx); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index e25cd42e871..79343bfdfd2 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -8950,6 +8950,124 @@ sh_insn_length_adjustment (rtx insn) return 0; } +/* Return TRUE for a valid displacement for the REG+disp addressing + with MODE. */ + +/* ??? The SH2e does not have the REG+disp addressing mode when loading values + into the FRx registers. We implement this by setting the maximum offset + to zero when the value is SFmode. This also restricts loading of SFmode + values into the integer registers, but that can't be helped. */ + +/* The SH allows a displacement in a QI or HI amode, but only when the + other operand is R0. GCC doesn't handle this very well, so we forgot + all of that. + + A legitimate index for a QI or HI is 0, SI can be any number 0..63, + DI can be any number 0..60. */ + +bool +sh_legitimate_index_p (enum machine_mode mode, rtx op) +{ + if (GET_CODE (op) == CONST_INT) + { + if (TARGET_SHMEDIA) + { + int size; + + /* Check if this the address of an unaligned load / store. */ + if (mode == VOIDmode) + return CONST_OK_FOR_I06 (INTVAL (op)); + + size = GET_MODE_SIZE (mode); + return (!(INTVAL (op) & (size - 1)) + && INTVAL (op) >= -512 * size + && INTVAL (op) < 512 * size); + } + + if (TARGET_SH2A) + { + if (GET_MODE_SIZE (mode) == 1 + && (unsigned) INTVAL (op) < 4096) + return true; + } + + if ((GET_MODE_SIZE (mode) == 4 + && (unsigned) INTVAL (op) < 64 + && !(INTVAL (op) & 3) + && !(TARGET_SH2E && mode == SFmode)) + || (GET_MODE_SIZE (mode) == 4 + && (unsigned) INTVAL (op) < 16383 + && !(INTVAL (op) & 3) && TARGET_SH2A)) + return true; + + if ((GET_MODE_SIZE (mode) == 8 + && (unsigned) INTVAL (op) < 60 + && !(INTVAL (op) & 3) + && !((TARGET_SH4 || TARGET_SH2A) && mode == DFmode)) + || ((GET_MODE_SIZE (mode)==8) + && (unsigned) INTVAL (op) < 8192 + && !(INTVAL (op) & (TARGET_SH2A_DOUBLE ? 7 : 3)) + && (TARGET_SH2A && mode == DFmode))) + return true; + } + + return false; +} + +/* Recognize an RTL expression that is a valid memory address for + an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + Allow REG + REG+disp + REG+r0 + REG++ + --REG */ + +bool +sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +{ + if (MAYBE_BASE_REGISTER_RTX_P (x, strict)) + return true; + else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) + && ! TARGET_SHMEDIA + && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) + return true; + else if (GET_CODE (x) == PLUS + && (mode != PSImode || reload_completed)) + { + rtx xop0 = XEXP (x, 0); + rtx xop1 = XEXP (x, 1); + + if (GET_MODE_SIZE (mode) <= 8 + && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) + && sh_legitimate_index_p (mode, xop1)) + return true; + + if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode + || ((xop0 == stack_pointer_rtx + || xop0 == hard_frame_pointer_rtx) + && REG_P (xop1) && REGNO (xop1) == R0_REG) + || ((xop1 == stack_pointer_rtx + || xop1 == hard_frame_pointer_rtx) + && REG_P (xop0) && REGNO (xop0) == R0_REG)) + && ((!TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 4) + || (TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 8) + || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) + && TARGET_FMOVD && mode == DFmode))) + { + if (MAYBE_BASE_REGISTER_RTX_P (xop1, strict) + && MAYBE_INDEX_REGISTER_RTX_P (xop0, strict)) + return true; + if (MAYBE_INDEX_REGISTER_RTX_P (xop1, strict) + && MAYBE_BASE_REGISTER_RTX_P (xop0, strict)) + return true; + } + } + + return false; +} + /* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol isn't protected by a PIC unspec. */ int diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 71e202a87dd..0b6294a6ce6 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -2191,45 +2191,25 @@ struct sh_args { /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. - We have two alternate definitions for each of them. - The usual definition accepts all pseudo regs; the other rejects - them unless they have been allocated suitable hard regs. - The symbol REG_OK_STRICT causes the latter definition to be used. */ + The suitable hard regs are always accepted and all pseudo regs + are also accepted if STRICT is not set. */ -#ifndef REG_OK_STRICT +/* Nonzero if X is a reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X, STRICT) \ + (GENERAL_OR_AP_REGISTER_P (REGNO (X)) \ + || (!STRICT && REGNO (X) >= FIRST_PSEUDO_REGISTER)) -/* Nonzero if X is a hard reg that can be used as a base reg - or if it is a pseudo reg. */ -#define REG_OK_FOR_BASE_P(X) \ - (GENERAL_OR_AP_REGISTER_P (REGNO (X)) || REGNO (X) >= FIRST_PSEUDO_REGISTER) +/* Nonzero if X is a reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X, STRICT) \ + ((TARGET_SHMEDIA ? GENERAL_REGISTER_P (REGNO (X)) \ + : REGNO (X) == R0_REG) \ + || (!STRICT && REGNO (X) >= FIRST_PSEUDO_REGISTER)) -/* Nonzero if X is a hard reg that can be used as an index - or if it is a pseudo reg. */ -#define REG_OK_FOR_INDEX_P(X) \ - ((TARGET_SHMEDIA ? GENERAL_REGISTER_P (REGNO (X)) \ - : REGNO (X) == R0_REG) || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -/* Nonzero if X/OFFSET is a hard reg that can be used as an index - or if X is a pseudo reg. */ -#define SUBREG_OK_FOR_INDEX_P(X, OFFSET) \ - ((TARGET_SHMEDIA ? GENERAL_REGISTER_P (REGNO (X)) \ - : REGNO (X) == R0_REG && OFFSET == 0) || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#else - -/* Nonzero if X is a hard reg that can be used as a base reg. */ -#define REG_OK_FOR_BASE_P(X) \ - REGNO_OK_FOR_BASE_P (REGNO (X)) - -/* Nonzero if X is a hard reg that can be used as an index. */ -#define REG_OK_FOR_INDEX_P(X) \ - REGNO_OK_FOR_INDEX_P (REGNO (X)) - -/* Nonzero if X/OFFSET is a hard reg that can be used as an index. */ -#define SUBREG_OK_FOR_INDEX_P(X, OFFSET) \ - (REGNO_OK_FOR_INDEX_P (REGNO (X)) && (OFFSET) == 0) - -#endif +/* Nonzero if X/OFFSET is a reg that can be used as an index. */ +#define SUBREG_OK_FOR_INDEX_P(X, OFFSET, STRICT) \ + ((TARGET_SHMEDIA ? GENERAL_REGISTER_P (REGNO (X)) \ + : REGNO (X) == R0_REG && OFFSET == 0) \ + || (!STRICT && REGNO (X) >= FIRST_PSEUDO_REGISTER)) /* Macros for extra constraints. */ @@ -2305,144 +2285,55 @@ struct sh_args { || PCREL_SYMOFF_P (OP)) \ : NON_PIC_REFERENCE_P (OP)) -/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression - that is a valid memory address for an instruction. - The MODE argument is the machine mode for the MEM expression - that wants to use this address. */ - -#define MODE_DISP_OK_4(X,MODE) \ -(GET_MODE_SIZE (MODE) == 4 && (unsigned) INTVAL (X) < 64 \ - && ! (INTVAL (X) & 3) && ! (TARGET_SH2E && (MODE) == SFmode)) - -#define MODE_DISP_OK_8(X,MODE) \ -((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60) \ - && ! (INTVAL(X) & 3) && ! (TARGET_SH4 && (MODE) == DFmode)) - -#undef MODE_DISP_OK_4 -#define MODE_DISP_OK_4(X,MODE) \ -((GET_MODE_SIZE (MODE) == 4 && (unsigned) INTVAL (X) < 64 \ - && ! (INTVAL (X) & 3) && ! (TARGET_SH2E && (MODE) == SFmode)) \ - || ((GET_MODE_SIZE(MODE)==4) && ((unsigned)INTVAL(X)<16383) \ - && ! (INTVAL(X) & 3) && TARGET_SH2A)) - -#undef MODE_DISP_OK_8 -#define MODE_DISP_OK_8(X,MODE) \ -(((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60) \ - && ! (INTVAL(X) & 3) && ! ((TARGET_SH4 || TARGET_SH2A) && (MODE) == DFmode)) \ - || ((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<8192) \ - && ! (INTVAL(X) & (TARGET_SH2A_DOUBLE ? 7 : 3)) && (TARGET_SH2A && (MODE) == DFmode))) - -#define BASE_REGISTER_RTX_P(X) \ - ((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ - || (GET_CODE (X) == SUBREG \ - && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE ((X))), \ +#define MAYBE_BASE_REGISTER_RTX_P(X, STRICT) \ + ((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X, STRICT)) \ + || (GET_CODE (X) == SUBREG \ + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE ((X))), \ GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (X)))) \ - && GET_CODE (SUBREG_REG (X)) == REG \ - && REG_OK_FOR_BASE_P (SUBREG_REG (X)))) + && GET_CODE (SUBREG_REG (X)) == REG \ + && REG_OK_FOR_BASE_P (SUBREG_REG (X), STRICT))) /* Since this must be r0, which is a single register class, we must check SUBREGs more carefully, to be sure that we don't accept one that extends outside the class. */ -#define INDEX_REGISTER_RTX_P(X) \ - ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ - || (GET_CODE (X) == SUBREG \ +#define MAYBE_INDEX_REGISTER_RTX_P(X, STRICT) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X, STRICT)) \ + || (GET_CODE (X) == SUBREG \ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE ((X))), \ GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (X)))) \ && GET_CODE (SUBREG_REG (X)) == REG \ - && SUBREG_OK_FOR_INDEX_P (SUBREG_REG (X), SUBREG_BYTE (X)))) + && SUBREG_OK_FOR_INDEX_P (SUBREG_REG (X), SUBREG_BYTE (X), STRICT))) -/* Jump to LABEL if X is a valid address RTX. This must also take - REG_OK_STRICT into account when deciding about valid registers, but it uses - the above macros so we are in luck. - - Allow REG - REG+disp - REG+r0 - REG++ - --REG */ - -/* ??? The SH2e does not have the REG+disp addressing mode when loading values - into the FRx registers. We implement this by setting the maximum offset - to zero when the value is SFmode. This also restricts loading of SFmode - values into the integer registers, but that can't be helped. */ - -/* The SH allows a displacement in a QI or HI amode, but only when the - other operand is R0. GCC doesn't handle this very well, so we forgo - all of that. - - A legitimate index for a QI or HI is 0, SI can be any number 0..63, - DI can be any number 0..60. */ - -#define GO_IF_LEGITIMATE_INDEX(MODE, OP, LABEL) \ - do { \ - if (GET_CODE (OP) == CONST_INT) \ - { \ - if (TARGET_SHMEDIA) \ - { \ - int MODE_SIZE; \ - /* Check if this the address of an unaligned load / store. */\ - if ((MODE) == VOIDmode) \ - { \ - if (CONST_OK_FOR_I06 (INTVAL (OP))) \ - goto LABEL; \ - break; \ - } \ - MODE_SIZE = GET_MODE_SIZE (MODE); \ - if (! (INTVAL (OP) & (MODE_SIZE - 1)) \ - && INTVAL (OP) >= -512 * MODE_SIZE \ - && INTVAL (OP) < 512 * MODE_SIZE) \ - goto LABEL; \ - else \ - break; \ - } \ - if (TARGET_SH2A) \ - { \ - if (GET_MODE_SIZE (MODE) == 1 \ - && (unsigned) INTVAL (OP) < 4096) \ - goto LABEL; \ - } \ - if (MODE_DISP_OK_4 ((OP), (MODE))) goto LABEL; \ - if (MODE_DISP_OK_8 ((OP), (MODE))) goto LABEL; \ - } \ - } while(0) +#ifdef REG_OK_STRICT +#define BASE_REGISTER_RTX_P(X) MAYBE_BASE_REGISTER_RTX_P(X, true) +#define INDEX_REGISTER_RTX_P(X) MAYBE_INDEX_REGISTER_RTX_P(X, true) +#else +#define BASE_REGISTER_RTX_P(X) MAYBE_BASE_REGISTER_RTX_P(X, false) +#define INDEX_REGISTER_RTX_P(X) MAYBE_INDEX_REGISTER_RTX_P(X, false) +#endif #define ALLOW_INDEXED_ADDRESS \ ((!TARGET_SHMEDIA32 && !TARGET_SHCOMPACT) || TARGET_ALLOW_INDEXED_ADDRESS) -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ -{ \ - if (BASE_REGISTER_RTX_P (X)) \ - goto LABEL; \ - else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \ - && ! TARGET_SHMEDIA \ - && BASE_REGISTER_RTX_P (XEXP ((X), 0))) \ - goto LABEL; \ - else if (GET_CODE (X) == PLUS \ - && ((MODE) != PSImode || reload_completed)) \ - { \ - rtx xop0 = XEXP ((X), 0); \ - rtx xop1 = XEXP ((X), 1); \ - if (GET_MODE_SIZE (MODE) <= 8 && BASE_REGISTER_RTX_P (xop0)) \ - GO_IF_LEGITIMATE_INDEX ((MODE), xop1, LABEL); \ - if ((ALLOW_INDEXED_ADDRESS || GET_MODE (X) == DImode \ - || ((xop0 == stack_pointer_rtx \ - || xop0 == hard_frame_pointer_rtx) \ - && REG_P (xop1) && REGNO (xop1) == R0_REG) \ - || ((xop1 == stack_pointer_rtx \ - || xop1 == hard_frame_pointer_rtx) \ - && REG_P (xop0) && REGNO (xop0) == R0_REG)) \ - && ((!TARGET_SHMEDIA && GET_MODE_SIZE (MODE) <= 4) \ - || (TARGET_SHMEDIA && GET_MODE_SIZE (MODE) <= 8) \ - || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) \ - && TARGET_FMOVD && MODE == DFmode))) \ - { \ - if (BASE_REGISTER_RTX_P (xop1) && INDEX_REGISTER_RTX_P (xop0))\ - goto LABEL; \ - if (INDEX_REGISTER_RTX_P (xop1) && BASE_REGISTER_RTX_P (xop0))\ - goto LABEL; \ - } \ - } \ -} +#define GO_IF_LEGITIMATE_INDEX(MODE, OP, WIN) \ + do { \ + if (sh_legitimate_index_p ((MODE), (OP))) \ + goto WIN; \ + } while (0) + +#ifdef REG_OK_STRICT +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ + do { \ + if (sh_legitimate_address_p ((MODE), (X), true)) \ + goto LABEL; \ + } while (0) +#else +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ + do { \ + if (sh_legitimate_address_p ((MODE), (X), false)) \ + goto LABEL; \ + } while (0) +#endif /* A C compound statement that attempts to replace X, which is an address that needs reloading, with a valid memory address for an operand of