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
This commit is contained in:
Joseph Myers 2006-12-01 02:25:22 +00:00 committed by Joseph Myers
parent 877c1c555f
commit 8521c41417
7 changed files with 123 additions and 60 deletions

View File

@ -1,3 +1,27 @@
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.
2006-11-30 Richard Sandiford <richard@codesourcery.com>
* simplify-rtx.c (simplify_rtx): Use simplify_subreg rather than

View File

@ -917,6 +917,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)

View File

@ -3822,9 +3822,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;
@ -3832,6 +3829,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;
}
@ -4200,8 +4205,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
/* 128-bit constant floating-point values on Darwin should really be
loaded as two parts. */
if (!TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
&& mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
{
/* DImode is used, not DFmode, because simplify_gen_subreg doesn't
@ -12744,6 +12748,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);

View File

@ -8518,8 +8518,7 @@
(define_expand "movtf"
[(set (match_operand:TF 0 "general_operand" "")
(match_operand:TF 1 "any_operand" ""))]
"!TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
"!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
"{ rs6000_emit_move (operands[0], operands[1], TFmode); DONE; }")
; It's important to list the o->f and f->o moves before f->f because
@ -8538,6 +8537,19 @@
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "8,8,8,20,20,16")])
(define_insn_and_split "*movtf_softfloat"
[(set (match_operand:TF 0 "nonimmediate_operand" "=r,Y,r")
(match_operand:TF 1 "input_operand" "YGHF,r,r"))]
"!TARGET_IEEEQUAD
&& (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128
&& (gpc_reg_operand (operands[0], TFmode)
|| gpc_reg_operand (operands[1], TFmode))"
"#"
"&& reload_completed"
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "20,20,16")])
(define_expand "extenddftf2"
[(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "")
(float_extend:TF (match_operand:DF 1 "input_operand" "")))

View File

@ -895,4 +895,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 */

View File

@ -1978,6 +1978,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

View File

@ -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;