re PR target/11848 ([darwin] [no support for 128 doubles] internal compiler error...
authorGeoffrey Keating <geoffk@apple.com>
Tue, 9 Dec 2003 01:57:45 +0000 (01:57 +0000)
committerGeoffrey Keating <geoffk@gcc.gnu.org>
Tue, 9 Dec 2003 01:57:45 +0000 (01:57 +0000)
PR target/11848
* rs6000.h (CANNOT_CHANGE_MODE_CLASS): Allow change of mode
in floating-point registers between TFmode and DImode.
* rs6000.c (rs6000_emit_move): Split moves early.
(secondary_reload_class): Random Whitespace Change.
(rs6000_split_multireg_move): Support moves involving FP registers.
Emit instructions directly.
* rs6000-protos.h (rs6000_split_multireg_move): Update prototype.
* altivec.md: Update for changes to rs6000_split_multireg_move.
* rs6000.md: Update for changes to rs6000_split_multireg_move.
(movtf_internal): Support moves to/from GPRs.

From-SVN: r74454

gcc/ChangeLog
gcc/config/rs6000/altivec.md
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/testsuite/gcc.c-torture/compile/20031208-1.c [new file with mode: 0644]

index 984fa45..113bdcb 100644 (file)
@@ -1,3 +1,17 @@
+2003-12-08  Geoffrey Keating  <geoffk@apple.com>
+
+       PR target/11848
+       * rs6000.h (CANNOT_CHANGE_MODE_CLASS): Allow change of mode
+       in floating-point registers between TFmode and DImode.
+       * rs6000.c (rs6000_emit_move): Split moves early.
+       (secondary_reload_class): Random Whitespace Change.
+       (rs6000_split_multireg_move): Support moves involving FP registers.
+       Emit instructions directly.
+       * rs6000-protos.h (rs6000_split_multireg_move): Update prototype.
+       * altivec.md: Update for changes to rs6000_split_multireg_move.
+       * rs6000.md: Update for changes to rs6000_split_multireg_move.
+       (movtf_internal): Support moves to/from GPRs.
+
 2003-12-08  Stuart Hastings  <stuart@apple.com>
 
        * config/i386/i386.md: Typo in split of fp-valued if_then_else.
index 5fccb98..73d0417 100644 (file)
 (define_split
   [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
         (match_operand:V4SI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64 
+  "TARGET_ALTIVEC && reload_completed
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-(define_split
-  [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
-        (match_operand:V4SI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64 
-   && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_split
   [(set (match_operand:V4SI 0 "altivec_register_operand" "")
 (define_split
   [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
         (match_operand:V8HI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64 
+  "TARGET_ALTIVEC && reload_completed
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-(define_split
-  [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
-        (match_operand:V8HI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64 
-   && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_split
   [(set (match_operand:V8HI 0 "altivec_register_operand" "")
 (define_split
   [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
         (match_operand:V16QI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64 
+  "TARGET_ALTIVEC && reload_completed
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-(define_split
-  [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
-        (match_operand:V16QI 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64 
-   && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_split
   [(set (match_operand:V16QI 0 "altivec_register_operand" "")
 (define_split
   [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
         (match_operand:V4SF 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && TARGET_POWERPC64 
+  "TARGET_ALTIVEC && reload_completed
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-(define_split
-  [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
-        (match_operand:V4SF 1 "input_operand" ""))]
-  "TARGET_ALTIVEC && reload_completed && !TARGET_POWERPC64 
-   && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_insn "get_vrsave_internal"
   [(set (match_operand:SI 0 "register_operand" "=r")
index 57fca19..79679f4 100644 (file)
@@ -125,7 +125,7 @@ extern int mfcr_operation (rtx, enum machine_mode);
 extern int mtcrf_operation (rtx, enum machine_mode);
 extern int lmw_operation (rtx, enum machine_mode);
 extern struct rtx_def *create_TOC_reference (rtx);
-extern void rs6000_split_multireg_move (rtx *);
+extern void rs6000_split_multireg_move (rtx, rtx);
 extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
 extern rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode);
 extern rtx rs6000_legitimize_reload_address (rtx, enum machine_mode,
index 4f91e80..647469f 100644 (file)
@@ -3457,7 +3457,26 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
   /* Handle the case of CONSTANT_P_RTX.  */
   if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
     goto emit_set;
-  
+
+  /* 128-bit constant floating-point values on Darwin should really be
+     loaded as two parts.  */
+  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+      && 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
+        know how to get a DFmode SUBREG of a TFmode.  */
+      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
+                       simplify_gen_subreg (DImode, operands[1], mode, 0),
+                       DImode);
+      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
+                                            GET_MODE_SIZE (DImode)),
+                       simplify_gen_subreg (DImode, operands[1], mode,
+                                            GET_MODE_SIZE (DImode)),
+                       DImode);
+      return;
+    }
+
   /* FIXME:  In the long term, this switch statement should go away
      and be replaced by a sequence of tests based on things like
      mode == Pmode.  */
@@ -8302,7 +8321,8 @@ addrs_ok_for_quad_peep (rtx addr1, rtx addr2)
 
 enum reg_class
 secondary_reload_class (enum reg_class class, 
-               enum machine_mode mode ATTRIBUTE_UNUSED, rtx in)
+                       enum machine_mode mode ATTRIBUTE_UNUSED,
+                       rtx in)
 {
   int regno;
 
@@ -10007,73 +10027,72 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
     emit_move_insn (dest, target);
 }
 
-/* Called by splitter for multireg moves.
-   Input: 
-          operands[0] : Destination of move
-          operands[1] : Source of move
-
-   Output:
-         operands[2-n] : Destination slots
-         operands[n-m] : Source slots
-   where n = 2 + HARD_REGNO_NREGS (reg, GET_MODE (operands[0]))
-         m = 2 + 2 * HARD_REGNO_NREGS (reg, GET_MODE (operands[0])) - 1
+/* Emit instructions to move SRC to DST.  Called by splitters for
+   multi-register moves.  It will emit at most one instruction for
+   each register that is accessed; that is, it won't emit li/lis pairs
+   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
+   register.  */
 
-   Splits the move of operands[1] to operands[0].
-   This is done, if GPRs are one of the operands.  In this case
-   a sequence of simple move insns has to be issued.  The sequence of these
-   move insns has to be done in correct order to avoid early clobber of the
-   base register or destructive overlap of registers. 
-*/
-         
 void
-rs6000_split_multireg_move (rtx *operands)
+rs6000_split_multireg_move (rtx dst, rtx src)
 {
-  int nregs, reg, i, j, used_update = 0;
-  enum machine_mode mode; 
-  rtx dst = operands[0];
-  rtx src = operands[1];
-  rtx insn = 0;
-
-  /* Calculate number to move (2/4 for 32/64 bit mode).  */ 
-
-  reg = REG_P (operands[0]) ? REGNO (operands[0]) : REGNO (operands[1]); 
-  mode = GET_MODE (operands[0]);
-  nregs = HARD_REGNO_NREGS (reg, mode);                                  
+  /* The register number of the first register being moved.  */
+  int reg;
+  /* The mode that is to be moved.  */
+  enum machine_mode mode;
+  /* The mode that the move is being done in, and its size.  */
+  enum machine_mode reg_mode;
+  int reg_mode_size;
+  /* The number of registers that will be moved.  */
+  int nregs;
+
+  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
+  mode = GET_MODE (dst);
+  nregs = HARD_REGNO_NREGS (reg, mode);
+  if (FP_REGNO_P (reg))
+    reg_mode = DFmode;
+  else if (ALTIVEC_REGNO_P (reg))
+    reg_mode = V16QImode;
+  else
+    reg_mode = word_mode;
+  reg_mode_size = GET_MODE_SIZE (reg_mode);
   
-  if (REG_P (operands[1]) 
-      && REG_P (operands[0]) 
-      && (REGNO (operands[1]) < REGNO (operands[0])))
-    {  
-      /* Move register range backwards, if we have destructive overlap.  */
-
-      j = nregs;
-      for (i = 0; i < nregs; i++)
-        {
-          j--;
-          operands[i+2] = operand_subword (operands[0], j, 0, mode);
-          operands[i+2+nregs] = 
-            operand_subword (operands[1], j, 0, mode);   
-        }
-    }     
+  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
+    abort ();
+  
+  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
+    {
+      /* Move register range backwards, if we might have destructive
+        overlap.  */
+      int i;
+      for (i = nregs - 1; i >= 0; i--)
+       emit_insn (gen_rtx_SET (VOIDmode, 
+                               simplify_gen_subreg (reg_mode, dst, mode,
+                                                    i * reg_mode_size),
+                               simplify_gen_subreg (reg_mode, src, mode,
+                                                    i * reg_mode_size)));
+    }
   else
     {
-      j = -1;
+      int i;
+      int j = -1;
+      bool used_update = false;
 
-      if (GET_CODE (operands[1]) == MEM)
+      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
         {
           rtx breg;
 
-         if (GET_CODE (XEXP (operands[1], 0)) == PRE_INC
-             || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
+         if (GET_CODE (XEXP (src, 0)) == PRE_INC
+             || GET_CODE (XEXP (src, 0)) == PRE_DEC)
            {
              rtx delta_rtx;
-             breg = XEXP (XEXP (operands[1], 0), 0);
-             delta_rtx =  GET_CODE (XEXP (operands[1], 0)) == PRE_INC 
-                 ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[1]))) 
-                 : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[1]))); 
-             insn = emit_insn (TARGET_32BIT
-                               ? gen_addsi3 (breg, breg, delta_rtx)
-                               : gen_adddi3 (breg, breg, delta_rtx));
+             breg = XEXP (XEXP (src, 0), 0);
+             delta_rtx =  GET_CODE (XEXP (src, 0)) == PRE_INC 
+                 ? GEN_INT (GET_MODE_SIZE (GET_MODE (src))) 
+                 : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))); 
+             emit_insn (TARGET_32BIT
+                        ? gen_addsi3 (breg, breg, delta_rtx)
+                        : gen_adddi3 (breg, breg, delta_rtx));
              src = gen_rtx_MEM (mode, breg);
            }
 
@@ -10093,35 +10112,34 @@ rs6000_split_multireg_move (rtx *operands)
            j = REGNO (breg) - REGNO (dst);
         }
 
-      if (GET_CODE (operands[0]) == MEM)
+      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
        {
          rtx breg;
 
-         if (GET_CODE (XEXP (operands[0], 0)) == PRE_INC
-             || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
+         if (GET_CODE (XEXP (dst, 0)) == PRE_INC
+             || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
            {
              rtx delta_rtx;
-             breg = XEXP (XEXP (operands[0], 0), 0);
-             delta_rtx = GET_CODE (XEXP (operands[0], 0)) == PRE_INC 
-               ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))) 
-               : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0]))); 
+             breg = XEXP (XEXP (dst, 0), 0);
+             delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC 
+               ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst))) 
+               : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))); 
 
              /* We have to update the breg before doing the store.
                 Use store with update, if available.  */
 
              if (TARGET_UPDATE)
                {
-                 insn = emit_insn (TARGET_32BIT
-                                   ? gen_movsi_update (breg, breg, delta_rtx, 
-                                       operand_subword (src, 0, 0, mode))
-                                   : gen_movdi_update (breg, breg, delta_rtx,
-                                       operand_subword (src, 0, 0, mode)));
-                 used_update = 1;
+                 rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
+                 emit_insn (TARGET_32BIT
+                            ? gen_movsi_update (breg, breg, delta_rtx, nsrc)
+                            : gen_movdi_update (breg, breg, delta_rtx, nsrc));
+                 used_update = true;
                }
              else
-                 insn = emit_insn (TARGET_32BIT
-                                   ? gen_addsi3 (breg, breg, delta_rtx)
-                                   : gen_adddi3 (breg, breg, delta_rtx));
+               emit_insn (TARGET_32BIT
+                          ? gen_addsi3 (breg, breg, delta_rtx)
+                          : gen_adddi3 (breg, breg, delta_rtx));
              dst = gen_rtx_MEM (mode, breg);
            }
        }
@@ -10133,15 +10151,16 @@ rs6000_split_multireg_move (rtx *operands)
          if (j == nregs) 
            j = 0;
 
-         operands[i+2] = operand_subword (dst, j, 0, mode);
-         operands[i+2+nregs] = operand_subword (src, j, 0, mode);
-
+         /* If compiler already emited move of first word by 
+            store with update, no need to do anything.  */
          if (j == 0 && used_update)
-           {
-             /* Already emited move of first word by 
-                store with update -> emit dead insn instead (r := r).  */
-             operands[i+2] = operands[i+2+nregs];
-           }
+           continue;
+         
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 simplify_gen_subreg (reg_mode, dst, mode,
+                                                      j * reg_mode_size),
+                                 simplify_gen_subreg (reg_mode, src, mode,
+                                                      j * reg_mode_size)));
        }
     }
 }
index f0f351e..761873d 100644 (file)
@@ -1480,11 +1480,14 @@ enum reg_class
 
 /* Return a class of registers that cannot change FROM mode to TO mode.  */
 
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)                      \
-  (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)                          \
-   ? reg_classes_intersect_p (FLOAT_REGS, CLASS)                       \
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)                        \
+  (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)                \
+    && GET_MODE_SIZE (FROM) >= 8 && GET_MODE_SIZE (TO) >= 8)             \
+   ? 0                                                                   \
+   : GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)                                  \
+   ? reg_classes_intersect_p (FLOAT_REGS, CLASS)                         \
    : (TARGET_SPE && (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1) \
-   ? reg_classes_intersect_p (GENERAL_REGS, CLASS)                     \
+   ? reg_classes_intersect_p (GENERAL_REGS, CLASS)                       \
    : 0)
 
 /* Stack layout; function entry, exit and calling.  */
