diff options
author | Joseph Myers <joseph@codesourcery.com> | 2006-12-01 02:25:22 +0000 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2006-12-01 02:25:22 +0000 |
commit | 8521c41417b57bf46fc57efccf3befaf6fc0a712 (patch) | |
tree | 3b6620756f6468172f9d6c83a27617279a0da87c /gcc/rtlanal.c | |
parent | 877c1c555fdcc46467c9fe9e9dccb8aaf8efe178 (diff) | |
download | gcc-8521c41417b57bf46fc57efccf3befaf6fc0a712.zip gcc-8521c41417b57bf46fc57efccf3befaf6fc0a712.tar.gz gcc-8521c41417b57bf46fc57efccf3befaf6fc0a712.tar.bz2 |
re PR target/24036 ([e500] ICE in subreg_offset_representable_p, at rtlanal.c:3143)
2006-12-01 Joseph Myers <joseph@codesourcery.com>
David Edelsohn <edelsohn@gnu.org>
PR target/24036
* doc/tm.texi (HARD_REGNO_NREGS_HAS_PADDING,
HARD_REGNO_NREGS_WITH_PADDING): Document new target macros.
* defaults.h (HARD_REGNO_NREGS_HAS_PADDING,
HARD_REGNO_NREGS_WITH_PADDING): Define.
* config/i386/i386.h (HARD_REGNO_NREGS_HAS_PADDING,
HARD_REGNO_NREGS_WITH_PADDING): Define.
* rtlanal.c (subreg_regno_offset, subreg_offset_representable_p):
Use new macros to detect modes with holes; do not look at integer
units.
(subreg_offset_representable_p): Check for and disallow cases
where the modes use different numbers of bits from registers.
* config/rs6000/rs6000.c (rs6000_emit_move): Handle TFmode
constant for soft-float.
(rs6000_hard_regno_nregs): Use UNITS_PER_FP_WORD for e500 GPRs
containing doubles.
(rs6000_split_multireg_move): Use DFmode reg_mode for TFmode moves
in E500 double case.
* config/rs6000/rs6000.md (movtf): Allow soft-float.
(movtf_softfloat): New.
Co-Authored-By: David Edelsohn <edelsohn@gnu.org>
From-SVN: r119395
Diffstat (limited to 'gcc/rtlanal.c')
-rw-r--r-- | gcc/rtlanal.c | 86 |
1 files changed, 33 insertions, 53 deletions
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 8a7c914..fd7fa01 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -2925,34 +2925,15 @@ unsigned int subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode, nregs_xmode_unit_int; + int nregs_xmode, nregs_ymode; int mode_multiple, nregs_multiple; int y_offset; - enum machine_mode xmode_unit, xmode_unit_int; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - if (GET_MODE_INNER (xmode) == VOIDmode) - xmode_unit = xmode; - else - xmode_unit = GET_MODE_INNER (xmode); - - if (FLOAT_MODE_P (xmode_unit)) - { - xmode_unit_int = int_mode_for_mode (xmode_unit); - if (xmode_unit_int == BLKmode) - /* It's probably bad to be here; a port should have an integer mode - that's the same size as anything of which it takes a SUBREG. */ - xmode_unit_int = xmode_unit; - } - else - xmode_unit_int = xmode_unit; - - nregs_xmode_unit_int = hard_regno_nregs[xregno][xmode_unit_int]; - /* Adjust nregs_xmode to allow for 'holes'. */ - if (nregs_xmode_unit_int != hard_regno_nregs[xregno][xmode_unit]) - nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); + if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) + nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -2990,38 +2971,31 @@ bool subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode, nregs_xmode_unit, nregs_xmode_unit_int; + int nregs_xmode, nregs_ymode; int mode_multiple, nregs_multiple; int y_offset; - enum machine_mode xmode_unit, xmode_unit_int; + int regsize_xmode, regsize_ymode; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - if (GET_MODE_INNER (xmode) == VOIDmode) - xmode_unit = xmode; - else - xmode_unit = GET_MODE_INNER (xmode); - - if (FLOAT_MODE_P (xmode_unit)) - { - xmode_unit_int = int_mode_for_mode (xmode_unit); - if (xmode_unit_int == BLKmode) - /* It's probably bad to be here; a port should have an integer mode - that's the same size as anything of which it takes a SUBREG. */ - xmode_unit_int = xmode_unit; - } - else - xmode_unit_int = xmode_unit; - - nregs_xmode_unit = hard_regno_nregs[xregno][xmode_unit]; - nregs_xmode_unit_int = hard_regno_nregs[xregno][xmode_unit_int]; - /* If there are holes in a non-scalar mode in registers, we expect that it is made up of its units concatenated together. */ - if (nregs_xmode_unit != nregs_xmode_unit_int) + if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) { - gcc_assert (nregs_xmode_unit * GET_MODE_NUNITS (xmode) - == hard_regno_nregs[xregno][xmode]); + enum machine_mode xmode_unit; + + nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); + if (GET_MODE_INNER (xmode) == VOIDmode) + xmode_unit = xmode; + else + xmode_unit = GET_MODE_INNER (xmode); + gcc_assert (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode_unit)); + gcc_assert (nregs_xmode + == (GET_MODE_NUNITS (xmode) + * HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode_unit))); + gcc_assert (hard_regno_nregs[xregno][xmode] + == (hard_regno_nregs[xregno][xmode_unit] + * GET_MODE_NUNITS (xmode))); /* You can only ask for a SUBREG of a value with holes in the middle if you don't cross the holes. (Such a SUBREG should be done by @@ -3031,15 +3005,12 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, 3 for each part, but in memory it's two 128-bit parts. Padding is assumed to be at the end (not necessarily the 'high part') of each unit. */ - if (nregs_xmode_unit != nregs_xmode_unit_int - && (offset / GET_MODE_SIZE (xmode_unit_int) + 1 - < GET_MODE_NUNITS (xmode)) - && (offset / GET_MODE_SIZE (xmode_unit_int) + if ((offset / GET_MODE_SIZE (xmode_unit) + 1 + < GET_MODE_NUNITS (xmode)) + && (offset / GET_MODE_SIZE (xmode_unit) != ((offset + GET_MODE_SIZE (ymode) - 1) - / GET_MODE_SIZE (xmode_unit_int)))) + / GET_MODE_SIZE (xmode_unit)))) return false; - - nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); } else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -3053,6 +3024,15 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) return true; + /* If registers store different numbers of bits in the different + modes, we cannot generally form this subreg. */ + regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; + regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; + if (regsize_xmode > regsize_ymode && nregs_ymode > 1) + return false; + if (regsize_ymode > regsize_xmode && nregs_xmode > 1) + return false; + /* Lowpart subregs are otherwise valid. */ if (offset == subreg_lowpart_offset (ymode, xmode)) return true; |