diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2fe77890a0e..22f639bd8be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2008-08-28 Richard Sandiford + + * rtl.h (simplify_subreg_regno): Declare. + * rtlanal.c (simplify_subreg_regno): New function, split out from... + * simplify-rtx.c (simplify_subreg): ...here. + * reload.c (find_reloads): Use simplify_subreg_regno instead of + subreg_offset_representable_p. + 2008-08-28 Manuel Lopez-Ibanez PR c/30949 diff --git a/gcc/reload.c b/gcc/reload.c index 81637007995..e353c50acdb 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2999,12 +2999,11 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, if (REG_P (SUBREG_REG (operand)) && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) { - if (!subreg_offset_representable_p - (REGNO (SUBREG_REG (operand)), - GET_MODE (SUBREG_REG (operand)), - SUBREG_BYTE (operand), - GET_MODE (operand))) - force_reload = 1; + if (simplify_subreg_regno (REGNO (SUBREG_REG (operand)), + GET_MODE (SUBREG_REG (operand)), + SUBREG_BYTE (operand), + GET_MODE (operand)) < 0) + force_reload = 1; offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)), GET_MODE (SUBREG_REG (operand)), SUBREG_BYTE (operand), diff --git a/gcc/rtl.h b/gcc/rtl.h index 42fc2ad6b64..9e7d40ad6e5 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1084,6 +1084,8 @@ extern unsigned int subreg_regno_offset (unsigned int, enum machine_mode, extern bool subreg_offset_representable_p (unsigned int, enum machine_mode, unsigned int, enum machine_mode); extern unsigned int subreg_regno (const_rtx); +extern int simplify_subreg_regno (unsigned int, enum machine_mode, + unsigned int, enum machine_mode); extern unsigned int subreg_nregs (const_rtx); extern unsigned int subreg_nregs_with_regno (unsigned int, const_rtx); extern unsigned HOST_WIDE_INT nonzero_bits (const_rtx, enum machine_mode); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 00a63cd9b96..9c5a1e53c7f 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3244,6 +3244,64 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, return info.representable_p; } +/* Return the number of a YMODE register to which + + (subreg:YMODE (reg:XMODE XREGNO) OFFSET) + + can be simplified. Return -1 if the subreg can't be simplified. + + XREGNO is a hard register number. */ + +int +simplify_subreg_regno (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode) +{ + struct subreg_info info; + unsigned int yregno; + +#ifdef CANNOT_CHANGE_MODE_CLASS + /* Give the backend a chance to disallow the mode change. */ + if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT + && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)) + return -1; +#endif + + /* We shouldn't simplify stack-related registers. */ + if ((!reload_completed || frame_pointer_needed) + && (xregno == FRAME_POINTER_REGNUM + || xregno == HARD_FRAME_POINTER_REGNUM)) + return -1; + + if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && xregno == ARG_POINTER_REGNUM) + return -1; + + if (xregno == STACK_POINTER_REGNUM) + return -1; + + /* Try to get the register offset. */ + subreg_get_info (xregno, xmode, offset, ymode, &info); + if (!info.representable_p) + return -1; + + /* Make sure that the offsetted register value is in range. */ + yregno = xregno + info.offset; + if (!HARD_REGISTER_NUM_P (yregno)) + return -1; + + /* See whether (reg:YMODE YREGNO) is valid. + + ??? We allow invalid registers if (reg:XMODE XREGNO) is also invalid. + This is a kludge to work around how float/complex arguments are passed + on 32-bit SPARC and should be fixed. */ + if (!HARD_REGNO_MODE_OK (yregno, ymode) + && HARD_REGNO_MODE_OK (xregno, xmode)) + return -1; + + return (int) yregno; +} + /* Return the final regno that a subreg expression refers to. */ unsigned int subreg_regno (const_rtx x) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 6fd77ff1543..606a850622c 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -5069,35 +5069,13 @@ simplify_subreg (enum machine_mode outermode, rtx op, suppress this simplification. If the hard register is the stack, frame, or argument pointer, leave this as a SUBREG. */ - if (REG_P (op) - && REGNO (op) < FIRST_PSEUDO_REGISTER -#ifdef CANNOT_CHANGE_MODE_CLASS - && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), innermode, outermode) - && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT - && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT) -#endif - && ((reload_completed && !frame_pointer_needed) - || (REGNO (op) != FRAME_POINTER_REGNUM -#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM - && REGNO (op) != HARD_FRAME_POINTER_REGNUM -#endif - )) -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - && REGNO (op) != ARG_POINTER_REGNUM -#endif - && REGNO (op) != STACK_POINTER_REGNUM - && subreg_offset_representable_p (REGNO (op), innermode, - byte, outermode)) + if (REG_P (op) && HARD_REGISTER_P (op)) { - unsigned int regno = REGNO (op); - unsigned int final_regno - = regno + subreg_regno_offset (regno, innermode, byte, outermode); + unsigned int regno, final_regno; - /* ??? We do allow it if the current REG is not valid for - its mode. This is a kludge to work around how float/complex - arguments are passed on 32-bit SPARC and should be fixed. */ - if (HARD_REGNO_MODE_OK (final_regno, outermode) - || ! HARD_REGNO_MODE_OK (regno, innermode)) + regno = REGNO (op); + final_regno = simplify_subreg_regno (regno, innermode, byte, outermode); + if (HARD_REGISTER_NUM_P (final_regno)) { rtx x; int final_offset = byte;