Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Created December 24, 2025 22:12
Show Gist options
  • Select an option

  • Save uyjulian/3a2b5227440aa0e2dec17ba8d67b4047 to your computer and use it in GitHub Desktop.

Select an option

Save uyjulian/3a2b5227440aa0e2dec17ba8d67b4047 to your computer and use it in GitHub Desktop.
--- gcc-2.96-20000731/gcc/config/mips/mips.c 2000-07-18 14:15:50.000000000 -0500
+++ ee/gcc/src/gcc/config/mips/mips.c 2001-04-22 19:58:34.000000000 -0500
@@ -114,6 +114,25 @@
static int symbolic_expression_p PARAMS ((rtx));
static void mips_add_gc_roots PARAMS ((void));
+/* Describe a builtin function.
+ Needed here so that it can be used in the protoypes below. */
+struct builtin_description
+{
+ enum insn_code icode;
+ const char *name;
+ enum mips_builtins code;
+};
+
+static rtx mips_expand_mtsax_builtin PARAMS ((struct builtin_description *, tree));
+static rtx mips_expand_shiftc_builtin PARAMS ((struct builtin_description *, tree, rtx));
+static rtx mips_expand_binop_builtin PARAMS ((struct builtin_description *, tree, rtx));
+static rtx safe_vector_operand PARAMS ((rtx, enum machine_mode));
+static void mips_r5900_lengthen_loops PARAMS ((rtx));
+static rtx mips_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
+static rtx mips_expand_mtspr_builtin PARAMS ((enum insn_code, tree));
+static rtx mips_expand_mfspr_builtin PARAMS ((enum insn_code, rtx));
+static void mips_check_reg_mode PARAMS ((rtx, rtx, void *));
+
/* Global variables for machine-dependent things. */
/* Threshold for data being put into the small data/bss area, instead
@@ -255,13 +274,17 @@
initialized in override_options. */
REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
-/* Mode used for saving/restoring general purpose registers. */
-static enum machine_mode gpr_mode;
+/* CYGNUS LOCAL: declaration of gpr_mode deleted. */
/* Array giving truth value on whether or not a given hard register
can support a given mode. */
char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
+/* The mode that will be used to save a given gpr on the stack. Note
+ the entry for $0 is special; it indicates the generic size of a gpr
+ save/restore by the prologue/epilogue and must be the maximum mode
+ ever used to save a GPR. This is typically WORD_MODE. */
+enum machine_mode mips_reg_mode[GP_REG_NUM];
/* Current frame information calculated by compute_frame_size. */
struct mips_frame_info current_frame_info;
@@ -323,6 +346,7 @@
"$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
"hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
"$fcc5","$fcc6","$fcc7","$rap"
+ , "hi1", "lo1", "accum1"
};
/* Mips software names for the registers, used to overwrite the
@@ -340,6 +364,7 @@
"$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
"hi", "lo", "accum","$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
"$fcc5","$fcc6","$fcc7","$rap"
+ , "hi1", "lo1", "accum1"
};
/* Map hard register number to register class */
@@ -352,7 +377,7 @@
M16_NA_REGS, M16_NA_REGS, GR_REGS, GR_REGS,
GR_REGS, GR_REGS, GR_REGS, GR_REGS,
T_REG, GR_REGS, GR_REGS, GR_REGS,
- GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, ARGP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
@@ -363,7 +388,8 @@
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
HI_REG, LO_REG, HILO_REG, ST_REGS,
ST_REGS, ST_REGS, ST_REGS, ST_REGS,
- ST_REGS, ST_REGS, ST_REGS, GR_REGS
+ ST_REGS, ST_REGS, ST_REGS, ARGP_REGS,
+ HI1_REG, LO1_REG, HILO1_REG
};
/* Map register constraint character to register class. */
@@ -554,6 +580,37 @@
return 0;
}
+/* Return truth value of whether OP is a register, a memory operand,
+ or a constant. This is used by the r5900 lq/sq support. */
+
+int
+movti_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ if (TARGET_MIPS16)
+ return FALSE;
+ return TRUE;
+
+ case CONST_DOUBLE:
+ if (TARGET_MIPS16 || GET_MODE (op) != VOIDmode)
+ return FALSE;
+ return TRUE;
+
+ case REG:
+ case SUBREG:
+ return register_operand (op, mode);
+
+ case MEM:
+ return memory_operand (op, mode);
+
+ default:
+ return FALSE;
+ }
+}
/* Return truth value of whether OP is a register or the constant 0,
even in mips16 mode. */
@@ -692,7 +749,7 @@
off = 0x100;
else
off = 0x20;
- if (INTVAL (offset) >= 0 && INTVAL (offset) < off * size)
+ if (INTVAL (offset) >= 0 && INTVAL (offset) < (HOST_WIDE_INT)(off * size))
return 1;
return 0;
}
@@ -715,7 +772,7 @@
/* ??? This isn't strictly correct. It is OK to accept multiword modes
here, since the length attributes are being set correctly, but only
if the address is offsettable. LO_SUM is not offsettable. */
- if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
+ if (GET_MODE_SIZE (GET_MODE (op)) > (unsigned) UNITS_PER_WORD)
return 0;
/* Decode the address now. */
@@ -777,6 +834,15 @@
/* fall through */
+ /* The symbol_ref_5900 stuff was done as part of the 5900
+ enhancement project.
+
+ By #if 0-ing the SYMBOL_REF case out here, the compiler doesn't
+ notice that GP relative references are only one insn long, and
+ won't put then in delay slots. I've moved the SYMBOL_REF case
+ back out of the #if 0. I believe the PIC case is now handled
+ by the compiler, and I'd rather find and fix the G++ problem. */
+
case SYMBOL_REF:
return SYMBOL_REF_FLAG (addr);
#endif
@@ -784,6 +850,11 @@
/* This SYMBOL_REF case is for the mips16. If the above case is
reenabled, this one should be merged in. */
case SYMBOL_REF:
+ /* If the symbol is going to referenced using GP relative addressing
+ then it is a simple_memory_operand. SYMBOL_REF_FLAG is used for
+ a number of things, as descibed near ENCODE_SECTION_INFO in mips.h. */
+ if (!TARGET_MIPS16 && !TARGET_EMBEDDED_DATA && !TARGET_EMBEDDED_PIC)
+ return SYMBOL_REF_FLAG (addr);
/* References to the constant pool on the mips16 use a small
offset if the function is small. The only time we care about
getting this right is during delayed branch scheduling, so
@@ -868,7 +939,7 @@
address will get reloaded anyhow. */
if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == REG
- && (REGNO (XEXP (addr, 0)) == HARD_FRAME_POINTER_REGNUM
+ && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
|| REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
&& ((GET_CODE (XEXP (addr, 1)) == CONST_INT
&& ! SMALL_INT (XEXP (addr, 1)))
@@ -885,7 +956,7 @@
maddr = XEXP (addr, 0);
if (GET_CODE (maddr) == PLUS
&& GET_CODE (XEXP (maddr, 0)) == REG
- && (REGNO (XEXP (maddr, 0)) == HARD_FRAME_POINTER_REGNUM
+ && (REGNO (XEXP (maddr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
|| REGNO (XEXP (maddr, 0)) == STACK_POINTER_REGNUM)
&& ((GET_CODE (XEXP (maddr, 1)) == CONST_INT
&& ! SMALL_INT (XEXP (maddr, 1)))
@@ -905,7 +976,7 @@
addr = XEXP (XEXP (addr, 0), 0);
if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == REG
- && (REGNO (XEXP (addr, 0)) == HARD_FRAME_POINTER_REGNUM
+ && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
|| REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
&& ((GET_CODE (XEXP (addr, 1)) == CONST_INT
&& ! SMALL_INT (XEXP (addr, 1)))
@@ -1176,6 +1247,80 @@
return CONSTANT_P (op);
}
+/* Return truth value of whether OP is a register, a memory operand,
+ or a constant. This is used by the r5900 lq/sq support. */
+
+int
+vector_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ return TARGET_MIPS5900;
+
+ case CONST_DOUBLE:
+ return TARGET_MIPS5900;
+
+ case REG:
+ case SUBREG:
+ return register_operand (op, mode);
+
+ case MEM:
+ return memory_operand (op, mode);
+
+ default:
+ return FALSE;
+ }
+}
+
+int
+movv16qi_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return vector_operand (op, mode);
+}
+
+int
+movv8hi_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return vector_operand (op, mode);
+}
+
+int
+movv4si_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return vector_operand (op, mode);
+}
+
+int
+movv2di_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return vector_operand (op, mode);
+}
+
+int
+movv2si_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return vector_operand (op, mode);
+}
+
+int register_or_int_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return const_int_operand (op, mode) || register_operand (op, mode);
+}
/* Return nonzero if we split the address into high and low parts. */
/* ??? We should also handle reg+array somewhere. We get four
@@ -1199,7 +1344,7 @@
{
/* ??? This is the same check used in simple_memory_operand.
We use it here because LO_SUM is not offsettable. */
- if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)
return 0;
if ((GET_CODE (address) == SYMBOL_REF && ! SYMBOL_REF_FLAG (address))
@@ -1247,6 +1392,8 @@
accept (subreg (const_int)) which will fail to reload. */
if (CONSTANT_ADDRESS_P (xinsn)
&& ! (mips_split_addresses && mips_check_split (xinsn, mode))
+ && ! (TARGET_MIPS5900 && mode == TImode)
+ && ! (SIMD_MODE_SUPPORTED_P (mode))
&& (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))
return 1;
@@ -1325,11 +1472,16 @@
|| mips_abi == ABI_O64
|| mips_abi == ABI_EABI)
&& CONSTANT_ADDRESS_P (xplus1)
- && ! mips_split_addresses
+ && ! (mips_split_addresses && mips_check_split (xinsn, mode))
&& (!TARGET_EMBEDDED_PIC
|| code1 != CONST
|| GET_CODE (XEXP (xplus1, 0)) != MINUS)
- && !TARGET_MIPS16)
+ /* When assembling for machines with 64 bit registers,
+ the assembler will not sign-extend the constant "foo"
+ in "la x, foo(x)" */
+ && (!TARGET_64BIT || (INTVAL (xplus1) > 0))
+ && !TARGET_MIPS16
+ && !(TARGET_MIPS5900 && mode == TImode))
return 1;
}
}
@@ -1578,6 +1730,8 @@
else if (type == DELAY_HILO)
num_nops = 2;
+ else if (type == DELAY_HILO1)
+ num_nops = 2;
else
num_nops = 0;
@@ -1615,7 +1769,7 @@
dslots_number_nops = num_nops;
mips_load_reg = set_reg;
if (GET_MODE_SIZE (mode)
- > (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD))
+ > (unsigned) (FP_REG_P (REGNO (set_reg)) ? UNITS_PER_FPREG : UNITS_PER_WORD))
mips_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1);
else
mips_load_reg2 = 0;
@@ -1625,6 +1779,11 @@
mips_load_reg3 = gen_rtx_REG (SImode, MD_REG_FIRST);
mips_load_reg4 = gen_rtx_REG (SImode, MD_REG_FIRST+1);
}
+ else if (type == DELAY_HILO1)
+ {
+ mips_load_reg3 = gen_rtx_REG (SImode, MD1_REG_FIRST);
+ mips_load_reg4 = gen_rtx_REG (SImode, MD1_REG_FIRST+1);
+ }
else
{
mips_load_reg3 = 0;
@@ -1853,6 +2012,14 @@
ret = "mflo\t%0";
}
+ else if (MD1_REG_P (regno1))
+ {
+ delay = DELAY_HILO1;
+ if (regno1 != HILO1_REGNUM)
+ ret = "mf%1\t%0";
+ else
+ ret = "mflo1\t%0";
+ }
else if (ST_REG_P (regno1) && ISA_HAS_8CC)
ret = "li\t%0,1\n\tmovf\t%0,%.,%1";
@@ -1889,6 +2056,15 @@
}
}
+ else if (MD1_REG_P (regno0))
+ {
+ if (GP_REG_P (regno1))
+ {
+ delay = DELAY_HILO1;
+ if (regno0 != HILO1_REGNUM && ! TARGET_MIPS16)
+ ret = "mt%0\t%1";
+ }
+ }
else if (regno0 == FPSW_REGNUM && ! ISA_HAS_8CC)
{
if (GP_REG_P (regno1))
@@ -1974,6 +2150,11 @@
delay = DELAY_HILO;
ret = "mt%0\t%.";
}
+ else if (MD1_REG_P (regno0))
+ {
+ delay = DELAY_HILO1;
+ ret = "mt%0\t%.";
+ }
}
else if (GP_REG_P (regno0))
@@ -2302,6 +2483,19 @@
ret = "mthi\t%M1\n\tmtlo\t%L1";
}
+ else if (MD1_REG_P (regno0) && GP_REG_P (regno1) && !TARGET_MIPS16)
+ {
+ delay = DELAY_HILO1;
+ if (TARGET_64BIT)
+ {
+ if (regno0 != HILO1_REGNUM)
+ ret = "mt%0\t%1";
+ else if (regno1 == 0)
+ ret = "mtlo%H0\t%.\n\tmthi%H0\t%.";
+ }
+ else
+ ret = "mthi%H0\t%M1\n\tmtlo%H0\t%L1";
+ }
else if (GP_REG_P (regno0) && MD_REG_P (regno1))
{
delay = DELAY_HILO;
@@ -2314,6 +2508,17 @@
ret = "mfhi\t%M0\n\tmflo\t%L0";
}
+ else if (GP_REG_P (regno0) && MD1_REG_P (regno1))
+ {
+ delay = DELAY_HILO1;
+ if (TARGET_64BIT)
+ {
+ if (regno1 != HILO1_REGNUM)
+ ret = "mf%1\t%0";
+ }
+ else
+ ret = "mfhi%H1\t%M0\n\tmflo%H1\t%L0";
+ }
else if (TARGET_64BIT)
ret = "move\t%0,%1";
@@ -2419,6 +2624,13 @@
? "mtlo\t%.\n\tmthi\t%."
: "mt%0\t%.\n");
}
+ else if (MD1_REG_P (regno0))
+ {
+ delay = DELAY_HILO1;
+ ret = (regno0 == HILO1_REGNUM
+ ? "mtlo%H0\t%.\n\tmthi%H0\t%."
+ : "mt%0\t%.\n");
+ }
}
else if (code1 == CONST_INT && GET_MODE (op0) == DImode
@@ -3179,7 +3391,7 @@
rtx bytes_rtx;
int leftover;
- if (bytes < 2 * MAX_MOVE_BYTES)
+ if (bytes < (unsigned)2 * MAX_MOVE_BYTES)
abort ();
leftover = bytes % MAX_MOVE_BYTES;
@@ -3246,7 +3458,7 @@
/* We want to pass the size as Pmode, which will normally be SImode
but will be DImode if we are using 64 bit longs and pointers. */
if (GET_MODE (bytes_rtx) != VOIDmode
- && GET_MODE (bytes_rtx) != Pmode)
+ && GET_MODE (bytes_rtx) != (unsigned) Pmode)
bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);
#ifdef TARGET_MEM_FUNCTIONS
@@ -3288,7 +3500,7 @@
if (constp && bytes == 0)
return;
- if (align > UNITS_PER_WORD)
+ if (align > (unsigned) UNITS_PER_WORD)
align = UNITS_PER_WORD;
/* Move the address into scratch registers. */
@@ -3298,18 +3510,18 @@
if (TARGET_MEMCPY)
block_move_call (dest_reg, src_reg, bytes_rtx);
- else if (constp && bytes <= 2 * MAX_MOVE_BYTES
- && align == UNITS_PER_WORD)
+ else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES
+ && align == (unsigned) UNITS_PER_WORD)
move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD);
- else if (constp && bytes <= 2 * MAX_MOVE_BYTES)
+ else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES)
emit_insn (gen_movstrsi_internal (change_address (orig_dest, BLKmode,
dest_reg),
change_address (orig_src, BLKmode,
src_reg),
bytes_rtx, align_rtx));
- else if (constp && align >= UNITS_PER_WORD && optimize)
+ else if (constp && align >= (unsigned) UNITS_PER_WORD && optimize)
block_move_loop (dest_reg, src_reg, bytes, align, orig_dest, orig_src);
else if (constp && optimize)
@@ -3782,7 +3994,7 @@
"function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
cum->gp_reg_found, cum->arg_number, cum->arg_words,
GET_MODE_NAME (mode));
- fprintf (stderr, HOST_PTR_PRINTF, type);
+ fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type);
fprintf (stderr, ", %d )\n\n", named);
}
@@ -3793,6 +4005,15 @@
break;
default:
+ /* The r5900 only needs a single general register to pass a
+ SIMD vector mode. It should be impossible to reach this code
+ with any other port, so abort if it happens. */
+ if (SIMD_MODE_SUPPORTED_P (mode))
+ {
+ cum->gp_reg_found = 1;
+ cum->arg_words += 1;
+ break;
+ }
if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
abort ();
@@ -3831,6 +4052,15 @@
cum->arg_words += (TARGET_64BIT ? 1 : 2);
break;
+ /* The r5900 only needs a single general register to pass a
+ TImode value. It should be impossible to reach this code
+ with any other port, so abort if it happens. */
+ case TImode:
+ if (!TARGET_MIPS5900)
+ abort ();
+ cum->gp_reg_found = 1;
+ cum->arg_words += 1;
+ break;
case QImode:
case HImode:
case SImode:
@@ -3853,7 +4083,7 @@
rtx ret;
int regbase = -1;
int bias = 0;
- int *arg_words = &cum->arg_words;
+ unsigned int *arg_words = &cum->arg_words;
int struct_p = (type != 0
&& (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE
@@ -3865,7 +4095,7 @@
"function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
cum->gp_reg_found, cum->arg_number, cum->arg_words,
GET_MODE_NAME (mode));
- fprintf (stderr, HOST_PTR_PRINTF, type);
+ fprintf (stderr, HOST_PTR_PRINTF, (const PTR) type);
fprintf (stderr, ", %d ) = ", named);
}
@@ -3928,13 +4158,21 @@
break;
default:
+ /* The r5900 only needs a single general register to pass a
+ SIMD vector mode. It should be impossible to reach this code
+ with any other port, so abort if it happens. */
+ if (SIMD_MODE_SUPPORTED_P (mode))
+ {
+ regbase = GP_ARG_FIRST;
+ break;
+ }
if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
abort ();
/* Drops through. */
case BLKmode:
- if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD
+ if (type != NULL_TREE && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST;
@@ -3947,13 +4185,21 @@
regbase = GP_ARG_FIRST;
break;
+ /* The r5900 only needs a single general register to pass a
+ TImode value. It should be impossible to reach this code
+ with any other port, so abort if it happens. */
+ case TImode:
+ if (!TARGET_MIPS5900)
+ abort ();
+ regbase = GP_ARG_FIRST;
+ break;
case DImode:
if (! TARGET_64BIT)
cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST;
}
- if (*arg_words >= MAX_ARGS_IN_REGISTERS)
+ if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS)
{
if (TARGET_DEBUG_E_MODE)
fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
@@ -4003,7 +4249,7 @@
chunks
= tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD;
- if (chunks + *arg_words + bias > MAX_ARGS_IN_REGISTERS)
+ if (chunks + *arg_words + bias > (unsigned) MAX_ARGS_IN_REGISTERS)
chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias;
/* assign_parms checks the mode of ENTRY_PARM, so we must
@@ -4026,7 +4272,9 @@
&& int_bit_position (field) == bitpos
&& TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
- reg = gen_rtx_REG (DFmode,
+ reg = gen_rtx_REG (
+ DFmode
+ ,
regno + FP_ARG_FIRST - GP_ARG_FIRST);
else
reg = gen_rtx_REG (word_mode, regno);
@@ -4035,7 +4283,7 @@
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
- bitpos += 64;
+ bitpos += BITS_PER_WORD; /* CYGNUS LOCAL gavin */
regno++;
}
}
@@ -4104,9 +4352,11 @@
int named ATTRIBUTE_UNUSED;/* != 0 for normal args, == 0 for ... args */
{
if ((mode == BLKmode
+ || (mode == TImode && TARGET_MIPS5900)
+ || SIMD_MODE_SUPPORTED_P (mode)
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
|| GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
- && cum->arg_words < MAX_ARGS_IN_REGISTERS
+ && cum->arg_words < (unsigned) MAX_ARGS_IN_REGISTERS
&& mips_abi != ABI_EABI)
{
int words;
@@ -4116,7 +4366,7 @@
else
words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
+ if (words + cum->arg_words <= (unsigned) MAX_ARGS_IN_REGISTERS)
return 0; /* structure fits in registers */
if (TARGET_DEBUG_E_MODE)
@@ -4126,7 +4376,8 @@
return MAX_ARGS_IN_REGISTERS - cum->arg_words;
}
- else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1
+ else if (mode == DImode
+ && cum->arg_words == MAX_ARGS_IN_REGISTERS - (unsigned)1
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
{
if (TARGET_DEBUG_E_MODE)
@@ -4386,7 +4637,10 @@
indirect
= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
if (indirect)
- size = rsize = POINTER_SIZE / BITS_PER_UNIT;
+ {
+ size = POINTER_SIZE / BITS_PER_UNIT;
+ rsize = UNITS_PER_WORD;
+ }
addr_rtx = gen_reg_rtx (Pmode);
@@ -4623,6 +4877,20 @@
mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
+#ifndef MIPS_DISABLE_GPOPT
+#define MIPS_DISABLE_GPOPT 0
+#endif
+
+ if (MIPS_DISABLE_GPOPT)
+ {
+ if (mips_section_threshold != 0)
+ {
+ error ("-G not supported in this configuration.");
+ mips_section_threshold = 0;
+ }
+ target_flags &= ~MASK_GPOPT;
+ }
+ else
if (mips_section_threshold <= 0)
target_flags &= ~MASK_GPOPT;
else if (optimize)
@@ -4634,7 +4902,7 @@
user. */
#ifdef TARGET_DEFAULT
if (TARGET_SINGLE_FLOAT && TARGET_SOFT_FLOAT)
- target_flags &= ~(TARGET_DEFAULT&(MASK_SOFT_FLOAT|MASK_SINGLE_FLOAT));
+ target_flags &= ~((TARGET_DEFAULT) & (MASK_SOFT_FLOAT | MASK_SINGLE_FLOAT));
#endif
/* Get the architectural level. */
@@ -4673,6 +4941,9 @@
mips_isa = 1;
}
+ if (!TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG)
+ error ("-mhandle-ee-div-pipeline-bug is not supported.");
+
#ifdef MIPS_ABI_DEFAULT
/* Get the ABI to use. */
if (mips_abi_string == (char *) 0)
@@ -4733,9 +5004,14 @@
|| mips_abi == ABI_64))
target_flags |= MASK_LONG64;
- /* ??? This doesn't work yet, so don't let people try to use it. */
+ /* CYGNUS LOCAL vr4111/gavin */
+#ifndef MIPS_ENABLE_EMBEDDED_O32
+ /* ??? The native version of this have not been well tested;
+ enable O32 only for specific embedded targets. */
if (mips_abi == ABI_32)
error ("The -mabi=32 support does not work yet.");
+#endif
+ /* END CYGNUS LOCAL vr4111/gavin */
#else
if (mips_abi_string)
@@ -4751,10 +5027,10 @@
mips_cpu_string = MIPS_CPU_STRING_DEFAULT;
#endif
- /* Identify the processor type */
+ /* Identify the processor type. */
if (mips_cpu_string == 0
- || !strcmp (mips_cpu_string, "default")
- || !strcmp (mips_cpu_string, "DEFAULT"))
+ || ! strcmp (mips_cpu_string, "default")
+ || ! strcmp (mips_cpu_string, "DEFAULT"))
{
switch (mips_isa)
{
@@ -4776,7 +5052,6 @@
break;
}
}
-
else
{
const char *p = mips_cpu_string;
@@ -4818,6 +5093,11 @@
mips_cpu = PROCESSOR_R4100;
target_flags |= MASK_SOFT_FLOAT ;
}
+ else if (!strcmp (p, "4111"))
+ {
+ mips_cpu = PROCESSOR_R4100;
+ target_flags |= MASK_SOFT_FLOAT ;
+ }
/* The vr4300 is a standard ISA III processor, but with a different
pipeline. */
else if (!strcmp (p, "4300"))
@@ -4835,6 +5115,10 @@
case '5':
if (!strcmp (p, "5000") || !strcmp (p, "5k") || !strcmp (p, "5K"))
mips_cpu = PROCESSOR_R5000;
+ else if (!strcmp (p, "5400"))
+ mips_cpu = PROCESSOR_R5400;
+ else if (!strcmp (p, "5900"))
+ mips_cpu = PROCESSOR_R5900;
break;
case '6':
@@ -4851,11 +5135,28 @@
if (!strcmp (p, "orion"))
mips_cpu = PROCESSOR_R4600;
break;
+ case 'm':
+ case 'M':
+ switch (atoi (p + 1))
+ {
+ case 5200:
+ case 5230:
+ case 5231:
+ case 5261:
+ case 5721:
+ case 7000:
+ target_flags |= MASK_MAD;
+ mips_cpu = PROCESSOR_R5000;
+ break;
+ default:
+ break;
+ }
}
if (seen_v
&& mips_cpu != PROCESSOR_R4300
&& mips_cpu != PROCESSOR_R4100
+ && mips_cpu != PROCESSOR_R5400
&& mips_cpu != PROCESSOR_R5000)
mips_cpu = PROCESSOR_DEFAULT;
@@ -5024,9 +5325,14 @@
mips_char_to_class['l'] = LO_REG;
mips_char_to_class['a'] = HILO_REG;
mips_char_to_class['x'] = MD_REGS;
+ mips_char_to_class['u'] = HI1_REG;
+ mips_char_to_class['v'] = LO1_REG;
+ mips_char_to_class['q'] = HILO1_REG;
+ mips_char_to_class['w'] = MD1_REGS;
mips_char_to_class['b'] = ALL_REGS;
mips_char_to_class['y'] = GR_REGS;
mips_char_to_class['z'] = ST_REGS;
+ mips_char_to_class['A'] = ARGP_REGS;
/* Set up array to map GCC register number to debug register number.
Ignore the special purpose register numbers. */
@@ -5069,11 +5375,22 @@
|| FP_REG_P (regno));
}
+ /* The general registers can hold 128-bit integer and vector
+ integer values on the r5900. So can HI and LO. */
+ else if ((GP_REG_P (regno) || MD_REG_P (regno))
+ && (class == MODE_INT || class == MODE_VECTOR_INT)
+ && size <= UNITS_PER_WORD * 2
+ && TARGET_MIPS5900)
+ temp = 1;
+ /* General registers can hold SIMD vector mode values. */
+ else if (GP_REG_P (regno) && SIMD_MODE_SUPPORTED_P (mode))
+ temp = 1;
else if (GP_REG_P (regno))
temp = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
else if (FP_REG_P (regno))
- temp = ((TARGET_FLOAT64 || ((regno & 1) == 0))
+ temp = ((TARGET_FLOAT64 || ((regno & 1) == 0)
+ )
&& (class == MODE_FLOAT
|| class == MODE_COMPLEX_FLOAT
|| (TARGET_DEBUG_H_MODE && class == MODE_INT))
@@ -5085,6 +5402,12 @@
|| (regno == MD_REG_FIRST
&& size == 2 * UNITS_PER_WORD)));
+ else if (MD1_REG_P (regno))
+ temp = (class == MODE_INT
+ && (size <= UNITS_PER_WORD
+ || (regno == MD1_REG_FIRST
+ && size == 2 * UNITS_PER_WORD)))
+ || TARGET_SIMD;
else
temp = 0;
@@ -5094,8 +5417,15 @@
/* Save GPR registers in word_mode sized hunks. word_mode hasn't been
initialized yet, so we can't use that here. */
- gpr_mode = TARGET_64BIT ? DImode : SImode;
+ /* CYGNUS LOCAL gpr_mode */
+ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+ mips_reg_mode[regno] = TARGET_64BIT ? DImode : SImode;
+ /* Saves/restores of general purpose registers on the r5900 use
+ a mode wider than word_mode. */
+ if (TARGET_MIPS5900)
+ mips_reg_mode[0] = TImode;
+ /* END CYGNUS LOCAL */
/* Provide default values for align_* for 64-bit targets. */
if (TARGET_64BIT && !TARGET_MIPS16)
{
@@ -5157,7 +5487,7 @@
if (reg == stack_pointer_rtx || reg == frame_pointer_rtx
|| reg == hard_frame_pointer_rtx)
{
- HOST_WIDE_INT frame_size = (!current_frame_info.initialized)
+ HOST_WIDE_INT frame_size = (current_frame_info.state != fi_initialized)
? compute_frame_size (get_frame_size ())
: current_frame_info.total_size;
@@ -5397,6 +5727,15 @@
default:
abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%C");
}
+ else if (letter == 'H')
+ {
+ if (true_regnum (op) >= MD_REG_FIRST
+ && true_regnum (op) <= MD_REG_LAST)
+ ;
+ else if (true_regnum (op) >= MD1_REG_FIRST
+ && true_regnum (op) <= MD1_REG_LAST)
+ fputs ("1", file);
+ }
else if (letter == 'N')
switch (code)
@@ -5455,6 +5794,15 @@
if (regnum != ST_REG_FIRST)
fprintf (file, "%s,", reg_names[regnum]);
}
+ else if ((letter == 'L' || letter == 'M')
+ && code == CONST_DOUBLE
+ && GET_MODE (op) == VOIDmode)
+ {
+ if (letter == 'L')
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (op));
+ else
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_HIGH (op));
+ }
else if (code == REG || code == SUBREG)
{
@@ -5904,6 +6252,8 @@
mips_asm_file_start (stream)
FILE *stream;
{
+ const char * abi_string = NULL;
+
ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
/* Versions of the MIPS assembler before 2.20 generate errors if a branch
@@ -5914,6 +6264,32 @@
if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
fprintf (stream, "\t.set\tnobopt\n");
+#ifdef OBJECT_FORMAT_ELF
+ /* Generate a special section to describe the ABI switches used to produce
+ the resultant binary. This used to be done by the assembler setting bits
+ in the ELF header's flags field, but we have run out of bits. GDB needs
+ this information in order to be able to correctly debug these binaries.
+ See the function mips_gdbarch_init() in gdb/mips-tdep.c. */
+ switch (mips_abi)
+ {
+ case ABI_32: abi_string = "abi32"; break;
+ case ABI_N32: abi_string = "abiN32"; break;
+ case ABI_64: abi_string = "abi64"; break;
+ case ABI_O64: abi_string = "abiO64"; break;
+ case ABI_EABI: abi_string = TARGET_64BIT ? "eabi64" : "eabi32"; break;
+ default:
+ abort ();
+ }
+ /* Note - we use fprintf directly rather than called named_section()
+ because in this way we can avoid creating an allocated section. We
+ do not want this section to take up any space in the running
+ executable. */
+ fprintf (stream, "\t.section .mdebug.%s\n", abi_string);
+
+ /* Restore the default section. */
+ fprintf (stream, "\t.previous\n");
+#endif
+
/* Generate the pseudo ops that System V.4 wants. */
#ifndef ABICALLS_ASM_OP
#define ABICALLS_ASM_OP ".abicalls"
@@ -6138,13 +6514,19 @@
HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up */
HOST_WIDE_INT extra_size; /* # extra bytes */
HOST_WIDE_INT gp_reg_rounded; /* # bytes needed to store gp after rounding */
- HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs */
+ HOST_WIDE_INT gp_quad_size; /* # bytes needed to store 128 bit gp regs */
+ HOST_WIDE_INT gp_reg_size; /* # total bytes needed to store gp regs */
HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs */
long mask; /* mask of saved gp registers */
long fmask; /* mask of saved fp registers */
int fp_inc; /* 1 or 2 depending on the size of fp regs */
long fp_bits; /* bitmask to use for each fp register */
+ int num_gp = 0;
+
+ /* If we are called before reload, mips_reg_mode isn't final. */
+ int tentative = current_frame_info.state < fi_modes_known;
+ gp_quad_size = 0;
gp_reg_size = 0;
fp_reg_size = 0;
mask = 0;
@@ -6187,20 +6569,26 @@
|| (GET_MODE_SIZE (DECL_MODE (DECL_RESULT (current_function_decl)))
<= 4))))
{
- gp_reg_size += GET_MODE_SIZE (gpr_mode);
+ int this_size = GET_MODE_SIZE (tentative ? TImode : mips_reg_mode[regno]);
+
+ gp_reg_size += this_size;
+ if (this_size == 16)
+ gp_quad_size += this_size;
mask |= 1L << (regno - GP_REG_FIRST);
+ num_gp++;
+ }
+ }
/* The entry and exit pseudo instructions can not save $17
without also saving $16. */
if (mips_entry
- && regno == GP_REG_FIRST + 17
+ && MUST_SAVE_REGISTER (GP_REG_FIRST + 17)
&& ! MUST_SAVE_REGISTER (GP_REG_FIRST + 16))
{
+ /* This is only for mips16, so we 'know' the register size. */
gp_reg_size += UNITS_PER_WORD;
mask |= 1L << 16;
}
- }
- }
/* Calculate space needed for fp registers. */
if (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT)
@@ -6228,7 +6616,13 @@
}
gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
- total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size);
+
+ /* On the 5900, gp registers are already 8 byte aligned, plenty for fp
+ registers. MIPS_STACK_ALIGN would force 16 byte alignment, often
+ wasting 8 bytes stack space. */
+ if (TARGET_MIPS5900)
+ gp_reg_rounded = gp_reg_size;
+ total_size += MIPS_STACK_ALIGN (gp_reg_rounded + fp_reg_size);
/* The gp reg is caller saved in the 32 bit ABI, so there is no need
for leaf routines (total_size == extra_size) to save the gp reg.
@@ -6264,11 +6658,13 @@
current_frame_info.args_size = args_size;
current_frame_info.extra_size = extra_size;
current_frame_info.gp_reg_size = gp_reg_size;
+ current_frame_info.gp_quad_size = gp_quad_size;
current_frame_info.fp_reg_size = fp_reg_size;
current_frame_info.mask = mask;
current_frame_info.fmask = fmask;
- current_frame_info.initialized = reload_completed;
- current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
+ current_frame_info.state
+ = tentative ? fi_partially_initialized : fi_initialized;
+ current_frame_info.num_gp = num_gp;
current_frame_info.num_fp = fp_reg_size / (fp_inc * UNITS_PER_FPREG);
if (mask)
@@ -6278,13 +6674,20 @@
/* When using mips_entry, the registers are always saved at the
top of the stack. */
if (! mips_entry)
- offset = (args_size + extra_size + var_size
- + gp_reg_size - GET_MODE_SIZE (gpr_mode));
+ offset = args_size + extra_size + var_size + gp_reg_size;
else
- offset = total_size - GET_MODE_SIZE (gpr_mode);
+ offset = total_size;
current_frame_info.gp_sp_offset = offset;
+ current_frame_info.rap_offset
+ = (offset - GET_MODE_SIZE (mips_reg_mode[31])
+ + (((UNITS_PER_WORD > 8 ? 8 : UNITS_PER_WORD)
+ - (POINTER_SIZE / BITS_PER_UNIT))
+ * (BYTES_BIG_ENDIAN != 0)));
current_frame_info.gp_save_offset = offset - total_size;
+ /* Point to last saved register. */
+ current_frame_info.gp_save_offset
+ -= GET_MODE_SIZE (gp_reg_size == gp_quad_size ? TImode : DImode);
}
else
{
@@ -6317,6 +6720,34 @@
is not modified within save_restore_insns. */
#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
+/* If modifying X uses a larger mode than in mips_reg_mode,
+ indicate that fact by setting mips_reg_mode. */
+
+static void
+mips_check_reg_mode (x, insn, data)
+ rtx x;
+ rtx insn ATTRIBUTE_UNUSED;
+ void * data ATTRIBUTE_UNUSED;
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ if (GET_CODE (x) == SUBREG)
+ {
+ x = SUBREG_REG (x);
+ }
+ /* QI clobbers are what asm() clobbers generate. We must
+ assume the whole register is clobbered. */
+ if (GET_CODE (insn) == CLOBBER
+ && mode == QImode)
+ mode = TImode;
+ if (GET_CODE (x) == REG
+ && REGNO (x) <= GP_REG_LAST
+ && (GET_MODE_SIZE (mode)
+ > GET_MODE_SIZE (mips_reg_mode[REGNO (x)])))
+ {
+ mips_reg_mode[REGNO (x)] = mode;
+ }
+}
static void
save_restore_insns (store_p, large_reg, large_offset, file)
@@ -6331,6 +6762,10 @@
rtx base_reg_rtx;
HOST_WIDE_INT base_offset;
HOST_WIDE_INT gp_offset;
+ HOST_WIDE_INT gp_start;
+ HOST_WIDE_INT gp_end;
+ HOST_WIDE_INT gp_quad_offset;
+ HOST_WIDE_INT gp_word_offset;
HOST_WIDE_INT fp_offset;
HOST_WIDE_INT end_offset;
rtx insn;
@@ -6356,29 +6791,30 @@
the constant created in the prologue/epilogue to adjust the stack
frame. */
- gp_offset = current_frame_info.gp_sp_offset;
- end_offset
- = gp_offset - (current_frame_info.gp_reg_size
- - GET_MODE_SIZE (gpr_mode));
-
- if (gp_offset < 0 || end_offset < 0)
- fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
- (long) gp_offset, (long) end_offset);
+ gp_end = current_frame_info.gp_sp_offset;
+ gp_start = gp_end - current_frame_info.gp_reg_size;
+ gp_quad_offset = gp_start;
+ gp_word_offset = gp_start + current_frame_info.gp_quad_size;
+
+ if (gp_end < 0 || gp_start < 0)
+ fatal ("gp_end (%ld) or gp_start (%ld) is less than zero.",
+ (long) gp_end , (long) gp_start);
/* If we see a large frame in mips16 mode, we save the registers
before adjusting the stack pointer, and load them afterward. */
else if (TARGET_MIPS16 && large_offset > 32767)
base_reg_rtx = stack_pointer_rtx, base_offset = large_offset;
- else if (gp_offset < 32768)
+ else if (gp_end <= 32768)
base_reg_rtx = stack_pointer_rtx, base_offset = 0;
else if (large_reg != 0
- && (unsigned HOST_WIDE_INT) (large_offset - gp_offset) < 32768
- && (unsigned HOST_WIDE_INT) (large_offset - end_offset) < 32768)
+ && (unsigned HOST_WIDE_INT) (large_offset - gp_end) <= 32768
+ && (unsigned HOST_WIDE_INT) (large_offset - gp_start) < 32768)
{
base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = large_offset;
+ gp_offset = base_offset;
if (file == 0)
{
if (Pmode == DImode)
@@ -6402,10 +6838,10 @@
{
base_reg_rtx = gen_rtx_REG (Pmode, MIPS_TEMP2_REGNUM);
base_offset = gp_offset;
+ gp_offset = base_offset;
if (file == 0)
{
rtx gp_offset_rtx = GEN_INT (gp_offset);
-
/* Instruction splitting doesn't preserve the RTX_FRAME_RELATED_P
bit, so make sure that we don't emit anything that can be
split. */
@@ -6415,7 +6851,7 @@
&& GET_MODE (base_reg_rtx) == SImode)
{
insn = emit_move_insn (base_reg_rtx,
- GEN_INT (gp_offset & 0xffff0000));
+ GEN_INT (gp_offset & 0xffff0000U));
if (store_p)
RTX_FRAME_RELATED_P (insn) = 1;
insn
@@ -6466,14 +6902,31 @@
&& large_offset <= 32767)
base_offset += current_function_outgoing_args_size;
- for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
+ /* Process registers in forward order to improve burst reads from
+ memory. */
+ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
if (BITSET_P (mask, regno - GP_REG_FIRST))
{
+ HOST_WIDE_INT gp_offset;
+
+ if (GET_MODE_SIZE (mips_reg_mode[regno]) == 16)
+ {
+ gp_offset = gp_quad_offset;
+ gp_quad_offset += 16;
+ }
+ else
+ {
+ gp_offset = gp_word_offset;
+ gp_word_offset += GET_MODE_SIZE (mips_reg_mode[regno]);
+ }
+
if (file == 0)
{
rtx reg_rtx;
rtx mem_rtx
- = gen_rtx (MEM, gpr_mode,
+ /* CYGNUS LOCAL gpr_mode */
+ = gen_rtx (MEM, mips_reg_mode[regno],
+ /* END CYGNUS LOCAL */
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (gp_offset - base_offset)));
@@ -6483,23 +6936,34 @@
$31, so we load $7 instead, and work things out
in the caller. */
if (TARGET_MIPS16 && ! store_p && regno == GP_REG_FIRST + 31)
- reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 7);
+ /* CYGNUS LOCAL gpr_mode */
+ reg_rtx = gen_rtx (REG, mips_reg_mode[7], GP_REG_FIRST + 7);
+ /* END CYGNUS LOCAL */
/* The mips16 sometimes needs to save $18. */
else if (TARGET_MIPS16
&& regno != GP_REG_FIRST + 31
&& ! M16_REG_P (regno))
{
if (! store_p)
- reg_rtx = gen_rtx (REG, gpr_mode, 6);
+ /* CYGNUS LOCAL gpr_mode */
+ reg_rtx = gen_rtx (REG, mips_reg_mode[6], 6);
+ /* END CYGNUS LOCAL */
else
{
- reg_rtx = gen_rtx (REG, gpr_mode, 3);
+ /* CYGNUS LOCAL gpr_mode */
+ reg_rtx = gen_rtx (REG, mips_reg_mode[3], 3);
emit_move_insn (reg_rtx,
- gen_rtx (REG, gpr_mode, regno));
+ gen_rtx (REG, mips_reg_mode[regno],
+ regno));
+ /* END CYGNUS LOCAL */
}
}
else
- reg_rtx = gen_rtx (REG, gpr_mode, regno);
+ /* CYGNUS LOCAL gpr_mode */
+ reg_rtx = gen_rtx (REG,
+ mips_reg_mode[regno],
+ regno);
+ /* END CYGNUS LOCAL */
if (store_p)
{
@@ -6514,7 +6978,10 @@
if (TARGET_MIPS16
&& regno != GP_REG_FIRST + 31
&& ! M16_REG_P (regno))
- emit_move_insn (gen_rtx (REG, gpr_mode, regno),
+ /* CYGNUS LOCAL gpr_mode */
+ emit_move_insn (gen_rtx (REG, mips_reg_mode[regno],
+ regno),
+ /* END CYGNUS LOCAL */
reg_rtx);
}
}
@@ -6562,7 +7029,9 @@
}
}
- gp_offset -= GET_MODE_SIZE (gpr_mode);
+ /* CYGNUS LOCAL gpr_mode */
+ gp_offset -= GET_MODE_SIZE (mips_reg_mode[0]);
+ /* END CYGNUS LOCAL */
}
}
else
@@ -6633,7 +7102,7 @@
&& GET_MODE (base_reg_rtx) == SImode)
{
insn = emit_move_insn (base_reg_rtx,
- GEN_INT (fp_offset & 0xffff0000));
+ GEN_INT (fp_offset & 0xffff0000U));
if (store_p)
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_insn (gen_iorsi3 (base_reg_rtx, base_reg_rtx,
@@ -6835,9 +7304,9 @@
dest = SET_DEST (set);
if (GET_CODE (dest) != MEM)
continue;
- if (GET_MODE_SIZE (GET_MODE (dest)) == UNITS_PER_WORD)
+ if (GET_MODE_SIZE (GET_MODE (dest)) == (unsigned) UNITS_PER_WORD)
;
- else if (GET_MODE_SIZE (GET_MODE (dest)) == 2 * UNITS_PER_WORD
+ else if (GET_MODE_SIZE (GET_MODE (dest)) == (unsigned)2 * UNITS_PER_WORD
&& REGNO (src) < GP_REG_FIRST + 7)
;
else
@@ -6847,11 +7316,12 @@
if (GET_CODE (base) != REG
|| GET_CODE (offset) != CONST_INT)
continue;
- if (REGNO (base) == STACK_POINTER_REGNUM
- && INTVAL (offset) == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
+ if (REGNO (base) == (unsigned) STACK_POINTER_REGNUM
+ && (unsigned HOST_WIDE_INT) INTVAL (offset)
+ == tsize + (REGNO (src) - 4) * UNITS_PER_WORD)
;
- else if (REGNO (base) == HARD_FRAME_POINTER_REGNUM
- && (INTVAL (offset)
+ else if (REGNO (base) == (unsigned) HARD_FRAME_POINTER_REGNUM
+ && ((unsigned HOST_WIDE_INT) INTVAL (offset)
== (tsize
+ (REGNO (src) - 4) * UNITS_PER_WORD
- current_function_outgoing_args_size)))
@@ -7045,6 +7515,87 @@
}
}
+ if (TARGET_MIPS5900)
+ {
+ static void mips_arg_pointer_elimination PARAMS ((rtx));
+ int regno;
+ rtx first_insn, insn, sqnc_first_insn, sqnc_last_insn, set;
+ tree attr;
+
+ /* We must end the existing sequence so that we can examine the RTL
+ chain for the entire function. When finished we will start a
+ new sequence for the prologue insns.
+ Make sure we have at least one insn in the sequence, lest
+ set_new_first_and_last_insn will set cur_insn_uid to 1. */
+
+ emit_note (NULL_PTR, NOTE_INSN_DELETED);
+ sqnc_first_insn = get_insns();
+ sqnc_last_insn = get_last_insn();
+ end_sequence();
+ push_topmost_sequence ();
+
+ first_insn = get_insns ();
+
+ pop_topmost_sequence ();
+
+ start_sequence();
+ set_new_first_and_last_insn (sqnc_first_insn, sqnc_last_insn);
+
+ if (current_frame_info.state == fi_blank || current_frame_info.mask)
+ {
+ if (current_function_has_nonlocal_label)
+ {
+ for (regno = GP_REG_LAST; regno >= 0; regno--)
+ mips_reg_mode[regno] = TImode;
+ }
+ else
+ {
+ for (regno = GP_REG_LAST; regno >= 0; regno--)
+ mips_reg_mode[regno] = DImode;
+ for (insn = first_insn; insn != NULL_RTX; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ note_stores (PATTERN (insn), mips_check_reg_mode, NULL);
+ }
+ /* The return address register cannot be variably sized, since
+ DWARF_FRAME_REGNUM is used on it before gen_prologue. The
+ unwinder thinks of it as 64 bit anyways, so just save 64 bit,
+ making the upper half call-clobbered. */
+ mips_reg_mode[GP_REG_FIRST + 31] = DImode;
+ if ((attr = lookup_attribute
+ ("register_precision",
+ DECL_MACHINE_ATTRIBUTES (current_function_decl)))
+ != 0)
+ for (; attr; attr = TREE_CHAIN (attr))
+ {
+ char *reg_expr
+ = IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+ tree reg_length = TREE_VALUE (TREE_CHAIN (TREE_VALUE (attr)));
+ enum machine_mode mode = VOIDmode;
+ int j;
+ switch (TREE_INT_CST_LOW (reg_length))
+ {
+ case 32:
+ mode= SImode;
+ break;
+ case 64:
+ mode= DImode;
+ break;
+ case 128:
+ mode= TImode;
+ break;
+ }
+
+ j = decode_reg_name (reg_expr);
+ if (j > 0)
+ mips_reg_mode[j] = mode;
+ }
+ }
+ current_frame_info.state = fi_modes_known;
+ tsize = compute_frame_size (get_frame_size ());
+
+ mips_arg_pointer_elimination (first_insn);
+ }
+ else
tsize = compute_frame_size (get_frame_size ());
/* If this function is a varargs function, store any registers that
@@ -7066,10 +7617,12 @@
{
if (offset != 0)
ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset));
- emit_move_insn (gen_rtx (MEM, gpr_mode, ptr),
- gen_rtx (REG, gpr_mode, regno));
+ /* CYGNUS LOCAL gpr_mode */
+ emit_move_insn (gen_rtx (MEM, mips_reg_mode[regno], ptr),
+ gen_rtx (REG, mips_reg_mode[regno], regno));
- offset += GET_MODE_SIZE (gpr_mode);
+ offset += GET_MODE_SIZE (mips_reg_mode[0]);
+ /* END CYGNUS LOCAL */
}
}
@@ -7114,7 +7667,10 @@
moment. */
if (TARGET_MIPS16 && BITSET_P (current_frame_info.mask, 18))
{
- rtx reg_rtx = gen_rtx (REG, gpr_mode, GP_REG_FIRST + 3);
+ /* CYGNUS LOCAL gpr_mode */
+ rtx reg_rtx = gen_rtx (REG, mips_reg_mode[GP_REG_FIRST + 3],
+ GP_REG_FIRST + 3);
+ /* END CYGNUS LOCAL */
long gp_offset, base_offset;
gp_offset = current_frame_info.gp_sp_offset;
@@ -7130,12 +7686,15 @@
base_offset = 0;
start_sequence ();
emit_move_insn (reg_rtx,
- gen_rtx (REG, gpr_mode, GP_REG_FIRST + 18));
- emit_move_insn (gen_rtx (MEM, gpr_mode,
+ /* CYGNUS LOCAL gpr_mode */
+ gen_rtx (REG, mips_reg_mode[GP_REG_FIRST + 18],
+ GP_REG_FIRST + 18));
+ emit_move_insn (gen_rtx (MEM, mips_reg_mode[GP_REG_FIRST + 18],
gen_rtx (PLUS, Pmode, stack_pointer_rtx,
GEN_INT (gp_offset
- base_offset))),
reg_rtx);
+ /* END CYGNUS LOCAL */
reg_18_save = gen_sequence ();
end_sequence ();
}
@@ -7175,7 +7734,7 @@
&& GET_MODE (tmp_rtx) == SImode)
{
insn = emit_move_insn (tmp_rtx,
- GEN_INT (tsize & 0xffff0000));
+ GEN_INT (tsize & 0xffff0000U));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_insn (gen_iorsi3 (tmp_rtx, tmp_rtx,
GEN_INT (tsize & 0x0000ffff)));
@@ -7294,7 +7853,7 @@
/* Do any necessary cleanup after a function to restore stack, frame,
and regs. */
-#define RA_MASK ((long) 0x80000000) /* 1 << 31 */
+#define RA_MASK ((unsigned long) 0x80000000U) /* 1 << 31 */
#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
void
@@ -7371,7 +7930,6 @@
num_refs[2] = 0;
mips_load_reg = 0;
mips_load_reg2 = 0;
- current_frame_info = zero_frame_info;
while (string_constants != NULL)
{
@@ -7392,14 +7950,16 @@
/* Expand the epilogue into a bunch of separate insns. */
+/* CYGNUS LOCAL sibcall/law */
void
-mips_expand_epilogue ()
+mips_expand_epilogue (sibcall)
+ int sibcall;
{
HOST_WIDE_INT tsize = current_frame_info.total_size;
rtx tsize_rtx = GEN_INT (tsize);
rtx tmp_rtx = (rtx)0;
- if (mips_can_use_return_insn ())
+ if (!sibcall && mips_can_use_return_insn ())
{
emit_insn (gen_return ());
return;
@@ -7487,13 +8047,14 @@
}
/* The mips16 loads the return address into $7, not $31. */
- if (TARGET_MIPS16 && (current_frame_info.mask & RA_MASK) != 0)
+ if (!sibcall && TARGET_MIPS16 && (current_frame_info.mask & RA_MASK) != 0)
emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode,
GP_REG_FIRST + 7)));
- else
+ else if (!sibcall)
emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode,
GP_REG_FIRST + 31)));
}
+/* END CYGNUS LOCAL */
/* Return nonzero if this function is known to have a null epilogue.
This allows the optimizer to omit jumps to jumps if no stack
@@ -7521,7 +8082,7 @@
<= 4)))
return 0;
- if (current_frame_info.initialized)
+ if (current_frame_info.state == fi_initialized)
return current_frame_info.total_size == 0;
return compute_frame_size (get_frame_size ()) == 0;
@@ -7576,7 +8137,7 @@
/* For hosted applications, always put constants in small data if
possible, as this gives the best performance. */
- if (GET_MODE_SIZE (mode) <= mips_section_threshold
+ if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold
&& mips_section_threshold > 0)
SMALL_DATA_SECTION ();
else if (flag_pic && symbolic_expression_p (x))
@@ -7785,7 +8346,8 @@
to prevent it, or add code to function.c to properly handle the case. */
/* ??? cum can be NULL when called from mips_va_arg. The problem handled
here hopefully is not relevant to mips_va_arg. */
- if (cum && MUST_PASS_IN_STACK (mode, type))
+ if (
+ cum && MUST_PASS_IN_STACK (mode, type))
{
/* Don't pass the actual CUM to FUNCTION_ARG, because we would
get double copies of any offsets generated for small structs
@@ -7796,7 +8358,6 @@
return 1;
}
-
/* Otherwise, we only do this if EABI is selected. */
if (mips_abi != ABI_EABI)
return 0;
@@ -7805,6 +8366,16 @@
if (type == NULL_TREE || mode == DImode || mode == DFmode)
return 0;
+ /* The r5900 can pass TImode values in a single register, so
+ there is no need to pass it by reference. */
+ if (mode == TImode && (TARGET_MIPS5900
+ ))
+ return 0;
+
+ /* SIMD vector modes can be passed in a single register, so
+ there is no need to pass it by reference. */
+ if (SIMD_MODE_SUPPORTED_P (mode))
+ return 0;
size = int_size_in_bytes (type);
return size == -1 || size > UNITS_PER_WORD;
}
@@ -7862,11 +8433,21 @@
&& gp_reg_p
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
? NO_REGS : gr_regs);
+ else if (class == HILO1_REG && regno != GP_REG_FIRST + 0)
+ return ((! in_p
+ && gp_reg_p
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
+ ? NO_REGS : gr_regs);
else if (regno == HILO_REGNUM)
return ((in_p
&& class == gr_regs
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
? NO_REGS : gr_regs);
+ else if (regno == HILO1_REGNUM)
+ return ((in_p
+ && class == gr_regs
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
+ ? NO_REGS : gr_regs);
/* Copying from HI or LO to anywhere other than a general register
requires a general register. */
@@ -7879,6 +8460,15 @@
}
return gp_reg_p ? NO_REGS : gr_regs;
}
+ else if (class == HI1_REG || class == LO1_REG || class == MD1_REGS)
+ {
+ if (TARGET_MIPS16 && in_p)
+ {
+ /* We can't really copy to HI or LO at all in mips16 mode. */
+ return M16_REGS;
+ }
+ return gp_reg_p ? NO_REGS : gr_regs;
+ }
if (MD_REG_P (regno))
{
if (TARGET_MIPS16 && ! in_p)
@@ -7888,6 +8478,15 @@
}
return class == gr_regs ? NO_REGS : gr_regs;
}
+ else if (MD1_REG_P (regno))
+ {
+ if (TARGET_MIPS16 && ! in_p)
+ {
+ /* We can't really copy to HI or LO at all in mips16 mode. */
+ return M16_REGS;
+ }
+ return class == gr_regs ? NO_REGS : gr_regs;
+ }
/* We can only copy a value to a condition code register from a
floating point register, and even then we require a scratch
@@ -8141,7 +8740,10 @@
knows how to handle this. We can always accept a string
constant, which is the other case in which SYMBOL_REF_FLAG
will be set. */
- if (! addr && ! addend && SYMBOL_REF_FLAG (x) && mode == Pmode)
+ if (! addr
+ && ! addend
+ && SYMBOL_REF_FLAG (x)
+ && mode == (enum machine_mode) Pmode)
return 1;
/* We can accept a string constant, which will have
@@ -8695,7 +9297,7 @@
{
rtx set;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (! INSN_P (insn))
continue;
set = PATTERN (insn);
@@ -8712,14 +9314,14 @@
&& GET_CODE (XEXP (SET_SRC (set), 0)) == REG
&& REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28
&& GET_CODE (SET_DEST (set)) == REG
- && GET_MODE (SET_DEST (set)) == Pmode)
+ && GET_MODE (SET_DEST (set)) == (unsigned) Pmode)
gpcopy = SET_DEST (set);
else if (slot == NULL_RTX
&& gpcopy != NULL_RTX
&& GET_CODE (SET_DEST (set)) == MEM
&& GET_CODE (SET_SRC (set)) == REG
&& REGNO (SET_SRC (set)) == REGNO (gpcopy)
- && GET_MODE (SET_DEST (set)) == Pmode)
+ && GET_MODE (SET_DEST (set)) == (unsigned) Pmode)
{
rtx base, offset;
@@ -8736,7 +9338,7 @@
&& reg_overlap_mentioned_p (SET_DEST (set), gpcopy)
&& (GET_CODE (SET_DEST (set)) != REG
|| REGNO (SET_DEST (set)) != REGNO (gpcopy)
- || GET_MODE (SET_DEST (set)) != Pmode
+ || GET_MODE (SET_DEST (set)) != (unsigned) Pmode
|| ((GET_CODE (SET_SRC (set)) != CONST
|| GET_CODE (XEXP (SET_SRC (set), 0)) != REG
|| (REGNO (XEXP (SET_SRC (set), 0))
@@ -8794,10 +9396,10 @@
if (next == NULL_RTX)
break;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (! INSN_P (insn))
continue;
- if (GET_RTX_CLASS (GET_CODE (next)) != 'i')
+ if (! INSN_P (next))
continue;
set1 = PATTERN (insn);
@@ -8850,12 +9452,12 @@
{
rtx set;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (! INSN_P (insn))
continue;
set = PATTERN (insn);
if (GET_CODE (set) != SET
- || GET_MODE (SET_DEST (set)) != Pmode)
+ || GET_MODE (SET_DEST (set)) != (unsigned) Pmode)
continue;
if (GET_CODE (SET_DEST (set)) == MEM
@@ -9019,6 +9621,108 @@
return NULL_RTX;
}
+
+/* On the R5900, we must ensure that the compiler never generates loops
+ that satisfy all of the following conditions:
+
+ * a loop consists of less than equal to six instructions(includes
+ branch delay slot).
+
+ * a loop contains only one conditional branch instruction at the
+ end of the loop.
+
+ * a loop does not contain any other branch or jump instructions.
+
+ We need to do this because of a bug in the chip. */
+
+static void
+mips_r5900_lengthen_loops (first)
+ rtx first;
+{
+ rtx insn;
+ int n = 1;
+ int max_uid = get_max_uid ();
+ int *seen_before = alloca (sizeof seen_before[0] * max_uid);
+
+ bzero ((char *) seen_before, sizeof seen_before[0] * max_uid);
+
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ switch (GET_CODE (insn))
+ {
+ case CODE_LABEL:
+ seen_before [INSN_UID (insn)] = n;
+ break;
+
+ case INSN:
+ if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ rtx x = XVECEXP (PATTERN (insn), 0, 0);
+ if (condjump_p (x))
+ {
+ rtx target = condjump_label (x);
+
+ if (seen_before [INSN_UID (XEXP (target, 0))])
+ {
+ int distance
+ = n - seen_before [INSN_UID (XEXP (target, 0))] + 2;
+ for (; distance <= 6; distance++)
+ emit_insn_before (gen_nop (), insn);
+ }
+ }
+ else if (GET_CODE (x) == CALL_INSN)
+ bzero ((char *) seen_before, sizeof seen_before[0] * max_uid);
+ else
+ n += XVECLEN (PATTERN (insn), 0);
+ }
+ else
+ n++;
+ break;
+
+ case JUMP_INSN:
+ if (condjump_p (insn))
+ {
+ rtx target = condjump_label (insn);
+
+ if (seen_before [INSN_UID (XEXP (target, 0))])
+ {
+ int distance
+ = n - seen_before [INSN_UID (XEXP (target, 0))];
+
+ for (; distance <= 6; distance++)
+ {
+ emit_insn_before (gen_nop (), insn);
+ }
+ }
+ }
+
+ /* Falls through. */
+
+ case CALL_INSN:
+ bzero ((char *) seen_before, sizeof seen_before[0] * max_uid);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Exported to toplev.c.
+
+ Do a final pass over the function, just after delayed branch
+ scheduling. */
+
+void
+machine_dependent_reorg2 (first)
+ rtx first;
+{
+ /* Currently, this is only used to modify certain loops in order
+ to workaround problems in the defective 5900 component. */
+ if (TARGET_MIPS5900)
+ mips_r5900_lengthen_loops (first);
+}
+
/* Exported to toplev.c.
Do a final pass over the function, just before delayed branch
@@ -9250,6 +9954,351 @@
|| code == ROTATE);
}
+/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
+ attribute for DECL. The attributes in ATTRIBUTES have previously been
+ assigned to DECL. */
+int
+mips_valid_decl_attribute_p (decl, attributes, identifier, args)
+ tree decl;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree identifier;
+ tree args;
+{
+ /* The register_precision attribute is only useful on the r5900
+ for functions and methods. It specifies what mode to save
+ registers on the stack with. */
+ if (TARGET_MIPS5900
+ && (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ && is_attribute_p ("register_precision", identifier)
+ && args
+ && TREE_CODE (args) == TREE_LIST)
+ {
+ int j;
+ char *reg_expr = IDENTIFIER_POINTER (TREE_VALUE (args));
+ tree reg_length = TREE_VALUE (TREE_CHAIN (args));
+ enum machine_mode mode = VOIDmode;
+ tree attr = DECL_MACHINE_ATTRIBUTES (decl);
+
+ /* TREE_CHAIN (TREE_VALUE (args)) = TREE_CHAIN (args);*/
+ /* TREE_CHAIN (args) = 0;*/
+ if (attr)
+ chainon (attr, build_tree_list (NULL_TREE, args));
+
+ switch (TREE_INT_CST_LOW (reg_length))
+ {
+ case 32:
+ mode= SImode;
+ break;
+ case 64:
+ mode= DImode;
+ break;
+ case 128:
+ mode= TImode;
+ break;
+ default:
+ error ("Register precision must be 32, 64, or 128, not `%d'",
+ TREE_INT_CST_LOW (reg_length));
+ }
+
+ if ((j = decode_reg_name (reg_expr)) == 0)
+ warning ("unknown register name: %s", reg_expr);
+
+ return 1;
+ }
+ return 0;
+}
+
+/* Reorder the ready list as needed to improve performance. */
+
+void
+mips_sched_reorder (stream, verbose, ready, n_ready)
+ FILE *stream ATTRIBUTE_UNUSED;
+ int verbose ATTRIBUTE_UNUSED;
+ rtx *ready;
+ int n_ready;
+{
+ static int imuldivunit = -1;
+ int i;
+
+ /* Right now this is only used to improve a couple scheduling problems
+ for the r5900. There is also no point in trying these tweaks after
+ reload has completed. */
+ if (!(TARGET_MIPS5900
+ ) || reload_completed)
+ return;
+
+ /* If there are less than three insns on the queue, then there's nothing
+ to do. */
+ if (n_ready < 3)
+ return;
+
+ /* We need to know what value will be returned by function_units_used for
+ the r5900's multiply/divide units. If we have not computed it yet,
+ do so now. */
+ if (imuldivunit == -1)
+ {
+ for (i = 0; i < FUNCTION_UNITS_SIZE; i++)
+ {
+ if (!strcmp ("r5900imuldiv", function_units[i].name))
+ {
+ imuldivunit = i;
+ break;
+ }
+ }
+
+ if (imuldivunit == -1)
+ return;
+ }
+
+ /* Loop through the instructions and try to pair up two instructions
+ which use the imuldiv pipelines.
+
+ We want such instructions to appear back to back in the RTL chain
+ so that the register allocator will allocate a different HILO
+ register for the two imuldiv instructions.
+
+ Note the ready list is ordered backwards.
+
+ If we do not find an idivmul insn which could issue this cycle, quit
+ to save time. */
+ for (i = n_ready - 1; i >= n_ready - 2; i--)
+ {
+ rtx insn = ready[i];
+ enum rtx_code code;
+
+ /* Ignore anything we do not understand. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+ || (code = GET_CODE (PATTERN (insn))) == USE
+ || code == CLOBBER || code == ADDR_VEC)
+ continue;
+
+ /* We are looking for instructions that issue to the imuldiv
+ pipelines. */
+ if (function_units_used (insn) == imuldivunit)
+ {
+ int j;
+
+ /* We have found one insn that uses the imuldiv pipeline, so
+ now look for another imuldiv instruction. */
+ for (j = i - 1; j >= 0; j--)
+ {
+ rtx temp = ready[j];
+
+ /* Ignore anything we do not understand. */
+ if (GET_RTX_CLASS (GET_CODE (temp)) != 'i'
+ || (code = GET_CODE (PATTERN (temp))) == USE
+ || code == CLOBBER || code == ADDR_VEC)
+ continue;
+
+ /* Again, we are looking for an imuldiv insn. */
+ if (function_units_used (temp) == imuldivunit)
+ {
+ /* Make the idivmul insns consecutive if they were
+ not already consecutive. */
+ if (i - j != 1)
+ {
+ rtx temp = ready[j];
+
+ bcopy (&ready[j+1], &ready[j],
+ (i - j - 1) * sizeof (rtx *));
+ ready[i - 1] = temp;
+ }
+
+ /* Now the imuldiv insns are consecutive. We can
+ still lose if they issue at different clocks, so
+ move them as a pair to the head of ready list.
+
+ Note I must either be the head of the queue or
+ the second insn in the queue. */
+ if (i != n_ready - 1)
+ {
+ rtx temp1, temp2;
+
+ /* Rotate the first three elements in the
+ ready queue. */
+ temp1 = ready[n_ready - 1];
+ temp2 = ready[n_ready - 2];
+ ready[n_ready - 2] = ready[n_ready - 3];
+ ready[n_ready - 3] = temp1;
+ ready[n_ready - 1] = temp2;
+ }
+ return;
+ }
+ }
+ }
+ }
+}
+
+/* Return nonzero if INSN, which is a valid madd pattern is profitable
+ to implement as a madd instruction.
+
+ The r5900 has dual integer multiply pipelines which allows independent
+ integer multiplies to run in parallel with each other.
+
+ Thus it is not profitable to generate an madd if doing so creates a data
+ dependency which prevents running two multiplies in parallel.
+
+ We have access to any feeding insn via LOG_LINKS. If it is a multiply or
+ multiply-add insn which feeds the register operand of the PLUS, then it
+ is not profitable to generate an madd instruction.
+
+ It is also probably not profitable if the second operand of this PLUS
+ is fed by any insns since we will have to generate a mtlo. So we reject
+ all cases where an earlier insn feeds into the second operand of the
+ PLUS in the candidate madd insn. */
+
+int
+r5900_madd_profitable_p (insn)
+ rtx insn;
+{
+ rtx temp, madd_reg, link;
+
+ temp = PATTERN (insn);
+
+ /* Verify we have an madd pattern and that the second operand to the
+ PLUS is a register. */
+ if (GET_CODE (temp) == PARALLEL)
+ temp = XVECEXP (temp, 0, 0);
+
+ if (GET_CODE (temp) != SET
+ || GET_CODE (SET_SRC (temp)) != PLUS
+ || GET_CODE (XEXP (SET_SRC (temp), 0)) != MULT
+ || ! REG_P (XEXP (SET_SRC (temp), 1)))
+ return 0;
+
+ madd_reg = XEXP (SET_SRC (temp), 1);
+
+ /* Now examine the insn which feed INSN. */
+ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+ {
+ rtx dep_insn = XEXP (link, 0);
+
+ if (reg_set_p (madd_reg, dep_insn))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Expand RTL for a call which does not return a a value. If SIBCALL is
+ nonzero, then this is a sibling call, else it is a normal call. */
+
+void
+mips_expand_call (operands, sibcall)
+ rtx *operands;
+ int sibcall;
+{
+ rtx addr;
+
+ addr = XEXP (operands[0], 0);
+ if ((GET_CODE (addr) != REG
+ && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
+ || ! call_insn_operand (addr, VOIDmode))
+ XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
+
+ /* In order to pass small structures by value in registers
+ compatibly with the MIPS compiler, we need to shift the value
+ into the high part of the register. Function_arg has encoded
+ a PARALLEL rtx, holding a vector of adjustments to be made
+ as the next_arg_reg variable, so we split up the insns,
+ and emit them separately. */
+ if (operands[2] != NULL_RTX && GET_CODE (operands[2]) == PARALLEL)
+ {
+ rtvec adjust = XVEC (operands[2], 0);
+ int num = GET_NUM_ELEM (adjust);
+ int i;
+
+ for (i = 0; i < num; i++)
+ emit_insn (RTVEC_ELT (adjust, i));
+ }
+
+ if (TARGET_MIPS16
+ && mips16_hard_float
+ && operands[2] != 0
+ && (int) GET_MODE (operands[2]) != 0)
+ {
+ if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1],
+ (int) GET_MODE (operands[2])))
+ return;
+ }
+
+ if (sibcall)
+ emit_call_insn (gen_sibcall_internal0 (operands[0], operands[1]));
+ else
+ emit_call_insn (gen_call_internal0 (operands[0], operands[1],
+ gen_rtx (REG, SImode,
+ GP_REG_FIRST + 31)));
+}
+
+/* Expand RTL for a call which returns a value. If SIBCALL is nonzero,
+ then this is a sibling call, else it is a normal call. */
+void
+mips_expand_call_value (operands, sibcall)
+ rtx *operands;
+ int sibcall;
+{
+ rtx addr = XEXP (operands[1], 0);
+
+ if ((GET_CODE (addr) != REG
+ && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
+ || ! call_insn_operand (addr, VOIDmode))
+ XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
+
+ /* In order to pass small structures by value in registers
+ compatibly with the MIPS compiler, we need to shift the value
+ into the high part of the register. Function_arg has encoded
+ a PARALLEL rtx, holding a vector of adjustments to be made
+ as the next_arg_reg variable, so we split up the insns,
+ and emit them separately. */
+ if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL)
+ {
+ rtvec adjust = XVEC (operands[3], 0);
+ int num = GET_NUM_ELEM (adjust);
+ int i;
+
+ for (i = 0; i < num; i++)
+ emit_insn (RTVEC_ELT (adjust, i));
+ }
+
+ if (TARGET_MIPS16
+ && mips16_hard_float
+ && ((operands[3] != 0
+ && (int) GET_MODE (operands[3]) != 0)
+ || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT))
+ {
+ if (build_mips16_call_stub (operands[0], operands[1], operands[2],
+ (operands[3] == 0 ? 0
+ : (int) GET_MODE (operands[3]))))
+ return;
+ }
+
+ /* Handle Irix6 function calls that have multiple non-contiguous
+ results. */
+ if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1)
+ {
+ emit_call_insn (gen_call_value_multiple_internal0
+ (XEXP (XVECEXP (operands[0], 0, 0), 0),
+ operands[1], operands[2],
+ XEXP (XVECEXP (operands[0], 0, 1), 0),
+ gen_rtx (REG, SImode, GP_REG_FIRST + 31)));
+ return;
+ }
+
+ /* We have a call returning a DImode structure in an FP reg.
+ Strip off the now unnecessary PARALLEL. */
+ if (GET_CODE (operands[0]) == PARALLEL)
+ operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
+
+ if (sibcall)
+ emit_call_insn (gen_sibcall_value_internal0 (operands[0], operands[1],
+ operands[2]));
+ else
+ emit_call_insn (gen_call_value_internal0 (operands[0], operands[1],
+ operands[2],
+ gen_rtx (REG, SImode,
+ GP_REG_FIRST + 31)));
+}
/* Return the length of INSN. LENGTH is the initial length computed by
attributes in the machine-description file. */
@@ -9318,6 +10367,9 @@
const char *comp = (float_p ? "%F0" : "%C0");
/* The operand-printing string for the inverted comparison. */
const char *inverted_comp = (float_p ? "%W0" : "%N0");
+ /* GAS warns about branches that are always false so avoid
+ producing them. */
+ int always_false = 0;
/* The MIPS processors (for levels of the ISA at least two), have
"likely" variants of each branch instruction. These instructions
@@ -9351,6 +10403,7 @@
case LTU:
/* A condition which will always be false. */
+ always_false = 1;
code = NE;
op1 = "%.";
break;
@@ -9379,6 +10432,9 @@
case 4:
case 8:
/* Just a simple conditional branch. */
+ if (always_false) /* nop */
+ sprintf (buffer, "nop\t\t# branch always false");
+ else
if (float_p)
sprintf (buffer, "%%*b%s%%?\t%%Z2%%1",
inverted_p ? inverted_comp : comp);
@@ -9558,3 +10614,945 @@
ggc_add_rtx_root (&embedded_pic_fnaddr_rtx, 1);
ggc_add_rtx_root (&mips16_gp_pseudo_rtx, 1);
}
+
+#define def_builtin(NAME, TYPE, CODE) \
+ builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL_PTR)
+
+/* Table describing builtin functions which are unary operations. */
+static struct builtin_description bdesc_1arg[] =
+{
+ { CODE_FOR_mips5900_pabsh, "__builtin_mips5900_pabsh",
+ MIPS5900_BUILTIN_PABSH
+ },
+ { CODE_FOR_mips5900_pabsw, "__builtin_mips5900_pabsw",
+ MIPS5900_BUILTIN_PABSW
+ },
+ { CODE_FOR_mips5900_pcpyh, "__builtin_mips5900_pcpyh",
+ MIPS5900_BUILTIN_PCPYH
+ },
+ { CODE_FOR_mips5900_pexch, "__builtin_mips5900_pexch",
+ MIPS5900_BUILTIN_PEXCH
+ },
+ { CODE_FOR_mips5900_pexcw, "__builtin_mips5900_pexcw",
+ MIPS5900_BUILTIN_PEXCW
+ },
+ { CODE_FOR_mips5900_pexeh, "__builtin_mips5900_pexeh",
+ MIPS5900_BUILTIN_PEXEH
+ },
+ { CODE_FOR_mips5900_pexew, "__builtin_mips5900_pexew",
+ MIPS5900_BUILTIN_PEXEW
+ },
+ { CODE_FOR_mips5900_pext5, "__builtin_mips5900_pext5",
+ MIPS5900_BUILTIN_PEXT5
+ },
+ { CODE_FOR_mips5900_plzcw, "__builtin_mips5900_plzcw",
+ MIPS5900_BUILTIN_PLZCW
+ },
+ { CODE_FOR_mips5900_ppac5, "__builtin_mips5900_ppac5",
+ MIPS5900_BUILTIN_PPAC5
+ },
+ { CODE_FOR_mips5900_prevh, "__builtin_mips5900_prevh",
+ MIPS5900_BUILTIN_PREVH
+ },
+ { CODE_FOR_mips5900_prot3w, "__builtin_mips5900_prot3w",
+ MIPS5900_BUILTIN_PROT3W
+ }
+};
+
+/* Table describing builtin functions which are binary operations. */
+static struct builtin_description bdesc_2arg[] =
+{
+ { CODE_FOR_mips5900_paddb, "__builtin_mips5900_paddb",
+ MIPS5900_BUILTIN_PADDB
+ },
+ { CODE_FOR_mips5900_paddh, "__builtin_mips5900_paddh",
+ MIPS5900_BUILTIN_PADDH
+ },
+ { CODE_FOR_mips5900_paddsb, "__builtin_mips5900_paddsb",
+ MIPS5900_BUILTIN_PADDSB
+ },
+ { CODE_FOR_mips5900_paddsh, "__builtin_mips5900_paddsh",
+ MIPS5900_BUILTIN_PADDSH
+ },
+ { CODE_FOR_mips5900_paddsw, "__builtin_mips5900_paddsw",
+ MIPS5900_BUILTIN_PADDSW
+ },
+ { CODE_FOR_mips5900_paddub, "__builtin_mips5900_paddub",
+ MIPS5900_BUILTIN_PADDUB
+ },
+ { CODE_FOR_mips5900_padduh, "__builtin_mips5900_padduh",
+ MIPS5900_BUILTIN_PADDUH
+ },
+ { CODE_FOR_mips5900_padduw, "__builtin_mips5900_padduw",
+ MIPS5900_BUILTIN_PADDUW
+ },
+ { CODE_FOR_mips5900_paddw, "__builtin_mips5900_paddw",
+ MIPS5900_BUILTIN_PADDW
+ },
+ { CODE_FOR_mips5900_padsbh, "__builtin_mips5900_padsbh",
+ MIPS5900_BUILTIN_PADSBH
+ },
+ { CODE_FOR_mips5900_pand, "__builtin_mips5900_pand",
+ MIPS5900_BUILTIN_PAND
+ },
+ { CODE_FOR_mips5900_pceqb, "__builtin_mips5900_pceqb",
+ MIPS5900_BUILTIN_PCEQB
+ },
+ { CODE_FOR_mips5900_pceqh, "__builtin_mips5900_pceqh",
+ MIPS5900_BUILTIN_PCEQH
+ },
+ { CODE_FOR_mips5900_pceqw, "__builtin_mips5900_pceqw",
+ MIPS5900_BUILTIN_PCEQW
+ },
+ { CODE_FOR_mips5900_pcgtb, "__builtin_mips5900_pcgtb",
+ MIPS5900_BUILTIN_PCGTB
+ },
+ { CODE_FOR_mips5900_pcgth, "__builtin_mips5900_pcgth",
+ MIPS5900_BUILTIN_PCGTH
+ },
+ { CODE_FOR_mips5900_pcgtw, "__builtin_mips5900_pcgtw",
+ MIPS5900_BUILTIN_PCGTW
+ },
+ { CODE_FOR_mips5900_pcpyld, "__builtin_mips5900_pcpyld",
+ MIPS5900_BUILTIN_PCPYLD
+ },
+ { CODE_FOR_mips5900_pcpyud, "__builtin_mips5900_pcpyud",
+ MIPS5900_BUILTIN_PCPYUD
+ },
+ { CODE_FOR_mips5900_pextlb, "__builtin_mips5900_pextlb",
+ MIPS5900_BUILTIN_PEXTLB
+ },
+ { CODE_FOR_mips5900_pextlh, "__builtin_mips5900_pextlh",
+ MIPS5900_BUILTIN_PEXTLH
+ },
+ { CODE_FOR_mips5900_pextlw, "__builtin_mips5900_pextlw",
+ MIPS5900_BUILTIN_PEXTLW
+ },
+ { CODE_FOR_mips5900_pextub, "__builtin_mips5900_pextub",
+ MIPS5900_BUILTIN_PEXTUB
+ },
+ { CODE_FOR_mips5900_pextuh, "__builtin_mips5900_pextuh",
+ MIPS5900_BUILTIN_PEXTUH
+ },
+ { CODE_FOR_mips5900_pextuw, "__builtin_mips5900_pextuw",
+ MIPS5900_BUILTIN_PEXTUW
+ },
+ { CODE_FOR_mips5900_pinth, "__builtin_mips5900_pinth",
+ MIPS5900_BUILTIN_PINTH
+ },
+ { CODE_FOR_mips5900_pinteh, "__builtin_mips5900_pinteh",
+ MIPS5900_BUILTIN_PINTEH
+ },
+ { CODE_FOR_mips5900_pmaxh, "__builtin_mips5900_pmaxh",
+ MIPS5900_BUILTIN_PMAXH
+ },
+ { CODE_FOR_mips5900_pmaxw, "__builtin_mips5900_pmaxw",
+ MIPS5900_BUILTIN_PMAXW
+ },
+ { CODE_FOR_mips5900_pminh, "__builtin_mips5900_pminh",
+ MIPS5900_BUILTIN_PMINH
+ },
+ { CODE_FOR_mips5900_pminw, "__builtin_mips5900_pminw",
+ MIPS5900_BUILTIN_PMINW
+ },
+ { CODE_FOR_mips5900_pnor, "__builtin_mips5900_pnor",
+ MIPS5900_BUILTIN_PNOR
+ },
+ { CODE_FOR_mips5900_por, "__builtin_mips5900_por",
+ MIPS5900_BUILTIN_POR
+ },
+ { CODE_FOR_mips5900_ppacb, "__builtin_mips5900_ppacb",
+ MIPS5900_BUILTIN_PPACB
+ },
+ { CODE_FOR_mips5900_ppach, "__builtin_mips5900_ppach",
+ MIPS5900_BUILTIN_PPACH
+ },
+ { CODE_FOR_mips5900_ppacw, "__builtin_mips5900_ppacw",
+ MIPS5900_BUILTIN_PPACW
+ },
+ { CODE_FOR_mips5900_psllvw, "__builtin_mips5900_psllvw",
+ MIPS5900_BUILTIN_PSLLVW
+ },
+ { CODE_FOR_mips5900_psravw, "__builtin_mips5900_psravw",
+ MIPS5900_BUILTIN_PSRAVW
+ },
+ { CODE_FOR_mips5900_psrlvw, "__builtin_mips5900_psrlvw",
+ MIPS5900_BUILTIN_PSRLVW
+ },
+ { CODE_FOR_mips5900_psubb, "__builtin_mips5900_psubb",
+ MIPS5900_BUILTIN_PSUBB
+ },
+ { CODE_FOR_mips5900_psubh, "__builtin_mips5900_psubh",
+ MIPS5900_BUILTIN_PSUBH
+ },
+ { CODE_FOR_mips5900_psubsb, "__builtin_mips5900_psubsb",
+ MIPS5900_BUILTIN_PSUBSB
+ },
+ { CODE_FOR_mips5900_psubsh, "__builtin_mips5900_psubsh",
+ MIPS5900_BUILTIN_PSUBSH
+ },
+ { CODE_FOR_mips5900_psubsw, "__builtin_mips5900_psubsw",
+ MIPS5900_BUILTIN_PSUBSW
+ },
+ { CODE_FOR_mips5900_psubub, "__builtin_mips5900_psubub",
+ MIPS5900_BUILTIN_PSUBUB
+ },
+ { CODE_FOR_mips5900_psubuh, "__builtin_mips5900_psubuh",
+ MIPS5900_BUILTIN_PSUBUH
+ },
+ { CODE_FOR_mips5900_psubuw, "__builtin_mips5900_psubuw",
+ MIPS5900_BUILTIN_PSUBUW
+ },
+ { CODE_FOR_mips5900_psubw, "__builtin_mips5900_psubw",
+ MIPS5900_BUILTIN_PSUBW
+ },
+ { CODE_FOR_mips5900_pxor, "__builtin_mips5900_pxor",
+ MIPS5900_BUILTIN_PXOR
+ },
+ { CODE_FOR_mips5900_qfsrv, "__builtin_mips5900_qfsrv",
+ MIPS5900_BUILTIN_QFSRV
+ },
+ { CODE_FOR_mips5900_pdivbw, "__builtin_mips5900_pdivbw",
+ MIPS5900_BUILTIN_PDIVBW
+ },
+ { CODE_FOR_mips5900_pdivuw, "__builtin_mips5900_pdivuw",
+ MIPS5900_BUILTIN_PDIVUW
+ },
+ { CODE_FOR_mips5900_pdivw, "__builtin_mips5900_pdivw",
+ MIPS5900_BUILTIN_PDIVW
+ },
+ { CODE_FOR_mips5900_phmadh, "__builtin_mips5900_phmadh",
+ MIPS5900_BUILTIN_PHMADH
+ },
+ { CODE_FOR_mips5900_phmsbh, "__builtin_mips5900_phmsbh",
+ MIPS5900_BUILTIN_PHMSBH
+ },
+ { CODE_FOR_mips5900_pmaddh, "__builtin_mips5900_pmaddh",
+ MIPS5900_BUILTIN_PMADDH
+ },
+ { CODE_FOR_mips5900_pmadduw, "__builtin_mips5900_pmadduw",
+ MIPS5900_BUILTIN_PMADDUW
+ },
+ { CODE_FOR_mips5900_pmaddw, "__builtin_mips5900_pmaddw",
+ MIPS5900_BUILTIN_PMADDW
+ },
+ { CODE_FOR_mips5900_pmsubh, "__builtin_mips5900_pmsubh",
+ MIPS5900_BUILTIN_PMSUBH
+ },
+ { CODE_FOR_mips5900_pmsubw, "__builtin_mips5900_pmsubw",
+ MIPS5900_BUILTIN_PMSUBW
+ },
+ { CODE_FOR_mips5900_pmulth, "__builtin_mips5900_pmulth",
+ MIPS5900_BUILTIN_PMULTH
+ },
+ { CODE_FOR_mips5900_pmultuw, "__builtin_mips5900_pmultuw",
+ MIPS5900_BUILTIN_PMULTUW
+ },
+ { CODE_FOR_mips5900_pmultw, "__builtin_mips5900_pmultw",
+ MIPS5900_BUILTIN_PMULTW
+ },
+};
+
+/* Table describing builtin functions which are shift-by-constant operations. */
+static struct builtin_description bdesc_shiftc[] =
+{
+ { CODE_FOR_mips5900_psllh, "__builtin_mips5900_psllh",
+ MIPS5900_BUILTIN_PSLLH
+ },
+ { CODE_FOR_mips5900_psllw, "__builtin_mips5900_psllw",
+ MIPS5900_BUILTIN_PSLLW
+ },
+ { CODE_FOR_mips5900_psrah, "__builtin_mips5900_psrah",
+ MIPS5900_BUILTIN_PSRAH
+ },
+ { CODE_FOR_mips5900_psraw, "__builtin_mips5900_psraw",
+ MIPS5900_BUILTIN_PSRAW
+ },
+ { CODE_FOR_mips5900_psrlh, "__builtin_mips5900_psrlh",
+ MIPS5900_BUILTIN_PSRLH
+ },
+ { CODE_FOR_mips5900_psrlw, "__builtin_mips5900_psrlw",
+ MIPS5900_BUILTIN_PSRLW
+ }
+};
+
+/* Table describing builtin functions which are move-to-sa-size operations. */
+static struct builtin_description bdesc_mtsax[] =
+{
+ { CODE_FOR_mips5900_mtsab, "__builtin_mips5900_mtsab",
+ MIPS5900_BUILTIN_MTSAB
+ },
+ { CODE_FOR_mips5900_mtsah, "__builtin_mips5900_mtsah",
+ MIPS5900_BUILTIN_MTSAH
+ }
+};
+
+/* Table describing builtin functions which are move-to-special-purpose-register
+ operations. */
+static struct builtin_description bdesc_mfspr[] =
+{
+ { CODE_FOR_mips5900_mfsa, "__builtin_mips5900_mfsa",
+ MIPS5900_BUILTIN_MFSA
+ },
+ { CODE_FOR_mips5900_pmfhi, "__builtin_mips5900_pmfhi",
+ MIPS5900_BUILTIN_PMFHI
+ },
+ { CODE_FOR_mips5900_pmflo, "__builtin_mips5900_pmflo",
+ MIPS5900_BUILTIN_PMFLO
+ },
+ { CODE_FOR_mips5900_pmfhl_lw, "__builtin_mips5900_pmfhl_lw",
+ MIPS5900_BUILTIN_PMFHL_LW
+ },
+ { CODE_FOR_mips5900_pmfhl_uw, "__builtin_mips5900_pmfhl_uw",
+ MIPS5900_BUILTIN_PMFHL_UW
+ },
+ { CODE_FOR_mips5900_pmfhl_slw, "__builtin_mips5900_pmfhl_slw",
+ MIPS5900_BUILTIN_PMFHL_SLW
+ },
+ { CODE_FOR_mips5900_pmfhl_lh, "__builtin_mips5900_pmfhl_lh",
+ MIPS5900_BUILTIN_PMFHL_LH
+ },
+ { CODE_FOR_mips5900_pmfhl_sh, "__builtin_mips5900_pmfhl_sh",
+ MIPS5900_BUILTIN_PMFHL_SH
+ }
+};
+
+/* Table describing builtin functions which are
+ move-from-special-purpose-register operations. */
+static struct builtin_description bdesc_mtspr[] =
+{
+ { CODE_FOR_mips5900_mtsa, "__builtin_mips5900_mtsa",
+ MIPS5900_BUILTIN_MTSA
+ },
+ { CODE_FOR_mips5900_pmthi, "__builtin_mips5900_pmthi",
+ MIPS5900_BUILTIN_PMTHI
+ },
+ { CODE_FOR_mips5900_pmtlo, "__builtin_mips5900_pmtlo",
+ MIPS5900_BUILTIN_PMTLO
+ },
+ { CODE_FOR_mips5900_pmthl_lw, "__builtin_mips5900_pmthl_lw",
+ MIPS5900_BUILTIN_PMTHL_LW
+ }
+};
+
+void
+mips_init_builtins ()
+{
+ tree endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
+ struct builtin_description *d;
+ unsigned int i;
+
+ /* Type nodes for unary builtin functions. */
+ tree v8hi_ftype_v8hi
+ = build_function_type (V8HI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ endlink));
+
+ tree v8hi_ftype_v4si
+ = build_function_type (V8HI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ endlink));
+
+ tree v4si_ftype_v4si
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ endlink));
+
+ tree v4si_ftype_v8hi
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ endlink));
+
+ tree v2si_ftype_v2si
+ = build_function_type (V2SI_type_node,
+ tree_cons (NULL_TREE, V2SI_type_node,
+ endlink));
+
+ /* Type nodes for binary builtin functions. */
+ tree v16qi_ftype_v16qi_v16qi
+ = build_function_type (V16QI_type_node,
+ tree_cons (NULL_TREE, V16QI_type_node,
+ tree_cons (NULL_TREE, V16QI_type_node,
+ endlink)));
+ tree v8hi_ftype_v8hi_v8hi
+ = build_function_type (V8HI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ endlink)));
+ tree v4si_ftype_v8hi_v8hi
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ endlink)));
+ tree v4si_ftype_v4si_v4si
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ endlink)));
+ tree v2di_ftype_v4si_v4si
+ = build_function_type (V2DI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ endlink)));
+ tree v2di_ftype_v2di_v2di
+ = build_function_type (V2DI_type_node,
+ tree_cons (NULL_TREE, V2DI_type_node,
+ tree_cons (NULL_TREE, V2DI_type_node,
+ endlink)));
+ tree void_ftype_v4si_v8hi
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ endlink)));
+ /* Type nodes for shift-by-constant functions. */
+ tree v8hi_ftype_v8hi_int
+ = build_function_type (V8HI_type_node,
+ tree_cons (NULL_TREE, V8HI_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+ tree v4si_ftype_v4si_int
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+ /* Type nodes used by the funnel shift builtins. */
+ tree void_ftype_int_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+ tree void_ftype_di
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, long_integer_type_node,
+ endlink));
+ tree di_ftype_void
+ = build_function_type (long_integer_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ endlink));
+ tree ti_ftype_ti_ti
+ = build_function_type (intTI_type_node,
+ tree_cons (NULL_TREE, intTI_type_node,
+ tree_cons (NULL_TREE, intTI_type_node,
+ endlink)));
+ /* Moves to and from HI and LO */
+ tree v2di_ftype_void
+ = build_function_type (V2DI_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ endlink));
+ tree v4si_ftype_void
+ = build_function_type (V4SI_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ endlink));
+ tree v8hi_ftype_void
+ = build_function_type (V8HI_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ endlink));
+ tree void_ftype_v4si
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, V4SI_type_node,
+ endlink));
+ tree void_ftype_v2di
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, V2DI_type_node,
+ endlink));
+ /* Now define the builtins. */
+ /* Add all builtins that are simple operations on one operand. */
+ for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ enum machine_mode mode;
+ tree type;
+
+ if (d->name == 0)
+ continue;
+
+ mode = insn_data[d->icode].operand[1].mode;
+
+ switch (mode)
+ {
+ case V8HImode:
+ if (d->icode == CODE_FOR_mips5900_ppac5)
+ type = v8hi_ftype_v4si;
+ else
+ type = v8hi_ftype_v8hi;
+ break;
+ case V4SImode:
+ if (d->icode == CODE_FOR_mips5900_pext5)
+ type = v4si_ftype_v8hi;
+ else
+ type = v4si_ftype_v4si;
+ break;
+ case V2SImode:
+ type = v2si_ftype_v2si;
+ break;
+ default:
+ abort ();
+ }
+ def_builtin (d->name, type, d->code);
+ }
+
+ /* Add all builtins that are simple operations on two operands. */
+ for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ enum machine_mode mode;
+ tree type;
+
+ if (d->name == 0)
+ continue;
+
+ mode = insn_data[d->icode].operand[1].mode;
+
+ switch (mode)
+ {
+ case V16QImode:
+ type = v16qi_ftype_v16qi_v16qi;
+ break;
+ case V8HImode:
+ if (insn_data[d->icode].operand[0].mode == V4SImode)
+ type = v4si_ftype_v8hi_v8hi;
+ else
+ type = v8hi_ftype_v8hi_v8hi;
+ break;
+ case V4SImode:
+ if (d->icode == CODE_FOR_mips5900_pdivbw)
+ type = void_ftype_v4si_v8hi;
+ else if (insn_data[d->icode].operand[0].mode == V2DImode)
+ type = v2di_ftype_v4si_v4si;
+ else
+ type = v4si_ftype_v4si_v4si;
+ break;
+ case V2DImode:
+ type = v2di_ftype_v2di_v2di;
+ break;
+ case TImode:
+ type = ti_ftype_ti_ti;
+ break;
+ default:
+ abort ();
+ }
+ def_builtin (d->name, type, d->code);
+ }
+
+ /* Add all builtins that are shift-by-constant operations. */
+ for (i = 0, d = bdesc_shiftc; i < sizeof (bdesc_shiftc) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ enum machine_mode mode;
+ tree type;
+
+ if (d->name == 0)
+ continue;
+
+ mode = insn_data[d->icode].operand[1].mode;
+
+ switch (mode)
+ {
+ case V8HImode:
+ type = v8hi_ftype_v8hi_int;
+ break;
+ case V4SImode:
+ type = v4si_ftype_v4si_int;
+ break;
+ default:
+ abort ();
+ }
+ def_builtin (d->name, type, d->code);
+ }
+
+ /* Add all builtins that are move-to-sa-size operations. */
+ for (i = 0, d = bdesc_mtsax; i < sizeof (bdesc_mtsax) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ if (d->name == 0)
+ continue;
+
+ def_builtin (d->name, void_ftype_int_int, d->code);
+ }
+
+ /* Add all builtins that are move-from-special-purpose-register operations. */
+ for (i = 0, d = bdesc_mfspr; i < sizeof (bdesc_mfspr) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ enum machine_mode mode;
+ tree type;
+
+ if (d->name == 0)
+ continue;
+
+ mode = insn_data[d->icode].operand[0].mode;
+
+ switch (mode)
+ {
+ case DImode:
+ type = di_ftype_void;
+ break;
+ case V2DImode:
+ type = v2di_ftype_void;
+ break;
+ case V4SImode:
+ type = v4si_ftype_void;
+ break;
+ case V8HImode:
+ type = v8hi_ftype_void;
+ break;
+ default:
+ abort ();
+ }
+ def_builtin (d->name, type, d->code);
+ }
+
+ /* Add all builtins that are move-to-special-purpose-register operations. */
+ for (i = 0, d = bdesc_mtspr; i < sizeof (bdesc_mtspr) / sizeof *d; i++, d++)
+ {
+ /* Use one of the operands; the target can have a different mode for
+ mask-generating compares. */
+ enum machine_mode mode;
+ tree type;
+
+ if (d->name == 0)
+ continue;
+
+ mode = insn_data[d->icode].operand[0].mode;
+
+ switch (mode)
+ {
+ case DImode:
+ type = void_ftype_di;
+ break;
+ case V4SImode:
+ type = void_ftype_v4si;
+ break;
+ case V2DImode:
+ type = void_ftype_v2di;
+ break;
+ default:
+ abort ();
+ }
+
+ def_builtin (d->name, type, d->code);
+ }
+}
+
+/* Errors in the source file can cause expand_expr to return const0_rtx
+ where we expect a vector. To avoid crashing, use one of the vector
+ clear instructions. */
+
+static rtx
+safe_vector_operand (x, mode)
+ rtx x;
+ enum machine_mode mode;
+{
+ if (x != const0_rtx)
+ return x;
+ return gen_reg_rtx (mode);
+}
+
+static rtx
+mips_expand_unop_builtin (icode, arglist, target)
+ enum insn_code icode;
+ tree arglist;
+ rtx target;
+{
+ tree arg0;
+ rtx op0;
+ rtx pat;
+ enum machine_mode tmode, mode0;
+
+ arg0 = TREE_VALUE (arglist);
+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ tmode = insn_data[icode].operand[0].mode;
+ mode0 = insn_data[icode].operand[1].mode;
+
+ if (VECTOR_MODE_P (mode0))
+ op0 = safe_vector_operand (op0, mode0);
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ pat = GEN_FCN (icode) (target, op0);
+
+ if (! pat)
+ return safe_vector_operand (const0_rtx, tmode);
+
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+mips_expand_binop_builtin (d, arglist, target)
+ struct builtin_description *d;
+ tree arglist;
+ rtx target;
+{
+ rtx pat;
+ tree arg0 = TREE_VALUE (arglist);
+ tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ enum insn_code icode = d->icode;
+ enum machine_mode tmode = insn_data[d->icode].operand[0].mode;
+ enum machine_mode mode0 = insn_data[d->icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[d->icode].operand[2].mode;
+
+ if (VECTOR_MODE_P (mode0))
+ op0 = safe_vector_operand (op0, mode0);
+ if (VECTOR_MODE_P (mode1))
+ op1 = safe_vector_operand (op1, mode1);
+
+ if (! target
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+ if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1)
+ abort ();
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+ if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+ op1 = copy_to_mode_reg (mode1, op1);
+
+ pat = GEN_FCN (icode) (target, op0, op1);
+ if (! pat)
+ return safe_vector_operand (const0_rtx, tmode);
+ emit_insn (pat);
+
+ return target;
+}
+
+static rtx
+mips_expand_shiftc_builtin (d, arglist, target)
+ struct builtin_description *d;
+ tree arglist;
+ rtx target;
+{
+ rtx pat;
+ tree arg0 = TREE_VALUE (arglist);
+ tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ enum insn_code icode = d->icode;
+ enum machine_mode tmode = insn_data[d->icode].operand[0].mode;
+ enum machine_mode mode0 = insn_data[d->icode].operand[1].mode;
+
+ if (VECTOR_MODE_P (mode0))
+ op0 = safe_vector_operand (op0, mode0);
+
+ if (! target
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+ if (GET_MODE (op0) != mode0)
+ abort ();
+
+ if (GET_CODE (op1) != CONST_INT)
+ {
+ error ("second argument of '%s' must be an integer constant", d->name);
+ return safe_vector_operand (const0_rtx, tmode);
+ }
+
+ pat = GEN_FCN (icode) (target, op0, op1);
+ if (! pat)
+ return safe_vector_operand (const0_rtx, tmode);
+ emit_insn (pat);
+
+ return target;
+}
+
+static rtx
+mips_expand_mtsax_builtin (d, arglist)
+ struct builtin_description *d;
+ tree arglist;
+{
+ rtx pat;
+ tree arg0 = TREE_VALUE (arglist);
+ tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+ enum insn_code icode = d->icode;
+ enum machine_mode mode0 = insn_data[d->icode].operand[0].mode;
+
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+ if (GET_MODE (op0) != mode0)
+ abort ();
+
+ if (GET_CODE (op1) != CONST_INT)
+ {
+ error ("second argument of '%s' must be an integer constant", d->name);
+ return NULL_RTX;
+ }
+
+ pat = GEN_FCN (icode) (op0, op1);
+ if (pat)
+ emit_insn (pat);
+
+ return NULL_RTX;
+}
+
+static rtx
+mips_expand_mfspr_builtin (icode, target)
+ enum insn_code icode;
+ rtx target;
+{
+ rtx pat;
+ enum machine_mode tmode = insn_data[icode].operand[0].mode;
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
+
+ pat = GEN_FCN (icode) (target, GEN_INT(0));
+ if (! pat)
+ return const0_rtx;
+ emit_insn (pat);
+
+ return target;
+}
+
+static rtx
+mips_expand_mtspr_builtin (icode, arglist)
+ enum insn_code icode;
+ tree arglist;
+{
+ rtx pat;
+ tree arg0 = TREE_VALUE (arglist);
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+ enum machine_mode mode0 = insn_data[icode].operand[0].mode;
+
+ if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ op0 = copy_to_mode_reg (mode0, op0);
+
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+ if (GET_MODE (op0) != mode0)
+ abort ();
+
+ pat = GEN_FCN (icode) (op0);
+ if (pat)
+ emit_insn (pat);
+
+ return NULL_RTX;
+}
+
+/* Expand an expression EXP that calls a built-in function,
+ with result going to TARGET if that's convenient
+ (and in mode MODE if that's convenient).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+rtx
+mips_expand_builtin (exp, target, subtarget, mode, ignore)
+ tree exp;
+ rtx target;
+ rtx subtarget ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ int ignore ATTRIBUTE_UNUSED;
+{
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+ tree arglist = TREE_OPERAND (exp, 1);
+ struct builtin_description *d;
+ unsigned int i;
+
+ for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_binop_builtin (d, arglist, target);
+
+ for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_unop_builtin (d->icode, arglist, target);
+
+ for (i = 0, d = bdesc_shiftc; i < sizeof (bdesc_shiftc) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_shiftc_builtin (d, arglist, target);
+
+ for (i = 0, d = bdesc_mtsax; i < sizeof (bdesc_mtsax) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_mtsax_builtin (d, arglist);
+
+ for (i = 0, d = bdesc_mfspr; i < sizeof (bdesc_mfspr) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_mfspr_builtin (d->icode, target);
+
+ for (i = 0, d = bdesc_mtspr; i < sizeof (bdesc_mtspr) / sizeof *d; i++, d++)
+ if (d->code == fcode)
+ return mips_expand_mtspr_builtin (d->icode, arglist);
+
+ /* @@@ Should really do something sensible here. */
+ abort ();
+ return const0_rtx;
+}
+
+static int
+mips_arg_pointer_elimination1 (addrp, data)
+ rtx *addrp;
+ void *data;
+{
+ rtx addr = *addrp;
+ rtx eliminate_to
+ = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
+
+ if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == arg_pointer_rtx)
+ *addrp = gen_rtx_PLUS (Pmode, eliminate_to,
+ plus_constant (XEXP (addr, 1),
+ current_frame_info.total_size));
+ else if (addr == arg_pointer_rtx)
+ *addrp = gen_rtx_PLUS (Pmode, eliminate_to,
+ GEN_INT (current_frame_info.total_size));
+ else if (GET_CODE (addr) == PLUS
+ && XEXP (addr, 0) == return_address_pointer_rtx)
+ *addrp = gen_rtx_PLUS (Pmode, eliminate_to,
+ plus_constant (XEXP (addr, 1),
+ current_frame_info.rap_offset));
+ else if (addr == return_address_pointer_rtx)
+ *addrp = gen_rtx_PLUS (Pmode, eliminate_to,
+ GEN_INT (current_frame_info.rap_offset));
+ else return 0;
+
+ *(int *) data = 1;
+ return -1;
+}
+
+static void
+mips_arg_pointer_elimination (first)
+ rtx first;
+{
+ HOST_WIDE_INT offset = current_frame_info.total_size;
+ for (; first; first = NEXT_INSN (first))
+ {
+ int tmp_flag;
+
+ if (GET_CODE (first) != INSN)
+ continue;
+
+ tmp_flag = 0;
+ for_each_rtx (&PATTERN (first), mips_arg_pointer_elimination1,
+ &tmp_flag);
+ if (tmp_flag)
+ INSN_CODE (first) = -1;
+ }
+}
--- gcc-2.96-20000731/gcc/config/mips/mips.md 2000-07-15 18:53:05.000000000 -0500
+++ ee/gcc/src/gcc/config/mips/mips.md 2000-11-06 22:30:04.000000000 -0600
@@ -41,11 +41,14 @@
;; load load instruction(s)
;; store store instruction(s)
;; move data movement within same register set
+;; cmove conditional move instructions
;; xfer transfer to/from coprocessor
;; hilo transfer of hi/lo registers
-;; arith integer arithmetic instruction
+;; arith integer arithmetic instruction (that aren't shifts)
;; darith double precision integer arithmetic instructions
+;; shift integer shift instructions
;; imul integer multiply
+;; imul3 integer multiply 3 operand
;; idiv integer divide
;; icmp integer compare
;; fadd floating point add/subtract
@@ -57,15 +60,16 @@
;; fcmp floating point compare
;; fcvt floating point convert
;; fsqrt floating point square root
+;; frsqrt floating point reciprocal square root
;; multi multiword sequence (or user asm statements)
;; nop no operation
(define_attr "type"
- "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop"
+ "unknown,branch,jump,call,load,store,move,cmove,xfer,hilo,arith,darith,shift,imul,imul3,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop,simd" ; CYGNUS LOCAL vr5400/raeburn
(const_string "unknown"))
;; Main data type used by the insn
-(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" (const_string "unknown"))
+(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,FPSW,V16QI,V8HI,V4SI,V2DI,V2SI" (const_string "unknown"))
;; Length (in # of bytes). A conditional branch is allowed only to a
;; location within a signed 18-bit offset of the delay slot. If that
@@ -98,7 +102,7 @@
;; ??? Fix everything that tests this attribute.
(define_attr "cpu"
- "default,r3000,r3900,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r8000"
+ "default,r3000,r3900,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r5400,r5900,r8000,r4kc,r5kc,r20kc" ; CYGNUS LOCAL vr5400/raeburn
(const (symbol_ref "mips_cpu_attr")))
;; Does the instruction have a mandatory delay slot?
@@ -169,28 +173,33 @@
(define_function_unit "memory" 1 0
(and (eq_attr "type" "load")
- (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4300,r5000"))
+ (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
3 0)
(define_function_unit "memory" 1 0
(and (eq_attr "type" "load")
- (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4300,r5000"))
+ (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4300,r5000,r5400")) ; CYGNUS LOCAL vr5400/raeburn
2 0)
-(define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)
+;; CYGNUS LOCAL law
+(define_function_unit "memory" 1 0
+ (and (eq_attr "type" "store") (eq_attr "cpu" "!r5900")) 1 0)
-(define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0)
+(define_function_unit "memory" 1 0
+ (and (eq_attr "type" "xfer") (eq_attr "cpu" "!r5900")) 2 0)
(define_function_unit "imuldiv" 1 0
- (eq_attr "type" "hilo")
+ (and (eq_attr "type" "hilo")
+ (eq_attr "cpu" "!r5900"))
1 3)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
- (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000"))
+ (and (eq_attr "type" "imul,imul3")
+ (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
17 17)
+;; END CYGNUS LOCAL
-;; On them mips16, we want to stronly discourage a mult from appearing
+;; On them mips16, we want to strongly discourage a mult from appearing
;; after an mflo, since that requires explicit nop instructions. We
;; do this by pretending that mflo ties up the function unit for long
;; enough that the scheduler will ignore load stalls and the like when
@@ -201,45 +210,57 @@
1 5)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul") (eq_attr "cpu" "r3000,r3900"))
+ (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r3000,r3900"))
12 12)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul") (eq_attr "cpu" "r4000,r4600"))
+ (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r4000,r4600"))
10 10)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul") (eq_attr "cpu" "r4650"))
+ (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r4650"))
4 4)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
+ (and (eq_attr "type" "imul,imul3")
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
1 1)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
+ (and (eq_attr "type" "imul,imul3")
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
4 4)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
+ (and (eq_attr "type" "imul,imul3")
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300,r5000")))
5 5)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
+ (and (eq_attr "type" "imul,imul3")
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
8 8)
(define_function_unit "imuldiv" 1 0
- (and (eq_attr "type" "imul")
+ (and (eq_attr "type" "imul,imul3")
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
9 9)
+;; CYGNUS LOCAL vr5400/raeburn
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul,imul3")
+ (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5400")))
+ 3 1)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul,imul3")
+ (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5400")))
+ 4 2)
+;; END CYGNUS LOCAL
+
(define_function_unit "imuldiv" 1 0
(and (eq_attr "type" "idiv")
- (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000"))
+ (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
38 38)
(define_function_unit "imuldiv" 1 0
@@ -288,6 +309,18 @@
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
68 68)
+;; CYGNUS LOCAL vr5400/raeburn
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5400")))
+ 34 34)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5400")))
+ 66 66)
+;; END CYGNUS LOCAL
+
;; The R4300 does *NOT* have a separate Floating Point Unit, instead
;; the FP hardware is part of the normal ALU circuitry. This means FP
;; instructions affect the pipe-line, and no functional unit
@@ -296,7 +329,7 @@
;; instructions to be processed in the "imuldiv" unit.
(define_function_unit "adder" 1 1
- (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000"))
+ (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
3 0)
(define_function_unit "adder" 1 1
@@ -308,7 +341,7 @@
1 0)
(define_function_unit "adder" 1 1
- (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r3900,r6000,r4300"))
+ (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
4 0)
(define_function_unit "adder" 1 1
@@ -321,7 +354,7 @@
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fabs,fneg")
- (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000"))
+ (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000,r5400,r5900")) ; CYGNUS LOCAL vr5400/raeburn
2 0)
(define_function_unit "adder" 1 1
@@ -331,7 +364,7 @@
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul")
(and (eq_attr "mode" "SF")
- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000")))
+ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn
7 0)
(define_function_unit "mult" 1 1
@@ -351,7 +384,7 @@
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul")
- (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000")))
+ (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000,r5400"))) ; CYGNUS LOCAL vr5400/raeburn
8 0)
(define_function_unit "mult" 1 1
@@ -367,7 +400,7 @@
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv")
(and (eq_attr "mode" "SF")
- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000")))
+ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn
23 0)
(define_function_unit "divide" 1 1
@@ -393,7 +426,7 @@
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv")
(and (eq_attr "mode" "DF")
- (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300")))
+ (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5400"))) ; CYGNUS LOCAL vr5400/raeburn
36 0)
(define_function_unit "divide" 1 1
@@ -413,33 +446,33 @@
;;; ??? Is this number right?
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
- (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
+ (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r5400,r5900"))) ; CYGNUS LOCAL vr5400/raeburn
54 0)
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
31 0)
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000")))
21 0)
;;; ??? Is this number right?
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
- (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
+ (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000,r5400"))) ; CYGNUS LOCAL vr5400/raeburn
112 0)
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
60 0)
(define_function_unit "divide" 1 1
- (and (eq_attr "type" "fsqrt")
+ (and (eq_attr "type" "fsqrt,frsqrt") ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000")))
36 0)
@@ -462,14 +495,144 @@
8 8)
(define_function_unit "imuldiv" 1 0
- (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt"))
+ (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300")))
29 29)
(define_function_unit "imuldiv" 1 0
- (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt"))
+ (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) ; CYGNUS LOCAL vr5400/raeburn
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300")))
58 58)
+;; CYGNUS LOCAL vr5400/raeburn
+(define_function_unit "alu_5400" 2 0
+ (and (eq_attr "type" "move,cmove,arith,darith,shift,icmp,nop")
+ (eq_attr "cpu" "r5400"))
+ 1 0)
+
+(define_function_unit "alu_5400" 2 0
+ (and (eq_attr "type" "fadd")
+ (eq_attr "cpu" "r5400"))
+ 4 3)
+
+(define_function_unit "alu_5400" 2 0
+ (and (eq_attr "type" "fcmp,fabs,fneg")
+ (eq_attr "cpu" "r5400"))
+ 2 1)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fmul")
+ (eq_attr "mode" "SF"))
+ (eq_attr "cpu" "r5400"))
+ 5 4)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fmul")
+ (eq_attr "mode" "DF"))
+ (eq_attr "cpu" "r5400"))
+ 6 5)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fdiv,fsqrt")
+ (eq_attr "mode" "SF"))
+ (eq_attr "cpu" "r5400"))
+ 31 30)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fdiv,fsqrt")
+ (eq_attr "mode" "DF"))
+ (eq_attr "cpu" "r5400"))
+ 59 58)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "frsqrt")
+ (eq_attr "mode" "SF"))
+ (eq_attr "cpu" "r5400"))
+ 61 60)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "frsqrt")
+ (eq_attr "mode" "DF"))
+ (eq_attr "cpu" "r5400"))
+ 121 120)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fmadd")
+ (eq_attr "mode" "SF"))
+ (eq_attr "cpu" "r5400"))
+ 9 8)
+
+(define_function_unit "alu_5400" 2 0
+ (and (and (eq_attr "type" "fmadd")
+ (eq_attr "mode" "DF"))
+ (eq_attr "cpu" "r5400"))
+ 10 9)
+
+(define_function_unit "alu_5400" 2 0
+ (and (eq_attr "type" "fcvt")
+ (eq_attr "cpu" "r5400"))
+ 6 5)
+;; END CYGNUS LOCAL
+
+;; Using a value immediately after a load causes a one cycle delay.
+(define_function_unit "memory" 1 0
+ (and (eq_attr "type" "load") (eq_attr "cpu" "r5900")) 2 0)
+
+;; The r5900 has a store buffer which can cause an interlock for
+;; consecutive stores in some cases. So try to separate stores.
+(define_function_unit "memory" 1 0
+ (and (eq_attr "type" "store") (eq_attr "cpu" "r5900")) 2 1)
+
+;; Transfer to/from coprocessor. This is just a guess. There may or
+;; may not be an interlock for such transfers.
+(define_function_unit "memory" 1 0
+ (and (eq_attr "type" "xfer") (eq_attr "cpu" "r5900")) 2 0)
+
+;; The r5900 has two independent ALUs.
+(define_function_unit "alu" 2 0
+ (and (eq_attr "type" "move,cmove,arith,darith,shift,icmp,nop,branch,jump,call")
+ (eq_attr "cpu" "r5900")) 1 0)
+
+;; XXX There is differing data between the architecture manual
+;; about what these values should be.
+(define_function_unit "r5900imuldiv" 2 0
+ (and (eq_attr "type" "hilo") (eq_attr "cpu" "r5900")) 1 0)
+
+(define_function_unit "r5900imuldiv" 2 0
+ (and (eq_attr "type" "imul,imul3") (eq_attr "cpu" "r5900")) 4 1)
+
+(define_function_unit "r5900imuldiv" 2 0
+ (and (eq_attr "type" "idiv") (eq_attr "cpu" "r5900")) 37 36)
+
+;; The r5900 FP unit has three independent units.
+;; fmac -- all computational instructions except fdiv, fsqrt, rsqrt
+;; fdiv -- fdiv, fsqrt, rsqrt
+;; load/store -- load store and transfer unit
+;;
+;; It appears that fmac/fdiv can dual issue with load/store.
+(define_function_unit "fmac" 1 0
+ (and (eq_attr "type" "fadd,fmul,fmadd,fabs,fneg,fcmp,fcvt")
+ (eq_attr "cpu" "r5900")) 4 0)
+
+(define_function_unit "fdiv" 1 1
+ (and (eq_attr "type" "fdiv,fsqrt") (eq_attr "cpu" "r5900")) 8 6)
+
+(define_function_unit "fdiv" 1 1
+ (and (eq_attr "type" "frsqrt") (eq_attr "cpu" "r5900")) 14 12)
+
+
+;; And now a few fake units to encourage dual issue.
+;; We can only issue one operation to the FPU per cycle.
+(define_function_unit "flop" 1 0
+ (and (eq_attr "type"
+ "fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,xfer")
+ (eq_attr "cpu" "r5900")) 1 0)
+
+;; I don't think we need any other fake units to describe common
+;; cases.
+
+;;
+
+
;; The following functional units do not use the cpu type, and use
;; much less memory in genattrtab.c.
@@ -481,7 +644,7 @@
;; (define_function_unit "transfer" 1 0 (eq_attr "type" "xfer") 2 0)
;; (define_function_unit "transfer" 1 0 (eq_attr "type" "hilo") 3 0)
;;
-;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul") 17 0)
+;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul,imul3") 17 0)
;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "idiv") 38 0)
;;
;; (define_function_unit "adder" 1 1 (eq_attr "type" "fadd") 4 0)
@@ -493,8 +656,12 @@
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "SF")) 23 0)
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "DF")) 36 0)
;;
-;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 0)
-;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 0)
+;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (eq_attr "mode" "SF")) 54 0) CYGNUS LOCAL vr5400/raeburn
+;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (eq_attr "mode" "DF")) 112 0) CYGNUS LOCAL vr5400/raeburn
+
+
+
+
;;
@@ -542,7 +709,7 @@
(define_insn "addsi3_internal"
[(set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJA")
(match_operand:SI 2 "arith_operand" "dI")))]
"! TARGET_MIPS16
&& (TARGET_GAS
@@ -582,7 +749,7 @@
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
+ (plus:SI (match_operand:SI 1 "register_operand" "0,dA,dA")
(match_operand:SI 2 "arith_operand" "IQ,O,d")))]
"TARGET_MIPS16
&& (GET_CODE (operands[1]) != REG
@@ -1043,6 +1210,104 @@
(const_int 8))
(const_int 4)])])
+(define_expand "addvsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
+ (match_operand:SI 2 "arith_operand" "dI")))
+ (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (plus:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))])]
+ ""
+ "
+{
+ /* The mips16 assembler handles -32768 correctly, and so does gas,
+ but some other MIPS assemblers think that -32768 needs to be
+ loaded into a register before it can be added in. */
+ if (! TARGET_MIPS16
+ && ! TARGET_GAS
+ && GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -32768)
+ operands[2] = force_reg (SImode, operands[2]);
+
+ emit_insn (gen_addvsi3_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "addvsi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
+ (match_operand:SI 2 "arith_operand" "dI")))
+ (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (plus:SI (match_dup 1) (match_dup 2))))
+ (const_int 0))]
+ "! TARGET_MIPS16
+ && flag_trapv
+ && (TARGET_GAS
+ || GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) != -32768)"
+ "add\\t%0,%z1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "1")])
+
+(define_expand "addvdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "se_register_operand" "")
+ (match_operand:DI 2 "se_arith_operand" "")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))
+ (clobber (match_dup 3))])]
+ "TARGET_64BIT || (! TARGET_DEBUG_G_MODE && ! TARGET_MIPS16)"
+ "
+{
+ /* The mips16 assembler handles -32768 correctly, and so does gas,
+ but some other MIPS assemblers think that -32768 needs to be
+ loaded into a register before it can be added in. */
+ if (! TARGET_MIPS16
+ && ! TARGET_GAS
+ && GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -32768)
+ operands[2] = force_reg (DImode, operands[2]);
+
+ if (TARGET_64BIT)
+ {
+ emit_insn (gen_addvdi3_internal_3 (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "addvdi3_internal_3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (plus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ")
+ (match_operand:DI 2 "se_arith_operand" "dI")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "TARGET_64BIT
+ && ! TARGET_MIPS16
+ && (TARGET_GAS
+ || GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) != -32768)"
+ "*
+{
+ return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
+ ? \"dsub\\t%0,%z1,%n2\"
+ : \"dadd\\t%0,%z1,%2\";
+}"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "1")])
;;
;; ....................
@@ -1544,6 +1809,82 @@
(const_int 4)])])
+(define_expand "subvsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
+ (match_operand:SI 2 "arith_operand" "dI")))
+ (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (minus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))])]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == -32768
+ || (TARGET_MIPS16
+ && INTVAL (operands[2]) == -0x4000)))
+ operands[2] = force_reg (SImode, operands[2]);
+}")
+
+(define_insn "subvsi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
+ (match_operand:SI 2 "arith_operand" "dI")))
+ (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (minus:DI (match_dup 1) (match_dup 2))))
+ (const_int 0))]
+ "! TARGET_MIPS16
+ && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
+ "sub\\t%0,%z1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "1")])
+
+(define_expand "subvdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=d")
+ (minus:DI (match_operand:DI 1 "se_register_operand" "d")
+ (match_operand:DI 2 "se_register_operand" "d")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1) (match_dup 2)
+)))
+ (const_int 0))
+ (clobber (match_dup 3))])]
+ "TARGET_64BIT || (! TARGET_DEBUG_G_MODE && ! TARGET_MIPS16)"
+ "
+{
+ if (TARGET_64BIT)
+ {
+ emit_insn (gen_subvdi3_internal_3 (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "subvdi3_internal_3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (minus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ")
+ (match_operand:DI 2 "se_arith_operand" "dI")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1) (match_dup 2))))
+ (const_int 0))]
+ "TARGET_64BIT && ! TARGET_MIPS16
+ && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
+ "*
+{
+ return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
+ ? \"dadd\\t%0,%z1,%n2\"
+ : \"dsub\\t%0,%z1,%2\";
+}"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "1")])
;;
;; ....................
@@ -1649,6 +1990,21 @@
""
"
{
+ /* mulsi3_mult3_r5900 is just like the other mulsi3_mult3 pattern, except
+ that it has additional alternatives, slightly different output
+ templates and clobbers pseudos instead of scratches.
+
+ We generate a different pattern merely to keep the sanitize issues from
+ driving us crazy. Long term we may want the other multiply patterns to
+ clobber pseudos instead of scratches. */
+ if (HAVE_mulsi3_mult3_r5900)
+ {
+ emit_insn (gen_mulsi3_mult3_r5900 (operands[0], operands[1], operands[2],
+ gen_reg_rtx (SImode),
+ gen_reg_rtx (SImode),
+ gen_reg_rtx (SImode)));
+ DONE;
+ }
if (HAVE_mulsi3_mult3)
emit_insn (gen_mulsi3_mult3 (operands[0], operands[1], operands[2]));
else if (mips_cpu != PROCESSOR_R4000 || TARGET_MIPS16)
@@ -1658,6 +2014,24 @@
DONE;
}")
+(define_insn "mulsi3_mult3_r5900"
+ [(set (match_operand:SI 0 "register_operand" "=d,l,d,v")
+ (mult:SI (match_operand:SI 1 "register_operand" "d,d,d,d")
+ (match_operand:SI 2 "register_operand" "d,d,d,d")))
+ (clobber (match_operand:SI 3 "register_operand" "=h,h,u,u"))
+ (clobber (match_operand:SI 4 "register_operand" "=l,X,v,X"))
+ (clobber (match_operand:SI 5 "register_operand" "=a,a,q,q"))]
+ "TARGET_MIPS5900 && GENERATE_MULT3"
+ "*
+{
+ if (which_alternative == 1 || which_alternative == 3)
+ return \"mult%H5\\t%1,%2\";
+ return \"mult%H5\\t%0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
(define_insn "mulsi3_mult3"
[(set (match_operand:SI 0 "register_operand" "=d,l")
(mult:SI (match_operand:SI 1 "register_operand" "d,d")
@@ -1665,18 +2039,21 @@
(clobber (match_scratch:SI 3 "=h,h"))
(clobber (match_scratch:SI 4 "=l,X"))
(clobber (match_scratch:SI 5 "=a,a"))]
- "GENERATE_MULT3
- || TARGET_MAD"
+ "(GENERATE_MULT3
+ || TARGET_MIPS5400 /* CYGNUS LOCAL vr5400/raeburn */
+ || TARGET_MAD)
+ && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"*
{
if (which_alternative == 1)
return \"mult\\t%1,%2\";
- if (TARGET_MAD)
+ if (TARGET_MIPS5400 /* CYGNUS LOCAL vr5400/raeburn */
+ || TARGET_MAD)
return \"mul\\t%0,%1,%2\";
return \"mult\\t%0,%1,%2\";
}"
- [(set_attr "type" "imul")
- (set_attr "mode" "SI")])
+ [(set_attr "type" "imul3,imul")
+ (set_attr "mode" "SI,SI")])
(define_insn "mulsi3_internal"
[(set (match_operand:SI 0 "register_operand" "=l")
@@ -1713,8 +2090,8 @@
(set_attr "length" "12")]) ;; mult + mflo + delay
;; Multiply-accumulate patterns
-
-;; For processors that can copy the output to a general register:
+;
+; For processors that can copy the output to a general register:
;;
;; The all-d alternative is needed because the combiner will find this
;; pattern and then register alloc/reload will move registers around to
@@ -1724,6 +2101,29 @@
;; "?" to the constraint is too strong, and causes values to be loaded into
;; LO even when that's more costly. For now, using "*d" mostly does the
;; trick.
+;; Like the standard multiply-accumulate, except with more alternatives and
+;; works with both pipelines. Temporarily disabled. */
+(define_insn "*mul_acc_si_r5900"
+ [(set (match_operand:SI 0 "register_operand" "=l,*d,*d,v,*d,*d")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d,d,d,d")
+ (match_operand:SI 2 "register_operand" "d,d,d,d,d,d"))
+ (match_operand:SI 3 "register_operand" "0,l,*d,0,v,*d")))
+ (clobber (match_scratch:SI 4 "=h,h,h,u,u,u"))
+ (clobber (match_scratch:SI 5 "=X,3,l,X,3,v"))
+ (clobber (match_scratch:SI 6 "=a,a,a,q,q,q"))
+ (clobber (match_scratch:SI 7 "=X,X,d,X,X,d"))]
+ "(TARGET_MIPS5900 && !TARGET_MIPS16) && r5900_madd_profitable_p (insn)"
+ "*
+{
+ static char *const madd[] = { \"madd%H6\\t%1,%2\",
+ \"madd%H6\\t%0,%1,%2\",
+ \"#\" };
+ return madd[which_alternative % 3];
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,4,8,4,4,8")])
+
(define_insn "*mul_acc_si"
[(set (match_operand:SI 0 "register_operand" "=l,*d,*d")
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
@@ -1733,13 +2133,19 @@
(clobber (match_scratch:SI 5 "=X,3,l"))
(clobber (match_scratch:SI 6 "=a,a,a"))
(clobber (match_scratch:SI 7 "=X,X,d"))]
- "TARGET_MIPS3900
+ "(TARGET_MIPS3900
+ || TARGET_MIPS5400) /* CYGNUS LOCAL vr5400/raeburn */
&& !TARGET_MIPS16"
"*
{
static const char *const madd[] = { \"madd\\t%1,%2\", \"madd\\t%0,%1,%2\" };
+ static const char *const macc[] = { \"macc\\t$0,%1,%2\", \"macc\\t%0,%1,%2\" }; /* CYGNUS LOCAL vr5400/raeburn */
if (which_alternative == 2)
return \"#\";
+ /* CYGNUS LOCAL vr5400/raeburn */
+ if (TARGET_MIPS5400)
+ return macc[which_alternative];
+ /* END CYGNUS LOCAL */
return madd[which_alternative];
}"
[(set_attr "type" "imul,imul,multi")
@@ -1765,6 +2171,43 @@
(set (match_dup 0) (plus:SI (match_dup 7) (match_dup 3)))]
"")
+
+
+
+;; CYGNUS LOCAL vr5400/raeburn
+(define_insn "*muls_r5400"
+ [(set (match_operand:SI 0 "register_operand" "=l,d")
+ (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "register_operand" "d,d"))))
+ (clobber (match_scratch:SI 3 "=h,h"))
+ (clobber (match_scratch:SI 4 "=a,a"))
+ (clobber (match_scratch:SI 5 "=X,l"))]
+ "TARGET_MIPS5400"
+ "@
+ muls\\t$0,%1,%2
+ muls\\t%0,%1,%2"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")])
+
+;; See comments above for mul_acc_si.
+(define_insn "*msac_r5400"
+ [(set (match_operand:SI 0 "register_operand" "=l,*d,*d")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,l,*d")
+ (mult:SI (match_operand:SI 2 "register_operand" "d,d,d")
+ (match_operand:SI 3 "register_operand" "d,d,d"))))
+ (clobber (match_scratch:SI 4 "=h,h,h"))
+ (clobber (match_scratch:SI 5 "=X,1,l"))
+ (clobber (match_scratch:SI 6 "=a,a,a"))
+ (clobber (match_scratch:SI 7 "=X,X,d"))]
+ "TARGET_MIPS5400"
+ "@
+ msac\\t$0,%2,%3
+ msac\\t%0,%2,%3
+ #"
+ [(set_attr "type" "imul,imul,multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,4,8")])
+
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 1 "register_operand" "")
@@ -1782,6 +2225,7 @@
(clobber (match_dup 6))])
(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 7)))]
"")
+;; END CYGNUS LOCAL
(define_expand "muldi3"
[(set (match_operand:DI 0 "register_operand" "=l")
@@ -1789,7 +2233,7 @@
(match_operand:DI 2 "register_operand" "d")))
(clobber (match_scratch:DI 3 "=h"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT"
+ "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
@@ -1811,7 +2255,7 @@
(match_operand:DI 2 "register_operand" "d")))
(clobber (match_scratch:DI 3 "=h"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT && mips_cpu != PROCESSOR_R4000 && !TARGET_MIPS16"
+ "TARGET_64BIT && mips_cpu != PROCESSOR_R4000 && !TARGET_MIPS16 && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"dmult\\t%1,%2"
[(set_attr "type" "imul")
(set_attr "mode" "DI")])
@@ -1823,7 +2267,7 @@
(clobber (match_scratch:DI 3 "=h"))
(clobber (match_scratch:DI 4 "=l"))
(clobber (match_scratch:DI 5 "=a"))]
- "TARGET_64BIT && (GENERATE_MULT3 || mips_cpu == PROCESSOR_R4000 || TARGET_MIPS16)"
+ "TARGET_64BIT && (GENERATE_MULT3 || mips_cpu == PROCESSOR_R4000 || TARGET_MIPS16) && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"*
{
if (GENERATE_MULT3)
@@ -1857,6 +2301,15 @@
"
{
rtx dummy = gen_rtx (SIGN_EXTEND, DImode, const0_rtx);
+ if (TARGET_64BIT && TARGET_MIPS5900)
+ {
+ emit_insn (gen_mulsidi3_64bit_r5900 (operands[0], operands[1],
+ operands[2],
+ dummy, dummy,
+ gen_reg_rtx (DImode),
+ gen_reg_rtx (DImode)));
+ DONE;
+ }
if (TARGET_64BIT)
emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2],
dummy, dummy));
@@ -1874,6 +2327,15 @@
"
{
rtx dummy = gen_rtx (ZERO_EXTEND, DImode, const0_rtx);
+ if (TARGET_64BIT && TARGET_MIPS5900)
+ {
+ emit_insn (gen_mulsidi3_64bit_r5900 (operands[0], operands[1],
+ operands[2],
+ dummy, dummy,
+ gen_reg_rtx (DImode),
+ gen_reg_rtx (DImode)));
+ DONE;
+ }
if (TARGET_64BIT)
emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2],
dummy, dummy));
@@ -1900,6 +2362,26 @@
[(set_attr "type" "imul")
(set_attr "mode" "SI")])
+(define_insn "mulsidi3_64bit_r5900"
+ [(set (match_operand:DI 0 "register_operand" "=a,q")
+ (mult:DI (match_operator:DI 3 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d,d")])
+ (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d,d")])))
+ (clobber (match_operand:DI 5 "register_operand" "=l,v"))
+ (clobber (match_operand:DI 6 "register_operand" "=h,u"))]
+ "TARGET_64BIT && TARGET_MIPS5900
+ && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "*
+{
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return \"mult%H0\\t%1,%2\";
+ return \"multu%H0\\t%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
(define_insn "mulsidi3_64bit"
[(set (match_operand:DI 0 "register_operand" "=a")
(mult:DI (match_operator:DI 3 "extend_operator"
@@ -1908,7 +2390,7 @@
[(match_operand:SI 2 "register_operand" "d")])))
(clobber (match_scratch:DI 5 "=l"))
(clobber (match_scratch:DI 6 "=h"))]
- "TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "TARGET_64BIT && !TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])" ;; CYGNUS LOCAL law
"*
{
if (GET_CODE (operands[3]) == SIGN_EXTEND)
@@ -1918,6 +2400,56 @@
[(set_attr "type" "imul")
(set_attr "mode" "SI")])
+;; CYGNUS LOCAL vr5400/raeburn
+
+;; widening multiply with accumulator and/or negation
+;; These don't match yet for zero-extending; too complex for combine?
+;; Possible additions we should have:
+;; "=x" variants for when !TARGET_64BIT ?
+;; all-d alternatives with splits like pure SImode versions
+(define_insn "*muls_r5400_di"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (neg:DI
+ (mult:DI (match_operator:DI 3 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d")])
+ (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d")]))))
+ (clobber (match_scratch:SI 5 "=h"))
+ (clobber (match_scratch:SI 6 "=l"))]
+ "TARGET_64BIT && TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "*
+{
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return \"muls\\t$0,%1,%2\";
+ else
+ return \"mulsu\\t$0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "4")
+ (set_attr "mode" "SI")])
+
+(define_insn "*msac_r5400_di"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (minus:DI (match_operand:DI 3 "register_operand" "0")
+ (mult:DI (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d")])
+ (match_operator:DI 5 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d")]))))
+ (clobber (match_scratch:SI 6 "=h"))
+ (clobber (match_scratch:SI 7 "=l"))]
+ "TARGET_64BIT && TARGET_MIPS5400 && GET_CODE (operands[4]) == GET_CODE (operands[5])"
+ "*
+{
+ if (GET_CODE (operands[4]) == SIGN_EXTEND)
+ return \"msac\\t$0,%1,%2\";
+ else
+ return \"msacu\\t$0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "4")
+ (set_attr "mode" "SI")])
+;; END CYGNUS LOCAL
+
;; _highpart patterns
(define_expand "smulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=h")
@@ -1936,6 +2468,12 @@
rtx (*genfn) ();
#endif
genfn = gen_xmulsi3_highpart_internal;
+ /* CYGNUS LOCAL vr5400/raeburn */
+ if (TARGET_MIPS5400)
+ genfn = gen_xmulsi3_highpart_5400;
+ /* END CYGNUS LOCAL */
+ if (TARGET_MIPS5900)
+ genfn = gen_xmulsi3_highpart_r5900;
emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy,
dummy, dummy2));
DONE;
@@ -1958,11 +2496,40 @@
rtx (*genfn) ();
#endif
genfn = gen_xmulsi3_highpart_internal;
+ /* CYGNUS LOCAL vr5400/raeburn */
+ if (TARGET_MIPS5400)
+ genfn = gen_xmulsi3_highpart_5400;
+ /* END CYGNUS LOCAL */
+ if (TARGET_MIPS5900)
+ genfn = gen_xmulsi3_highpart_r5900;
emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy,
dummy, dummy2));
DONE;
}")
+(define_insn "xmulsi3_highpart_r5900"
+ [(set (match_operand:SI 0 "register_operand" "=h,u")
+ (truncate:SI
+ (match_operator:DI 5 "highpart_shift_operator"
+ [(mult:DI (match_operator:DI 3 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d,d")])
+ (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d,d")]))
+ (const_int 32)])))
+ (clobber (match_scratch:SI 6 "=l,v"))
+ (clobber (match_scratch:SI 7 "=a,q"))]
+ "TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "*
+{
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return \"mult%H0\\t%1,%2\";
+ else
+ return \"multu%H0\\t%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
(define_insn "xmulsi3_highpart_internal"
[(set (match_operand:SI 0 "register_operand" "=h")
(truncate:SI
@@ -1974,7 +2541,7 @@
(const_int 32)])))
(clobber (match_scratch:SI 6 "=l"))
(clobber (match_scratch:SI 7 "=a"))]
- "GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "! TARGET_MIPS5400 && !TARGET_MIPS5900 && GET_CODE (operands[3]) == GET_CODE (operands[4])" ;; CYGNUS LOCAL vr5400/raeburn ;; CYGNUS LOCAL law
"*
{
if (GET_CODE (operands[3]) == SIGN_EXTEND)
@@ -1985,6 +2552,61 @@
[(set_attr "type" "imul")
(set_attr "mode" "SI")])
+;; CYGNUS LOCAL vr5400/raeburn
+(define_insn "xmulsi3_highpart_5400"
+ [(set (match_operand:SI 0 "register_operand" "=h,d")
+ (truncate:SI
+ (match_operator:DI 5 "highpart_shift_operator"
+ [(mult:DI (match_operator:DI 3 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d,d")])
+ (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d,d")]))
+ (const_int 32)])))
+ (clobber (match_scratch:SI 6 "=l,l"))
+ (clobber (match_scratch:SI 7 "=a,a"))
+ (clobber (match_scratch:SI 8 "=X,h"))]
+ "TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "*
+{
+ char *const sign[] = { \"mult\\t%1,%2\", \"mulhi\\t%0,%1,%2\" };
+ char *const zero[] = { \"multu\\t%1,%2\", \"mulhiu\\t%0,%1,%2\" };
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return sign[which_alternative];
+ else
+ return zero[which_alternative];
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "*xmulsi3_neg_highpart_5400"
+ [(set (match_operand:SI 0 "register_operand" "=h,d")
+ (truncate:SI
+ (match_operator:DI 5 "highpart_shift_operator"
+ [(neg:DI
+ (mult:DI (match_operator:DI 3 "extend_operator"
+ [(match_operand:SI 1 "register_operand" "d,d")])
+ (match_operator:DI 4 "extend_operator"
+ [(match_operand:SI 2 "register_operand" "d,d")])))
+ (const_int 32)])))
+ (clobber (match_scratch:SI 6 "=l,l"))
+ (clobber (match_scratch:SI 7 "=a,a"))
+ (clobber (match_scratch:SI 8 "=X,h"))]
+ "TARGET_MIPS5400 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "*
+{
+ char *const sign[] = { \"mulshi\\t$0,%1,%2\", \"mulshi\\t%0,%1,%2\" };
+ char *const zero[] = { \"mulshiu\\t$0,%1,%2\", \"mulshiu\\t%0,%1,%2\" };
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return sign[which_alternative];
+ else
+ return zero[which_alternative];
+}"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+;; END CYGNUS LOCAL
+
(define_insn "smuldi3_highpart"
[(set (match_operand:DI 0 "register_operand" "=h")
(truncate:DI
@@ -1993,7 +2615,7 @@
(const_int 64))))
(clobber (match_scratch:DI 3 "=l"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT"
+ "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"dmult\\t%1,%2"
[(set_attr "type" "imul")
(set_attr "mode" "DI")])
@@ -2006,7 +2628,7 @@
(const_int 64))))
(clobber (match_scratch:DI 3 "=l"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT"
+ "TARGET_64BIT && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"dmultu\\t%1,%2"
[(set_attr "type" "imul")
(set_attr "mode" "DI")])
@@ -2056,15 +2678,28 @@
(match_dup 0)))
(clobber (match_scratch:SI 5 "=h"))
(clobber (match_scratch:SI 6 "=l"))]
- "TARGET_MAD
- && TARGET_64BIT
- && GET_CODE (operands[3]) == GET_CODE (operands[4])"
+ "(TARGET_MAD || TARGET_MIPS5400) /* CYGNUS LOCAL vr5400/raeburn */
+ && TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])"
"*
{
+ if (TARGET_MAD)
+ {
if (GET_CODE (operands[3]) == SIGN_EXTEND)
return \"mad\\t%1,%2\";
else
return \"madu\\t%1,%2\";
+ }
+ /* CYGNUS LOCAL vr5400/raeburn */
+ else if (TARGET_MIPS5400)
+ {
+ if (GET_CODE (operands[3]) == SIGN_EXTEND)
+ return \"macc\\t$0,%1,%2\";
+ else
+ return \"maccu\\t$0,%1,%2\";
+ }
+ /* END CYGNUS LOCAL */
+ else
+ abort ();
}"
[(set_attr "type" "imul")
(set_attr "mode" "SI")])
@@ -2152,6 +2787,128 @@
[(set_attr "type" "fmadd")
(set_attr "mode" "SF")])
+(define_expand "mulvsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "=l")
+ (mult:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (mult:SI (match_dup 1) (match_dup 2))
+))
+ (const_int 0))
+ (clobber (match_scratch:SI 3 "=h"))
+ (clobber (match_scratch:SI 4 "=l"))
+ (clobber (match_scratch:SI 5 "=a"))])]
+ "HAVE_mulvsi3_mult3_r5900"
+ "
+{
+ /* mulvsi3_mult3_r5900 is just like the other mulsi3_mult3 pattern, except
+ that it has additional alternatives, slightly different output
+ templates and clobbers pseudos instead of scratches.
+
+ We generate a different pattern merely to keep the sanitize issues from
+ driving us crazy. Long term we may want the other multiply patterns to
+ clobber pseudos instead of scratches. */
+ if (HAVE_mulvsi3_mult3_r5900)
+ {
+ emit_insn (gen_mulvsi3_mult3_r5900 (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+ DONE;
+}")
+
+(define_insn "mulvsi3_mult3_r5900"
+
+ [(set (match_operand:SI 0 "register_operand" "=d,l")
+ (mult:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "register_operand" "d,d")))
+ (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (mult:SI (match_dup 1) (match_dup 2))))
+ (const_int 0))
+ (clobber (match_scratch:SI 3 "=d,d"))
+ (clobber (match_scratch:SI 4 "=h,h"))
+ (clobber (match_scratch:SI 5 "=l,d"))
+ (clobber (match_scratch:SI 6 "=a,a"))]
+ "TARGET_MIPS5900 && GENERATE_MULT3"
+ "@
+ mult\\t%0,%1,%2\\n\\tpmfhl.lw\\t%3\\n\\ttne\\t%0,%3
+ mult\\t%5,%1,%2\\n\\tpmfhl.lw\\t%3\\n\\ttne\\t%4,%3"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "3")])
+
+(define_expand "mulvdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=&r")
+ (mult:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "register_operand" "r")))
+ (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (mult:DI (match_dup 1) (match_dup 2))
+))
+ (const_int 0))
+ (clobber (match_scratch:TI 3 "=&r"))
+ (clobber (match_scratch:TI 4 "=&r"))
+ (clobber (match_scratch:TI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&h"))
+ (clobber (match_scratch:SI 7 "=&l"))
+ (clobber (match_scratch:SI 8 "=&a"))])]
+ "TARGET_64BIT && TARGET_MIPS5900"
+ "
+{
+ emit_insn (gen_mulvdi3_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mulvdi3_internal"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (mult:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "register_operand" "r")))
+ (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (mult:DI (match_dup 1) (match_dup 2))))
+ (const_int 0))
+ (clobber (match_scratch:TI 3 "=&r"))
+ (clobber (match_scratch:TI 4 "=&r"))
+ (clobber (match_scratch:TI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&h"))
+ (clobber (match_scratch:SI 7 "=&l"))
+ (clobber (match_scratch:SI 8 "=&a"))
+ (clobber (subreg:TI (match_dup 0) 0))]
+
+ "TARGET_64BIT && TARGET_MIPS5900"
+ "pextlw\\t%3,%1,%1 \
+\\tpextlw\\t%4,%2,%2 \
+\\tpsravw\\t%3,%3,$0 \
+\\tpsravw\\t%4,%4,$0 \
+\\tpmultuw\\t%0,%3,%4 \
+\\tmtsah\\t$0,4 \
+\\tqfsrv\\t%3,%3,%3 \
+\\tpmultuw\\t%3,%3,%4 \
+\\tdsrl32\\t%5,%0,0 \
+\\tqfsrv\\t%4,$0,%0 \
+\\tdaddu\\t%3,%3,%5 \
+\\tdsrl32\\t%5,%3,0 \
+\\tdaddu\\t%4,%4,%5 \
+\\tpextlw\\t%5,$0,%3 \
+\\tqfsrv\\t%3,$0,%3 \
+\\tdaddu\\t%3,%3,%5 \
+\\tdsrl32\\t%5,%3,0 \
+\\tdaddu\\t%4,%4,%5 \
+\\tpextlw\\t%0,%3,%0 \
+\\tdsra32\\t%5,%1,31 \
+\\tdsra32\\t%3,%2,31 \
+\\tand\\t%5,%5,%2 \
+\\tand\\t%3,%3,%1 \
+\\tdsubu\\t%4,%4,%5 \
+\\tdsra32\\t%5,%0,31 \
+\\tdsubu\\t%4,%4,%3 \
+\\ttne\\t%4,%5"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "DI")
+ (set_attr "length" "27")])
+
;;
;; ....................
;;
@@ -2174,9 +2931,19 @@
(div:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
- "div.s\\t%0,%1,%2"
+ "*
+{
+ if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG)
+ return \"%(nop\;nop\;div.s\\t%0,%1,%2%)\";
+ return \"div.s\\t%0,%1,%2\";
+}"
[(set_attr "type" "fdiv")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set (attr "length")
+ (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG")
+ (const_int 0))
+ (const_int 4)
+ (const_int 12)))])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -2222,8 +2989,16 @@
"optimize"
"
{
+ if (TARGET_MIPS5900)
+ {
+ emit_insn (gen_divmodsi4_internal_r5900 (operands[0], operands[1],
+ operands[2], operands[3]));
+ goto zero_div_check;
+ }
+
emit_insn (gen_divmodsi4_internal (operands[0], operands[1], operands[2],
operands[3]));
+ zero_div_check:
if (!TARGET_NO_CHECK_ZERO_DIV)
{
emit_insn (gen_div_trap (operands[2],
@@ -2243,6 +3018,20 @@
DONE;
}")
+(define_insn "divmodsi4_internal_r5900"
+ [(set (match_operand:SI 0 "register_operand" "=l,v")
+ (div:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "register_operand" "d,d")))
+ (set (match_operand:SI 3 "register_operand" "=h,u")
+ (mod:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 6 "=a,q"))]
+ "optimize && TARGET_MIPS5900"
+ "div%H0\\t$0,%1,%2"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
(define_insn "divmodsi4_internal"
[(set (match_operand:SI 0 "register_operand" "=l")
(div:SI (match_operand:SI 1 "register_operand" "d")
@@ -2251,7 +3040,7 @@
(mod:SI (match_dup 1)
(match_dup 2)))
(clobber (match_scratch:SI 6 "=a"))]
- "optimize"
+ "optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"div\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")])
@@ -2266,7 +3055,7 @@
(clobber (match_scratch:DI 4 "=l"))
(clobber (match_scratch:DI 5 "=h"))
(clobber (match_scratch:DI 6 "=a"))]
- "TARGET_64BIT && optimize"
+ "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_divmoddi4_internal (operands[0], operands[1], operands[2],
@@ -2298,7 +3087,7 @@
(mod:DI (match_dup 1)
(match_dup 2)))
(clobber (match_scratch:DI 6 "=a"))]
- "TARGET_64BIT && optimize"
+ "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddiv\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")])
@@ -2316,8 +3105,15 @@
"optimize"
"
{
+ if (TARGET_MIPS5900)
+ {
+ emit_insn (gen_udivmodsi4_internal_r5900 (operands[0], operands[1],
+ operands[2], operands[3]));
+ goto zero_div_check;
+ }
emit_insn (gen_udivmodsi4_internal (operands[0], operands[1], operands[2],
operands[3]));
+ zero_div_check:
if (!TARGET_NO_CHECK_ZERO_DIV)
{
emit_insn (gen_div_trap (operands[2],
@@ -2328,6 +3124,20 @@
DONE;
}")
+(define_insn "udivmodsi4_internal_r5900"
+ [(set (match_operand:SI 0 "register_operand" "=l,v")
+ (udiv:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "register_operand" "d,d")))
+ (set (match_operand:SI 3 "register_operand" "=h,u")
+ (umod:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 6 "=a,q"))]
+ "optimize && TARGET_MIPS5900"
+ "divu%H0\\t$0,%1,%2"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
(define_insn "udivmodsi4_internal"
[(set (match_operand:SI 0 "register_operand" "=l")
(udiv:SI (match_operand:SI 1 "register_operand" "d")
@@ -2336,7 +3146,7 @@
(umod:SI (match_dup 1)
(match_dup 2)))
(clobber (match_scratch:SI 6 "=a"))]
- "optimize"
+ "optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"divu\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")])
@@ -2351,7 +3161,7 @@
(clobber (match_scratch:DI 4 "=l"))
(clobber (match_scratch:DI 5 "=h"))
(clobber (match_scratch:DI 6 "=a"))]
- "TARGET_64BIT && optimize"
+ "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_udivmoddi4_internal (operands[0], operands[1], operands[2],
@@ -2374,7 +3184,7 @@
(umod:DI (match_dup 1)
(match_dup 2)))
(clobber (match_scratch:DI 6 "=a"))]
- "TARGET_64BIT && optimize"
+ "TARGET_64BIT && optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddivu\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")])
@@ -2518,7 +3328,7 @@
(match_operand:DI 2 "se_register_operand" "d")))
(clobber (match_scratch:DI 3 "=h"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_divdi3_internal (operands[0], operands[1], operands[2]));
@@ -2547,7 +3357,7 @@
(match_operand:DI 2 "se_nonmemory_operand" "di")))
(clobber (match_scratch:SI 3 "=h"))
(clobber (match_scratch:SI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddiv\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "DI")])
@@ -2598,7 +3408,7 @@
(match_operand:DI 2 "se_register_operand" "d")))
(clobber (match_scratch:DI 3 "=l"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_moddi3_internal (operands[0], operands[1], operands[2]));
@@ -2627,7 +3437,7 @@
(match_operand:DI 2 "se_nonmemory_operand" "di")))
(clobber (match_scratch:SI 3 "=l"))
(clobber (match_scratch:SI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddiv\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "DI")])
@@ -2669,7 +3479,7 @@
(match_operand:DI 2 "se_register_operand" "di")))
(clobber (match_scratch:DI 3 "=h"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_udivdi3_internal (operands[0], operands[1], operands[2]));
@@ -2689,7 +3499,7 @@
(match_operand:DI 2 "se_nonmemory_operand" "di")))
(clobber (match_scratch:SI 3 "=h"))
(clobber (match_scratch:SI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddivu\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "DI")])
@@ -2731,7 +3541,7 @@
(match_operand:DI 2 "se_register_operand" "di")))
(clobber (match_scratch:DI 3 "=l"))
(clobber (match_scratch:DI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"
{
emit_insn (gen_umoddi3_internal (operands[0], operands[1], operands[2]));
@@ -2751,7 +3561,7 @@
(match_operand:DI 2 "se_nonmemory_operand" "di")))
(clobber (match_scratch:SI 3 "=l"))
(clobber (match_scratch:SI 4 "=a"))]
- "TARGET_64BIT && !optimize"
+ "TARGET_64BIT && !optimize && !TARGET_MIPS5900" ;; CYGNUS LOCAL law
"ddivu\\t$0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "DI")])
@@ -2775,9 +3585,19 @@
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT && HAVE_SQRT_P()"
- "sqrt.s\\t%0,%1"
+"*
+{
+if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG)
+ return \"%(nop\;nop\;sqrt.s\\t%0,%1%)\";
+ return \"sqrt.s\\t%0,%1\";
+}"
[(set_attr "type" "fsqrt")
- (set_attr "mode" "SF")])
+ (set_attr "mode" "SF")
+ (set (attr "length")
+ (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG")
+ (const_int 0))
+ (const_int 4)
+ (const_int 12)))])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -2785,7 +3605,7 @@
(sqrt:DF (match_operand:DF 2 "register_operand" "f"))))]
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math"
"rsqrt.d\\t%0,%2"
- [(set_attr "type" "fsqrt")
+ [(set_attr "type" "frsqrt") ; CYGNUS LOCAL vr5400/raeburn
(set_attr "mode" "DF")])
(define_insn ""
@@ -2793,10 +3613,37 @@
(div:SF (match_operand:SF 1 "const_float_1_operand" "")
(sqrt:SF (match_operand:SF 2 "register_operand" "f"))))]
"ISA_HAS_FP4 && TARGET_HARD_FLOAT && flag_fast_math"
- "rsqrt.s\\t%0,%2"
- [(set_attr "type" "fsqrt")
- (set_attr "mode" "SF")])
+"*
+{
+if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG)
+ return \"%(nop\;nop\;rsqrt.s\\t%0,%2%)\";
+ return \"rsqrt.s\\t%0,%2\";
+}"
+ [(set_attr "type" "frsqrt") ; CYGNUS LOCAL vr5400/raeburn
+ (set_attr "mode" "SF")
+ (set (attr "length")
+ (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG")
+ (const_int 0))
+ (const_int 4)
+ (const_int 12)))])
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (div:SF (match_operand:SF 1 "register_operand" "f")
+ (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))]
+ "TARGET_MIPS5900 && TARGET_HARD_FLOAT && flag_fast_math"
+"*
+{if (TARGET_MIPS5900 && TARGET_MIPS5900_DIVIDE_BUG)
+ return \"%(nop\;nop\;rsqrt.s\\t%0,%1,%2%)\";
+ return \"rsqrt.s\\t%0,%2\";
+}"
+ [(set_attr "type" "frsqrt")
+ (set_attr "mode" "SF")
+ (set (attr "length")
+ (if_then_else (eq (symbol_ref "TARGET_MIPS5900_DIVIDE_BUG")
+ (const_int 0))
+ (const_int 4)
+ (const_int 12)))])
;;
;; ....................
@@ -2857,6 +3704,81 @@
(set_attr "mode" "DI")
(set_attr "length" "12")])
+(define_expand "absvsi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "=d")
+ (abs:SI (match_operand:SI 1 "register_operand" "d")))
+ (trap_if (ne (abs:DI (sign_extend:DI (match_dup 1)))
+ (sign_extend:DI (abs:SI (match_dup 1))))
+ (const_int 0))])]
+"! TARGET_MIPS16"
+ "
+{
+ emit_insn (gen_absvsi2_internal (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "absvsi2_internal"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (abs:SI (match_operand:SI 1 "register_operand" "d")))
+ (trap_if (ne (abs:DI (sign_extend:DI (match_dup 1)))
+ (sign_extend:DI (abs:SI (match_dup 1))))
+ (const_int 0))]
+ "! TARGET_MIPS16"
+ "*
+{
+ dslots_jump_total++;
+ dslots_jump_filled++;
+ operands[2] = const0_rtx;
+
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ {
+ if (GENERATE_BRANCHLIKELY)
+ return \"%(bltzl\\t%1,1f\\n\\tsub\\t%0,%z2,%0\\n1:%)\";
+ else
+ return \"bgez\\t%1,1f%#\\n\\tsub\\t%0,%z2,%0\\n1:\";
+ }
+ else
+ return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tsub\\t%0,%z2,%0\\n1:%)\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_expand "absvdi2"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=d")
+ (abs:DI (match_operand:DI 1 "se_register_operand" "d")))
+ (trap_if (ne (abs:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (abs:DI (match_dup 1))))
+ (const_int 0))])]
+ "TARGET_64BIT && ! TARGET_MIPS16"
+ "
+{
+ emit_insn (gen_absvdi2_internal (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "absvdi2_internal"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (abs:DI (match_operand:DI 1 "se_register_operand" "d")))
+ (trap_if (ne (abs:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (abs:DI (match_dup 1))))
+ (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ dslots_jump_total++;
+ dslots_jump_filled++;
+ operands[2] = const0_rtx;
+
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ return \"%(bltzl\\t%1,1f\\n\\tdsub\\t%0,%z2,%0\\n1:%)\";
+ else
+ return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tdsub\\t%0,%z2,%0\\n1:%)\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "mode" "DI")
+ (set_attr "length" "4")])
+
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "register_operand" "f")))]
@@ -2877,6 +3799,41 @@
;;
;; ....................
;;
+;; MIN & MAX
+;;
+;; ....................
+;;
+
+(define_insn "minsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (if_then_else (lt:SF
+ (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f"))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_MIPS5900"
+ "min.s\\t%0,%1,%2"
+ [(set_attr "type" "move")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "maxsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (if_then_else (gt:SF
+ (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f"))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_MIPS5900"
+ "max.s\\t%0,%1,%2"
+ [(set_attr "type" "move")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+
+;;
+;; ....................
+;;
;; FIND FIRST BIT INSTRUCTION
;;
;; ....................
@@ -3018,6 +3975,59 @@
[(set_attr "type" "arith")
(set_attr "mode" "DI")])
+(define_insn "negvsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (neg:SI (match_operand:SI 1 "register_operand" "d")))
+ (trap_if (ne (neg:DI (sign_extend:DI (match_dup 1)))
+ (sign_extend:DI (neg:SI (match_dup 1))))
+ (const_int 0))]
+ ""
+ "*
+{
+ if (TARGET_MIPS16)
+ return \"neg\\t%0,%1\";
+ operands[2] = const0_rtx;
+ return \"sub\\t%0,%z2,%1\";
+}"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "1")])
+
+(define_expand "negvdi2"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "=d")
+ (neg:DI (match_operand:DI 1 "se_register_operand" "d")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))
+ (clobber (match_dup 2))])]
+ "(TARGET_64BIT || ! TARGET_DEBUG_G_MODE) && ! TARGET_MIPS16"
+ "
+{
+ if (TARGET_64BIT)
+ {
+ emit_insn (gen_negvdi2_internal_2 (operands[0], operands[1]));
+ DONE;
+ }
+
+ operands[2] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "negvdi2_internal_2"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (neg:DI (match_operand:DI 1 "se_register_operand" "d")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))]
+ "TARGET_64BIT && ! TARGET_MIPS16"
+ "*
+{
+ operands[2] = const0_rtx;
+ return \"dsub\\t%0,%z2,%1\";
+}"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "1")])
+
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "register_operand" "f")))]
@@ -3879,9 +4889,10 @@
;; general register, we can sign extend from SImode to DImode just by
;; doing a move.
+;; CYGNUS LOCAL law
(define_insn "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,y,d,*d,d,d")
- (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x,R,m")))]
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x*w,R,m")))]
"TARGET_64BIT"
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "move,move,move,hilo,load,load")
@@ -4107,6 +5118,21 @@
{
rtx xoperands[10];
+ /* ??? trunc.w.s isn't implemented on the r5900, but cvt.w.s */
+ /* truncates, so use it here. */
+ if (TARGET_MIPS5900)
+ {
+ if (which_alternative == 1)
+ return \"cvt.w.s %0,%1\";
+
+ output_asm_insn (\"cvt.w.s %3,%1\", operands);
+
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[3];
+ output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
+ return \"\";
+ }
+
if (which_alternative == 1)
return \"trunc.w.s %0,%1,%2\";
@@ -4718,6 +5744,386 @@
[(set_attr "type" "arith")
(set_attr "mode" "SI")])
+;; 128bit integer moves
+
+;; Unlike most other insns, the move insns can't be split with
+;; different predicates, because register spilling and other parts of
+;; the compiler, have memoized the insn number already.
+
+(define_expand "movti"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "")
+ (match_operand:TI 1 "general_operand" ""))]
+ "TARGET_MIPS5900"
+ "
+{
+ /* I think this code is unnecessary since we'll never split when
+ the mode is larger than UNITS_PER_WORD. */
+ if (mips_split_addresses && mips_check_split (operands[1], TImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function.
+
+ For now we abort this case on the R5900. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ abort ();
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does.
+ For now we abort this case on the R5900. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ abort ();
+
+ /* Make operand1 a register if it isn't already. */
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], TImode)
+ && !register_operand (operands[1], TImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (TImode))
+ {
+ rtx temp = force_reg (TImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
+(define_insn "movti_internal"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d")
+ (match_operand:TI 1 "movti_operand" "d,R,m,d,d,J,K,L,M,i"))]
+ "TARGET_MIPS5900
+ && (register_operand (operands[0], TImode)
+ || se_register_operand (operands[1], TImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (TImode))"
+ "@
+ por %0,$0,%1
+ lq %0,%1
+ lq %0,%1
+ sq %1,%0
+ sq %1,%0
+ por %0,%.,%.
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui
+ por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro
+ dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1"
+ [(set_attr "type" "move,load,load,store,store,move,move,move,move,move")
+;; Really DI, but not important for the cases we care about.
+ (set_attr "mode" "DI")
+;; The general li macro on a 64 bit machine can be up to 7 instructions long.
+ (set_attr "length" "4,4,4,4,4,4,8,8,32,60")])
+
+(define_expand "movv16qi"
+ [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
+ (match_operand:V16QI 1 "general_operand" ""))]
+ "TARGET_SIMD"
+ "
+{
+ /* I think this code is unnecessary since we'll never split when
+ the mode is larger than UNITS_PER_WORD. */
+ if (mips_split_addresses && mips_check_split (operands[1], V16QImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function.
+
+ For now we abort this case on the R5900. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ abort ();
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does.
+ For now we abort this case on the R5900. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ abort ();
+
+ /* Make operand1 a register if it isn't already. */
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], V16QImode)
+ && !register_operand (operands[1], V16QImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (V16QImode))
+ {
+ rtx temp = force_reg (V16QImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
+(define_expand "movv8hi"
+ [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
+ (match_operand:V8HI 1 "general_operand" ""))]
+ "TARGET_SIMD"
+ "
+{
+ /* I think this code is unnecessary since we'll never split when
+ the mode is larger than UNITS_PER_WORD. */
+ if (mips_split_addresses && mips_check_split (operands[1], V8HImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function.
+
+ For now we abort this case on the R5900. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ abort ();
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does.
+ For now we abort this case on the R5900. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ abort ();
+
+ /* Make operand1 a register if it isn't already. */
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], V8HImode)
+ && !register_operand (operands[1], V8HImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (V8HImode))
+ {
+ rtx temp = force_reg (V8HImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
+(define_expand "movv4si"
+ [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
+ (match_operand:V4SI 1 "general_operand" ""))]
+ "TARGET_SIMD"
+ "
+{
+ /* I think this code is unnecessary since we'll never split when
+ the mode is larger than UNITS_PER_WORD. */
+ if (mips_split_addresses && mips_check_split (operands[1], V4SImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function.
+
+ For now we abort this case on the R5900. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ abort ();
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does.
+ For now we abort this case on the R5900. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ abort ();
+
+ /* Make operand1 a register if it isn't already. */
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], V4SImode)
+ && !register_operand (operands[1], V4SImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (V4SImode))
+ {
+ rtx temp = force_reg (V4SImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
+(define_expand "movv2di"
+ [(set (match_operand:V2DI 0 "nonimmediate_operand" "")
+ (match_operand:V2DI 1 "general_operand" ""))]
+ "TARGET_SIMD"
+ "
+{
+ /* I think this code is unnecessary since we'll never split when
+ the mode is larger than UNITS_PER_WORD. */
+ if (mips_split_addresses && mips_check_split (operands[1], V2DImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function.
+
+ For now we abort this case on the R5900. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ abort ();
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does.
+ For now we abort this case on the R5900. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ abort ();
+
+ /* Make operand1 a register if it isn't already. */
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], V2DImode)
+ && !register_operand (operands[1], V2DImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (V2DImode))
+ {
+ rtx temp = force_reg (V2DImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
+(define_insn "movv16qi_internal"
+ [(set (match_operand:V16QI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d")
+ (match_operand:V16QI 1 "movv16qi_operand" "d,R,m,d,d,J,K,L,M,i"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V16QImode)
+ || se_register_operand (operands[1], V16QImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V16QImode))"
+ "@
+ por %0,$0,%1
+ lq %0,%1
+ lq %0,%1
+ sq %1,%0
+ sq %1,%0
+ por %0,%.,%.
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui
+ por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro
+ dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1"
+ [(set_attr "type" "move,load,load,store,store,move,move,move,move,move")
+;; Really DI, but not important for the cases we care about.
+ (set_attr "mode" "DI")
+;; The general li macro on a 64 bit machine can be up to 7 instructions long.
+ (set_attr "length" "1,1,1,1,1,1,2,2,8,15")])
+
+(define_insn "movv8hi_internal"
+ [(set (match_operand:V8HI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d")
+ (match_operand:V8HI 1 "movv8hi_operand" "d,R,m,d,d,J,K,L,M,i"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V8HImode)
+ || se_register_operand (operands[1], V8HImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V8HImode))"
+ "@
+ por %0,$0,%1
+ lq %0,%1
+ lq %0,%1
+ sq %1,%0
+ sq %1,%0
+ por %0,%.,%.
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui
+ por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro
+ dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1"
+ [(set_attr "type" "move,load,load,store,store,move,move,move,move,move")
+;; Really DI, but not important for the cases we care about.
+ (set_attr "mode" "DI")
+;; The general li macro on a 64 bit machine can be up to 7 instructions long.
+ (set_attr "length" "1,1,1,1,1,1,2,2,8,15")])
+
+(define_insn "movv4si_internal"
+ [(set (match_operand:V4SI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d")
+ (match_operand:V4SI 1 "movv4si_operand" "d,R,m,d,d,J,K,L,M,i"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V4SImode)
+ || se_register_operand (operands[1], V4SImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V4SImode))"
+ "@
+ por %0,$0,%1
+ lq %0,%1
+ lq %0,%1
+ sq %1,%0
+ sq %1,%0
+ por %0,%.,%.
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui
+ por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro
+ dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1"
+ [(set_attr "type" "move,load,load,store,store,move,move,move,move,move")
+;; Really DI, but not important for the cases we care about.
+ (set_attr "mode" "DI")
+;; The general li macro on a 64 bit machine can be up to 7 instructions long.
+ (set_attr "length" "1,1,1,1,1,1,2,2,8,15")])
+
+(define_insn "movv2di_internal"
+ [(set (match_operand:V2DI 0 "nonimmediate_operand" "=d,d,d,R,m,d,d,d,d,d")
+ (match_operand:V2DI 1 "movv2di_operand" "d,R,m,d,d,J,K,L,M,i"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V2DImode)
+ || se_register_operand (operands[1], V2DImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V2DImode))"
+ "@
+ por %0,$0,%1
+ lq %0,%1
+ lq %0,%1
+ sq %1,%0
+ sq %1,%0
+ por %0,%.,%.
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# ori
+ por\\t%0,%.,%.\;li\\t%0,%1 \\t\\t\\t# lui
+ por\\t%0,%.,%.\;dli\\t%0,%1 \\t\\t\\t# general li macro
+ dli\\t%0,%M1\;pcpyld\\t%0,%0,%.\;dli\\t%0,%L1"
+ [(set_attr "type" "move,load,load,store,store,move,move,move,move,move")
+;; Really DI, but not important for the cases we care about.
+ (set_attr "mode" "DI")
+;; The general li macro on a 64 bit machine can be up to 7 instructions long.
+ (set_attr "length" "1,1,1,1,1,1,2,2,8,15")])
;; 64-bit integer moves
;; Unlike most other insns, the move insns can't be split with
@@ -4827,6 +6233,109 @@
}
}")
+(define_expand "movv2si"
+ [(set (match_operand:V2SI 0 "nonimmediate_operand" "")
+ (match_operand:V2SI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (mips_split_addresses && mips_check_split (operands[1], V2SImode))
+ {
+ enum machine_mode mode = GET_MODE (operands[0]);
+ rtx tem = ((reload_in_progress | reload_completed)
+ ? operands[0] : gen_reg_rtx (mode));
+
+ emit_insn (gen_rtx (SET, VOIDmode, tem,
+ gen_rtx (HIGH, mode, operands[1])));
+
+ operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
+ }
+
+ /* If we are generating embedded PIC code, and we are referring to a
+ symbol in the .text section, we must use an offset from the start
+ of the function. */
+ if (TARGET_EMBEDDED_PIC
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == SYMBOL_REF
+ && ! SYMBOL_REF_FLAG (operands[1]))))
+ {
+ rtx temp;
+
+ temp = embedded_pic_offset (operands[1]);
+ temp = gen_rtx (PLUS, Pmode, embedded_pic_fnaddr_rtx,
+ force_reg (V2SImode, temp));
+ emit_move_insn (operands[0], force_reg (V2SImode, temp));
+ DONE;
+ }
+
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ {
+ rtx temp = force_reg (V2SImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
+
+ if (! SMALL_INT (temp2))
+ temp2 = force_reg (V2SImode, temp2);
+
+ emit_move_insn (operands[0], gen_rtx (PLUS, V2SImode, temp, temp2));
+ DONE;
+ }
+
+ /* On the mips16, we can handle a GP relative reference by adding in
+ $gp. We need to check the name to see whether this is a string
+ constant. */
+ if (TARGET_MIPS16
+ && register_operand (operands[0], V2SImode)
+ && GET_CODE (operands[1]) == SYMBOL_REF
+ && SYMBOL_REF_FLAG (operands[1]))
+ {
+ char *name = XSTR (operands[1], 0);
+
+ if (name[0] != '*'
+ || strncmp (name + 1, LOCAL_LABEL_PREFIX,
+ sizeof LOCAL_LABEL_PREFIX - 1) != 0)
+ {
+ rtx base_reg;
+
+ if (reload_in_progress || reload_completed)
+ {
+ /* In movsi we use the constant table here. However, in
+ this case, we're better off copying $28 into a
+ register and adding, because the constant table entry
+ would be 8 bytes. */
+ base_reg = operands[0];
+ emit_move_insn (base_reg,
+ gen_rtx (CONST, V2SImode,
+ gen_rtx (REG, V2SImode,
+ GP_REG_FIRST + 28)));
+ }
+ else
+ {
+ base_reg = gen_reg_rtx (Pmode);
+ emit_move_insn (base_reg, mips16_gp_pseudo_reg ());
+ }
+
+ emit_move_insn (operands[0],
+ gen_rtx (PLUS, Pmode, base_reg,
+ mips16_gp_offset (operands[1])));
+ DONE;
+ }
+ }
+
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], V2SImode)
+ && !register_operand (operands[1], V2SImode)
+ && (TARGET_MIPS16
+ || ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (V2SImode))))
+ {
+ rtx temp = force_reg (V2SImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+}")
+
;; For mips16, we need a special case to handle storing $31 into
;; memory, since we don't have a constraint to match $31. This
;; instruction can be generated by save_restore_insns.
@@ -4844,8 +6353,9 @@
(set_attr "mode" "DI")
(set_attr "length" "4,8")])
+;; CYGNUS LOCAL law
(define_insn "movdi_internal"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x")
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x*w,*d,*x*w")
(match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))]
"!TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode)
@@ -4857,9 +6367,23 @@
(set_attr "mode" "DI")
(set_attr "length" "8,16,8,16,8,16,8,8,8")])
+(define_insn "movv2si_internal"
+ [(set (match_operand:V2SI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x*w,*d,*x*w")
+ (match_operand:V2SI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V2SImode)
+ || register_operand (operands[1], V2SImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V2SImode))"
+ "* return mips_move_2words (operands, insn); "
+ [(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo")
+ (set_attr "mode" "V2SI")
+ (set_attr "length" "2,4,2,4,2,4,2,2,2")])
+
+;; CYGNUS LOCAL law
(define_insn ""
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,To,*d")
- (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,*x"))]
+ (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,*x*w"))]
"!TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
@@ -4879,9 +6403,10 @@
(set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))]
"")
+;; CYGNUS LOCAL law
(define_insn "movdi_internal2"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x,*d,*x,*a")
- (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x*w,*d,*x*w,*a*q")
+ (match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x*w,*d,*J"))]
"TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| se_register_operand (operands[1], DImode)
@@ -4892,9 +6417,23 @@
(set_attr "mode" "DI")
(set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,8")])
+(define_insn "movv2si_internal2"
+ [(set (match_operand:V2SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x*w,*d,*x*w,*a*q")
+ (match_operand:V2SI 1 "movv2si_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x*w,*d,*J"))]
+ "TARGET_SIMD
+ && (register_operand (operands[0], V2SImode)
+ || se_register_operand (operands[1], V2SImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
+ || operands[1] == CONST0_RTX (V2SImode))"
+ "* return mips_move_2words (operands, insn); "
+ [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo")
+ (set_attr "mode" "V2SI")
+ (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,2")])
+
+;; CYGNUS LOCAL law
(define_insn ""
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d")
- (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,*x"))]
+ (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,*x*w"))]
"TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| se_register_operand (operands[1], DImode))"
@@ -5023,6 +6562,57 @@
}
DONE;
}
+ if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO1_REGNUM)
+ {
+ if (GET_CODE (operands[1]) == MEM)
+ {
+ rtx memword, offword, hiword, loword;
+ rtx addr = find_replacement (&XEXP (operands[1], 0));
+ rtx op1 = change_address (operands[1], VOIDmode, addr);
+
+ scratch = gen_rtx (REG, SImode, REGNO (scratch));
+ memword = change_address (op1, SImode, NULL_RTX);
+ offword = change_address (adj_offsettable_operand (op1, 4),
+ SImode, NULL_RTX);
+ if (BYTES_BIG_ENDIAN)
+ {
+ hiword = memword;
+ loword = offword;
+ }
+ else
+ {
+ hiword = offword;
+ loword = memword;
+ }
+ emit_move_insn (scratch, hiword);
+ emit_move_insn (gen_rtx (REG, SImode, 76), scratch);
+ emit_move_insn (scratch, loword);
+ emit_move_insn (gen_rtx (REG, SImode, 77), scratch);
+ emit_insn (gen_rtx_USE (VOIDmode, operands[0]));
+
+ }
+ else
+ {
+ emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32)));
+ emit_insn (gen_movdi (gen_rtx (REG, DImode, 76), scratch));
+ emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32)));
+ emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_movdi (gen_rtx (REG, DImode, 77), scratch));
+ emit_insn (gen_rtx_USE (VOIDmode, operands[0]));
+ }
+ DONE;
+ }
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO1_REGNUM)
+ {
+ emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77)));
+ emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 76)));
+ emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
+ emit_insn (gen_iordi3 (operands[0], operands[0], scratch));
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+ DONE;
+ }
if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM)
{
emit_insn (gen_movdi (scratch, gen_rtx_REG (DImode, 65)));
@@ -5064,6 +6654,16 @@
emit_insn (gen_rtx_USE (VOIDmode, operands[0]));
DONE;
}
+ if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO1_REGNUM)
+ {
+ emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32)));
+ emit_insn (gen_movdi (gen_rtx (REG, DImode, 76), scratch));
+ emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32)));
+ emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_movdi (gen_rtx (REG, DImode, 77), scratch));
+ emit_insn (gen_rtx_USE (VOIDmode, operands[0]));
+ DONE;
+ }
if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM)
{
if (GET_CODE (operands[0]) == MEM)
@@ -5119,6 +6719,61 @@
}
DONE;
}
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO1_REGNUM)
+ {
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ rtx scratch, memword, offword, hiword, loword;
+ rtx addr = find_replacement (&XEXP (operands[0], 0));
+ rtx op0 = change_address (operands[0], VOIDmode, addr);
+
+ scratch = gen_rtx (REG, SImode, REGNO (operands[2]));
+ memword = change_address (op0, SImode, NULL_RTX);
+ offword = change_address (adj_offsettable_operand (op0, 4),
+ SImode, NULL_RTX);
+ if (BYTES_BIG_ENDIAN)
+ {
+ hiword = memword;
+ loword = offword;
+ }
+ else
+ {
+ hiword = offword;
+ loword = memword;
+ }
+ emit_move_insn (scratch, gen_rtx (REG, SImode, 76));
+ emit_move_insn (hiword, scratch);
+ emit_move_insn (scratch, gen_rtx (REG, SImode, 77));
+ emit_move_insn (loword, scratch);
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+ }
+ else if (TARGET_MIPS16 && ! M16_REG_P (REGNO (operands[0])))
+ {
+ /* Handle the case where operand[0] is not a 'd' register,
+ and hence we can not directly move from the HILO register
+ into it. */
+ rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1);
+ emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77)));
+ emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_movdi (scratch2, gen_rtx (REG, DImode, 76)));
+ emit_insn (gen_ashldi3 (scratch2, scratch2, GEN_INT (32)));
+ emit_insn (gen_iordi3 (scratch, scratch, scratch2));
+ emit_insn (gen_movdi (operands[0], scratch));
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+ }
+ else
+ {
+ emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 77)));
+ emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32)));
+ emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 76)));
+ emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
+ emit_insn (gen_iordi3 (operands[0], operands[0], scratch));
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+ }
+ DONE;
+ }
/* This handles moves between a float register and HI/LO. */
emit_move_insn (scratch, operands[1]);
emit_move_insn (operands[0], scratch);
@@ -5238,7 +6893,9 @@
if ((reload_in_progress | reload_completed) == 0
&& !register_operand (operands[0], SImode)
- && !register_operand (operands[1], SImode)
+ && ! (register_operand (operands[1], SImode)
+ && operands[1] != arg_pointer_rtx
+ && operands[1] != virtual_incoming_args_rtx)
&& (TARGET_MIPS16
|| GET_CODE (operands[1]) != CONST_INT
|| INTVAL (operands[1]) != 0))
@@ -5269,9 +6926,10 @@
;; The difference between these two is whether or not ints are allowed
;; in FP registers (off by default, use -mdebugh to enable).
+;; CYGNUS LOCAL law
(define_insn "movsi_internal1"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d")
- (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x*w,*x*w,*d,*d")
+ (match_operand:SI 1 "move_operand" "dA,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x*w,*a*q"))]
"TARGET_DEBUG_H_MODE && !TARGET_MIPS16
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
@@ -5281,9 +6939,10 @@
(set_attr "mode" "SI")
(set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4")])
+;; CYGNUS LOCAL law
(define_insn "movsi_internal2"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d")
- (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x*w,*d,*x*w,*d")
+ (match_operand:SI 1 "move_operand" "dA,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x*w,*d,*a*q"))]
"!TARGET_DEBUG_H_MODE && !TARGET_MIPS16
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
@@ -6326,7 +7985,7 @@
return \"sll\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")])
(define_insn "ashlsi3_internal2"
@@ -6344,7 +8003,7 @@
return \"sll\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")
(set_attr_alternative "length"
[(const_int 4)
@@ -6603,7 +8262,7 @@
return \"dsll\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")])
(define_insn ""
@@ -6621,7 +8280,7 @@
return \"dsll\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")
(set_attr_alternative "length"
[(const_int 4)
@@ -6687,7 +8346,7 @@
return \"sra\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")])
(define_insn "ashrsi3_internal2"
@@ -6705,7 +8364,7 @@
return \"sra\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")
(set_attr_alternative "length"
[(const_int 4)
@@ -6956,7 +8615,7 @@
return \"dsra\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")])
(define_insn ""
@@ -6971,7 +8630,7 @@
return \"dsra\\t%0,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")
(set_attr_alternative "length"
[(const_int 4)
@@ -7036,7 +8695,7 @@
return \"srl\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")])
(define_insn "lshrsi3_internal2"
@@ -7054,7 +8713,7 @@
return \"srl\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "SI")
(set_attr_alternative "length"
[(const_int 4)
@@ -7341,8 +9000,40 @@
return \"dsrl\\t%0,%1,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
+ (set_attr "mode" "DI")])
+
+;; CYGNUS LOCAL vr5400/raeburn
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "dn")))]
+ "TARGET_MIPS5400"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
+ return \"ror\\t%0,%1,%2\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "mode" "SI")])
+
+(define_insn "rotrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (rotatert:DI (match_operand:DI 1 "register_operand" "d")
+ (match_operand:DI 2 "arith_operand" "dn")))]
+ "TARGET_MIPS5400 && TARGET_64BIT"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
+ return \"dror\\t%0,%1,%2\";
+}"
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")])
+;; END CYGNUS LOCAL
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -7356,7 +9047,7 @@
return \"dsrl\\t%0,%2\";
}"
- [(set_attr "type" "arith")
+ [(set_attr "type" "shift")
(set_attr "mode" "DI")
(set_attr_alternative "length"
[(const_int 4)
@@ -9379,6 +11070,7 @@
(set_attr "mode" "none")
(set_attr "length" "0")])
+;; CYGNUS LOCAL sibcall/law
(define_expand "epilogue"
[(const_int 2)]
""
@@ -9386,10 +11078,23 @@
{
if (mips_isa >= 0) /* avoid unused code warnings */
{
- mips_expand_epilogue ();
+ mips_expand_epilogue (0); /* CYGNUS LOCAL sibcall/law */
+ DONE;
+ }
+}")
+
+(define_expand "sibcall_epilogue"
+ [(const_int 3)]
+ "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS"
+ "
+{
+ if (mips_isa >= 0) /* avoid unused code warnings */
+ {
+ mips_expand_epilogue (1); /* CYGNUS LOCAL sibcall/law */
DONE;
}
}")
+;; END CYGNUS LOCAL
;; Trivial return. Make it look like a normal return insn as that
;; allows jump optimizations to work better .
@@ -9446,47 +11151,10 @@
""
"
{
- rtx addr;
-
- if (operands[0]) /* eliminate unused code warnings */
- {
- addr = XEXP (operands[0], 0);
- if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
- || ! call_insn_operand (addr, VOIDmode))
- XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
-
- /* In order to pass small structures by value in registers
- compatibly with the MIPS compiler, we need to shift the value
- into the high part of the register. Function_arg has encoded
- a PARALLEL rtx, holding a vector of adjustments to be made
- as the next_arg_reg variable, so we split up the insns,
- and emit them separately. */
-
- if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL)
- {
- rtvec adjust = XVEC (operands[2], 0);
- int num = GET_NUM_ELEM (adjust);
- int i;
-
- for (i = 0; i < num; i++)
- emit_insn (RTVEC_ELT (adjust, i));
- }
-
- if (TARGET_MIPS16
- && mips16_hard_float
- && operands[2] != 0
- && (int) GET_MODE (operands[2]) != 0)
- {
- if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1],
- (int) GET_MODE (operands[2])))
- DONE;
- }
-
- emit_call_insn (gen_call_internal0 (operands[0], operands[1],
- gen_rtx_REG (SImode,
- GP_REG_FIRST + 31)));
+ /* CYGNUS LOCAL sibcall/law */
+ mips_expand_call (operands, 0);
DONE;
- }
+ /* END CYGNUS LOCAL */
}")
(define_expand "call_internal0"
@@ -9619,6 +11287,48 @@
(set_attr "mode" "none")
(set_attr "length" "8")])
+;; CYGNUS LOCAL sibcall/law
+(define_expand "sibcall"
+ [(parallel [(call (match_operand 0 "memory_operand" "m")
+ (match_operand 1 "" "i"))
+ (use (match_operand 2 "" "")) ;; next_arg_reg
+ (use (match_operand 3 "" "")) ;; struct_value_size_rtx
+ (use (reg:SI 31))])] ;; need $ra to return
+ ""
+ "
+{
+ mips_expand_call (operands, 1);
+ DONE;
+}")
+
+(define_expand "sibcall_internal0"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (reg:SI 31))])] ;; need $ra to return
+ "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS"
+ "")
+
+(define_insn "sibcall_internal1"
+ [(parallel [(call (mem (match_operand 0 "call_insn_operand" "ri"))
+ (match_operand 1 "" "i"))
+ (use (reg:SI 31))])]
+ "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS"
+ "*
+{
+ register rtx target = operands[0];
+
+ if (GET_CODE (target) == SYMBOL_REF)
+ return \"%*j\\t%0\";
+ else if (GET_CODE (target) == CONST_INT)
+ return \"%[li\\t%@,%0\\n\\t%*j\\t%@%]\";
+ else
+ return \"%*j\\t%0\";
+}"
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+;; END CYGNUS LOCAL
+
;; calls.c now passes a fourth argument, make saber happy
(define_expand "call_value"
@@ -9632,65 +11342,10 @@
{
rtx addr;
- if (operands[0]) /* eliminate unused code warning */
- {
- addr = XEXP (operands[1], 0);
- if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
- || ! call_insn_operand (addr, VOIDmode))
- XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
-
- /* In order to pass small structures by value in registers
- compatibly with the MIPS compiler, we need to shift the value
- into the high part of the register. Function_arg has encoded
- a PARALLEL rtx, holding a vector of adjustments to be made
- as the next_arg_reg variable, so we split up the insns,
- and emit them separately. */
-
- if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL)
- {
- rtvec adjust = XVEC (operands[3], 0);
- int num = GET_NUM_ELEM (adjust);
- int i;
-
- for (i = 0; i < num; i++)
- emit_insn (RTVEC_ELT (adjust, i));
- }
-
- if (TARGET_MIPS16
- && mips16_hard_float
- && ((operands[3] != 0
- && (int) GET_MODE (operands[3]) != 0)
- || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT))
- {
- if (build_mips16_call_stub (operands[0], operands[1], operands[2],
- (operands[3] == 0 ? 0
- : (int) GET_MODE (operands[3]))))
- DONE;
- }
-
- /* Handle Irix6 function calls that have multiple non-contiguous
- results. */
- if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1)
- {
- emit_call_insn (gen_call_value_multiple_internal0
- (XEXP (XVECEXP (operands[0], 0, 0), 0),
- operands[1], operands[2],
- XEXP (XVECEXP (operands[0], 0, 1), 0),
- gen_rtx_REG (SImode, GP_REG_FIRST + 31)));
- DONE;
- }
-
- /* We have a call returning a DImode structure in an FP reg.
- Strip off the now unnecessary PARALLEL. */
- if (GET_CODE (operands[0]) == PARALLEL)
- operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
-
- emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2],
- gen_rtx_REG (SImode,
- GP_REG_FIRST + 31)));
-
+ /* CYGNUS LOCAL sibcall/law */
+ mips_expand_call_value (operands, 0);
DONE;
- }
+ /* END CYGNUS LOCAL */
}")
(define_expand "call_value_internal0"
@@ -9831,6 +11486,52 @@
(set_attr "mode" "none")
(set_attr "length" "8")])
+;; CYGNUS LOCAL sibcall/law
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0 "register_operand" "=df")
+ (call (match_operand 1 "memory_operand" "m")
+ (match_operand 2 "" "i")))
+ (use (match_operand 3 "" "")) ;; next_arg_reg
+ (use (reg:SI 31))])] ;; need $ra to return
+ ""
+ "
+{
+ rtx addr;
+
+ mips_expand_call_value (operands, 1);
+ DONE;
+}")
+
+(define_expand "sibcall_value_internal0"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (use (reg:SI 31))])] ;; need $ra to return
+ ""
+ "")
+
+(define_insn "sibcall_value_internal1"
+ [(parallel [(set (match_operand 0 "register_operand" "=df")
+ (call (mem (match_operand 1 "call_insn_operand" "ri"))
+ (match_operand 2 "" "i")))
+ (use (reg:SI 31))])] ;; need $ra to return
+ "!TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS"
+ "*
+{
+ register rtx target = operands[1];
+
+ if (GET_CODE (target) == SYMBOL_REF)
+ return \"%*j\\t%1\";
+ else if (GET_CODE (target) == CONST_INT)
+ return \"%[li\\t%@,%1\\n\\t%*j\\t%@%]\";
+ else
+ return \"%*j\\t%1\";
+}"
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+;; END CYGNUS LOCAL
+
(define_expand "call_value_multiple_internal0"
[(parallel [(set (match_operand 0 "" "")
(call (match_operand 1 "" "")
@@ -9914,7 +11615,7 @@
{
int i;
- emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
@@ -9973,7 +11674,7 @@
"@
mov%B4\\t%0,%z2,%1
mov%b4\\t%0,%z3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SI")])
(define_insn ""
@@ -9988,7 +11689,7 @@
"@
mov%B4\\t%0,%z2,%1
mov%b4\\t%0,%z3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SI")])
(define_insn ""
@@ -10004,7 +11705,7 @@
"@
mov%T3\\t%0,%z1,%4
mov%t3\\t%0,%z2,%4"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SI")])
(define_insn ""
@@ -10019,7 +11720,7 @@
"@
mov%B4\\t%0,%z2,%1
mov%b4\\t%0,%z3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DI")])
(define_insn ""
@@ -10034,7 +11735,7 @@
"@
mov%B4\\t%0,%z2,%1
mov%b4\\t%0,%z3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DI")])
(define_insn ""
@@ -10050,7 +11751,7 @@
"@
mov%T3\\t%0,%z1,%4
mov%t3\\t%0,%z2,%4"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DI")])
(define_insn ""
@@ -10065,7 +11766,7 @@
"@
mov%B4.s\\t%0,%2,%1
mov%b4.s\\t%0,%3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SF")])
(define_insn ""
@@ -10080,7 +11781,7 @@
"@
mov%B4.s\\t%0,%2,%1
mov%b4.s\\t%0,%3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SF")])
(define_insn ""
@@ -10096,7 +11797,7 @@
"@
mov%T3.s\\t%0,%1,%4
mov%t3.s\\t%0,%2,%4"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "SF")])
(define_insn ""
@@ -10111,7 +11812,7 @@
"@
mov%B4.d\\t%0,%2,%1
mov%b4.d\\t%0,%3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DF")])
(define_insn ""
@@ -10126,7 +11827,7 @@
"@
mov%B4.d\\t%0,%2,%1
mov%b4.d\\t%0,%3,%1"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DF")])
(define_insn ""
@@ -10142,7 +11843,7 @@
"@
mov%T3.d\\t%0,%1,%4
mov%t3.d\\t%0,%2,%4"
- [(set_attr "type" "move")
+ [(set_attr "type" "cmove")
(set_attr "mode" "DF")])
;; These are the main define_expand's used to make conditional moves.
@@ -10156,6 +11857,10 @@
"ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE"
"
{
+ if (TARGET_MIPS5900
+ && GET_MODE_CLASS (GET_MODE (branch_cmp[0])) == MODE_FLOAT)
+ FAIL;
+
gen_conditional_move (operands);
DONE;
}")
@@ -10169,6 +11874,11 @@
"ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE"
"
{
+ if (TARGET_MIPS5900
+ && GET_MODE_CLASS (GET_MODE (branch_cmp[0])) == MODE_FLOAT)
+ FAIL;
+
+
gen_conditional_move (operands);
DONE;
}")
@@ -10455,3 +12165,1371 @@
[(set_attr "type" "arith")
(set_attr "mode" "DI")
(set_attr "length" "40")])
+
+(define_insn "mips5900_pabsh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 40))]
+ "TARGET_SIMD"
+ "pabsh\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pabsw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 41))]
+ "TARGET_SIMD"
+ "pabsw\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 42))]
+ "TARGET_SIMD"
+ "paddb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 43))]
+ "TARGET_SIMD"
+ "paddh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddsb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 44))]
+ "TARGET_SIMD"
+ "paddsb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddsh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 45))]
+ "TARGET_SIMD"
+ "paddsh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddsw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 46))]
+ "TARGET_SIMD"
+ "paddsw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddub"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 47))]
+ "TARGET_SIMD"
+ "paddub\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_padduh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 48))]
+ "TARGET_SIMD"
+ "padduh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_padduw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 49))]
+ "TARGET_SIMD"
+ "padduw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_paddw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 50))]
+ "TARGET_SIMD"
+ "paddw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_padsbh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 51))]
+ "TARGET_SIMD"
+ "padsbh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pand"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 52))]
+ "TARGET_SIMD"
+ "pand\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pceqb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 53))]
+ "TARGET_SIMD"
+ "pceqb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pceqh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 54))]
+ "TARGET_SIMD"
+ "pceqh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pceqw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 55))]
+ "TARGET_SIMD"
+ "pceqw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcgtb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 56))]
+ "TARGET_SIMD"
+ "pcgtb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcgth"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 57))]
+ "TARGET_SIMD"
+ "pcgth\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcgtw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 58))]
+ "TARGET_SIMD"
+ "pcgtw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcpyh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 59))]
+ "TARGET_SIMD"
+ "pcpyh\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcpyld"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 60))]
+ "TARGET_SIMD"
+ "pcpyld\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pcpyud"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 61))]
+ "TARGET_SIMD"
+ "pcpyud\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pdivbw"
+ [(set (match_operand:V4SI 0 "register_operand" "=a")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 62))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pdivbw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pdivbw_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=a")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 62))
+ (clobber (match_operand:V4SI 3 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pdivbw\\t%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pexch"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 63))]
+ "TARGET_SIMD"
+ "pexch\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pexcw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 64))]
+ "TARGET_SIMD"
+ "pexcw\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pexeh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 65))]
+ "TARGET_SIMD"
+ "pexeh\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pexew"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 66))]
+ "TARGET_SIMD"
+ "pexew\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pext5"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")] 67))]
+ "TARGET_SIMD"
+ "pext5\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextlb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 68))]
+ "TARGET_SIMD"
+ "pextlb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextlh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 69))]
+ "TARGET_SIMD"
+ "pextlh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextlw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 70))]
+ "TARGET_SIMD"
+ "pextlw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextub"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 71))]
+ "TARGET_SIMD"
+ "pextub\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextuh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 72))]
+ "TARGET_SIMD"
+ "pextuh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pextuw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 73))]
+ "TARGET_SIMD"
+ "pextuw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pinth"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 74))]
+ "TARGET_SIMD"
+ "pinth\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pinteh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 75))]
+ "TARGET_SIMD"
+ "pinteh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_plzcw"
+ [(set (match_operand:V2SI 0 "register_operand" "=d")
+ (unspec:V2SI [(match_operand:V2SI 1 "register_operand" "d")] 76))]
+ "TARGET_SIMD"
+ "plzcw\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmaxh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 77))]
+ "TARGET_SIMD"
+ "pmaxh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmaxw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 78))]
+ "TARGET_SIMD"
+ "pmaxw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pminh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 79))]
+ "TARGET_SIMD"
+ "pminh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pminw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 80))]
+ "TARGET_SIMD"
+ "pminw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pnor"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 81))]
+ "TARGET_SIMD"
+ "pnor\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_por"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 82))]
+ "TARGET_SIMD"
+ "por\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_ppac5"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V4SI 1 "register_operand" "d")] 83))]
+ "TARGET_SIMD"
+ "ppac5\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_ppacb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 84))]
+ "TARGET_SIMD"
+ "ppacb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_ppach"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 85))]
+ "TARGET_SIMD"
+ "ppach\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_ppacw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 86))]
+ "TARGET_SIMD"
+ "ppacw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_prevh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")] 87))]
+ "TARGET_SIMD"
+ "prevh\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_prot3w"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")] 88))]
+ "TARGET_SIMD"
+ "prot3w\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psllh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 89))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0xf;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psllh_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psllh_internal"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 89))]
+ "TARGET_SIMD"
+ "psllh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psllvw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 90))]
+ "TARGET_SIMD"
+ "psllvw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psllw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 91))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0x1f;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psllw_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psllw_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 91))]
+ "TARGET_SIMD"
+ "psllw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psrah"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 92))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0xf;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psrah_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psrah_internal"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 92))]
+ "TARGET_SIMD"
+ "psrah\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psravw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 93))]
+ "TARGET_SIMD"
+ "psravw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psraw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 94))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0x1f;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psraw_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psraw_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 94))]
+ "TARGET_SIMD"
+ "psraw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psrlh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 95))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0xf;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psrlh_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psrlh_internal"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 95))]
+ "TARGET_SIMD"
+ "psrlh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psrlvw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 96))]
+ "TARGET_SIMD"
+ "psrlvw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_psrlw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_or_int_operand" "")] 97))]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ x = INTVAL (operands[2]);
+ x &= 0x1f;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[2] = GEN_INT (x);
+ emit_insn (gen_mips5900_psrlw_internal (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mips5900_psrlw_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:SI 2 "const_int_operand" "")] 97))]
+ "TARGET_SIMD"
+ "psrlw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 98))]
+ "TARGET_SIMD"
+ "psubb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 99))]
+ "TARGET_SIMD"
+ "psubh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubsb"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 100))]
+ "TARGET_SIMD"
+ "psubsb\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubsh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 101))]
+ "TARGET_SIMD"
+ "psubsh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubsw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 102))]
+ "TARGET_SIMD"
+ "psubsw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubub"
+ [(set (match_operand:V16QI 0 "register_operand" "=d")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "d")
+ (match_operand:V16QI 2 "register_operand" "d")] 103))]
+ "TARGET_SIMD"
+ "psubub\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V16QI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubuh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 104))]
+ "TARGET_SIMD"
+ "psubuh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubuw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 105))]
+ "TARGET_SIMD"
+ "psubuw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_psubw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 106))]
+ "TARGET_SIMD"
+ "psubw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pxor"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 107))]
+ "TARGET_SIMD"
+ "pxor\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_mtsa"
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "d")] 108)]
+ "TARGET_SIMD"
+ "mtsa\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "none")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_mfsa"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (unspec:DI [(const_int 0)] 109))]
+ "TARGET_SIMD"
+ "mfsa\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_mtsab"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "register_or_int_operand" "")] 109)]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ x = INTVAL (operands[1]);
+ x &= 0xffff;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[1] = GEN_INT (x);
+ emit_insn (gen_mips5900_mtsab_internal (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "mips5900_mtsab_internal"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "const_int_operand" "")] 109)]
+ "TARGET_SIMD"
+ "mtsab\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "none")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_mtsah"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "register_or_int_operand" "")] 110)]
+ ""
+ "
+{
+ int x;
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ x = INTVAL (operands[1]);
+ x &= 0xffff;
+ }
+ else
+ x = 0; /* nop if operand is not const int */
+ operands[1] = GEN_INT (x);
+ emit_insn (gen_mips5900_mtsah_internal (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "mips5900_mtsah_internal"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "const_int_operand" "")] 110)]
+ "TARGET_SIMD"
+ "mtsah\\t%0,%1"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "none")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_qfsrv"
+ [(set (match_operand:TI 0 "register_operand" "=d")
+ (unspec:TI [(match_operand:TI 1 "register_operand" "d")
+ (match_operand:TI 2 "register_operand" "d")] 111))]
+ "TARGET_SIMD"
+ "qfsrv\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "TI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhi"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(const_int 0)] 112))
+; (use (reg:V2DI 64)) ; HI register
+; (use (reg:V2DI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhi\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmflo"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(const_int 0)] 113))
+; (use (reg:V2DI 65)) ; LO register
+; (use (reg:V2DI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmflo\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhl_lw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(const_int 0)] 114))
+; (use (reg:V4SI 65)) ; LO register
+; (use (reg:V4SI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhl.lw\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhl_uw"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(const_int 0)] 115))
+; (use (reg:V4SI 65)) ; LO register
+; (use (reg:V4SI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhl.uw\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhl_slw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(const_int 0)] 116))
+; (use (reg:V2DI 65)) ; LO register
+; (use (reg:V2DI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhl.slw\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhl_lh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(const_int 0)] 117))
+; (use (reg:V8HI 65)) ; LO register
+; (use (reg:V8HI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhl.lh\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_insn "mips5900_pmfhl_sh"
+ [(set (match_operand:V8HI 0 "register_operand" "=d")
+ (unspec:V8HI [(const_int 0)] 118))
+; (use (reg:V8HI 65)) ; LO register
+; (use (reg:V8HI 66)) ; HILO register
+ ]
+ "TARGET_SIMD"
+ "pmfhl.sh\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V8HI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pdivuw"
+ [(set (match_operand:V2DI 0 "register_operand" "=a")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 119))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pdivuw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pdivuw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=a")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 119))
+ (clobber (match_operand:V2DI 3 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pdivuw\\t%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pdivw"
+ [(set (match_operand:V2DI 0 "register_operand" "=a")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 120))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pdivw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pdivw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=a")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "d")
+ (match_operand:V2DI 2 "register_operand" "d")] 120))
+ (clobber (match_operand:V2DI 3 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pdivw\\t%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_phmadh"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 121))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_phmadh_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_phmadh_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 121))
+ (clobber (match_operand:V4SI 3 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "phmadh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_phmsbh"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 122))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_phmsbh_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_phmsbh_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 122))
+ (clobber (match_operand:V4SI 3 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "phmsbh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmaddh"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 123))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmaddh_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmaddh_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 123))
+ (clobber (match_operand:V4SI 3 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmaddh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmadduw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 124))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmadduw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmadduw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 124))
+ (clobber (match_operand:V2DI 3 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmadduw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmaddw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 125))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmaddw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmaddw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 125))
+ (clobber (match_operand:V2DI 3 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmaddw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmsubh"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 126))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmsubh_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmsubh_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 126))
+ (clobber (match_operand:V4SI 3 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmsubh\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmsubw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 127))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmsubw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmsubw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 127))
+ (clobber (match_operand:V2DI 3 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmsubw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmthi"
+ [(unspec [(match_operand:V2DI 0 "register_operand" "d")] 128)]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmthi_internal (operands[0],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmthi_internal"
+ [(unspec:V2DI [(match_operand:V2DI 0 "register_operand" "d")] 128)
+ (clobber (match_operand:V2DI 1 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 2 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmthi\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmtlo"
+ [(unspec [(match_operand:V2DI 0 "register_operand" "d")] 129)]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmtlo_internal (operands[0],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmtlo_internal"
+ [(unspec:V2DI [(match_operand:V2DI 0 "register_operand" "d")] 129)
+ (clobber (match_operand:V2DI 1 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 2 "register_operand" "=l"))]
+ "TARGET_SIMD"
+ "pmtlo\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmthl_lw"
+ [(unspec [(match_operand:V4SI 0 "register_operand" "d")] 130)]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmthl_lw_internal (operands[0],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmthl_lw_internal"
+ [(unspec:V4SI [(match_operand:V4SI 0 "register_operand" "d")] 130)
+ (clobber (match_operand:V4SI 1 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 2 "register_operand" "=h"))
+ (clobber (match_operand:V4SI 3 "register_operand" "=l"))]
+ "TARGET_SIMD"
+ "pmthl.lw\\t%0"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmulth"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 131))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmulth_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode),
+ gen_reg_rtx (V4SImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmulth_internal"
+ [(set (match_operand:V4SI 0 "register_operand" "=d")
+ (unspec:V4SI [(match_operand:V8HI 1 "register_operand" "d")
+ (match_operand:V8HI 2 "register_operand" "d")] 131))
+ (clobber (match_operand:V4SI 3 "register_operand" "=a"))
+ (clobber (match_operand:V4SI 4 "register_operand" "=l"))
+ (clobber (match_operand:V4SI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmulth\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V4SI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmultuw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 132))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmultuw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmultuw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 132))
+ (clobber (match_operand:V2DI 3 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmultuw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
+
+(define_expand "mips5900_pmultw"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 133))]
+ "TARGET_SIMD"
+ "
+{
+ emit_insn (gen_mips5900_pmultw_internal (operands[0], operands[1],
+ operands[2],
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode),
+ gen_reg_rtx (V2DImode)));
+ DONE;
+}")
+
+(define_insn "mips5900_pmultw_internal"
+ [(set (match_operand:V2DI 0 "register_operand" "=d")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "d")
+ (match_operand:V4SI 2 "register_operand" "d")] 133))
+ (clobber (match_operand:V2DI 3 "register_operand" "=a"))
+ (clobber (match_operand:V2DI 4 "register_operand" "=l"))
+ (clobber (match_operand:V2DI 5 "register_operand" "=h"))]
+ "TARGET_SIMD"
+ "pmultw\\t%0,%1,%2"
+ [(set_attr "type" "simd")
+ (set_attr "mode" "V2DI")
+ (set_attr "length" "1")])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment