aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/ia64/ia64.md
diff options
context:
space:
mode:
authorJim Wilson <wilson@gcc.gnu.org>2005-01-17 19:51:05 -0800
committerJim Wilson <wilson@gcc.gnu.org>2005-01-17 19:51:05 -0800
commit696a2ca15ffb199bf85594121380dc0d7399e0c9 (patch)
treee5493efa4813b7695d995d6f889ede488ee49aa3 /gcc/config/ia64/ia64.md
parent115a33c2196266e0462e516fac5bc7ff21276d13 (diff)
downloadgcc-696a2ca15ffb199bf85594121380dc0d7399e0c9.zip
gcc-696a2ca15ffb199bf85594121380dc0d7399e0c9.tar.gz
gcc-696a2ca15ffb199bf85594121380dc0d7399e0c9.tar.bz2
Fix ICE with long double after float HFA.
PR target/19357 * config/ia64/ia64.md (movxf): Handle general register source. Adjust comment to document why. * gcc.c-torture/compile/pr19357.c: New test. From-SVN: r93809
Diffstat (limited to 'gcc/config/ia64/ia64.md')
-rw-r--r--gcc/config/ia64/ia64.md45
1 files changed, 40 insertions, 5 deletions
diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md
index c406a79..b22f49e 100644
--- a/gcc/config/ia64/ia64.md
+++ b/gcc/config/ia64/ia64.md
@@ -685,10 +685,12 @@
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)))
{
@@ -708,7 +710,6 @@
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);
@@ -743,6 +744,40 @@
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);