OSDN Git Service

Fix ICE with long double after float HFA.
[pf3gnuchains/gcc-fork.git] / gcc / config / ia64 / ia64.md
index c406a79..b22f49e 100644 (file)
   if (GET_CODE (op0) == SUBREG)
     op0 = SUBREG_REG (op0);
 
-  /* We must support XFmode loads into general registers for stdarg/vararg
-     and unprototyped calls.  We split them into DImode loads for convenience.
-     We don't need XFmode stores from general regs, because a stdarg/vararg
-     routine does a block store to memory of unnamed arguments.  */
+  /* We must support XFmode loads into general registers for stdarg/vararg,
+     unprototyped calls, and a rare case where a long double is passed as
+     an argument after a float HFA fills the FP registers.  We split them into
+     DImode loads for convenience.  We also need to support XFmode stores
+     for the last case.  This case does not happen for stdarg/vararg routines,
+     because we do a block store to memory of unnamed arguments.  */
 
   if (GET_CODE (op0) == REG && GR_REGNO_P (REGNO (op0)))
     {
          if (GET_CODE (op1) == SUBREG)
            op1 = SUBREG_REG (op1);
          else
-           /* ??? Maybe we should make a SUBREG here?  */
            op1 = gen_rtx_REG (TImode, REGNO (op1));
 
          emit_move_insn (gen_rtx_REG (TImode, REGNO (op0)), op1);
       abort ();
     }
 
+  if (GET_CODE (operands[1]) == REG && GR_REGNO_P (REGNO (operands[1])))
+    {
+      /* We're hoping to transform everything that deals with XFmode
+        quantities and GR registers early in the compiler.  */
+      if (no_new_pseudos)
+       abort ();
+
+      /* Op0 can't be a GR_REG here, as that case is handled above.
+        If op0 is a register, then we spill op1, so that we now have a
+        MEM operand.  This requires creating an XFmode subreg of a TImode reg
+        to force the spill.  */
+      if (register_operand (operands[0], XFmode))
+       {
+         rtx op1 = gen_rtx_REG (TImode, REGNO (operands[1]));
+         op1 = gen_rtx_SUBREG (XFmode, op1, 0);
+         operands[1] = spill_xfmode_operand (op1, 0);
+       }
+
+      else if (GET_CODE (operands[0]) == MEM)
+       {
+         rtx in[2];
+
+         in[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]));
+         in[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
+
+         emit_move_insn (adjust_address (operands[0], DImode, 0), in[0]);
+         emit_move_insn (adjust_address (operands[0], DImode, 8), in[1]);
+         DONE;
+       }
+
+      else
+       abort ();
+    }
+
   if (! reload_in_progress && ! reload_completed)
     {
       operands[1] = spill_xfmode_operand (operands[1], 0);