aboutsummaryrefslogtreecommitdiff
path: root/gcc/rtlanal.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2006-12-01 02:25:22 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2006-12-01 02:25:22 +0000
commit8521c41417b57bf46fc57efccf3befaf6fc0a712 (patch)
tree3b6620756f6468172f9d6c83a27617279a0da87c /gcc/rtlanal.c
parent877c1c555fdcc46467c9fe9e9dccb8aaf8efe178 (diff)
downloadgcc-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.c86
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;