2006-12-21 Jakub Jelinek Revert: 2006-12-16 Joseph Myers David Edelsohn 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. --- gcc/doc/tm.texi (revision 119967) +++ gcc/doc/tm.texi (revision 119966) @@ -1937,33 +1937,6 @@ 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 --- gcc/defaults.h (revision 119967) +++ gcc/defaults.h (revision 119966) @@ -867,9 +867,4 @@ Software Foundation, 51 Franklin Street, #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 */ --- gcc/rtlanal.c (revision 119967) +++ gcc/rtlanal.c (revision 119966) @@ -3138,15 +3138,34 @@ unsigned int subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode; + int nregs_xmode, nregs_ymode, nregs_xmode_unit_int; 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 (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) - nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); + if (nregs_xmode_unit_int != hard_regno_nregs[xregno][xmode_unit]) + nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -3184,31 +3203,38 @@ bool subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode; + int nregs_xmode, nregs_ymode, nregs_xmode_unit, nregs_xmode_unit_int; int mode_multiple, nregs_multiple; int y_offset; - int regsize_xmode, regsize_ymode; + 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 = 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 (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) + if (nregs_xmode_unit != nregs_xmode_unit_int) { - 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))); + gcc_assert (nregs_xmode_unit * GET_MODE_NUNITS (xmode) + == hard_regno_nregs[xregno][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 @@ -3218,12 +3244,15 @@ subreg_offset_representable_p (unsigned 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 ((offset / GET_MODE_SIZE (xmode_unit) + 1 - < GET_MODE_NUNITS (xmode)) - && (offset / GET_MODE_SIZE (xmode_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) != ((offset + GET_MODE_SIZE (ymode) - 1) - / GET_MODE_SIZE (xmode_unit)))) + / GET_MODE_SIZE (xmode_unit_int)))) return false; + + nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); } else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -3237,15 +3266,6 @@ subreg_offset_representable_p (unsigned ? 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; --- gcc/config/i386/i386.h (revision 119967) +++ gcc/config/i386/i386.h (revision 119966) @@ -827,15 +827,6 @@ 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) --- gcc/config/rs6000/rs6000.c (revision 119967) +++ gcc/config/rs6000/rs6000.c (revision 119966) @@ -3573,6 +3573,9 @@ rs6000_hard_regno_nregs (int regno, enum 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; @@ -3580,14 +3583,6 @@ rs6000_hard_regno_nregs (int regno, enum 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; } @@ -3956,7 +3951,8 @@ rs6000_emit_move (rtx dest, rtx source, /* 128-bit constant floating-point values on Darwin should really be loaded as two parts. */ - if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128 + if (!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128 && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE) { /* DImode is used, not DFmode, because simplify_gen_subreg doesn't @@ -12402,8 +12398,6 @@ rs6000_split_multireg_move (rtx dst, rtx 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); --- gcc/config/rs6000/rs6000.md (revision 119967) +++ gcc/config/rs6000/rs6000.md (revision 119966) @@ -7789,7 +7789,8 @@ (define_insn "*movdf_softfloat64" (define_expand "movtf" [(set (match_operand:TF 0 "general_operand" "") (match_operand:TF 1 "any_operand" ""))] - "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && 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 @@ -7808,19 +7809,6 @@ (define_insn_and_split "*movtf_internal" { 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" "")))