static bool mips_get_unaligned_mem PARAMS ((rtx *, unsigned int,
int, rtx *, rtx *));
static rtx mips_add_large_offset_to_sp PARAMS ((HOST_WIDE_INT));
-static void mips_annotate_frame_insn PARAMS ((rtx, rtx));
-static rtx mips_frame_set PARAMS ((enum machine_mode,
- int, int));
+static void mips_set_frame_expr PARAMS ((rtx));
+static rtx mips_frame_set PARAMS ((rtx, int));
static void mips_emit_frame_related_store PARAMS ((rtx, rtx,
HOST_WIDE_INT));
static void save_restore_insns PARAMS ((int, rtx, long));
/* Map GCC register number to debugger register number. */
int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
-/* Buffer to use to enclose a load/store operation with %{ %} to
- turn on .set volatile. */
-static char volatile_buffer[60];
-
/* An alias set for the GOT. */
static int mips_got_alias_set;
case CONSTANT_RELOC:
/* When generating mips16 code, we need to set the destination to
- $0 and then add in the signed offset. See mips_move_1word. */
+ $0 and then add in the signed offset. See mips_output_move. */
return (TARGET_MIPS16 ? 3 : 1);
case CONSTANT_SYMBOLIC:
gen_rtx_MINUS (Pmode, x,
XEXP (DECL_RTL (current_function_decl), 0)));
}
+\f
+/* Return one word of double-word value OP, taking into account the fixed
+ endianness of certain registers. HIGH_P is true to select the high part,
+ false to select the low part. */
-/* Return the appropriate instructions to move one operand to another. */
+rtx
+mips_subword (op, high_p)
+ rtx op;
+ int high_p;
+{
+ unsigned int byte;
+ enum machine_mode mode;
-const char *
-mips_move_1word (operands, insn, unsignedp)
- rtx operands[];
- rtx insn;
- int unsignedp;
-{
- const char *ret = 0;
- rtx op0 = operands[0];
- rtx op1 = operands[1];
- enum rtx_code code0 = GET_CODE (op0);
- enum rtx_code code1 = GET_CODE (op1);
- enum machine_mode mode = GET_MODE (op0);
- int subreg_offset0 = 0;
- int subreg_offset1 = 0;
- enum delay_type delay = DELAY_NONE;
- struct mips_constant_info c;
+ mode = GET_MODE (op);
+ if (mode == VOIDmode)
+ mode = DImode;
- while (code0 == SUBREG)
- {
- subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
- GET_MODE (SUBREG_REG (op0)),
- SUBREG_BYTE (op0),
- GET_MODE (op0));
- op0 = SUBREG_REG (op0);
- code0 = GET_CODE (op0);
- }
+ if (TARGET_BIG_ENDIAN ? !high_p : high_p)
+ byte = UNITS_PER_WORD;
+ else
+ byte = 0;
- while (code1 == SUBREG)
+ if (GET_CODE (op) == REG)
{
- subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
- GET_MODE (SUBREG_REG (op1)),
- SUBREG_BYTE (op1),
- GET_MODE (op1));
- op1 = SUBREG_REG (op1);
- code1 = GET_CODE (op1);
+ if (FP_REG_P (REGNO (op)))
+ return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
+ if (REGNO (op) == HI_REGNUM)
+ return gen_rtx_REG (word_mode, high_p ? HI_REGNUM : LO_REGNUM);
}
- /* For our purposes, a condition code mode is the same as SImode. */
- if (mode == CCmode)
- mode = SImode;
-
- if (code0 == REG)
- {
- int regno0 = REGNO (op0) + subreg_offset0;
-
- if (code1 == REG)
- {
- int regno1 = REGNO (op1) + subreg_offset1;
-
- /* Just in case, don't do anything for assigning a register
- to itself, unless we are filling a delay slot. */
- if (regno0 == regno1 && set_nomacro == 0)
- ret = "";
-
- else if (GP_REG_P (regno0))
- {
- if (GP_REG_P (regno1))
- ret = "move\t%0,%1";
-
- else if (MD_REG_P (regno1))
- {
- delay = DELAY_HILO;
- if (regno1 != HILO_REGNUM)
- ret = "mf%1\t%0";
- else
- ret = "mflo\t%0";
- }
-
- else if (ST_REG_P (regno1) && ISA_HAS_8CC)
- ret = "li\t%0,1\n\tmovf\t%0,%.,%1";
-
- else
- {
- delay = DELAY_LOAD;
- if (FP_REG_P (regno1))
- ret = "mfc1\t%0,%1";
- else if (ALL_COP_REG_P (regno1))
- {
- static char retval[] = "mfc_\t%0,%1";
+ if (GET_CODE (op) == MEM)
+ return adjust_address (op, word_mode, byte);
- retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
- ret = retval;
- }
- else if (regno1 == FPSW_REGNUM && ! ISA_HAS_8CC)
- ret = "cfc1\t%0,$31";
- }
- }
+ return simplify_gen_subreg (word_mode, op, mode, byte);
+}
- else if (FP_REG_P (regno0))
- {
- if (GP_REG_P (regno1))
- {
- delay = DELAY_LOAD;
- ret = "mtc1\t%1,%0";
- }
- if (FP_REG_P (regno1))
- ret = "mov.s\t%0,%1";
- }
+/* Return true if a 64-bit move from SRC to DEST should be split into two. */
- else if (MD_REG_P (regno0))
- {
- if (GP_REG_P (regno1))
- {
- delay = DELAY_HILO;
- if (regno0 != HILO_REGNUM && ! TARGET_MIPS16)
- ret = "mt%0\t%1";
- }
- }
+bool
+mips_split_64bit_move_p (dest, src)
+ rtx dest, src;
+{
+ if (TARGET_64BIT)
+ return false;
- else if (regno0 == FPSW_REGNUM && ! ISA_HAS_8CC)
- {
- if (GP_REG_P (regno1))
- {
- delay = DELAY_LOAD;
- ret = "ctc1\t%0,$31";
- }
- }
- else if (ALL_COP_REG_P (regno0))
- {
- if (GP_REG_P (regno1))
- {
- static char retval[] = "mtc_\t%1,%0";
- char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
- if (cop == '0')
- abort_with_insn (insn,
- "mtc0 not supported; it disturbs virtual address translation");
- delay = DELAY_LOAD;
- retval[3] = cop;
- ret = retval;
- }
- }
- }
+ /* FP->FP moves can be done in a single instruction. */
+ if (FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
+ return false;
- else if (code1 == MEM)
- {
- delay = DELAY_LOAD;
+ /* Check for floating-point loads and stores. They can be done using
+ ldc1 and sdc1 on MIPS II and above. */
+ if (mips_isa > 1)
+ {
+ if (FP_REG_RTX_P (dest) && GET_CODE (src) == MEM)
+ return false;
+ if (FP_REG_RTX_P (src) && GET_CODE (dest) == MEM)
+ return false;
+ }
+ return true;
+}
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 1);
- if (GP_REG_P (regno0))
- {
- /* For loads, use the mode of the memory item, instead of the
- target, so zero/sign extend can use this code as well. */
- switch (GET_MODE (op1))
- {
- default:
- break;
- case SFmode:
- ret = "lw\t%0,%1";
- break;
- case SImode:
- case CCmode:
- ret = ((unsignedp && TARGET_64BIT)
- ? "lwu\t%0,%1"
- : "lw\t%0,%1");
- break;
- case HImode:
- ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1";
- break;
- case QImode:
- ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1";
- break;
- }
- }
+/* Split a 64-bit move from SRC to DEST assuming that
+ mips_split_64bit_move_p holds.
- else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
- ret = "lwc1\t%0,%1";
+ Moves into and out of FPRs cause some difficulty here. Such moves
+ will always be DFmode, since paired FPRs are not allowed to store
+ DImode values. The most natural representation would be two separate
+ 32-bit moves, such as:
- else if (ALL_COP_REG_P (regno0))
- {
- static char retval[] = "lwc_\t%0,%1";
- char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
- if (cop == '0')
- abort_with_insn (insn,
- "loads from memory to COP0 are illegal");
- delay = DELAY_LOAD;
- retval[3] = cop;
- ret = retval;
- }
+ (set (reg:SI $f0) (mem:SI ...))
+ (set (reg:SI $f1) (mem:SI ...))
- if (ret != (char *)0 && MEM_VOLATILE_P (op1))
- {
- size_t i = strlen (ret);
- if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
- abort ();
+ However, the second insn is invalid because odd-numbered FPRs are
+ not allowed to store independent values. Use the patterns load_df_low,
+ load_df_high and store_df_high instead. */
- sprintf (volatile_buffer, "%%{%s%%}", ret);
- ret = volatile_buffer;
- }
- }
+void
+mips_split_64bit_move (dest, src)
+ rtx dest, src;
+{
+ if (FP_REG_RTX_P (dest))
+ {
+ /* Loading an FPR from memory or from GPRs. */
+ emit_insn (gen_load_df_low (copy_rtx (dest), mips_subword (src, 0)));
+ emit_insn (gen_load_df_high (dest, mips_subword (src, 1),
+ copy_rtx (dest)));
+ }
+ else if (FP_REG_RTX_P (src))
+ {
+ /* Storing an FPR into memory or GPRs. */
+ emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0));
+ emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
+ }
+ else
+ {
+ /* The operation can be split into two normal moves. Decide in
+ which order to do them. */
+ rtx low_dest;
- else if (code1 == CONST_INT
- || (code1 == CONST_DOUBLE
- && GET_MODE (op1) == VOIDmode))
+ low_dest = mips_subword (dest, 0);
+ if (GET_CODE (low_dest) == REG
+ && reg_overlap_mentioned_p (low_dest, src))
{
- if (code1 == CONST_DOUBLE)
- {
- /* This can happen when storing constants into long long
- bitfields. Just store the least significant word of
- the value. */
- operands[1] = op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
- }
-
- if (INTVAL (op1) == 0 && ! TARGET_MIPS16)
- {
- if (GP_REG_P (regno0))
- ret = "move\t%0,%z1";
-
- else if (FP_REG_P (regno0))
- {
- delay = DELAY_LOAD;
- ret = "mtc1\t%z1,%0";
- }
-
- else if (MD_REG_P (regno0))
- {
- delay = DELAY_HILO;
- ret = "mt%0\t%.";
- }
- }
-
- else if (GP_REG_P (regno0))
- {
- /* Don't use X format, because that will give out of
- range numbers for 64 bit host and 32 bit target. */
- if (! TARGET_MIPS16)
- ret = "li\t%0,%1\t\t\t# %X1";
- else
- {
- if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
- ret = "li\t%0,%1";
- else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
- ret = "li\t%0,%n1\n\tneg\t%0";
- }
- }
+ emit_move_insn (mips_subword (dest, 1), mips_subword (src, 1));
+ emit_move_insn (low_dest, mips_subword (src, 0));
}
-
- else if (code1 == CONST_DOUBLE && mode == SFmode)
+ else
{
- if (op1 == CONST0_RTX (SFmode))
- {
- if (GP_REG_P (regno0))
- ret = "move\t%0,%.";
-
- else if (FP_REG_P (regno0))
- {
- delay = DELAY_LOAD;
- ret = "mtc1\t%.,%0";
- }
- }
-
- else
- {
- delay = DELAY_LOAD;
- ret = "li.s\t%0,%1";
- }
+ emit_move_insn (low_dest, mips_subword (src, 0));
+ emit_move_insn (mips_subword (dest, 1), mips_subword (src, 1));
}
+ }
+}
+\f
+/* Return the appropriate instructions to move SRC into DEST. Assume
+ that SRC is operand 1 and DEST is operand 0. */
- else if (code1 == PLUS)
- {
- rtx add_op0 = XEXP (op1, 0);
- rtx add_op1 = XEXP (op1, 1);
+const char *
+mips_output_move (dest, src)
+ rtx dest, src;
+{
+ enum rtx_code dest_code, src_code;
+ struct mips_constant_info c;
+ bool dbl_p;
- if (GET_CODE (XEXP (op1, 1)) == REG
- && GET_CODE (XEXP (op1, 0)) == CONST_INT)
- add_op0 = XEXP (op1, 1), add_op1 = XEXP (op1, 0);
+ dest_code = GET_CODE (dest);
+ src_code = GET_CODE (src);
+ dbl_p = (GET_MODE_SIZE (GET_MODE (dest)) == 8);
- operands[2] = add_op0;
- operands[3] = add_op1;
- ret = "add%:\t%0,%2,%3";
- }
+ if (dbl_p && mips_split_64bit_move_p (dest, src))
+ return "#";
- else if (code1 == HIGH)
+ if ((src_code == REG && GP_REG_P (REGNO (src)))
+ || (!TARGET_MIPS16 && src == CONST0_RTX (GET_MODE (dest))))
+ {
+ if (dest_code == REG)
{
- operands[1] = XEXP (op1, 0);
- ret = "lui\t%0,%%hi(%1)";
- }
+ if (GP_REG_P (REGNO (dest)))
+ return "move\t%0,%z1";
- else
- switch (mips_classify_constant (&c, op1))
- {
- case CONSTANT_NONE:
- break;
+ if (MD_REG_P (REGNO (dest)))
+ return "mt%0\t%z1";
- case CONSTANT_GP:
- ret = "move\t%0,%1";
- break;
+ if (FP_REG_P (REGNO (dest)))
+ return (dbl_p ? "dmtc1\t%z1,%0" : "mtc1\t%z1,%0");
- case CONSTANT_RELOC:
- ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
- break;
+ if (ALL_COP_REG_P (REGNO (dest)))
+ {
+ static char retval[] = "dmtc_\t%z1,%0";
- case CONSTANT_SYMBOLIC:
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 1);
- ret = "la\t%0,%a1";
- break;
- }
+ retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (dest));
+ return (dbl_p ? retval : retval + 1);
+ }
+ }
+ if (dest_code == MEM)
+ return (dbl_p ? "sd\t%z1,%0" : "sw\t%z1,%0");
}
-
- else if (code0 == MEM)
+ if (dest_code == REG && GP_REG_P (REGNO (dest)))
{
- if (TARGET_STATS)
- mips_count_memory_refs (op0, 1);
-
- if (code1 == REG)
+ if (src_code == REG)
{
- int regno1 = REGNO (op1) + subreg_offset1;
+ if (MD_REG_P (REGNO (src)))
+ return "mf%1\t%0";
- if (GP_REG_P (regno1))
- {
- switch (mode)
- {
- case SFmode: ret = "sw\t%1,%0"; break;
- case SImode: ret = "sw\t%1,%0"; break;
- case HImode: ret = "sh\t%1,%0"; break;
- case QImode: ret = "sb\t%1,%0"; break;
- default: break;
- }
- }
+ if (ST_REG_P (REGNO (src)) && ISA_HAS_8CC)
+ return "lui\t%0,0x3f80\n\tmovf\t%0,%.,%1";
- else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
- ret = "swc1\t%1,%0";
- else if (ALL_COP_REG_P (regno1))
+ if (FP_REG_P (REGNO (src)))
+ return (dbl_p ? "dmfc1\t%0,%1" : "mfc1\t%0,%1");
+
+ if (ALL_COP_REG_P (REGNO (src)))
{
- static char retval[] = "swc_\t%1,%0";
+ static char retval[] = "dmfc_\t%0,%1";
- retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
- ret = retval;
+ retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (src));
+ return (dbl_p ? retval : retval + 1);
}
}
- else if (code1 == CONST_INT && INTVAL (op1) == 0)
- {
- switch (mode)
- {
- case SFmode: ret = "sw\t%z1,%0"; break;
- case SImode: ret = "sw\t%z1,%0"; break;
- case HImode: ret = "sh\t%z1,%0"; break;
- case QImode: ret = "sb\t%z1,%0"; break;
- default: break;
- }
- }
+ if (src_code == MEM)
+ return (dbl_p ? "ld\t%0,%1" : "lw\t%0,%1");
- else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode))
+ if (src_code == CONST_INT)
{
- switch (mode)
- {
- case SFmode: ret = "sw\t%.,%0"; break;
- case SImode: ret = "sw\t%.,%0"; break;
- case HImode: ret = "sh\t%.,%0"; break;
- case QImode: ret = "sb\t%.,%0"; break;
- default: break;
- }
+ /* Don't use the X format, because that will give out of
+ range numbers for 64 bit hosts and 32 bit targets. */
+ if (!TARGET_MIPS16)
+ return "li\t%0,%1\t\t\t# %X1";
+
+ if (INTVAL (src) >= 0 && INTVAL (src) <= 0xffff)
+ return "li\t%0,%1";
+
+ if (INTVAL (src) < 0 && INTVAL (src) >= -0xffff)
+ return "li\t%0,%n1\n\tneg\t%0";
}
- if (ret != 0 && MEM_VOLATILE_P (op0))
+ if (src_code == HIGH)
+ return "lui\t%0,%h1";
+
+ switch (mips_classify_constant (&c, src))
{
- size_t i = strlen (ret);
+ case CONSTANT_NONE:
+ break;
- if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
- abort ();
+ case CONSTANT_GP:
+ return "move\t%0,%1";
- sprintf (volatile_buffer, "%%{%s%%}", ret);
- ret = volatile_buffer;
+ case CONSTANT_RELOC:
+ return (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
+
+ case CONSTANT_SYMBOLIC:
+ return (dbl_p ? "dla\t%0,%a1" : "la\t%0,%a1");
}
}
+ if (src_code == REG && FP_REG_P (REGNO (src)))
+ {
+ if (dest_code == REG && FP_REG_P (REGNO (dest)))
+ return (dbl_p ? "mov.d\t%0,%1" : "mov.s\t%0,%1");
- if (ret == 0)
+ if (dest_code == MEM)
+ return (dbl_p ? "sdc1\t%1,%0" : "swc1\t%1,%0");
+ }
+ if (dest_code == REG && FP_REG_P (REGNO (dest)))
{
- abort_with_insn (insn, "bad move");
- return 0;
+ if (src_code == MEM)
+ return (dbl_p ? "ldc1\t%0,%1" : "lwc1\t%0,%1");
}
+ if (dest_code == REG && ALL_COP_REG_P (REGNO (dest)) && src_code == MEM)
+ {
+ static char retval[] = "l_c_\t%0,%1";
- if (delay != DELAY_NONE)
- return mips_fill_delay_slot (ret, delay, operands, insn);
+ retval[1] = (dbl_p ? 'd' : 'w');
+ retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (dest));
+ return retval;
+ }
+ if (dest_code == MEM && src_code == REG && ALL_COP_REG_P (REGNO (src)))
+ {
+ static char retval[] = "s_c_\t%1,%0";
- return ret;
+ retval[1] = (dbl_p ? 'd' : 'w');
+ retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (REGNO (src));
+ return retval;
+ }
+ abort ();
}
\f
/* Return instructions to restore the global pointer from the stack,
the GP for exception handlers.
OPERANDS is an array of operands whose contents are undefined
- on entry. INSN is the exception_handler instruction. */
+ on entry. */
const char *
-mips_restore_gp (operands, insn)
- rtx *operands, insn;
+mips_restore_gp (operands)
+ rtx *operands;
{
rtx loc;
loc = plus_constant (loc, cfun->machine->frame.args_size);
operands[1] = gen_rtx_MEM (ptr_mode, loc);
- return mips_move_1word (operands, insn, 0);
+ return mips_output_move (operands[0], operands[1]);
}
\f
-/* Return the appropriate instructions to move 2 words */
-
-const char *
-mips_move_2words (operands, insn)
- rtx operands[];
- rtx insn;
-{
- const char *ret = 0;
- rtx op0 = operands[0];
- rtx op1 = operands[1];
- enum rtx_code code0 = GET_CODE (operands[0]);
- enum rtx_code code1 = GET_CODE (operands[1]);
- int subreg_offset0 = 0;
- int subreg_offset1 = 0;
- enum delay_type delay = DELAY_NONE;
- struct mips_constant_info c;
-
- while (code0 == SUBREG)
- {
- subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
- GET_MODE (SUBREG_REG (op0)),
- SUBREG_BYTE (op0),
- GET_MODE (op0));
- op0 = SUBREG_REG (op0);
- code0 = GET_CODE (op0);
- }
-
- while (code1 == SUBREG)
- {
- subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
- GET_MODE (SUBREG_REG (op1)),
- SUBREG_BYTE (op1),
- GET_MODE (op1));
- op1 = SUBREG_REG (op1);
- code1 = GET_CODE (op1);
- }
-
- if (code0 == REG)
- {
- int regno0 = REGNO (op0) + subreg_offset0;
-
- if (code1 == REG)
- {
- int regno1 = REGNO (op1) + subreg_offset1;
-
- /* Just in case, don't do anything for assigning a register
- to itself, unless we are filling a delay slot. */
- if (regno0 == regno1 && set_nomacro == 0)
- ret = "";
-
- else if (FP_REG_P (regno0))
- {
- if (FP_REG_P (regno1))
- ret = "mov.d\t%0,%1";
-
- else
- {
- delay = DELAY_LOAD;
- if (TARGET_FLOAT64)
- {
- if (!TARGET_64BIT)
- abort_with_insn (insn, "bad move");
-
-#ifdef TARGET_FP_CALL_32
- if (FP_CALL_GP_REG_P (regno1))
- ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tdmtc1\t%1,%0";
- else
-#endif
- ret = "dmtc1\t%1,%0";
- }
- else
- ret = "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
- }
- }
-
- else if (FP_REG_P (regno1))
- {
- delay = DELAY_LOAD;
- if (TARGET_FLOAT64)
- {
- if (!TARGET_64BIT)
- abort_with_insn (insn, "bad move");
-
-#ifdef TARGET_FP_CALL_32
- if (FP_CALL_GP_REG_P (regno0))
- ret = "dmfc1\t%0,%1\n\tmfc1\t%D0,%1\n\tdsrl\t%0,32";
- else
-#endif
- ret = "dmfc1\t%0,%1";
- }
- else
- ret = "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
- }
-
- else if (MD_REG_P (regno0) && GP_REG_P (regno1) && !TARGET_MIPS16)
- {
- delay = DELAY_HILO;
- if (TARGET_64BIT)
- {
- if (regno0 != HILO_REGNUM)
- ret = "mt%0\t%1";
- else if (regno1 == 0)
- ret = "mtlo\t%.\n\tmthi\t%.";
- }
- else
- ret = "mthi\t%M1\n\tmtlo\t%L1";
- }
-
- else if (GP_REG_P (regno0) && MD_REG_P (regno1))
- {
- delay = DELAY_HILO;
- if (TARGET_64BIT)
- {
- if (regno1 != HILO_REGNUM)
- ret = "mf%1\t%0";
- }
- else
- ret = "mfhi\t%M0\n\tmflo\t%L0";
- }
- else if (GP_REG_P (regno0) && ALL_COP_REG_P (regno1)
- && TARGET_64BIT)
- {
- static char retval[] = "dmfc_\t%0,%1";
-
- delay = DELAY_LOAD;
- retval[4] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
- ret = retval;
- }
- else if (ALL_COP_REG_P (regno0) && GP_REG_P (regno1)
- && TARGET_64BIT)
- {
- static char retval[] = "dmtc_\t%1,%0";
- char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
- if (cop == '0')
- abort_with_insn (insn,
- "dmtc0 not supported; it disturbs virtual address translation");
- delay = DELAY_LOAD;
- retval[4] = cop;
- ret = retval;
- }
- else if (TARGET_64BIT)
- ret = "move\t%0,%1";
-
- else if (regno0 != (regno1+1))
- ret = "move\t%0,%1\n\tmove\t%D0,%D1";
-
- else
- ret = "move\t%D0,%D1\n\tmove\t%0,%1";
- }
-
- else if (code1 == CONST_DOUBLE)
- {
- /* Move zero from $0 unless !TARGET_64BIT and recipient
- is 64-bit fp reg, in which case generate a constant. */
- if (op1 != CONST0_RTX (GET_MODE (op1))
- || (TARGET_FLOAT64 && !TARGET_64BIT && FP_REG_P (regno0)))
- {
- if (GET_MODE (op1) == DFmode)
- {
- delay = DELAY_LOAD;
-
-#ifdef TARGET_FP_CALL_32
- if (FP_CALL_GP_REG_P (regno0))
- {
- if (TARGET_FLOAT64 && !TARGET_64BIT)
- {
- split_double (op1, operands + 2, operands + 3);
- ret = "li\t%0,%2\n\tli\t%D0,%3";
- }
- else
- ret = "li.d\t%0,%1\n\tdsll\t%D0,%0,32\n\tdsrl\t%D0,32\n\tdsrl\t%0,32";
- }
- else
-#endif
- /* GNU as emits 64-bit code for li.d if the ISA is 3
- or higher. For !TARGET_64BIT && gp registers we
- need to avoid this by using two li instructions
- instead. */
- if (ISA_HAS_64BIT_REGS
- && ! TARGET_64BIT
- && ! FP_REG_P (regno0))
- {
- split_double (op1, operands + 2, operands + 3);
- ret = "li\t%0,%2\n\tli\t%D0,%3";
- }
- else
- ret = "li.d\t%0,%1";
- }
-
- else if (TARGET_64BIT)
- {
- if (! TARGET_MIPS16)
- ret = "dli\t%0,%1";
- }
-
- else
- {
- split_double (op1, operands + 2, operands + 3);
- ret = "li\t%0,%2\n\tli\t%D0,%3";
- }
- }
-
- else
- {
- if (GP_REG_P (regno0))
- ret = (TARGET_64BIT
-#ifdef TARGET_FP_CALL_32
- && ! FP_CALL_GP_REG_P (regno0)
-#endif
- ? "move\t%0,%."
- : "move\t%0,%.\n\tmove\t%D0,%.");
-
- else if (FP_REG_P (regno0))
- {
- delay = DELAY_LOAD;
- ret = (TARGET_64BIT
- ? "dmtc1\t%.,%0"
- : "mtc1\t%.,%0\n\tmtc1\t%.,%D0");
- }
- }
- }
-
- else if (code1 == CONST_INT && INTVAL (op1) == 0 && ! TARGET_MIPS16)
- {
- if (GP_REG_P (regno0))
- ret = (TARGET_64BIT
- ? "move\t%0,%."
- : "move\t%0,%.\n\tmove\t%D0,%.");
-
- else if (FP_REG_P (regno0))
- {
- delay = DELAY_LOAD;
- ret = (TARGET_64BIT
- ? "dmtc1\t%.,%0"
- : (TARGET_FLOAT64
- ? "li.d\t%0,%1"
- : "mtc1\t%.,%0\n\tmtc1\t%.,%D0"));
- }
- else if (MD_REG_P (regno0))
- {
- delay = DELAY_HILO;
- ret = (regno0 == HILO_REGNUM
- ? "mtlo\t%.\n\tmthi\t%."
- : "mt%0\t%.\n");
- }
- }
-
- else if (code1 == CONST_INT && GET_MODE (op0) == DImode
- && GP_REG_P (regno0))
- {
- if (TARGET_64BIT)
- {
- if (TARGET_MIPS16)
- {
- if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
- ret = "li\t%0,%1";
- else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
- ret = "li\t%0,%n1\n\tneg\t%0";
- }
- else if (GET_CODE (operands[1]) == SIGN_EXTEND)
- ret = "li\t%0,%1\t\t# %X1";
- else if (HOST_BITS_PER_WIDE_INT < 64)
- /* We can't use 'X' for negative numbers, because then we won't
- get the right value for the upper 32 bits. */
- ret = (INTVAL (op1) < 0
- ? "dli\t%0,%1\t\t\t# %X1"
- : "dli\t%0,%X1\t\t# %1");
- else
- /* We must use 'X', because otherwise LONG_MIN will print as
- a number that the assembler won't accept. */
- ret = "dli\t%0,%X1\t\t# %1";
- }
- else if (HOST_BITS_PER_WIDE_INT < 64)
- {
- operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1);
- if (TARGET_MIPS16)
- {
- if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
- ret = "li\t%M0,%2\n\tli\t%L0,%1";
- else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
- {
- operands[2] = GEN_INT (1);
- ret = "li\t%M0,%2\n\tneg\t%M0\n\tli\t%L0,%n1\n\tneg\t%L0";
- }
- }
- else
- ret = "li\t%M0,%2\n\tli\t%L0,%1";
- }
- else
- {
- /* We use multiple shifts here, to avoid warnings about out
- of range shifts on 32 bit hosts. */
- operands[2] = GEN_INT (INTVAL (operands[1]) >> 16 >> 16);
- operands[1]
- = GEN_INT (INTVAL (operands[1]) << 16 << 16 >> 16 >> 16);
- if (TARGET_MIPS16)
- {
- if (INTVAL (op1) >= 0 && INTVAL (op1) <= 0xffff)
- ret = "li\t%M0,%2\n\tli\t%L0,%1";
- else if (INTVAL (op1) < 0 && INTVAL (op1) >= -0xffff)
- {
- operands[2] = GEN_INT (1);
- ret = "li\t%M0,%2\n\tneg\t%M0\n\tli\t%L0,%n1\n\tneg\t%L0";
- }
- }
- else
- ret = "li\t%M0,%2\n\tli\t%L0,%1";
- }
- }
-
- else if (code1 == MEM)
- {
- delay = DELAY_LOAD;
-
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 2);
-
- if (FP_REG_P (regno0))
- ret = (TARGET_64BIT ? "ldc1\t%0,%1" : "l.d\t%0,%1");
-
- else if (ALL_COP_REG_P (regno0) && TARGET_64BIT)
- {
- static char retval[] = "ldc_\t%0,%1";
- char cop = COPNUM_AS_CHAR_FROM_REGNUM (regno0);
-
- if (cop == '0')
- abort_with_insn (insn,
- "loads from memory to COP0 are illegal");
- delay = DELAY_LOAD;
- retval[3] = cop;
- ret = retval;
- }
-
- else if (TARGET_64BIT)
- {
-
-#ifdef TARGET_FP_CALL_32
- if (FP_CALL_GP_REG_P (regno0))
- ret = "lwu\t%0,%1\n\tlwu\t%D0,4+%1";
- else
-#endif
- ret = "ld\t%0,%1";
- }
-
- else
- ret = (reg_mentioned_p (op0, op1)
- ? "lw\t%D0,%D1\n\tlw\t%0,%1"
- : "lw\t%0,%1\n\tlw\t%D0,%D1");
-
- if (ret != 0 && MEM_VOLATILE_P (op1))
- {
- size_t i = strlen (ret);
-
- if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
- abort ();
-
- sprintf (volatile_buffer, "%%{%s%%}", ret);
- ret = volatile_buffer;
- }
- }
- else if (code1 == HIGH)
- {
- operands[1] = XEXP (op1, 0);
- ret = "lui\t%0,%%hi(%1)";
- }
- else
- switch (mips_classify_constant (&c, op1))
- {
- case CONSTANT_NONE:
- break;
-
- case CONSTANT_GP:
- ret = "move\t%0,%1";
- break;
-
- case CONSTANT_RELOC:
- ret = (TARGET_MIPS16 ? "li\t%0,0\n\taddiu\t%0,%1" : "li\t%0,%1");
- break;
-
- case CONSTANT_SYMBOLIC:
- if (TARGET_STATS)
- mips_count_memory_refs (op1, 2);
- ret = "dla\t%0,%a1";
- break;
- }
- }
-
- else if (code0 == MEM)
- {
- if (code1 == REG)
- {
- int regno1 = REGNO (op1) + subreg_offset1;
-
- if (FP_REG_P (regno1))
- ret = (TARGET_64BIT ? "sdc1\t%1,%0" : "s.d\t%1,%0");
-
- else if (ALL_COP_REG_P (regno1) && TARGET_64BIT)
- {
- static char retval[] = "sdc_\t%1,%0";
-
- retval[3] = COPNUM_AS_CHAR_FROM_REGNUM (regno1);
- ret = retval;
- }
- else if (TARGET_64BIT)
- {
-
-#ifdef TARGET_FP_CALL_32
- if (FP_CALL_GP_REG_P (regno1))
- ret = "dsll\t%1,32\n\tor\t%1,%D1\n\tsd\t%1,%0";
- else
-#endif
- ret = "sd\t%1,%0";
- }
-
- else
- ret = "sw\t%1,%0\n\tsw\t%D1,%D0";
- }
-
- else if (((code1 == CONST_INT && INTVAL (op1) == 0)
- || (code1 == CONST_DOUBLE
- && op1 == CONST0_RTX (GET_MODE (op1)))))
- {
- if (TARGET_64BIT)
- ret = "sd\t%.,%0";
- else
- ret = "sw\t%.,%0\n\tsw\t%.,%D0";
- }
-
- if (TARGET_STATS)
- mips_count_memory_refs (op0, 2);
-
- if (ret != 0 && MEM_VOLATILE_P (op0))
- {
- size_t i = strlen (ret);
-
- if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
- abort ();
-
- sprintf (volatile_buffer, "%%{%s%%}", ret);
- ret = volatile_buffer;
- }
- }
-
- if (ret == 0)
- {
- abort_with_insn (insn, "bad move");
- return 0;
- }
-
- if (delay != DELAY_NONE)
- return mips_fill_delay_slot (ret, delay, operands, insn);
-
- return ret;
-}
\f
/* Make normal rtx_code into something we can index from an array */
'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
+ 'h' X is HIGH, prints %hi(X),
'd' output integer constant in decimal,
'z' if the operand is 0, use $0 instead of normal operand.
'D' print second part of double-word register or memory operand.
fputc (')', file);
}
+ else if (letter == 'h')
+ {
+ if (GET_CODE (op) != HIGH)
+ abort ();
+ fputs ("%hi(", file);
+ output_addr_const (file, XEXP (op, 0));
+ fputc (')', file);
+ }
+
else if (letter == 'C')
switch (code)
{
output_address (XEXP (op, 0));
}
- else if (code == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
- {
- char s[60];
-
- real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
- fputs (s, file);
- }
-
else if (letter == 'x' && GET_CODE (op) == CONST_INT)
fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL(op));
else if (letter == 'd' && GET_CODE(op) == CONST_INT)
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL(op)));
- else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+ else if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
fputs (reg_names[GP_REG_FIRST], file);
else if (letter == 'd' || letter == 'x' || letter == 'X')
return reg;
}
-/* Make INSN frame related and note that it performs the frame-related
- operation DWARF_PATTERN. */
+/* Make the last instruction frame related and note that it performs
+ the operation described by FRAME_PATTERN. */
static void
-mips_annotate_frame_insn (insn, dwarf_pattern)
- rtx insn, dwarf_pattern;
+mips_set_frame_expr (frame_pattern)
+ rtx frame_pattern;
{
+ rtx insn;
+
+ insn = get_last_insn ();
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- dwarf_pattern,
+ frame_pattern,
REG_NOTES (insn));
}
-/* Return a frame-related rtx that stores register REGNO at (SP + OFFSET).
- The expression should only be used to store single registers. */
+/* Return a frame-related rtx that stores REG at (SP + OFFSET).
+ REG must be a single register. */
static rtx
-mips_frame_set (mode, regno, offset)
- enum machine_mode mode;
- int regno;
+mips_frame_set (reg, offset)
+ rtx reg;
int offset;
{
rtx address = plus_constant (stack_pointer_rtx, offset);
- rtx set = gen_rtx_SET (mode,
- gen_rtx_MEM (mode, address),
- gen_rtx_REG (mode, regno));
+ rtx set = gen_rtx_SET (VOIDmode, gen_rtx_MEM (GET_MODE (reg), address), reg);
RTX_FRAME_RELATED_P (set) = 1;
return set;
}
rtx reg;
HOST_WIDE_INT offset;
{
- rtx dwarf_expr;
+ if (GET_MODE (reg) == DFmode && mips_split_64bit_move_p (mem, reg))
+ mips_split_64bit_move (mem, reg);
+ else
+ emit_move_insn (mem, reg);
- if (GET_MODE (reg) == DFmode && ! TARGET_FLOAT64)
+ if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
{
+ rtx x1, x2;
+
/* Two registers are being stored, so the frame-related expression
- must be a PARALLEL rtx with one SET for each register. The
- higher numbered register is stored in the lower address on
- big-endian targets. */
- int regno1 = TARGET_BIG_ENDIAN ? REGNO (reg) + 1 : REGNO (reg);
- int regno2 = TARGET_BIG_ENDIAN ? REGNO (reg) : REGNO (reg) + 1;
- rtx set1 = mips_frame_set (SFmode, regno1, offset);
- rtx set2 = mips_frame_set (SFmode, regno2, offset + UNITS_PER_FPREG);
- dwarf_expr = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2));
+ must be a PARALLEL rtx with one SET for each register. */
+ x1 = mips_frame_set (mips_subword (reg, TARGET_BIG_ENDIAN), offset);
+ x2 = mips_frame_set (mips_subword (reg, !TARGET_BIG_ENDIAN),
+ offset + UNITS_PER_FPREG);
+ mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
}
else
- dwarf_expr = mips_frame_set (GET_MODE (reg), REGNO (reg), offset);
-
- mips_annotate_frame_insn (emit_move_insn (mem, reg), dwarf_expr);
+ mips_set_frame_expr (mips_frame_set (reg, offset));
}
static void
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
&& (!TARGET_MIPS16 || tsize <= 32767))
{
- rtx adjustment_rtx, insn, dwarf_pattern;
+ rtx adjustment_rtx;
if (tsize > 32767)
{
adjustment_rtx = tsize_rtx;
if (Pmode == DImode)
- insn = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
- adjustment_rtx));
+ emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx,
+ adjustment_rtx));
else
- insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
- adjustment_rtx));
-
- dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,
- plus_constant (stack_pointer_rtx,
- -tsize));
+ emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ adjustment_rtx));
- mips_annotate_frame_insn (insn, dwarf_pattern);
+ mips_set_frame_expr
+ (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx, -tsize)));
}
if (! mips_entry)
;; Must include new entries for fmadd in addition to existing entries.
(define_constants
- [(UNSPEC_GET_FNADDR 4)
+ [(UNSPEC_LOAD_DF_LOW 0)
+ (UNSPEC_LOAD_DF_HIGH 1)
+ (UNSPEC_STORE_DF_HIGH 2)
+ (UNSPEC_GET_FNADDR 4)
(UNSPEC_HILO_DELAY 5)
(UNSPEC_BLOCKAGE 6)
(UNSPEC_LOADGP 7)
(clobber (match_scratch:SI 4 "=l"))
(clobber (match_scratch:SI 5 "=a"))]
"TARGET_MIPS4000 && !TARGET_MIPS16"
- "*
-{
- rtx xoperands[10];
-
- xoperands[0] = operands[0];
- xoperands[1] = gen_rtx_REG (SImode, LO_REGNUM);
-
- output_asm_insn (\"mult\\t%1,%2\", operands);
- output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
- return \"\";
-}"
+ "mult\t%1,%2\;mflo\t%0"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
- (set_attr "length" "12")]) ;; mult + mflo + delay
+ (set_attr "length" "8")])
;; Multiply-accumulate patterns
(clobber (match_scratch:DI 4 "=l"))
(clobber (match_scratch:DI 5 "=a"))]
"TARGET_64BIT && (GENERATE_MULT3_DI || TARGET_MIPS4000 || TARGET_MIPS16)"
- "*
-{
- if (GENERATE_MULT3_DI)
- output_asm_insn (\"dmult\\t%0,%1,%2\", operands);
- else
- {
- rtx xoperands[10];
-
- xoperands[0] = operands[0];
- xoperands[1] = gen_rtx_REG (DImode, LO_REGNUM);
-
- output_asm_insn (\"dmult\\t%1,%2\", operands);
- output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
- }
- return \"\";
-}"
+ {
+ if (GENERATE_MULT3_DI)
+ return "dmult\t%0,%1,%2";
+ else
+ return "dmult\t%1,%2\n\tmflo\t%0";
+ }
[(set_attr "type" "imul")
(set_attr "mode" "DI")
(set (attr "length")
(if_then_else (ne (symbol_ref "GENERATE_MULT3_DI") (const_int 0))
- (const_int 4)
- (const_int 12)))]) ;; mult + mflo + delay
+ (const_int 4)
+ (const_int 8)))])
;; ??? We could define a mulditi3 pattern when TARGET_64BIT.
(set_attr "mode" "DI")
(set_attr "length" "4,*")])
-;; These can be created when a paradoxical subreg operand with an implicit
-;; sign_extend operator is reloaded. Because of the subreg, this is really
-;; a zero extend.
-;; ??? It might be possible to eliminate the need for these patterns by adding
-;; more support to reload for implicit sign_extend operators.
-(define_insn "*paradoxical_extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (sign_extend:DI
- (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)))]
- "TARGET_64BIT"
- "*
-{
- return mips_move_1word (operands, insn, TRUE);
-}"
- [(set_attr "type" "load")
- (set_attr "mode" "DI")])
-
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d")
(zero_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
[(set (match_operand:DI 0 "memory_operand" "=m")
(reg:DI 31))]
"TARGET_MIPS16 && TARGET_64BIT"
- "*
-{
- operands[1] = gen_rtx (REG, DImode, 31);
- return mips_move_2words (operands, insn);
-}"
+ "sd\t$31,%0"
[(set_attr "type" "store")
(set_attr "mode" "DI")])
|| register_operand (operands[1], DImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|| operands[1] == CONST0_RTX (DImode))"
- "* return mips_move_2words (operands, insn); "
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,arith,load,store,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "DI")
(set_attr "length" "8,16,*,*,8,8,8,8,*,8,*")])
"!TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
- "* return mips_move_2words (operands, insn);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "DI")
(set_attr "length" "8,8,8,8,12,*,*,8")])
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (match_operand:DI 1 "register_operand" ""))]
- "reload_completed && !TARGET_64BIT
- && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
- && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
- && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
-
- [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
- (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
- "")
-
(define_insn "movdi_internal2"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*d,*m")
(match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*J,*x,*d,*J,*d,*m,*B*C*D,*B*C*D"))]
|| register_operand (operands[1], DImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|| operands[1] == CONST0_RTX (DImode))"
- "* return mips_move_2words (operands, insn); "
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,const,const,load,store,move,xfer,load,xfer,store,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "DI")
(set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,4,4,8,8,*,8,*")])
-;; Sign-extended operands are reloaded using this instruction, so the
-;; constraints must handle every SImode source operand X and destination
-;; register R for which:
-;;
-;; mips_secondary_reload_class (CLASS_OF (R), DImode, true,
-;; gen_rtx_SIGN_EXTEND (DImode, X))
-;;
-;; returns NO_REGS. Also handle memory destinations, where allowed.
-;;
-;; This pattern is essentially a trimmed-down version of movdi_internal2.
-;; The main difference is that dJ -> f and f -> d are the only constraints
-;; involving float registers. See mips_secondary_reload_class for details.
-
(define_insn "*movdi_internal2_mips16"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m,*d")
(match_operand:DI 1 "move_operand" "d,d,y,K,N,U,m,d,*x"))]
"TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
- "* return mips_move_2words (operands, insn);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,move,arith,arith,const,load,store,hilo")
(set_attr "mode" "DI")
(set_attr_alternative "length"
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,const,const,load,store,move,xfer,load,xfer,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,xfer,store")
(set_attr "mode" "SI")
(set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,4,4,4,4,4,4,*,4,*")])
"TARGET_MIPS16
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,move,arith,arith,const,load,store,hilo,hilo")
(set_attr "mode" "SI")
(set_attr_alternative "length"
}")
;; On the mips16, we can split a load of a negative constant into a
-;; load and a neg. That's what mips_move_1word will generate anyhow.
+;; load and a neg. That's what mips_output_move will generate anyhow.
(define_split
[(set (match_operand:SI 0 "register_operand" "")
[(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m")
(match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))]
"ISA_HAS_8CC && TARGET_HARD_FLOAT"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "SI")
(set_attr "length" "8,4,*,*,4,4,4,*,*")])
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "movhi_internal"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
- (match_operand:HI 1 "general_operand" "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x,*d")
+ (match_operand:HI 1 "general_operand" "d,IK,m,dJ,*f,*d,*f,*d,*x"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
- "* return mips_move_1word (operands, insn, TRUE);"
+ "@
+ move\t%0,%1
+ li\t%0,%1
+ lhu\t%0,%1
+ sh\t%z1,%0
+ mfc1\t%0,%1
+ mtc1\t%1,%0
+ mov.s\t%0,%1
+ mt%0\t%1
+ mf%1\t%0"
[(set_attr "type" "move,arith,load,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "HI")
(set_attr "length" "4,4,*,*,4,4,4,4,4")])
"TARGET_MIPS16
&& (register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode))"
- "* return mips_move_1word (operands, insn, TRUE);"
+ "@
+ move\t%0,%1
+ move\t%0,%1
+ move\t%0,%1
+ li\t%0,%1
+ li\t%0,%n1\;neg\t%0
+ lhu\t%0,%1
+ sh\t%1,%0
+ mf%1\t%0"
[(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "HI")
(set_attr_alternative "length"
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "movqi_internal"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f*z,*f,*x,*d")
- (match_operand:QI 1 "general_operand" "d,IK,m,dJ,*f*z,*d,*f,*d,*x"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x,*d")
+ (match_operand:QI 1 "general_operand" "d,IK,m,dJ,*f,*d,*f,*d,*x"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
- "* return mips_move_1word (operands, insn, TRUE);"
+ "@
+ move\t%0,%1
+ li\t%0,%1
+ lbu\t%0,%1
+ sb\t%z1,%0
+ mfc1\t%0,%1
+ mtc1\t%1,%0
+ mov.s\t%0,%1
+ mt%0\t%1
+ mf%1\t%0"
[(set_attr "type" "move,arith,load,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "QI")
(set_attr "length" "4,4,*,*,4,4,4,4,4")])
"TARGET_MIPS16
&& (register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode))"
- "* return mips_move_1word (operands, insn, TRUE);"
+ "@
+ move\t%0,%1
+ move\t%0,%1
+ move\t%0,%1
+ li\t%0,%1
+ li\t%0,%n1\;neg\t%0
+ lbu\t%0,%1
+ sb\t%1,%0
+ mf%1\t%0"
[(set_attr "type" "move,move,move,arith,arith,load,store,hilo")
(set_attr "mode" "QI")
- (set_attr_alternative "length"
- [(const_int 4)
- (const_int 4)
- (const_int 4)
- (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "")
- (const_int 4)
- (const_int 8))
- (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "")
- (const_int 8)
- (const_int 12))
- (const_string "*")
- (const_string "*")
- (const_int 4)])])
-
+ (set_attr "length" "4,4,4,4,8,*,*,4")])
;; On the mips16, we can split lb $r,N($r) into an add and a load,
;; when the original load is a 4 byte instruction but the add and the
"TARGET_HARD_FLOAT
&& (register_operand (operands[0], SFmode)
|| nonmemory_operand (operands[1], SFmode))"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,xfer,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "SF")
(set_attr "length" "4,4,*,*,4,4,4,*,*")])
"TARGET_SOFT_FLOAT && !TARGET_MIPS16
&& (register_operand (operands[0], SFmode)
|| nonmemory_operand (operands[1], SFmode))"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,load,store")
(set_attr "mode" "SF")
(set_attr "length" "4,*,*")])
"TARGET_MIPS16
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
- "* return mips_move_1word (operands, insn, FALSE);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,move,load,store")
(set_attr "mode" "SF")
(set_attr "length" "4,4,4,*,*")])
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_64BIT
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
- "* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
+ { return mips_output_move (operands[0], operands[1]); }
+ [(set_attr "type" "move,xfer,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "DF")
- (set_attr "length" "4,8,*,*,4,4,4,*,*")])
+ (set_attr "length" "4,4,*,*,4,4,4,*,*")])
(define_insn "movdf_internal1b"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,*f,*d,*d,*d,*m")
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
- "* return mips_move_2words (operands, insn); "
- [(set_attr "type" "move,move,load,store,xfer,xfer,move,load,store")
+ { return mips_output_move (operands[0], operands[1]); }
+ [(set_attr "type" "move,xfer,load,store,xfer,xfer,move,load,store")
(set_attr "mode" "DF")
(set_attr "length" "4,8,*,*,8,8,8,*,*")])
(define_insn "movdf_internal2"
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m,d,f,f")
- (match_operand:DF 1 "general_operand" "dG,m,d,f,d,f"))]
+ (match_operand:DF 1 "general_operand" "dG,m,dG,f,d,f"))]
"(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16
&& (register_operand (operands[0], DFmode)
|| nonmemory_operand (operands[1], DFmode))"
- "* return mips_move_2words (operands, insn); "
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,load,store,xfer,xfer,move")
(set_attr "mode" "DF")
- (set_attr "length" "8,*,*,8,8,4")])
+ (set_attr "length" "8,*,*,4,4,4")])
(define_insn ""
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m")
"TARGET_MIPS16
&& (register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode))"
- "* return mips_move_2words (operands, insn);"
+ { return mips_output_move (operands[0], operands[1]); }
[(set_attr "type" "move,move,move,load,store")
(set_attr "mode" "DF")
(set_attr "length" "8,8,8,*,*")])
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "register_operand" ""))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
"reload_completed && !TARGET_64BIT
- && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
- && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
- && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
- [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
- (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
- "")
+ && mips_split_64bit_move_p (operands[0], operands[1])"
+ [(const_int 0)]
+ {
+ mips_split_64bit_move (operands[0], operands[1]);
+ DONE;
+ })
+
+(define_split
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ "reload_completed && !TARGET_64BIT
+ && mips_split_64bit_move_p (operands[0], operands[1])"
+ [(const_int 0)]
+ {
+ mips_split_64bit_move (operands[0], operands[1]);
+ DONE;
+ })
+
+;; Patterns for loading or storing part of a paired floating point
+;; register. We need them because odd-numbered floating-point registers
+;; are not fully independent: see mips_split_64bit_move.
+
+;; Load the low word of operand 0 with operand 1.
+(define_insn "load_df_low"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")]
+ UNSPEC_LOAD_DF_LOW))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+ {
+ operands[0] = mips_subword (operands[0], 0);
+ return mips_output_move (operands[0], operands[1]);
+ }
+ [(set_attr "type" "xfer,load")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+;; Load the high word of operand 0 from operand 1, preserving the value
+;; in the low word.
+(define_insn "load_df_high"
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")
+ (match_operand:DF 2 "register_operand" "0,0")]
+ UNSPEC_LOAD_DF_HIGH))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+ {
+ operands[0] = mips_subword (operands[0], 1);
+ return mips_output_move (operands[0], operands[1]);
+ }
+ [(set_attr "type" "xfer,load")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+;; Store the high word of operand 1 in operand 0. The corresponding
+;; low-word move is done in the normal way.
+(define_insn "store_df_high"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m")
+ (unspec:SI [(match_operand:DF 1 "register_operand" "f,f")]
+ UNSPEC_STORE_DF_HIGH))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+ {
+ operands[1] = mips_subword (operands[1], 1);
+ return mips_output_move (operands[0], operands[1]);
+ }
+ [(set_attr "type" "xfer,store")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
;; Instructions to load the global pointer register.
;; This is volatile to make sure that the scheduler won't move any symbol_ref
(define_insn "exception_receiver"
[(unspec_volatile [(const_int 0)] UNSPEC_EH_RECEIVER)]
"TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
- "* return mips_restore_gp (operands, insn);"
+ { return mips_restore_gp (operands); }
[(set_attr "type" "load")
(set_attr "length" "8")])
\f