]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/24036 ([e500] ICE in subreg_offset_representable_p, at rtlanal.c:3143)
authorJoseph Myers <joseph@codesourcery.com>
Fri, 1 Dec 2006 02:25:22 +0000 (02:25 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 1 Dec 2006 02:25:22 +0000 (02:25 +0000)
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

gcc/ChangeLog
gcc/config/i386/i386.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/defaults.h
gcc/doc/tm.texi
gcc/rtlanal.c

index fbde18eb2a6037fa073ddb24730b1584b72cc2a3..559be89c453718af644e38770f9461a1633d1453 100644 (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
index 52118f98ab6f9a697ca1bd9fd774f97f737044d0..e30d6b7bdefa8f951a7a13763d0b48b0f1c730ba 100644 (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)
index d607de26f840e000371c70971eb9e5e2f8806f05..977a66d265daf4eedfee79f3dbdabda0c2fd36c6 100644 (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);
index 7e1d0a193268f94c7355b171efafc846c5a07041..62541df0cccc2482f2a7a98c9c7332758e30ebc2 100644 (file)
 (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
 { 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" "")))
index 3d470e94730753b5728d35ffc99228b12ba89992..6af5f17bd7dd75e6362837a34d1a44deea311156 100644 (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 */
index 2a21a5890efb62e3970866c713f2bfd2066d52f1..634f5f170c6703e6c40d6965172c2941841ce479 100644 (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
index 8a7c914022c6ddc3a2c20ccfd174875ca4c5ed31..fd7fa017eec05a9f8296b0a226d7404c6e833a79 100644 (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;