aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2006-12-01 02:32:04 +0000
committerJoseph Myers <joseph@codesourcery.com>2006-12-01 02:32:04 +0000
commitf279fd6f682ef1bdc82b2f2a7bf5e9b45fb0cdec (patch)
tree5b3da694bbfdaeb088c36a034c6a8d7a393362b7
parent95e386c4e5fdd4e7bf2001df845278a8e25ce2ec (diff)
2006-12-01 Joseph Myers <joseph@codesourcery.com>
David Edelsohn <edelsohn@gnu.org> gcc/ * 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_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. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl/sourcerygxx-4_1@119396 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog.csl20
-rw-r--r--gcc/config/i386/i386.h9
-rw-r--r--gcc/config/rs6000/rs6000.c13
-rw-r--r--gcc/defaults.h5
-rw-r--r--gcc/doc/tm.texi27
-rw-r--r--gcc/rtlanal.c86
6 files changed, 104 insertions, 56 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index 3ddf0378cbf..8a16fc0dc8f 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,23 @@
+2006-12-01 Joseph Myers <joseph@codesourcery.com>
+ David Edelsohn <edelsohn@gnu.org>
+
+ gcc/
+ * 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_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.
+
2006-11-30 Joseph Myers <joseph@codesourcery.com>
gcc/testsuite/
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index a2650fd6618..eeebaafd831 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -831,6 +831,15 @@ do { \
? (TARGET_64BIT ? 4 : 6) \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
+#define HARD_REGNO_NREGS_HAS_PADDING(REGNO, MODE) \
+ ((TARGET_128BIT_LONG_DOUBLE && !TARGET_64BIT) \
+ ? (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) \
+ ? 0 \
+ : ((MODE) == XFmode || (MODE) == XCmode)) \
+ : 0)
+
+#define HARD_REGNO_NREGS_WITH_PADDING(REGNO, MODE) ((MODE) == XFmode ? 4 : 8)
+
#define VALID_SSE2_REG_MODE(MODE) \
((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode \
|| (MODE) == V2DImode || (MODE) == DFmode)
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 4b7fc386d45..e474b7b5650 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -3571,9 +3571,6 @@ rs6000_hard_regno_nregs (int regno, enum machine_mode mode)
if (FP_REGNO_P (regno))
return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
- if (TARGET_E500_DOUBLE && mode == DFmode)
- return 1;
-
if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
return (GET_MODE_SIZE (mode) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD;
@@ -3581,6 +3578,14 @@ rs6000_hard_regno_nregs (int regno, enum machine_mode mode)
return
(GET_MODE_SIZE (mode) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD;
+ /* The value returned for SCmode in the E500 double case is 2 for
+ ABI compatibility; storing an SCmode value in a single register
+ would require function_arg and rs6000_spe_function_arg to handle
+ SCmode so as to pass the value correctly in a pair of
+ registers. */
+ if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode) && mode != SCmode)
+ return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
+
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}
@@ -12414,6 +12419,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
reg_mode = DFmode;
else if (ALTIVEC_REGNO_P (reg))
reg_mode = V16QImode;
+ else if (TARGET_E500_DOUBLE && mode == TFmode)
+ reg_mode = DFmode;
else
reg_mode = word_mode;
reg_mode_size = GET_MODE_SIZE (reg_mode);
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 55fc1c618cc..6d494225242 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -879,4 +879,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#define INCOMING_FRAME_SP_OFFSET 0
#endif
+#ifndef HARD_REGNO_NREGS_HAS_PADDING
+#define HARD_REGNO_NREGS_HAS_PADDING(REGNO, MODE) 0
+#define HARD_REGNO_NREGS_WITH_PADDING(REGNO, MODE) -1
+#endif
+
#endif /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 32f93fa5f0b..4baac440ab8 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1959,6 +1959,33 @@ definition of this macro is
@end smallexample
@end defmac
+@defmac HARD_REGNO_NREGS_HAS_PADDING (@var{regno}, @var{mode})
+A C expression that is nonzero if a value of mode @var{mode}, stored
+in memory, ends with padding that causes it to take up more space than
+in registers starting at register number @var{regno} (as determined by
+multiplying GCC's notion of the size of the register when containing
+this mode by the number of registers returned by
+@code{HARD_REGNO_NREGS}). By default this is zero.
+
+For example, if a floating-point value is stored in three 32-bit
+registers but takes up 128 bits in memory, then this would be
+nonzero.
+
+This macros only needs to be defined if there are cases where
+@code{subreg_regno_offset} and @code{subreg_offset_representable_p}
+would otherwise wrongly determine that a @code{subreg} can be
+represented by an offset to the register number, when in fact such a
+@code{subreg} would contain some of the padding not stored in
+registers and so not be representable.
+@end defmac
+
+@defmac HARD_REGNO_NREGS_WITH_PADDING (@var{regno}, @var{mode})
+For values of @var{regno} and @var{mode} for which
+@code{HARD_REGNO_NREGS_HAS_PADDING} returns nonzero, a C expression
+returning the greater number of registers required to hold the value
+including any padding. In the example above, the value would be four.
+@end defmac
+
@defmac REGMODE_NATURAL_SIZE (@var{mode})
Define this macro if the natural size of registers that hold values
of mode @var{mode} is not the word size. It is a C expression that
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index f5e5c4b45ed..93d07614a51 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3187,34 +3187,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];
@@ -3252,38 +3233,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
@@ -3293,15 +3267,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];
@@ -3315,6 +3286,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;