index 19b263a..50c3595 100644 (file)
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
   "{ rs6000_emit_move (operands[0], operands[1], TFmode); DONE; }")
 
-(define_insn "*movtf_internal"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=f,f,m,!r,!r,!r")
-       (match_operand:TF 1 "input_operand" "f,m,f,G,H,F"))]
+; It's important to list the o->f and f->o moves before f->f because
+; otherwise reload, given m->f, will try to pick f->f and reload it,
+; which doesn't make progress.
+(define_insn_and_split "*movtf_internal"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=o,f,f,rm,r")
+       (match_operand:TF 1 "input_operand"         "f,o,f,r,mGHF"))]
   "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
    && (gpc_reg_operand (operands[0], TFmode)
        || gpc_reg_operand (operands[1], TFmode))"
-  "*
-{
-  switch (which_alternative)
-    {
-    default:
-      abort ();
-    case 0:
-      /* We normally copy the low-numbered register first.  However, if
-        the first register operand 0 is the same as the second register of
-        operand 1, we must copy in the opposite order.  */
-      if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
-       return \"fmr %L0,%L1\;fmr %0,%1\";
-      else
-       return \"fmr %0,%1\;fmr %L0,%L1\";
-    case 1:
-      return \"lfd %0,%1\;lfd %L0,%Y1\";
-    case 2:
-      return \"stfd %1,%0\;stfd %L1,%Y0\";
-    case 3:
-    case 4:
-    case 5:
-      return \"#\";
-    }
-}"
-  [(set_attr "type" "fp,fpload,fpstore,*,*,*")
-   (set_attr "length" "8,8,8,12,16,20")])
-
-(define_split
-  [(set (match_operand:TF 0 "gpc_reg_operand" "")
-       (match_operand:TF 1 "easy_fp_constant" ""))]
-  "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
-   && TARGET_HARD_FLOAT && TARGET_FPRS && ! TARGET_POWERPC64
-   && TARGET_LONG_DOUBLE_128 && reload_completed
-   && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
-       || (GET_CODE (operands[0]) == SUBREG
-          && GET_CODE (SUBREG_REG (operands[0])) == REG
-          && REGNO (SUBREG_REG (operands[0])) <= 31))"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-  "
-{
-  long l[4];
-  REAL_VALUE_TYPE rv;
-
-  REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-  REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, l);
-
-  operands[2] = operand_subword (operands[0], 0, 0, TFmode);
-  operands[3] = operand_subword (operands[0], 1, 0, TFmode);
-  operands[4] = operand_subword (operands[0], 2, 0, TFmode);
-  operands[5] = operand_subword (operands[0], 3, 0, TFmode);
-  operands[6] = gen_int_mode (l[0], SImode);
-  operands[7] = gen_int_mode (l[1], SImode);
-  operands[8] = gen_int_mode (l[2], SImode);
-  operands[9] = gen_int_mode (l[3], SImode);
-}")
-
-(define_split
-  [(set (match_operand:TF 0 "gpc_reg_operand" "")
-       (match_operand:TF 1 "easy_fp_constant" ""))]
-  "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_POWERPC64
-   && TARGET_LONG_DOUBLE_128 && reload_completed
-   && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
-       || (GET_CODE (operands[0]) == SUBREG
-          && GET_CODE (SUBREG_REG (operands[0])) == REG
-          && REGNO (SUBREG_REG (operands[0])) <= 31))"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-  "
-{
-  long l[4];
-  REAL_VALUE_TYPE rv;
-#if HOST_BITS_PER_WIDE_INT >= 64
-  HOST_WIDE_INT val;
-#endif
-
-  REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-  REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, l);
-
-  operands[2] = gen_lowpart (DImode, operands[0]);
-  operands[3] = gen_highpart (DImode, operands[0]);
-#if HOST_BITS_PER_WIDE_INT >= 64
-  val = ((HOST_WIDE_INT)(unsigned long)l[0] << 32
-         | ((HOST_WIDE_INT)(unsigned long)l[1]));
-  operands[4] = gen_int_mode (val, DImode);
-
-  val = ((HOST_WIDE_INT)(unsigned long)l[2] << 32
-         | ((HOST_WIDE_INT)(unsigned long)l[3]));
-  operands[5] = gen_int_mode (val, DImode);
-#else
-  operands[4] = immed_double_const (l[1], l[0], DImode);
-  operands[5] = immed_double_const (l[3], l[2], DImode);
-#endif
-}")
+  "#"
+  "reload_completed"
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
+  [(set_attr "length" "8,8,8,20,20")])
 
 (define_insn "extenddftf2"
   [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
 }")
 
 (define_split
-  [(set (match_operand:DI 0 "gpc_reg_operand" "")
-       (match_operand:DI 1 "const_double_operand" ""))]
-  "HOST_BITS_PER_WIDE_INT == 32 && ! TARGET_POWERPC64 && reload_completed"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-  "
-{
-  operands[2] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN == 0,
-                                      DImode);
-  operands[3] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN != 0,
-                                      DImode);
-  operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
-  operands[5] = GEN_INT (CONST_DOUBLE_LOW  (operands[1]));
-}")
-
-(define_split
   [(set (match_operand:DI 0 "nonimmediate_operand" "")
         (match_operand:DI 1 "input_operand" ""))]
   "reload_completed && !TARGET_POWERPC64 
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_split
   [(set (match_operand:TI 0 "gpc_reg_operand" "")
 (define_split
   [(set (match_operand:TI 0 "nonimmediate_operand" "")
         (match_operand:TI 1 "input_operand" ""))]
-  "reload_completed && TARGET_POWERPC64 
-   && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-(define_split
-  [(set (match_operand:TI 0 "nonimmediate_operand" "")
-        (match_operand:TI 1 "input_operand" ""))]
-  "reload_completed && !TARGET_POWERPC64 
+  "reload_completed
    && gpr_or_gpr_p (operands[0], operands[1])"
-  [(set (match_dup 2) (match_dup 6))
-   (set (match_dup 3) (match_dup 7))
-   (set (match_dup 4) (match_dup 8))
-   (set (match_dup 5) (match_dup 9))]
-"{
-     rs6000_split_multireg_move (operands);
-}")
-
-
+  [(pc)]
+{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 \f
 (define_expand "load_multiple"
   [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
diff --git a/gcc/testsuite/gcc.c-torture/compile/20031208-1.c b/gcc/testsuite/gcc.c-torture/compile/20031208-1.c
new file mode 100644 (file)
index 0000000..02586df
--- /dev/null
@@ -0,0 +1,6 @@
+extern int foo(int, ...);
+int bar(void) {
+  long double l = 1.2345E6;
+  foo(0, l);
+  return 0;
+}