static unsigned
loongarch_pass_aggregate_num_fpr (const_tree type,
- loongarch_aggregate_field fields[2])
+ loongarch_aggregate_field fields[2])
{
int n = loongarch_flatten_aggregate_argument (type, fields);
{
rtx ptr = plus_constant (Pmode, virtual_incoming_args_rtx,
REG_PARM_STACK_SPACE (cfun->decl)
- - gp_saved * UNITS_PER_WORD);
+ - gp_saved * UNITS_PER_WORD);
rtx mem = gen_frame_mem (BLKmode, ptr);
set_mem_alias_set (mem, get_varargs_alias_set ());
loongarch_emit_move (rtx dest, rtx src)
{
return (can_create_pseudo_p () ? emit_move_insn (dest, src)
- : emit_move_insn_1 (dest, src));
+ : emit_move_insn_1 (dest, src));
}
/* Save register REG to MEM. Make the instruction frame-related. */
return false;
}
+/* Return true if OP is a constant vector with the number of units in MODE,
+ and each unit has the same bit set. */
+
+bool
+loongarch_const_vector_bitimm_set_p (rtx op, machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_VECTOR && op != CONST0_RTX (mode))
+ {
+ unsigned HOST_WIDE_INT val = UINTVAL (CONST_VECTOR_ELT (op, 0));
+ int vlog2 = exact_log2 (val & GET_MODE_MASK (GET_MODE_INNER (mode)));
+
+ if (vlog2 != -1)
+ {
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
+ gcc_assert (vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE (mode) - 1);
+ return loongarch_const_vector_same_val_p (op, mode);
+ }
+ }
+
+ return false;
+}
+
+/* Return true if OP is a constant vector with the number of units in MODE,
+ and each unit has the same bit clear. */
+
+bool
+loongarch_const_vector_bitimm_clr_p (rtx op, machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_VECTOR && op != CONSTM1_RTX (mode))
+ {
+ unsigned HOST_WIDE_INT val = ~UINTVAL (CONST_VECTOR_ELT (op, 0));
+ int vlog2 = exact_log2 (val & GET_MODE_MASK (GET_MODE_INNER (mode)));
+
+ if (vlog2 != -1)
+ {
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
+ gcc_assert (vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE (mode) - 1);
+ return loongarch_const_vector_same_val_p (op, mode);
+ }
+ }
+
+ return false;
+}
+
+/* Return true if OP is a constant vector with the number of units in MODE,
+ and each unit has the same value. */
+
+bool
+loongarch_const_vector_same_val_p (rtx op, machine_mode mode)
+{
+ int i, nunits = GET_MODE_NUNITS (mode);
+ rtx first;
+
+ if (GET_CODE (op) != CONST_VECTOR || GET_MODE (op) != mode)
+ return false;
+
+ first = CONST_VECTOR_ELT (op, 0);
+ for (i = 1; i < nunits; i++)
+ if (!rtx_equal_p (first, CONST_VECTOR_ELT (op, i)))
+ return false;
+
+ return true;
+}
+
+/* Return true if OP is a constant vector with the number of units in MODE,
+ and each unit has the same value as well as replicated bytes in the value.
+*/
+
+bool
+loongarch_const_vector_same_bytes_p (rtx op, machine_mode mode)
+{
+ int i, bytes;
+ HOST_WIDE_INT val, first_byte;
+ rtx first;
+
+ if (!loongarch_const_vector_same_val_p (op, mode))
+ return false;
+
+ first = CONST_VECTOR_ELT (op, 0);
+ bytes = GET_MODE_UNIT_SIZE (mode);
+ val = INTVAL (first);
+ first_byte = val & 0xff;
+ for (i = 1; i < bytes; i++)
+ {
+ val >>= 8;
+ if ((val & 0xff) != first_byte)
+ return false;
+ }
+
+ return true;
+}
+
+/* Return true if OP is a constant vector with the number of units in MODE,
+ and each unit has the same integer value in the range [LOW, HIGH]. */
+
+bool
+loongarch_const_vector_same_int_p (rtx op, machine_mode mode, HOST_WIDE_INT low,
+ HOST_WIDE_INT high)
+{
+ HOST_WIDE_INT value;
+ rtx elem0;
+
+ if (!loongarch_const_vector_same_val_p (op, mode))
+ return false;
+
+ elem0 = CONST_VECTOR_ELT (op, 0);
+ if (!CONST_INT_P (elem0))
+ return false;
+
+ value = INTVAL (elem0);
+ return (value >= low && value <= high);
+}
+
+/* Return true if OP is a constant vector with repeated 4-element sets
+ in mode MODE. */
+
+bool
+loongarch_const_vector_shuffle_set_p (rtx op, machine_mode mode)
+{
+ int nunits = GET_MODE_NUNITS (mode);
+ int nsets = nunits / 4;
+ int set = 0;
+ int i, j;
+
+ /* Check if we have the same 4-element sets. */
+ for (j = 0; j < nsets; j++, set = 4 * j)
+ for (i = 0; i < 4; i++)
+ if ((INTVAL (XVECEXP (op, 0, i))
+ != (INTVAL (XVECEXP (op, 0, set + i)) - set))
+ || !IN_RANGE (INTVAL (XVECEXP (op, 0, set + i)), 0, set + 3))
+ return false;
+ return true;
+}
+
/* Return true if rtx constants of mode MODE should be put into a small
data section. */
static int
loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode)
{
+ /* LSX LD.* and ST.* cannot support loading symbols via an immediate
+ operand. */
+ if (LSX_SUPPORTED_MODE_P (mode))
+ return 0;
+
switch (type)
{
case SYMBOL_GOT_DISP:
references, reload will consider forcing C into memory and using
one of the instruction's memory alternatives. Returning false
here will force it to use an input reload instead. */
- if (CONST_INT_P (x) && loongarch_legitimate_constant_p (mode, x))
+ if ((CONST_INT_P (x) || GET_CODE (x) == CONST_VECTOR)
+ && loongarch_legitimate_constant_p (mode, x))
return true;
split_const (x, &base, &offset);
&& !IMM12_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode) - UNITS_PER_WORD))
return false;
+ /* LSX LD.* and ST.* supports 10-bit signed offsets. */
+ if (LSX_SUPPORTED_MODE_P (mode)
+ && !loongarch_signed_immediate_p (INTVAL (x), 10,
+ loongarch_ldst_scaled_shift (mode)))
+ return false;
+
return true;
}
static bool
loongarch_valid_index_p (struct loongarch_address_info *info, rtx x,
- machine_mode mode, bool strict_p)
+ machine_mode mode, bool strict_p)
{
rtx index;
}
if (loongarch_valid_base_register_p (XEXP (x, 1), mode, strict_p)
- && loongarch_valid_index_p (info, XEXP (x, 0), mode, strict_p))
+ && loongarch_valid_index_p (info, XEXP (x, 0), mode, strict_p))
{
info->reg = XEXP (x, 1);
return true;
{
struct loongarch_address_info addr;
int factor;
+ bool lsx_p = !might_split_p && LSX_SUPPORTED_MODE_P (mode);
if (!loongarch_classify_address (&addr, x, mode, false))
return 0;
switch (addr.type)
{
case ADDRESS_REG:
+ if (lsx_p)
+ {
+ /* LSX LD.* and ST.* supports 10-bit signed offsets. */
+ if (loongarch_signed_immediate_p (INTVAL (addr.offset), 10,
+ loongarch_ldst_scaled_shift (mode)))
+ return 1;
+ else
+ return 0;
+ }
+ return factor;
+
case ADDRESS_REG_REG:
- case ADDRESS_CONST_INT:
return factor;
+ case ADDRESS_CONST_INT:
+ return lsx_p ? 0 : factor;
+
case ADDRESS_LO_SUM:
return factor + 1;
case ADDRESS_SYMBOLIC:
- return factor * loongarch_symbol_insns (addr.symbol_type, mode);
+ return lsx_p ? 0
+ : factor * loongarch_symbol_insns (addr.symbol_type, mode);
}
return 0;
}
return loongarch_unsigned_immediate_p (x, bits, shift);
}
+/* Return the scale shift that applied to LSX LD/ST address offset. */
+
+int
+loongarch_ldst_scaled_shift (machine_mode mode)
+{
+ int shift = exact_log2 (GET_MODE_UNIT_SIZE (mode));
+
+ if (shift < 0 || shift > 8)
+ gcc_unreachable ();
+
+ return shift;
+}
+
/* Return true if X is a legitimate address with a 12-bit offset
or addr.type is ADDRESS_LO_SUM.
MODE is the mode of the value being accessed. */
return loongarch_integer_cost (INTVAL (x));
case CONST_VECTOR:
+ if (LSX_SUPPORTED_MODE_P (GET_MODE (x))
+ && loongarch_const_vector_same_int_p (x, GET_MODE (x), -512, 511))
+ return 1;
/* Fall through. */
case CONST_DOUBLE:
return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
case SYMBOL_REF:
case LABEL_REF:
return loongarch_symbol_insns (
- loongarch_classify_symbol (x), MAX_MACHINE_MODE);
+ loongarch_classify_symbol (x), MAX_MACHINE_MODE);
default:
return 0;
return low + high;
}
-static bool loongarch_split_move_insn_p (rtx dest, rtx src);
+bool loongarch_split_move_insn_p (rtx dest, rtx src);
+/* Return one word of 128-bit value OP, taking into account the fixed
+ endianness of certain registers. BYTE selects from the byte address. */
+
+rtx
+loongarch_subword_at_byte (rtx op, unsigned int byte)
+{
+ machine_mode mode;
+
+ mode = GET_MODE (op);
+ if (mode == VOIDmode)
+ mode = TImode;
+
+ gcc_assert (!FP_REG_RTX_P (op));
+
+ if (MEM_P (op))
+ return loongarch_rewrite_small_data (adjust_address (op, word_mode, byte));
+
+ return simplify_gen_subreg (word_mode, op, mode, byte);
+}
/* Return the number of instructions needed to implement INSN,
given that it loads from or stores to MEM. */
/* Both src and dest are non-registers; one special case is supported where
the source is (const_int 0) and the store can source the zero register.
- */
+ LSX is never able to source the zero register directly in
+ memory operations. */
if (!register_operand (dest, mode) && !register_operand (src, mode)
- && !const_0_operand (src, mode))
+ && (!const_0_operand (src, mode) || LSX_SUPPORTED_MODE_P (mode)))
{
loongarch_emit_move (dest, force_reg (mode, src));
return true;
}
}
+/* Vectorizer cost model implementation. */
+
+/* Implement targetm.vectorize.builtin_vectorization_cost. */
+
+static int
+loongarch_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
+ tree vectype,
+ int misalign ATTRIBUTE_UNUSED)
+{
+ unsigned elements;
+
+ switch (type_of_cost)
+ {
+ case scalar_stmt:
+ case scalar_load:
+ case vector_stmt:
+ case vector_load:
+ case vec_to_scalar:
+ case scalar_to_vec:
+ case cond_branch_not_taken:
+ case vec_promote_demote:
+ case scalar_store:
+ case vector_store:
+ return 1;
+
+ case vec_perm:
+ return 1;
+
+ case unaligned_load:
+ case vector_gather_load:
+ return 2;
+
+ case unaligned_store:
+ case vector_scatter_store:
+ return 10;
+
+ case cond_branch_taken:
+ return 3;
+
+ case vec_construct:
+ elements = TYPE_VECTOR_SUBPARTS (vectype);
+ return elements / 2 + 1;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Implement TARGET_ADDRESS_COST. */
static int
if (FP_REG_RTX_P (src) && MEM_P (dest))
return false;
}
+
+ /* Check if LSX moves need splitting. */
+ if (LSX_SUPPORTED_MODE_P (GET_MODE (dest)))
+ return loongarch_split_128bit_move_p (dest, src);
+
/* Otherwise split all multiword moves. */
return size > UNITS_PER_WORD;
}
rtx low_dest;
gcc_checking_assert (loongarch_split_move_p (dest, src));
- if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src))
+ if (LSX_SUPPORTED_MODE_P (GET_MODE (dest)))
+ loongarch_split_128bit_move (dest, src);
+ else if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src))
{
if (!TARGET_64BIT && GET_MODE (dest) == DImode)
emit_insn (gen_move_doubleword_fprdi (dest, src));
/* Return true if a move from SRC to DEST in INSN should be split. */
-static bool
+bool
loongarch_split_move_insn_p (rtx dest, rtx src)
{
return loongarch_split_move_p (dest, src);
}
+/* Split a move from SRC to DEST in INSN, given that
+ loongarch_split_move_insn_p holds. */
+
+void
+loongarch_split_move_insn (rtx dest, rtx src, rtx insn)
+{
+ loongarch_split_move (dest, src, insn);
+}
+
/* Implement TARGET_CONSTANT_ALIGNMENT. */
static HOST_WIDE_INT
loongarch_output_move_index_float (rtx x, machine_mode mode, bool ldr)
{
int index = exact_log2 (GET_MODE_SIZE (mode));
- if (!IN_RANGE (index, 2, 3))
+ if (!IN_RANGE (index, 2, 4))
return NULL;
struct loongarch_address_info info;
|| !loongarch_legitimate_address_p (mode, x, false))
return NULL;
- const char *const insn[][2] =
+ const char *const insn[][3] =
{
{
"fstx.s\t%1,%0",
- "fstx.d\t%1,%0"
+ "fstx.d\t%1,%0",
+ "vstx\t%w1,%0"
},
{
"fldx.s\t%0,%1",
- "fldx.d\t%0,%1"
- },
+ "fldx.d\t%0,%1",
+ "vldx\t%w0,%1"
+ }
};
return insn[ldr][index-2];
}
+/* Return true if a 128-bit move from SRC to DEST should be split. */
+
+bool
+loongarch_split_128bit_move_p (rtx dest, rtx src)
+{
+ /* LSX-to-LSX moves can be done in a single instruction. */
+ if (FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
+ return false;
+
+ /* Check for LSX loads and stores. */
+ if (FP_REG_RTX_P (dest) && MEM_P (src))
+ return false;
+ if (FP_REG_RTX_P (src) && MEM_P (dest))
+ return false;
+
+ /* Check for LSX set to an immediate const vector with valid replicated
+ element. */
+ if (FP_REG_RTX_P (dest)
+ && loongarch_const_vector_same_int_p (src, GET_MODE (src), -512, 511))
+ return false;
+
+ /* Check for LSX load zero immediate. */
+ if (FP_REG_RTX_P (dest) && src == CONST0_RTX (GET_MODE (src)))
+ return false;
+
+ return true;
+}
+
+/* Split a 128-bit move from SRC to DEST. */
+
+void
+loongarch_split_128bit_move (rtx dest, rtx src)
+{
+ int byte, index;
+ rtx low_dest, low_src, d, s;
+
+ if (FP_REG_RTX_P (dest))
+ {
+ gcc_assert (!MEM_P (src));
+
+ rtx new_dest = dest;
+ if (!TARGET_64BIT)
+ {
+ if (GET_MODE (dest) != V4SImode)
+ new_dest = simplify_gen_subreg (V4SImode, dest, GET_MODE (dest), 0);
+ }
+ else
+ {
+ if (GET_MODE (dest) != V2DImode)
+ new_dest = simplify_gen_subreg (V2DImode, dest, GET_MODE (dest), 0);
+ }
+
+ for (byte = 0, index = 0; byte < GET_MODE_SIZE (TImode);
+ byte += UNITS_PER_WORD, index++)
+ {
+ s = loongarch_subword_at_byte (src, byte);
+ if (!TARGET_64BIT)
+ emit_insn (gen_lsx_vinsgr2vr_w (new_dest, s, new_dest,
+ GEN_INT (1 << index)));
+ else
+ emit_insn (gen_lsx_vinsgr2vr_d (new_dest, s, new_dest,
+ GEN_INT (1 << index)));
+ }
+ }
+ else if (FP_REG_RTX_P (src))
+ {
+ gcc_assert (!MEM_P (dest));
+
+ rtx new_src = src;
+ if (!TARGET_64BIT)
+ {
+ if (GET_MODE (src) != V4SImode)
+ new_src = simplify_gen_subreg (V4SImode, src, GET_MODE (src), 0);
+ }
+ else
+ {
+ if (GET_MODE (src) != V2DImode)
+ new_src = simplify_gen_subreg (V2DImode, src, GET_MODE (src), 0);
+ }
+
+ for (byte = 0, index = 0; byte < GET_MODE_SIZE (TImode);
+ byte += UNITS_PER_WORD, index++)
+ {
+ d = loongarch_subword_at_byte (dest, byte);
+ if (!TARGET_64BIT)
+ emit_insn (gen_lsx_vpickve2gr_w (d, new_src, GEN_INT (index)));
+ else
+ emit_insn (gen_lsx_vpickve2gr_d (d, new_src, GEN_INT (index)));
+ }
+ }
+ else
+ {
+ low_dest = loongarch_subword_at_byte (dest, 0);
+ low_src = loongarch_subword_at_byte (src, 0);
+ gcc_assert (REG_P (low_dest) && REG_P (low_src));
+ /* Make sure the source register is not written before reading. */
+ if (REGNO (low_dest) <= REGNO (low_src))
+ {
+ for (byte = 0; byte < GET_MODE_SIZE (TImode);
+ byte += UNITS_PER_WORD)
+ {
+ d = loongarch_subword_at_byte (dest, byte);
+ s = loongarch_subword_at_byte (src, byte);
+ loongarch_emit_move (d, s);
+ }
+ }
+ else
+ {
+ for (byte = GET_MODE_SIZE (TImode) - UNITS_PER_WORD; byte >= 0;
+ byte -= UNITS_PER_WORD)
+ {
+ d = loongarch_subword_at_byte (dest, byte);
+ s = loongarch_subword_at_byte (src, byte);
+ loongarch_emit_move (d, s);
+ }
+ }
+ }
+}
+
+
+/* Split a COPY_S.D with operands DEST, SRC and INDEX. GEN is a function
+ used to generate subregs. */
+
+void
+loongarch_split_lsx_copy_d (rtx dest, rtx src, rtx index,
+ rtx (*gen_fn)(rtx, rtx, rtx))
+{
+ gcc_assert ((GET_MODE (src) == V2DImode && GET_MODE (dest) == DImode)
+ || (GET_MODE (src) == V2DFmode && GET_MODE (dest) == DFmode));
+
+ /* Note that low is always from the lower index, and high is always
+ from the higher index. */
+ rtx low = loongarch_subword (dest, false);
+ rtx high = loongarch_subword (dest, true);
+ rtx new_src = simplify_gen_subreg (V4SImode, src, GET_MODE (src), 0);
+
+ emit_insn (gen_fn (low, new_src, GEN_INT (INTVAL (index) * 2)));
+ emit_insn (gen_fn (high, new_src, GEN_INT (INTVAL (index) * 2 + 1)));
+}
+
+/* Split a INSERT.D with operand DEST, SRC1.INDEX and SRC2. */
+
+void
+loongarch_split_lsx_insert_d (rtx dest, rtx src1, rtx index, rtx src2)
+{
+ int i;
+ gcc_assert (GET_MODE (dest) == GET_MODE (src1));
+ gcc_assert ((GET_MODE (dest) == V2DImode
+ && (GET_MODE (src2) == DImode || src2 == const0_rtx))
+ || (GET_MODE (dest) == V2DFmode && GET_MODE (src2) == DFmode));
+
+ /* Note that low is always from the lower index, and high is always
+ from the higher index. */
+ rtx low = loongarch_subword (src2, false);
+ rtx high = loongarch_subword (src2, true);
+ rtx new_dest = simplify_gen_subreg (V4SImode, dest, GET_MODE (dest), 0);
+ rtx new_src1 = simplify_gen_subreg (V4SImode, src1, GET_MODE (src1), 0);
+ i = exact_log2 (INTVAL (index));
+ gcc_assert (i != -1);
+
+ emit_insn (gen_lsx_vinsgr2vr_w (new_dest, low, new_src1,
+ GEN_INT (1 << (i * 2))));
+ emit_insn (gen_lsx_vinsgr2vr_w (new_dest, high, new_dest,
+ GEN_INT (1 << (i * 2 + 1))));
+}
+
+/* Split FILL.D. */
+
+void
+loongarch_split_lsx_fill_d (rtx dest, rtx src)
+{
+ gcc_assert ((GET_MODE (dest) == V2DImode
+ && (GET_MODE (src) == DImode || src == const0_rtx))
+ || (GET_MODE (dest) == V2DFmode && GET_MODE (src) == DFmode));
+
+ /* Note that low is always from the lower index, and high is always
+ from the higher index. */
+ rtx low, high;
+ if (src == const0_rtx)
+ {
+ low = src;
+ high = src;
+ }
+ else
+ {
+ low = loongarch_subword (src, false);
+ high = loongarch_subword (src, true);
+ }
+ rtx new_dest = simplify_gen_subreg (V4SImode, dest, GET_MODE (dest), 0);
+ emit_insn (gen_lsx_vreplgr2vr_w (new_dest, low));
+ emit_insn (gen_lsx_vinsgr2vr_w (new_dest, high, new_dest, GEN_INT (1 << 1)));
+ emit_insn (gen_lsx_vinsgr2vr_w (new_dest, high, new_dest, GEN_INT (1 << 3)));
+}
+
/* Return the appropriate instructions to move SRC into DEST. Assume
that SRC is operand 1 and DEST is operand 0. */
enum rtx_code src_code = GET_CODE (src);
machine_mode mode = GET_MODE (dest);
bool dbl_p = (GET_MODE_SIZE (mode) == 8);
+ bool lsx_p = LSX_SUPPORTED_MODE_P (mode);
if (loongarch_split_move_p (dest, src))
return "#";
+ if ((lsx_p)
+ && dest_code == REG && FP_REG_P (REGNO (dest))
+ && src_code == CONST_VECTOR
+ && CONST_INT_P (CONST_VECTOR_ELT (src, 0)))
+ {
+ gcc_assert (loongarch_const_vector_same_int_p (src, mode, -512, 511));
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 16:
+ return "vrepli.%v0\t%w0,%E1";
+ default: gcc_unreachable ();
+ }
+ }
+
if ((src_code == REG && GP_REG_P (REGNO (src)))
|| (src == CONST0_RTX (mode)))
{
return "or\t%0,%z1,$r0";
if (FP_REG_P (REGNO (dest)))
- return dbl_p ? "movgr2fr.d\t%0,%z1" : "movgr2fr.w\t%0,%z1";
+ {
+ if (lsx_p)
+ {
+ gcc_assert (src == CONST0_RTX (GET_MODE (src)));
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 16:
+ return "vrepli.b\t%w0,0";
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return dbl_p ? "movgr2fr.d\t%0,%z1" : "movgr2fr.w\t%0,%z1";
+ }
}
if (dest_code == MEM)
{
{
if (src_code == REG)
if (FP_REG_P (REGNO (src)))
- return dbl_p ? "movfr2gr.d\t%0,%1" : "movfr2gr.s\t%0,%1";
+ {
+ gcc_assert (!lsx_p);
+ return dbl_p ? "movfr2gr.d\t%0,%1" : "movfr2gr.s\t%0,%1";
+ }
if (src_code == MEM)
{
enum loongarch_symbol_type type = SYMBOL_PCREL;
if (UNSPEC_ADDRESS_P (x))
- type = UNSPEC_ADDRESS_TYPE (x);
+ type = UNSPEC_ADDRESS_TYPE (x);
if (type == SYMBOL_TLS_LE)
return "lu12i.w\t%0,%h1";
if (src_code == REG && FP_REG_P (REGNO (src)))
{
if (dest_code == REG && FP_REG_P (REGNO (dest)))
- return dbl_p ? "fmov.d\t%0,%1" : "fmov.s\t%0,%1";
+ {
+ if (lsx_p)
+ {
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 16:
+ return "vori.b\t%w0,%w1,0";
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return dbl_p ? "fmov.d\t%0,%1" : "fmov.s\t%0,%1";
+ }
if (dest_code == MEM)
{
if (insn)
return insn;
+ if (lsx_p)
+ {
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 16:
+ return "vst\t%w1,%0";
+ default:
+ gcc_unreachable ();
+ }
+ }
+
return dbl_p ? "fst.d\t%1,%0" : "fst.s\t%1,%0";
}
}
if (insn)
return insn;
+ if (lsx_p)
+ {
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 16:
+ return "vld\t%w0,%1";
+ default:
+ gcc_unreachable ();
+ }
+ }
return dbl_p ? "fld.d\t%0,%1" : "fld.s\t%0,%1";
}
}
}
}
+
/* Convert a comparison into something that can be used in a branch. On
entry, *OP0 and *OP1 are the values being compared and *CODE is the code
used to compare them. Update them to describe the final comparison. */
'A' Print a _DB suffix if the memory model requires a release.
'b' Print the address of a memory operand, without offset.
+ 'B' Print CONST_INT OP element 0 of a replicated CONST_VECTOR
+ as an unsigned byte [0..255].
'c' Print an integer.
'C' Print the integer branch condition for comparison OP.
'd' Print CONST_INT OP in decimal.
+ 'E' Print CONST_INT OP element 0 of a replicated CONST_VECTOR in decimal.
'F' Print the FPU branch condition for comparison OP.
'G' Print a DBAR insn if the memory model requires a release.
'H' Print address 52-61bit relocation associated with OP.
't' Like 'T', but with the EQ/NE cases reversed
'V' Print exact log2 of CONST_INT OP element 0 of a replicated
CONST_VECTOR in decimal.
+ 'v' Print the insn size suffix b, h, w or d for vector modes V16QI, V8HI,
+ V4SI, V2SI, and w, d for vector modes V4SF, V2DF respectively.
'W' Print the inverse of the FPU branch condition for comparison OP.
+ 'w' Print a LSX register.
'X' Print CONST_INT OP in hexadecimal format.
'x' Print the low 16 bits of CONST_INT OP in hexadecimal format.
'Y' Print loongarch_fp_conditions[INTVAL (OP)]
'y' Print exact log2 of CONST_INT OP in decimal.
'Z' Print OP and a comma for 8CC, otherwise print nothing.
- 'z' Print $0 if OP is zero, otherwise print OP normally. */
+ 'z' Print $r0 if OP is zero, otherwise print OP normally. */
static void
loongarch_print_operand (FILE *file, rtx op, int letter)
if (loongarch_memmodel_needs_rel_acq_fence ((enum memmodel) INTVAL (op)))
fputs ("_db", file);
break;
+ case 'E':
+ if (GET_CODE (op) == CONST_VECTOR)
+ {
+ gcc_assert (loongarch_const_vector_same_val_p (op, GET_MODE (op)));
+ op = CONST_VECTOR_ELT (op, 0);
+ gcc_assert (CONST_INT_P (op));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
+ }
+ else
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
+
case 'c':
if (CONST_INT_P (op))
loongarch_print_operand_reloc (file, op, false /* hi64_part*/,
false /* lo_reloc */);
break;
+ case 'B':
+ if (GET_CODE (op) == CONST_VECTOR)
+ {
+ gcc_assert (loongarch_const_vector_same_val_p (op, GET_MODE (op)));
+ op = CONST_VECTOR_ELT (op, 0);
+ gcc_assert (CONST_INT_P (op));
+ unsigned HOST_WIDE_INT val8 = UINTVAL (op) & GET_MODE_MASK (QImode);
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, val8);
+ }
+ else
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
case 'm':
if (CONST_INT_P (op))
output_operand_lossage ("invalid use of '%%%c'", letter);
break;
- case 'W':
- loongarch_print_float_branch_condition (file, reverse_condition (code),
- letter);
- break;
+ case 'v':
+ switch (GET_MODE (op))
+ {
+ case E_V16QImode:
+ case E_V32QImode:
+ fprintf (file, "b");
+ break;
+ case E_V8HImode:
+ case E_V16HImode:
+ fprintf (file, "h");
+ break;
+ case E_V4SImode:
+ case E_V4SFmode:
+ case E_V8SImode:
+ case E_V8SFmode:
+ fprintf (file, "w");
+ break;
+ case E_V2DImode:
+ case E_V2DFmode:
+ case E_V4DImode:
+ case E_V4DFmode:
+ fprintf (file, "d");
+ break;
+ default:
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ }
+ break;
+
+ case 'W':
+ loongarch_print_float_branch_condition (file, reverse_condition (code),
+ letter);
+ break;
+
+ case 'w':
+ if (code == REG && LSX_REG_P (REGNO (op)))
+ fprintf (file, "$vr%s", ®_names[REGNO (op)][2]);
+ else
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
case 'x':
if (CONST_INT_P (op))
size = GET_MODE_SIZE (mode);
mclass = GET_MODE_CLASS (mode);
- if (GP_REG_P (regno))
+ if (GP_REG_P (regno) && !LSX_SUPPORTED_MODE_P (mode))
return ((regno - GP_REG_FIRST) & 1) == 0 || size <= UNITS_PER_WORD;
+ /* For LSX, allow TImode and 128-bit vector modes in all FPR. */
+ if (FP_REG_P (regno) && LSX_SUPPORTED_MODE_P (mode))
+ return true;
+
if (FP_REG_P (regno))
{
if (mclass == MODE_FLOAT
return loongarch_hard_regno_mode_ok_p[mode][regno];
}
+
+static bool
+loongarch_hard_regno_call_part_clobbered (unsigned int,
+ unsigned int regno, machine_mode mode)
+{
+ if (ISA_HAS_LSX && FP_REG_P (regno) && GET_MODE_SIZE (mode) > 8)
+ return true;
+
+ return false;
+}
+
/* Implement TARGET_HARD_REGNO_NREGS. */
static unsigned int
return (GET_MODE_SIZE (mode) + 3) / 4;
if (FP_REG_P (regno))
- return (GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG;
+ {
+ if (LSX_SUPPORTED_MODE_P (mode))
+ return 1;
+
+ return (GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG;
+ }
/* All other registers are word-sized. */
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (hard_reg_set_intersect_p (left, reg_class_contents[(int) FP_REGS]))
{
if (loongarch_hard_regno_mode_ok (FP_REG_FIRST, mode))
- size = MIN (size, UNITS_PER_FPREG);
-
+ {
+ if (LSX_SUPPORTED_MODE_P (mode))
+ size = MIN (size, UNITS_PER_LSX_REG);
+ else
+ size = MIN (size, UNITS_PER_FPREG);
+ }
left &= ~reg_class_contents[FP_REGS];
}
if (!hard_reg_set_empty_p (left))
/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */
static bool
-loongarch_can_change_mode_class (machine_mode, machine_mode,
+loongarch_can_change_mode_class (machine_mode from, machine_mode to,
reg_class_t rclass)
{
+ /* Allow conversions between different LSX vector modes. */
+ if (LSX_SUPPORTED_MODE_P (from) && LSX_SUPPORTED_MODE_P (to))
+ return true;
+
return !reg_classes_intersect_p (FP_REGS, rclass);
}
return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT;
default:
- return 0;
+ return LSX_SUPPORTED_MODE_P (mode);
}
}
if (regno < 0
|| (MEM_P (x)
&& (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)))
- /* In this case we can use fld.s, fst.s, fld.d or fst.d. */
+ /* In this case we can use lwc1, swc1, ldc1 or sdc1. We'll use
+ pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported. */
+ return NO_REGS;
+
+ if (MEM_P (x) && LSX_SUPPORTED_MODE_P (mode))
+ /* In this case we can use LSX LD.* and ST.*. */
return NO_REGS;
if (GP_REG_P (regno) || x == CONST0_RTX (mode))
return mode == SImode || (TARGET_64BIT && mode == DImode);
}
+/* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
+
+static bool
+loongarch_vector_mode_supported_p (machine_mode mode)
+{
+ return LSX_SUPPORTED_MODE_P (mode);
+}
+
/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
static bool
return default_scalar_mode_supported_p (mode);
}
+/* Implement TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
+
+static machine_mode
+loongarch_preferred_simd_mode (scalar_mode mode)
+{
+ if (!ISA_HAS_LSX)
+ return word_mode;
+
+ switch (mode)
+ {
+ case E_QImode:
+ return E_V16QImode;
+ case E_HImode:
+ return E_V8HImode;
+ case E_SImode:
+ return E_V4SImode;
+ case E_DImode:
+ return E_V2DImode;
+
+ case E_SFmode:
+ return E_V4SFmode;
+
+ case E_DFmode:
+ return E_V2DFmode;
+
+ default:
+ break;
+ }
+ return word_mode;
+}
+
+static unsigned int
+loongarch_autovectorize_vector_modes (vector_modes *modes, bool)
+{
+ if (ISA_HAS_LSX)
+ {
+ modes->safe_push (V16QImode);
+ }
+
+ return 0;
+}
+
/* Return the assembly code for INSN, which has the operands given by
OPERANDS, and which branches to OPERANDS[0] if some condition is true.
BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[0]
return s;
}
+/* Return the assembly code for LSX DIV_{S,U}.DF or MOD_{S,U}.DF instructions,
+ which has the operands given by OPERANDS. Add in a divide-by-zero check
+ if needed. */
+
+const char *
+loongarch_lsx_output_division (const char *division, rtx *operands)
+{
+ const char *s;
+
+ s = division;
+ if (TARGET_CHECK_ZERO_DIV)
+ {
+ if (ISA_HAS_LSX)
+ {
+ output_asm_insn ("vsetallnez.%v0\t$fcc7,%w2",operands);
+ output_asm_insn (s, operands);
+ output_asm_insn ("bcnez\t$fcc7,1f", operands);
+ }
+ s = "break\t7\n1:";
+ }
+ return s;
+}
+
/* Implement TARGET_SCHED_ADJUST_COST. We assume that anti and output
dependencies have no cost. */
if (TARGET_DIRECT_EXTERN_ACCESS && flag_shlib)
error ("%qs cannot be used for compiling a shared library",
"-mdirect-extern-access");
+ if (loongarch_vector_access_cost == 0)
+ loongarch_vector_access_cost = 5;
+
switch (la_target.cmodel)
{
emit_insn (gen_clear_cache (addr, end_addr));
}
-/* Implement HARD_REGNO_CALLER_SAVE_MODE. */
-
-machine_mode
-loongarch_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs,
- machine_mode mode)
-{
- /* For performance, avoid saving/restoring upper parts of a register
- by returning MODE as save mode when the mode is known. */
- if (mode == VOIDmode)
- return choose_hard_reg_mode (regno, nregs, NULL);
- else
- return mode;
-}
+/* Generate or test for an insn that supports a constant permutation. */
-/* Implement TARGET_SPILL_CLASS. */
+#define MAX_VECT_LEN 32
-static reg_class_t
-loongarch_spill_class (reg_class_t rclass ATTRIBUTE_UNUSED,
- machine_mode mode ATTRIBUTE_UNUSED)
+struct expand_vec_perm_d
{
- return NO_REGS;
-}
-
-/* Implement TARGET_PROMOTE_FUNCTION_MODE. */
+ rtx target, op0, op1;
+ unsigned char perm[MAX_VECT_LEN];
+ machine_mode vmode;
+ unsigned char nelt;
+ bool one_vector_p;
+ bool testing_p;
+};
-/* This function is equivalent to default_promote_function_mode_always_promote
- except that it returns a promoted mode even if type is NULL_TREE. This is
- needed by libcalls which have no type (only a mode) such as fixed conversion
- routines that take a signed or unsigned char/short argument and convert it
- to a fixed type. */
+/* Construct (set target (vec_select op0 (parallel perm))) and
+ return true if that's a valid instruction in the active ISA. */
-static machine_mode
-loongarch_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
- machine_mode mode,
- int *punsignedp ATTRIBUTE_UNUSED,
- const_tree fntype ATTRIBUTE_UNUSED,
- int for_return ATTRIBUTE_UNUSED)
+static bool
+loongarch_expand_vselect (rtx target, rtx op0,
+ const unsigned char *perm, unsigned nelt)
{
- int unsignedp;
+ rtx rperm[MAX_VECT_LEN], x;
+ rtx_insn *insn;
+ unsigned i;
- if (type != NULL_TREE)
- return promote_mode (type, mode, punsignedp);
+ for (i = 0; i < nelt; ++i)
+ rperm[i] = GEN_INT (perm[i]);
- unsignedp = *punsignedp;
- PROMOTE_MODE (mode, unsignedp, type);
- *punsignedp = unsignedp;
- return mode;
+ x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelt, rperm));
+ x = gen_rtx_VEC_SELECT (GET_MODE (target), op0, x);
+ x = gen_rtx_SET (target, x);
+
+ insn = emit_insn (x);
+ if (recog_memoized (insn) < 0)
+ {
+ remove_insn (insn);
+ return false;
+ }
+ return true;
}
-/* Implement TARGET_STARTING_FRAME_OFFSET. See loongarch_compute_frame_info
- for details about the frame layout. */
+/* Similar, but generate a vec_concat from op0 and op1 as well. */
-static HOST_WIDE_INT
-loongarch_starting_frame_offset (void)
+static bool
+loongarch_expand_vselect_vconcat (rtx target, rtx op0, rtx op1,
+ const unsigned char *perm, unsigned nelt)
{
- if (FRAME_GROWS_DOWNWARD)
- return 0;
- return crtl->outgoing_args_size;
+ machine_mode v2mode;
+ rtx x;
+
+ if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+ return false;
+ x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
+ return loongarch_expand_vselect (target, x, perm, nelt);
}
static tree
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
#undef TARGET_ASM_ALIGNED_DI_OP
#define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
+/* Construct (set target (vec_select op0 (parallel selector))) and
+ return true if that's a valid instruction in the active ISA. */
-#undef TARGET_OPTION_OVERRIDE
-#define TARGET_OPTION_OVERRIDE loongarch_option_override
-
-#undef TARGET_LEGITIMIZE_ADDRESS
-#define TARGET_LEGITIMIZE_ADDRESS loongarch_legitimize_address
-
-#undef TARGET_ASM_SELECT_RTX_SECTION
-#define TARGET_ASM_SELECT_RTX_SECTION loongarch_select_rtx_section
-#undef TARGET_ASM_FUNCTION_RODATA_SECTION
-#define TARGET_ASM_FUNCTION_RODATA_SECTION loongarch_function_rodata_section
+static bool
+loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d)
+{
+ rtx x, elts[MAX_VECT_LEN];
+ rtvec v;
+ rtx_insn *insn;
+ unsigned i;
-#undef TARGET_SCHED_INIT
-#define TARGET_SCHED_INIT loongarch_sched_init
-#undef TARGET_SCHED_REORDER
-#define TARGET_SCHED_REORDER loongarch_sched_reorder
-#undef TARGET_SCHED_REORDER2
-#define TARGET_SCHED_REORDER2 loongarch_sched_reorder2
-#undef TARGET_SCHED_VARIABLE_ISSUE
-#define TARGET_SCHED_VARIABLE_ISSUE loongarch_variable_issue
-#undef TARGET_SCHED_ADJUST_COST
-#define TARGET_SCHED_ADJUST_COST loongarch_adjust_cost
-#undef TARGET_SCHED_ISSUE_RATE
-#define TARGET_SCHED_ISSUE_RATE loongarch_issue_rate
-#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
-#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
- loongarch_multipass_dfa_lookahead
+ if (!ISA_HAS_LSX)
+ return false;
-#undef TARGET_FUNCTION_OK_FOR_SIBCALL
-#define TARGET_FUNCTION_OK_FOR_SIBCALL loongarch_function_ok_for_sibcall
+ for (i = 0; i < d->nelt; i++)
+ elts[i] = GEN_INT (d->perm[i]);
-#undef TARGET_VALID_POINTER_MODE
-#define TARGET_VALID_POINTER_MODE loongarch_valid_pointer_mode
-#undef TARGET_REGISTER_MOVE_COST
-#define TARGET_REGISTER_MOVE_COST loongarch_register_move_cost
-#undef TARGET_MEMORY_MOVE_COST
-#define TARGET_MEMORY_MOVE_COST loongarch_memory_move_cost
-#undef TARGET_RTX_COSTS
-#define TARGET_RTX_COSTS loongarch_rtx_costs
-#undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST loongarch_address_cost
+ v = gen_rtvec_v (d->nelt, elts);
+ x = gen_rtx_PARALLEL (VOIDmode, v);
-#undef TARGET_IN_SMALL_DATA_P
-#define TARGET_IN_SMALL_DATA_P loongarch_in_small_data_p
+ if (!loongarch_const_vector_shuffle_set_p (x, d->vmode))
+ return false;
-#undef TARGET_PREFERRED_RELOAD_CLASS
-#define TARGET_PREFERRED_RELOAD_CLASS loongarch_preferred_reload_class
+ x = gen_rtx_VEC_SELECT (d->vmode, d->op0, x);
+ x = gen_rtx_SET (d->target, x);
-#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
-#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+ insn = emit_insn (x);
+ if (recog_memoized (insn) < 0)
+ {
+ remove_insn (insn);
+ return false;
+ }
+ return true;
+}
-#undef TARGET_EXPAND_BUILTIN_VA_START
-#define TARGET_EXPAND_BUILTIN_VA_START loongarch_va_start
+void
+loongarch_expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel)
+{
+ machine_mode vmode = GET_MODE (target);
-#undef TARGET_PROMOTE_FUNCTION_MODE
-#define TARGET_PROMOTE_FUNCTION_MODE loongarch_promote_function_mode
-#undef TARGET_RETURN_IN_MEMORY
-#define TARGET_RETURN_IN_MEMORY loongarch_return_in_memory
+ switch (vmode)
+ {
+ case E_V16QImode:
+ emit_insn (gen_lsx_vshuf_b (target, op1, op0, sel));
+ break;
+ case E_V2DFmode:
+ emit_insn (gen_lsx_vshuf_d_f (target, sel, op1, op0));
+ break;
+ case E_V2DImode:
+ emit_insn (gen_lsx_vshuf_d (target, sel, op1, op0));
+ break;
+ case E_V4SFmode:
+ emit_insn (gen_lsx_vshuf_w_f (target, sel, op1, op0));
+ break;
+ case E_V4SImode:
+ emit_insn (gen_lsx_vshuf_w (target, sel, op1, op0));
+ break;
+ case E_V8HImode:
+ emit_insn (gen_lsx_vshuf_h (target, sel, op1, op0));
+ break;
+ default:
+ break;
+ }
+}
-#undef TARGET_FUNCTION_VALUE
-#define TARGET_FUNCTION_VALUE loongarch_function_value
-#undef TARGET_LIBCALL_VALUE
-#define TARGET_LIBCALL_VALUE loongarch_libcall_value
+static bool
+loongarch_try_expand_lsx_vshuf_const (struct expand_vec_perm_d *d)
+{
+ int i;
+ rtx target, op0, op1, sel, tmp;
+ rtx rperm[MAX_VECT_LEN];
-#undef TARGET_ASM_OUTPUT_MI_THUNK
-#define TARGET_ASM_OUTPUT_MI_THUNK loongarch_output_mi_thunk
-#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
- hook_bool_const_tree_hwi_hwi_const_tree_true
+ if (d->vmode == E_V2DImode || d->vmode == E_V2DFmode
+ || d->vmode == E_V4SImode || d->vmode == E_V4SFmode
+ || d->vmode == E_V8HImode || d->vmode == E_V16QImode)
+ {
+ target = d->target;
+ op0 = d->op0;
+ op1 = d->one_vector_p ? d->op0 : d->op1;
-#undef TARGET_PRINT_OPERAND
-#define TARGET_PRINT_OPERAND loongarch_print_operand
-#undef TARGET_PRINT_OPERAND_ADDRESS
-#define TARGET_PRINT_OPERAND_ADDRESS loongarch_print_operand_address
-#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
-#define TARGET_PRINT_OPERAND_PUNCT_VALID_P \
- loongarch_print_operand_punct_valid_p
+ if (GET_MODE (op0) != GET_MODE (op1)
+ || GET_MODE (op0) != GET_MODE (target))
+ return false;
-#undef TARGET_SETUP_INCOMING_VARARGS
-#define TARGET_SETUP_INCOMING_VARARGS loongarch_setup_incoming_varargs
-#undef TARGET_STRICT_ARGUMENT_NAMING
-#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
-#undef TARGET_MUST_PASS_IN_STACK
-#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
-#undef TARGET_PASS_BY_REFERENCE
-#define TARGET_PASS_BY_REFERENCE loongarch_pass_by_reference
-#undef TARGET_ARG_PARTIAL_BYTES
-#define TARGET_ARG_PARTIAL_BYTES loongarch_arg_partial_bytes
-#undef TARGET_FUNCTION_ARG
-#define TARGET_FUNCTION_ARG loongarch_function_arg
-#undef TARGET_FUNCTION_ARG_ADVANCE
-#define TARGET_FUNCTION_ARG_ADVANCE loongarch_function_arg_advance
-#undef TARGET_FUNCTION_ARG_BOUNDARY
-#define TARGET_FUNCTION_ARG_BOUNDARY loongarch_function_arg_boundary
+ if (d->testing_p)
+ return true;
-#undef TARGET_SCALAR_MODE_SUPPORTED_P
-#define TARGET_SCALAR_MODE_SUPPORTED_P loongarch_scalar_mode_supported_p
+ for (i = 0; i < d->nelt; i += 1)
+ {
+ rperm[i] = GEN_INT (d->perm[i]);
+ }
-#undef TARGET_INIT_BUILTINS
+ if (d->vmode == E_V2DFmode)
+ {
+ sel = gen_rtx_CONST_VECTOR (E_V2DImode, gen_rtvec_v (d->nelt, rperm));
+ tmp = gen_rtx_SUBREG (E_V2DImode, d->target, 0);
+ emit_move_insn (tmp, sel);
+ }
+ else if (d->vmode == E_V4SFmode)
+ {
+ sel = gen_rtx_CONST_VECTOR (E_V4SImode, gen_rtvec_v (d->nelt, rperm));
+ tmp = gen_rtx_SUBREG (E_V4SImode, d->target, 0);
+ emit_move_insn (tmp, sel);
+ }
+ else
+ {
+ sel = gen_rtx_CONST_VECTOR (d->vmode, gen_rtvec_v (d->nelt, rperm));
+ emit_move_insn (d->target, sel);
+ }
+
+ switch (d->vmode)
+ {
+ case E_V2DFmode:
+ emit_insn (gen_lsx_vshuf_d_f (target, target, op1, op0));
+ break;
+ case E_V2DImode:
+ emit_insn (gen_lsx_vshuf_d (target, target, op1, op0));
+ break;
+ case E_V4SFmode:
+ emit_insn (gen_lsx_vshuf_w_f (target, target, op1, op0));
+ break;
+ case E_V4SImode:
+ emit_insn (gen_lsx_vshuf_w (target, target, op1, op0));
+ break;
+ case E_V8HImode:
+ emit_insn (gen_lsx_vshuf_h (target, target, op1, op0));
+ break;
+ case E_V16QImode:
+ emit_insn (gen_lsx_vshuf_b (target, op1, op0, target));
+ break;
+ default:
+ break;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool
+loongarch_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
+{
+ unsigned int i, nelt = d->nelt;
+ unsigned char perm2[MAX_VECT_LEN];
+
+ if (d->one_vector_p)
+ {
+ /* Try interleave with alternating operands. */
+ memcpy (perm2, d->perm, sizeof (perm2));
+ for (i = 1; i < nelt; i += 2)
+ perm2[i] += nelt;
+ if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1, perm2,
+ nelt))
+ return true;
+ }
+ else
+ {
+ if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1,
+ d->perm, nelt))
+ return true;
+
+ /* Try again with swapped operands. */
+ for (i = 0; i < nelt; ++i)
+ perm2[i] = (d->perm[i] + nelt) & (2 * nelt - 1);
+ if (loongarch_expand_vselect_vconcat (d->target, d->op1, d->op0, perm2,
+ nelt))
+ return true;
+ }
+
+ if (loongarch_expand_lsx_shuffle (d))
+ return true;
+ return false;
+}
+
+/* Implementation of constant vector permuatation. This function identifies
+ * recognized pattern of permuation selector argument, and use one or more
+ * instruction(s) to finish the permutation job correctly. For unsupported
+ * patterns, it will return false. */
+
+static bool
+loongarch_expand_vec_perm_const_2 (struct expand_vec_perm_d *d)
+{
+ /* Although we have the LSX vec_perm<mode> template, there's still some
+ 128bit vector permuatation operations send to vectorize_vec_perm_const.
+ In this case, we just simpliy wrap them by single vshuf.* instruction,
+ because LSX vshuf.* instruction just have the same behavior that GCC
+ expects. */
+ return loongarch_try_expand_lsx_vshuf_const (d);
+}
+
+/* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */
+
+static bool
+loongarch_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode,
+ rtx target, rtx op0, rtx op1,
+ const vec_perm_indices &sel)
+{
+ if (vmode != op_mode)
+ return false;
+
+ struct expand_vec_perm_d d;
+ int i, nelt, which;
+ unsigned char orig_perm[MAX_VECT_LEN];
+ bool ok;
+
+ d.target = target;
+ if (op0)
+ {
+ rtx nop0 = force_reg (vmode, op0);
+ if (op0 == op1)
+ op1 = nop0;
+ op0 = nop0;
+ }
+ if (op1)
+ op1 = force_reg (vmode, op1);
+ d.op0 = op0;
+ d.op1 = op1;
+
+ d.vmode = vmode;
+ gcc_assert (VECTOR_MODE_P (vmode));
+ d.nelt = nelt = GET_MODE_NUNITS (vmode);
+ d.testing_p = !target;
+
+ /* This is overly conservative, but ensures we don't get an
+ uninitialized warning on ORIG_PERM. */
+ memset (orig_perm, 0, MAX_VECT_LEN);
+ for (i = which = 0; i < nelt; ++i)
+ {
+ int ei = sel[i] & (2 * nelt - 1);
+ which |= (ei < nelt ? 1 : 2);
+ orig_perm[i] = ei;
+ }
+ memcpy (d.perm, orig_perm, MAX_VECT_LEN);
+
+ switch (which)
+ {
+ default:
+ gcc_unreachable ();
+
+ case 3:
+ d.one_vector_p = false;
+ if (d.testing_p || !rtx_equal_p (d.op0, d.op1))
+ break;
+ /* FALLTHRU */
+
+ case 2:
+ for (i = 0; i < nelt; ++i)
+ d.perm[i] &= nelt - 1;
+ d.op0 = d.op1;
+ d.one_vector_p = true;
+ break;
+
+ case 1:
+ d.op1 = d.op0;
+ d.one_vector_p = true;
+ break;
+ }
+
+ if (d.testing_p)
+ {
+ d.target = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 1);
+ d.op1 = d.op0 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 2);
+ if (!d.one_vector_p)
+ d.op1 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 3);
+
+ ok = loongarch_expand_vec_perm_const_2 (&d);
+ if (ok)
+ return ok;
+
+ start_sequence ();
+ ok = loongarch_expand_vec_perm_const_1 (&d);
+ end_sequence ();
+ return ok;
+ }
+
+ ok = loongarch_expand_vec_perm_const_2 (&d);
+ if (!ok)
+ ok = loongarch_expand_vec_perm_const_1 (&d);
+
+ /* If we were given a two-vector permutation which just happened to
+ have both input vectors equal, we folded this into a one-vector
+ permutation. There are several loongson patterns that are matched
+ via direct vec_select+vec_concat expansion, but we do not have
+ support in loongarch_expand_vec_perm_const_1 to guess the adjustment
+ that should be made for a single operand. Just try again with
+ the original permutation. */
+ if (!ok && which == 3)
+ {
+ d.op0 = op0;
+ d.op1 = op1;
+ d.one_vector_p = false;
+ memcpy (d.perm, orig_perm, MAX_VECT_LEN);
+ ok = loongarch_expand_vec_perm_const_1 (&d);
+ }
+
+ return ok;
+}
+
+static int
+loongarch_cpu_sched_reassociation_width (struct loongarch_target *target,
+ unsigned int opc, machine_mode mode)
+{
+ /* unreferenced argument */
+ (void) opc;
+
+ switch (target->cpu_tune)
+ {
+ case CPU_LOONGARCH64:
+ case CPU_LA464:
+ /* Vector part. */
+ if (LSX_SUPPORTED_MODE_P (mode))
+ {
+ /* Integer vector instructions execute in FP unit.
+ The width of integer/float-point vector instructions is 3. */
+ return 3;
+ }
+
+ /* Scalar part. */
+ else if (INTEGRAL_MODE_P (mode))
+ return 1;
+ else if (FLOAT_MODE_P (mode))
+ {
+ if (opc == PLUS_EXPR)
+ {
+ return 2;
+ }
+ return 4;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* default is 1 */
+ return 1;
+}
+
+/* Implement TARGET_SCHED_REASSOCIATION_WIDTH. */
+
+static int
+loongarch_sched_reassociation_width (unsigned int opc, machine_mode mode)
+{
+ return loongarch_cpu_sched_reassociation_width (&la_target, opc, mode);
+}
+
+/* Implement extract a scalar element from vecotr register */
+
+void
+loongarch_expand_vector_extract (rtx target, rtx vec, int elt)
+{
+ machine_mode mode = GET_MODE (vec);
+ machine_mode inner_mode = GET_MODE_INNER (mode);
+ rtx tmp;
+
+ switch (mode)
+ {
+ case E_V8HImode:
+ case E_V16QImode:
+ break;
+
+ default:
+ break;
+ }
+
+ tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (elt)));
+ tmp = gen_rtx_VEC_SELECT (inner_mode, vec, tmp);
+
+ /* Let the rtl optimizers know about the zero extension performed. */
+ if (inner_mode == QImode || inner_mode == HImode)
+ {
+ tmp = gen_rtx_ZERO_EXTEND (SImode, tmp);
+ target = gen_lowpart (SImode, target);
+ }
+ if (inner_mode == SImode || inner_mode == DImode)
+ {
+ tmp = gen_rtx_SIGN_EXTEND (inner_mode, tmp);
+ }
+
+ emit_insn (gen_rtx_SET (target, tmp));
+}
+
+/* Generate code to copy vector bits i / 2 ... i - 1 from vector SRC
+ to bits 0 ... i / 2 - 1 of vector DEST, which has the same mode.
+ The upper bits of DEST are undefined, though they shouldn't cause
+ exceptions (some bits from src or all zeros are ok). */
+
+static void
+emit_reduc_half (rtx dest, rtx src, int i)
+{
+ rtx tem, d = dest;
+ switch (GET_MODE (src))
+ {
+ case E_V4SFmode:
+ tem = gen_lsx_vbsrl_w_f (dest, src, GEN_INT (i == 128 ? 8 : 4));
+ break;
+ case E_V2DFmode:
+ tem = gen_lsx_vbsrl_d_f (dest, src, GEN_INT (8));
+ break;
+ case E_V16QImode:
+ case E_V8HImode:
+ case E_V4SImode:
+ case E_V2DImode:
+ d = gen_reg_rtx (V2DImode);
+ tem = gen_lsx_vbsrl_d (d, gen_lowpart (V2DImode, src), GEN_INT (i/16));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ emit_insn (tem);
+ if (d != dest)
+ emit_move_insn (dest, gen_lowpart (GET_MODE (dest), d));
+}
+
+/* Expand a vector reduction. FN is the binary pattern to reduce;
+ DEST is the destination; IN is the input vector. */
+
+void
+loongarch_expand_vector_reduc (rtx (*fn) (rtx, rtx, rtx), rtx dest, rtx in)
+{
+ rtx half, dst, vec = in;
+ machine_mode mode = GET_MODE (in);
+ int i;
+
+ for (i = GET_MODE_BITSIZE (mode);
+ i > GET_MODE_UNIT_BITSIZE (mode);
+ i >>= 1)
+ {
+ half = gen_reg_rtx (mode);
+ emit_reduc_half (half, vec, i);
+ if (i == GET_MODE_UNIT_BITSIZE (mode) * 2)
+ dst = dest;
+ else
+ dst = gen_reg_rtx (mode);
+ emit_insn (fn (dst, half, vec));
+ vec = dst;
+ }
+}
+
+/* Expand an integral vector unpack operation. */
+
+void
+loongarch_expand_vec_unpack (rtx operands[2], bool unsigned_p, bool high_p)
+{
+ machine_mode imode = GET_MODE (operands[1]);
+ rtx (*unpack) (rtx, rtx, rtx);
+ rtx (*cmpFunc) (rtx, rtx, rtx);
+ rtx tmp, dest;
+
+ if (ISA_HAS_LSX)
+ {
+ switch (imode)
+ {
+ case E_V4SImode:
+ if (high_p != 0)
+ unpack = gen_lsx_vilvh_w;
+ else
+ unpack = gen_lsx_vilvl_w;
+
+ cmpFunc = gen_lsx_vslt_w;
+ break;
+
+ case E_V8HImode:
+ if (high_p != 0)
+ unpack = gen_lsx_vilvh_h;
+ else
+ unpack = gen_lsx_vilvl_h;
+
+ cmpFunc = gen_lsx_vslt_h;
+ break;
+
+ case E_V16QImode:
+ if (high_p != 0)
+ unpack = gen_lsx_vilvh_b;
+ else
+ unpack = gen_lsx_vilvl_b;
+
+ cmpFunc = gen_lsx_vslt_b;
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ if (!unsigned_p)
+ {
+ /* Extract sign extention for each element comparing each element
+ with immediate zero. */
+ tmp = gen_reg_rtx (imode);
+ emit_insn (cmpFunc (tmp, operands[1], CONST0_RTX (imode)));
+ }
+ else
+ tmp = force_reg (imode, CONST0_RTX (imode));
+
+ dest = gen_reg_rtx (imode);
+
+ emit_insn (unpack (dest, operands[1], tmp));
+ emit_move_insn (operands[0], gen_lowpart (GET_MODE (operands[0]), dest));
+ return;
+ }
+ gcc_unreachable ();
+}
+
+/* Construct and return PARALLEL RTX with CONST_INTs for HIGH (high_p == TRUE)
+ or LOW (high_p == FALSE) half of a vector for mode MODE. */
+
+rtx
+loongarch_lsx_vec_parallel_const_half (machine_mode mode, bool high_p)
+{
+ int nunits = GET_MODE_NUNITS (mode);
+ rtvec v = rtvec_alloc (nunits / 2);
+ int base;
+ int i;
+
+ base = high_p ? nunits / 2 : 0;
+
+ for (i = 0; i < nunits / 2; i++)
+ RTVEC_ELT (v, i) = GEN_INT (base + i);
+
+ return gen_rtx_PARALLEL (VOIDmode, v);
+}
+
+/* A subroutine of loongarch_expand_vec_init, match constant vector
+ elements. */
+
+static inline bool
+loongarch_constant_elt_p (rtx x)
+{
+ return CONST_INT_P (x) || GET_CODE (x) == CONST_DOUBLE;
+}
+
+rtx
+loongarch_gen_const_int_vector_shuffle (machine_mode mode, int val)
+{
+ int nunits = GET_MODE_NUNITS (mode);
+ int nsets = nunits / 4;
+ rtx elts[MAX_VECT_LEN];
+ int set = 0;
+ int i, j;
+
+ /* Generate a const_int vector replicating the same 4-element set
+ from an immediate. */
+ for (j = 0; j < nsets; j++, set = 4 * j)
+ for (i = 0; i < 4; i++)
+ elts[set + i] = GEN_INT (set + ((val >> (2 * i)) & 0x3));
+
+ return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nunits, elts));
+}
+
+/* Expand a vector initialization. */
+
+void
+loongarch_expand_vector_init (rtx target, rtx vals)
+{
+ machine_mode vmode = GET_MODE (target);
+ machine_mode imode = GET_MODE_INNER (vmode);
+ unsigned i, nelt = GET_MODE_NUNITS (vmode);
+ unsigned nvar = 0;
+ bool all_same = true;
+ rtx x;
+
+ for (i = 0; i < nelt; ++i)
+ {
+ x = XVECEXP (vals, 0, i);
+ if (!loongarch_constant_elt_p (x))
+ nvar++;
+ if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
+ all_same = false;
+ }
+
+ if (ISA_HAS_LSX)
+ {
+ if (all_same)
+ {
+ rtx same = XVECEXP (vals, 0, 0);
+ rtx temp, temp2;
+
+ if (CONST_INT_P (same) && nvar == 0
+ && loongarch_signed_immediate_p (INTVAL (same), 10, 0))
+ {
+ switch (vmode)
+ {
+ case E_V16QImode:
+ case E_V8HImode:
+ case E_V4SImode:
+ case E_V2DImode:
+ temp = gen_rtx_CONST_VECTOR (vmode, XVEC (vals, 0));
+ emit_move_insn (target, temp);
+ return;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ temp = gen_reg_rtx (imode);
+ if (imode == GET_MODE (same))
+ temp2 = same;
+ else if (GET_MODE_SIZE (imode) >= UNITS_PER_WORD)
+ {
+ if (GET_CODE (same) == MEM)
+ {
+ rtx reg_tmp = gen_reg_rtx (GET_MODE (same));
+ loongarch_emit_move (reg_tmp, same);
+ temp2 = simplify_gen_subreg (imode, reg_tmp,
+ GET_MODE (reg_tmp), 0);
+ }
+ else
+ temp2 = simplify_gen_subreg (imode, same, GET_MODE (same), 0);
+ }
+ else
+ {
+ if (GET_CODE (same) == MEM)
+ {
+ rtx reg_tmp = gen_reg_rtx (GET_MODE (same));
+ loongarch_emit_move (reg_tmp, same);
+ temp2 = lowpart_subreg (imode, reg_tmp, GET_MODE (reg_tmp));
+ }
+ else
+ temp2 = lowpart_subreg (imode, same, GET_MODE (same));
+ }
+ emit_move_insn (temp, temp2);
+
+ switch (vmode)
+ {
+ case E_V16QImode:
+ case E_V8HImode:
+ case E_V4SImode:
+ case E_V2DImode:
+ loongarch_emit_move (target, gen_rtx_VEC_DUPLICATE (vmode, temp));
+ break;
+
+ case E_V4SFmode:
+ emit_insn (gen_lsx_vreplvei_w_f_scalar (target, temp));
+ break;
+
+ case E_V2DFmode:
+ emit_insn (gen_lsx_vreplvei_d_f_scalar (target, temp));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ emit_move_insn (target, CONST0_RTX (vmode));
+
+ for (i = 0; i < nelt; ++i)
+ {
+ rtx temp = gen_reg_rtx (imode);
+ emit_move_insn (temp, XVECEXP (vals, 0, i));
+ switch (vmode)
+ {
+ case E_V16QImode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_b_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv16qi (target, temp, GEN_INT (i)));
+ break;
+
+ case E_V8HImode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_h_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv8hi (target, temp, GEN_INT (i)));
+ break;
+
+ case E_V4SImode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_w_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv4si (target, temp, GEN_INT (i)));
+ break;
+
+ case E_V2DImode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_d_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv2di (target, temp, GEN_INT (i)));
+ break;
+
+ case E_V4SFmode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_w_f_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv4sf (target, temp, GEN_INT (i)));
+ break;
+
+ case E_V2DFmode:
+ if (i == 0)
+ emit_insn (gen_lsx_vreplvei_d_f_scalar (target, temp));
+ else
+ emit_insn (gen_vec_setv2df (target, temp, GEN_INT (i)));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ }
+ return;
+ }
+
+ /* Load constants from the pool, or whatever's handy. */
+ if (nvar == 0)
+ {
+ emit_move_insn (target, gen_rtx_CONST_VECTOR (vmode, XVEC (vals, 0)));
+ return;
+ }
+
+ /* For two-part initialization, always use CONCAT. */
+ if (nelt == 2)
+ {
+ rtx op0 = force_reg (imode, XVECEXP (vals, 0, 0));
+ rtx op1 = force_reg (imode, XVECEXP (vals, 0, 1));
+ x = gen_rtx_VEC_CONCAT (vmode, op0, op1);
+ emit_insn (gen_rtx_SET (target, x));
+ return;
+ }
+
+ /* Loongson is the only cpu with vectors with more elements. */
+ gcc_assert (0);
+}
+
+/* Implement HARD_REGNO_CALLER_SAVE_MODE. */
+
+machine_mode
+loongarch_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs,
+ machine_mode mode)
+{
+ /* For performance, avoid saving/restoring upper parts of a register
+ by returning MODE as save mode when the mode is known. */
+ if (mode == VOIDmode)
+ return choose_hard_reg_mode (regno, nregs, NULL);
+ else
+ return mode;
+}
+
+/* Generate RTL for comparing CMP_OP0 and CMP_OP1 using condition COND and
+ store the result -1 or 0 in DEST. */
+
+static void
+loongarch_expand_lsx_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
+{
+ machine_mode cmp_mode = GET_MODE (op0);
+ int unspec = -1;
+ bool negate = false;
+
+ switch (cmp_mode)
+ {
+ case E_V16QImode:
+ case E_V32QImode:
+ case E_V8HImode:
+ case E_V16HImode:
+ case E_V4SImode:
+ case E_V8SImode:
+ case E_V2DImode:
+ case E_V4DImode:
+ switch (cond)
+ {
+ case NE:
+ cond = reverse_condition (cond);
+ negate = true;
+ break;
+ case EQ:
+ case LT:
+ case LE:
+ case LTU:
+ case LEU:
+ break;
+ case GE:
+ case GT:
+ case GEU:
+ case GTU:
+ std::swap (op0, op1);
+ cond = swap_condition (cond);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ loongarch_emit_binary (cond, dest, op0, op1);
+ if (negate)
+ emit_move_insn (dest, gen_rtx_NOT (GET_MODE (dest), dest));
+ break;
+
+ case E_V4SFmode:
+ case E_V2DFmode:
+ switch (cond)
+ {
+ case UNORDERED:
+ case ORDERED:
+ case EQ:
+ case NE:
+ case UNEQ:
+ case UNLE:
+ case UNLT:
+ break;
+ case LTGT: cond = NE; break;
+ case UNGE: cond = UNLE; std::swap (op0, op1); break;
+ case UNGT: cond = UNLT; std::swap (op0, op1); break;
+ case LE: unspec = UNSPEC_LSX_VFCMP_SLE; break;
+ case LT: unspec = UNSPEC_LSX_VFCMP_SLT; break;
+ case GE: unspec = UNSPEC_LSX_VFCMP_SLE; std::swap (op0, op1); break;
+ case GT: unspec = UNSPEC_LSX_VFCMP_SLT; std::swap (op0, op1); break;
+ default:
+ gcc_unreachable ();
+ }
+ if (unspec < 0)
+ loongarch_emit_binary (cond, dest, op0, op1);
+ else
+ {
+ rtx x = gen_rtx_UNSPEC (GET_MODE (dest),
+ gen_rtvec (2, op0, op1), unspec);
+ emit_insn (gen_rtx_SET (dest, x));
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+}
+
+/* Expand VEC_COND_EXPR, where:
+ MODE is mode of the result
+ VIMODE equivalent integer mode
+ OPERANDS operands of VEC_COND_EXPR. */
+
+void
+loongarch_expand_vec_cond_expr (machine_mode mode, machine_mode vimode,
+ rtx *operands)
+{
+ rtx cond = operands[3];
+ rtx cmp_op0 = operands[4];
+ rtx cmp_op1 = operands[5];
+ rtx cmp_res = gen_reg_rtx (vimode);
+
+ loongarch_expand_lsx_cmp (cmp_res, GET_CODE (cond), cmp_op0, cmp_op1);
+
+ /* We handle the following cases:
+ 1) r = a CMP b ? -1 : 0
+ 2) r = a CMP b ? -1 : v
+ 3) r = a CMP b ? v : 0
+ 4) r = a CMP b ? v1 : v2 */
+
+ /* Case (1) above. We only move the results. */
+ if (operands[1] == CONSTM1_RTX (vimode)
+ && operands[2] == CONST0_RTX (vimode))
+ emit_move_insn (operands[0], cmp_res);
+ else
+ {
+ rtx src1 = gen_reg_rtx (vimode);
+ rtx src2 = gen_reg_rtx (vimode);
+ rtx mask = gen_reg_rtx (vimode);
+ rtx bsel;
+
+ /* Move the vector result to use it as a mask. */
+ emit_move_insn (mask, cmp_res);
+
+ if (register_operand (operands[1], mode))
+ {
+ rtx xop1 = operands[1];
+ if (mode != vimode)
+ {
+ xop1 = gen_reg_rtx (vimode);
+ emit_move_insn (xop1, gen_rtx_SUBREG (vimode, operands[1], 0));
+ }
+ emit_move_insn (src1, xop1);
+ }
+ else
+ {
+ gcc_assert (operands[1] == CONSTM1_RTX (vimode));
+ /* Case (2) if the below doesn't move the mask to src2. */
+ emit_move_insn (src1, mask);
+ }
+
+ if (register_operand (operands[2], mode))
+ {
+ rtx xop2 = operands[2];
+ if (mode != vimode)
+ {
+ xop2 = gen_reg_rtx (vimode);
+ emit_move_insn (xop2, gen_rtx_SUBREG (vimode, operands[2], 0));
+ }
+ emit_move_insn (src2, xop2);
+ }
+ else
+ {
+ gcc_assert (operands[2] == CONST0_RTX (mode));
+ /* Case (3) if the above didn't move the mask to src1. */
+ emit_move_insn (src2, mask);
+ }
+
+ /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
+ In any case, we eventually do vector mask-based copy. */
+ bsel = gen_rtx_IOR (vimode,
+ gen_rtx_AND (vimode,
+ gen_rtx_NOT (vimode, mask), src2),
+ gen_rtx_AND (vimode, mask, src1));
+ /* The result is placed back to a register with the mask. */
+ emit_insn (gen_rtx_SET (mask, bsel));
+ emit_move_insn (operands[0], gen_rtx_SUBREG (mode, mask, 0));
+ }
+}
+
+void
+loongarch_expand_vec_cond_mask_expr (machine_mode mode, machine_mode vimode,
+ rtx *operands)
+{
+ rtx cmp_res = operands[3];
+
+ /* We handle the following cases:
+ 1) r = a CMP b ? -1 : 0
+ 2) r = a CMP b ? -1 : v
+ 3) r = a CMP b ? v : 0
+ 4) r = a CMP b ? v1 : v2 */
+
+ /* Case (1) above. We only move the results. */
+ if (operands[1] == CONSTM1_RTX (vimode)
+ && operands[2] == CONST0_RTX (vimode))
+ emit_move_insn (operands[0], cmp_res);
+ else
+ {
+ rtx src1 = gen_reg_rtx (vimode);
+ rtx src2 = gen_reg_rtx (vimode);
+ rtx mask = gen_reg_rtx (vimode);
+ rtx bsel;
+
+ /* Move the vector result to use it as a mask. */
+ emit_move_insn (mask, cmp_res);
+
+ if (register_operand (operands[1], mode))
+ {
+ rtx xop1 = operands[1];
+ if (mode != vimode)
+ {
+ xop1 = gen_reg_rtx (vimode);
+ emit_move_insn (xop1, gen_rtx_SUBREG (vimode, operands[1], 0));
+ }
+ emit_move_insn (src1, xop1);
+ }
+ else
+ {
+ gcc_assert (operands[1] == CONSTM1_RTX (vimode));
+ /* Case (2) if the below doesn't move the mask to src2. */
+ emit_move_insn (src1, mask);
+ }
+
+ if (register_operand (operands[2], mode))
+ {
+ rtx xop2 = operands[2];
+ if (mode != vimode)
+ {
+ xop2 = gen_reg_rtx (vimode);
+ emit_move_insn (xop2, gen_rtx_SUBREG (vimode, operands[2], 0));
+ }
+ emit_move_insn (src2, xop2);
+ }
+ else
+ {
+ gcc_assert (operands[2] == CONST0_RTX (mode));
+ /* Case (3) if the above didn't move the mask to src1. */
+ emit_move_insn (src2, mask);
+ }
+
+ /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
+ In any case, we eventually do vector mask-based copy. */
+ bsel = gen_rtx_IOR (vimode,
+ gen_rtx_AND (vimode,
+ gen_rtx_NOT (vimode, mask), src2),
+ gen_rtx_AND (vimode, mask, src1));
+ /* The result is placed back to a register with the mask. */
+ emit_insn (gen_rtx_SET (mask, bsel));
+ emit_move_insn (operands[0], gen_rtx_SUBREG (mode, mask, 0));
+ }
+}
+
+/* Expand integer vector comparison */
+bool
+loongarch_expand_vec_cmp (rtx operands[])
+{
+
+ rtx_code code = GET_CODE (operands[1]);
+ loongarch_expand_lsx_cmp (operands[0], code, operands[2], operands[3]);
+ return true;
+}
+
+/* Implement TARGET_CASE_VALUES_THRESHOLD. */
+
+unsigned int
+loongarch_case_values_threshold (void)
+{
+ return default_case_values_threshold ();
+}
+
+/* Implement TARGET_SPILL_CLASS. */
+
+static reg_class_t
+loongarch_spill_class (reg_class_t rclass ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return NO_REGS;
+}
+
+/* Implement TARGET_PROMOTE_FUNCTION_MODE. */
+
+/* This function is equivalent to default_promote_function_mode_always_promote
+ except that it returns a promoted mode even if type is NULL_TREE. This is
+ needed by libcalls which have no type (only a mode) such as fixed conversion
+ routines that take a signed or unsigned char/short argument and convert it
+ to a fixed type. */
+
+static machine_mode
+loongarch_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
+ machine_mode mode,
+ int *punsignedp ATTRIBUTE_UNUSED,
+ const_tree fntype ATTRIBUTE_UNUSED,
+ int for_return ATTRIBUTE_UNUSED)
+{
+ int unsignedp;
+
+ if (type != NULL_TREE)
+ return promote_mode (type, mode, punsignedp);
+
+ unsignedp = *punsignedp;
+ PROMOTE_MODE (mode, unsignedp, type);
+ *punsignedp = unsignedp;
+ return mode;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. See loongarch_compute_frame_info
+ for details about the frame layout. */
+
+static HOST_WIDE_INT
+loongarch_starting_frame_offset (void)
+{
+ if (FRAME_GROWS_DOWNWARD)
+ return 0;
+ return crtl->outgoing_args_size;
+}
+
+/* A subroutine of loongarch_build_signbit_mask. If VECT is true,
+ then replicate the value for all elements of the vector
+ register. */
+
+rtx
+loongarch_build_const_vector (machine_mode mode, bool vect, rtx value)
+{
+ int i, n_elt;
+ rtvec v;
+ machine_mode scalar_mode;
+
+ switch (mode)
+ {
+ case E_V32QImode:
+ case E_V16QImode:
+ case E_V32HImode:
+ case E_V16HImode:
+ case E_V8HImode:
+ case E_V8SImode:
+ case E_V4SImode:
+ case E_V8DImode:
+ case E_V4DImode:
+ case E_V2DImode:
+ gcc_assert (vect);
+ /* FALLTHRU */
+ case E_V8SFmode:
+ case E_V4SFmode:
+ case E_V8DFmode:
+ case E_V4DFmode:
+ case E_V2DFmode:
+ n_elt = GET_MODE_NUNITS (mode);
+ v = rtvec_alloc (n_elt);
+ scalar_mode = GET_MODE_INNER (mode);
+
+ RTVEC_ELT (v, 0) = value;
+
+ for (i = 1; i < n_elt; ++i)
+ RTVEC_ELT (v, i) = vect ? value : CONST0_RTX (scalar_mode);
+
+ return gen_rtx_CONST_VECTOR (mode, v);
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Create a mask for the sign bit in MODE
+ for an register. If VECT is true, then replicate the mask for
+ all elements of the vector register. If INVERT is true, then create
+ a mask excluding the sign bit. */
+
+rtx
+loongarch_build_signbit_mask (machine_mode mode, bool vect, bool invert)
+{
+ machine_mode vec_mode, imode;
+ wide_int w;
+ rtx mask, v;
+
+ switch (mode)
+ {
+ case E_V16SImode:
+ case E_V16SFmode:
+ case E_V8SImode:
+ case E_V4SImode:
+ case E_V8SFmode:
+ case E_V4SFmode:
+ vec_mode = mode;
+ imode = SImode;
+ break;
+
+ case E_V8DImode:
+ case E_V4DImode:
+ case E_V2DImode:
+ case E_V8DFmode:
+ case E_V4DFmode:
+ case E_V2DFmode:
+ vec_mode = mode;
+ imode = DImode;
+ break;
+
+ case E_TImode:
+ case E_TFmode:
+ vec_mode = VOIDmode;
+ imode = TImode;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ machine_mode inner_mode = GET_MODE_INNER (mode);
+ w = wi::set_bit_in_zero (GET_MODE_BITSIZE (inner_mode) - 1,
+ GET_MODE_BITSIZE (inner_mode));
+ if (invert)
+ w = wi::bit_not (w);
+
+ /* Force this value into the low part of a fp vector constant. */
+ mask = immed_wide_int_const (w, imode);
+ mask = gen_lowpart (inner_mode, mask);
+
+ if (vec_mode == VOIDmode)
+ return force_reg (inner_mode, mask);
+
+ v = loongarch_build_const_vector (vec_mode, vect, mask);
+ return force_reg (vec_mode, v);
+}
+
+static bool
+loongarch_builtin_support_vector_misalignment (machine_mode mode,
+ const_tree type,
+ int misalignment,
+ bool is_packed)
+{
+ if (ISA_HAS_LSX && STRICT_ALIGNMENT)
+ {
+ if (optab_handler (movmisalign_optab, mode) == CODE_FOR_nothing)
+ return false;
+ if (misalignment == -1)
+ return false;
+ }
+ return default_builtin_support_vector_misalignment (mode, type, misalignment,
+ is_packed);
+}
+
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE loongarch_option_override
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS loongarch_legitimize_address
+
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define TARGET_ASM_SELECT_RTX_SECTION loongarch_select_rtx_section
+#undef TARGET_ASM_FUNCTION_RODATA_SECTION
+#define TARGET_ASM_FUNCTION_RODATA_SECTION loongarch_function_rodata_section
+
+#undef TARGET_SCHED_INIT
+#define TARGET_SCHED_INIT loongarch_sched_init
+#undef TARGET_SCHED_REORDER
+#define TARGET_SCHED_REORDER loongarch_sched_reorder
+#undef TARGET_SCHED_REORDER2
+#define TARGET_SCHED_REORDER2 loongarch_sched_reorder2
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE loongarch_variable_issue
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST loongarch_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE loongarch_issue_rate
+#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
+#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
+ loongarch_multipass_dfa_lookahead
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL loongarch_function_ok_for_sibcall
+
+#undef TARGET_VALID_POINTER_MODE
+#define TARGET_VALID_POINTER_MODE loongarch_valid_pointer_mode
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST loongarch_register_move_cost
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST loongarch_memory_move_cost
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS loongarch_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST loongarch_address_cost
+#undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
+#define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \
+ loongarch_builtin_vectorization_cost
+
+
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P loongarch_in_small_data_p
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS loongarch_preferred_reload_class
+
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START loongarch_va_start
+
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE loongarch_promote_function_mode
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY loongarch_return_in_memory
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE loongarch_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE loongarch_libcall_value
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK loongarch_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
+ hook_bool_const_tree_hwi_hwi_const_tree_true
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND loongarch_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS loongarch_print_operand_address
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P \
+ loongarch_print_operand_punct_valid_p
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS loongarch_setup_incoming_varargs
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE loongarch_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES loongarch_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG loongarch_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE loongarch_function_arg_advance
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY loongarch_function_arg_boundary
+
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P loongarch_vector_mode_supported_p
+
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P loongarch_scalar_mode_supported_p
+
+#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
+#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE loongarch_preferred_simd_mode
+
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+ loongarch_autovectorize_vector_modes
+
+#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS loongarch_init_builtins
#undef TARGET_BUILTIN_DECL
#define TARGET_BUILTIN_DECL loongarch_builtin_decl
#undef TARGET_MAX_ANCHOR_OFFSET
#define TARGET_MAX_ANCHOR_OFFSET (IMM_REACH/2-1)
+#undef TARGET_VECTORIZE_VEC_PERM_CONST
+#define TARGET_VECTORIZE_VEC_PERM_CONST loongarch_vectorize_vec_perm_const
+
+#undef TARGET_SCHED_REASSOCIATION_WIDTH
+#define TARGET_SCHED_REASSOCIATION_WIDTH loongarch_sched_reassociation_width
+
+#undef TARGET_CASE_VALUES_THRESHOLD
+#define TARGET_CASE_VALUES_THRESHOLD loongarch_case_values_threshold
#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV loongarch_atomic_assign_expand_fenv
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P loongarch_modes_tieable_p
+#undef TARGET_HARD_REGNO_CALL_PART_CLOBBERED
+#define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
+ loongarch_hard_regno_call_part_clobbered
+
#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 2
#define TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS \
loongarch_set_handled_components
+#undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
+#define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
+ loongarch_builtin_support_vector_misalignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-loongarch.h"
--- /dev/null
+;; Machine Description for LARCH Loongson SX ASE
+;;
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+;;
+
+(define_c_enum "unspec" [
+ UNSPEC_LSX_ABSD_S
+ UNSPEC_LSX_VABSD_U
+ UNSPEC_LSX_VAVG_S
+ UNSPEC_LSX_VAVG_U
+ UNSPEC_LSX_VAVGR_S
+ UNSPEC_LSX_VAVGR_U
+ UNSPEC_LSX_VBITCLR
+ UNSPEC_LSX_VBITCLRI
+ UNSPEC_LSX_VBITREV
+ UNSPEC_LSX_VBITREVI
+ UNSPEC_LSX_VBITSET
+ UNSPEC_LSX_VBITSETI
+ UNSPEC_LSX_BRANCH_V
+ UNSPEC_LSX_BRANCH
+ UNSPEC_LSX_VFCMP_CAF
+ UNSPEC_LSX_VFCLASS
+ UNSPEC_LSX_VFCMP_CUNE
+ UNSPEC_LSX_VFCVT
+ UNSPEC_LSX_VFCVTH
+ UNSPEC_LSX_VFCVTL
+ UNSPEC_LSX_VFLOGB
+ UNSPEC_LSX_VFRECIP
+ UNSPEC_LSX_VFRINT
+ UNSPEC_LSX_VFRSQRT
+ UNSPEC_LSX_VFCMP_SAF
+ UNSPEC_LSX_VFCMP_SEQ
+ UNSPEC_LSX_VFCMP_SLE
+ UNSPEC_LSX_VFCMP_SLT
+ UNSPEC_LSX_VFCMP_SNE
+ UNSPEC_LSX_VFCMP_SOR
+ UNSPEC_LSX_VFCMP_SUEQ
+ UNSPEC_LSX_VFCMP_SULE
+ UNSPEC_LSX_VFCMP_SULT
+ UNSPEC_LSX_VFCMP_SUN
+ UNSPEC_LSX_VFCMP_SUNE
+ UNSPEC_LSX_VFTINT_S
+ UNSPEC_LSX_VFTINT_U
+ UNSPEC_LSX_VSAT_S
+ UNSPEC_LSX_VSAT_U
+ UNSPEC_LSX_VREPLVEI
+ UNSPEC_LSX_VSRAR
+ UNSPEC_LSX_VSRARI
+ UNSPEC_LSX_VSRLR
+ UNSPEC_LSX_VSRLRI
+ UNSPEC_LSX_VSHUF
+ UNSPEC_LSX_VMUH_S
+ UNSPEC_LSX_VMUH_U
+ UNSPEC_LSX_VEXTW_S
+ UNSPEC_LSX_VEXTW_U
+ UNSPEC_LSX_VSLLWIL_S
+ UNSPEC_LSX_VSLLWIL_U
+ UNSPEC_LSX_VSRAN
+ UNSPEC_LSX_VSSRAN_S
+ UNSPEC_LSX_VSSRAN_U
+ UNSPEC_LSX_VSRAIN
+ UNSPEC_LSX_VSRAINS_S
+ UNSPEC_LSX_VSRAINS_U
+ UNSPEC_LSX_VSRARN
+ UNSPEC_LSX_VSRLN
+ UNSPEC_LSX_VSRLRN
+ UNSPEC_LSX_VSSRLRN_U
+ UNSPEC_LSX_VFRSTPI
+ UNSPEC_LSX_VFRSTP
+ UNSPEC_LSX_VSHUF4I
+ UNSPEC_LSX_VBSRL_V
+ UNSPEC_LSX_VBSLL_V
+ UNSPEC_LSX_VEXTRINS
+ UNSPEC_LSX_VMSKLTZ
+ UNSPEC_LSX_VSIGNCOV
+ UNSPEC_LSX_VFTINTRNE
+ UNSPEC_LSX_VFTINTRP
+ UNSPEC_LSX_VFTINTRM
+ UNSPEC_LSX_VFTINT_W_D
+ UNSPEC_LSX_VFFINT_S_L
+ UNSPEC_LSX_VFTINTRZ_W_D
+ UNSPEC_LSX_VFTINTRP_W_D
+ UNSPEC_LSX_VFTINTRM_W_D
+ UNSPEC_LSX_VFTINTRNE_W_D
+ UNSPEC_LSX_VFTINTL_L_S
+ UNSPEC_LSX_VFFINTH_D_W
+ UNSPEC_LSX_VFFINTL_D_W
+ UNSPEC_LSX_VFTINTRZL_L_S
+ UNSPEC_LSX_VFTINTRZH_L_S
+ UNSPEC_LSX_VFTINTRPL_L_S
+ UNSPEC_LSX_VFTINTRPH_L_S
+ UNSPEC_LSX_VFTINTRMH_L_S
+ UNSPEC_LSX_VFTINTRML_L_S
+ UNSPEC_LSX_VFTINTRNEL_L_S
+ UNSPEC_LSX_VFTINTRNEH_L_S
+ UNSPEC_LSX_VFTINTH_L_H
+ UNSPEC_LSX_VFRINTRNE_S
+ UNSPEC_LSX_VFRINTRNE_D
+ UNSPEC_LSX_VFRINTRZ_S
+ UNSPEC_LSX_VFRINTRZ_D
+ UNSPEC_LSX_VFRINTRP_S
+ UNSPEC_LSX_VFRINTRP_D
+ UNSPEC_LSX_VFRINTRM_S
+ UNSPEC_LSX_VFRINTRM_D
+ UNSPEC_LSX_VSSRARN_S
+ UNSPEC_LSX_VSSRARN_U
+ UNSPEC_LSX_VSSRLN_U
+ UNSPEC_LSX_VSSRLN
+ UNSPEC_LSX_VSSRLRN
+ UNSPEC_LSX_VLDI
+ UNSPEC_LSX_VSHUF_B
+ UNSPEC_LSX_VLDX
+ UNSPEC_LSX_VSTX
+ UNSPEC_LSX_VEXTL_QU_DU
+ UNSPEC_LSX_VSETEQZ_V
+ UNSPEC_LSX_VADDWEV
+ UNSPEC_LSX_VADDWEV2
+ UNSPEC_LSX_VADDWEV3
+ UNSPEC_LSX_VADDWOD
+ UNSPEC_LSX_VADDWOD2
+ UNSPEC_LSX_VADDWOD3
+ UNSPEC_LSX_VSUBWEV
+ UNSPEC_LSX_VSUBWEV2
+ UNSPEC_LSX_VSUBWOD
+ UNSPEC_LSX_VSUBWOD2
+ UNSPEC_LSX_VMULWEV
+ UNSPEC_LSX_VMULWEV2
+ UNSPEC_LSX_VMULWEV3
+ UNSPEC_LSX_VMULWOD
+ UNSPEC_LSX_VMULWOD2
+ UNSPEC_LSX_VMULWOD3
+ UNSPEC_LSX_VHADDW_Q_D
+ UNSPEC_LSX_VHADDW_QU_DU
+ UNSPEC_LSX_VHSUBW_Q_D
+ UNSPEC_LSX_VHSUBW_QU_DU
+ UNSPEC_LSX_VMADDWEV
+ UNSPEC_LSX_VMADDWEV2
+ UNSPEC_LSX_VMADDWEV3
+ UNSPEC_LSX_VMADDWOD
+ UNSPEC_LSX_VMADDWOD2
+ UNSPEC_LSX_VMADDWOD3
+ UNSPEC_LSX_VROTR
+ UNSPEC_LSX_VADD_Q
+ UNSPEC_LSX_VSUB_Q
+ UNSPEC_LSX_VEXTH_Q_D
+ UNSPEC_LSX_VEXTH_QU_DU
+ UNSPEC_LSX_VMSKGEZ
+ UNSPEC_LSX_VMSKNZ
+ UNSPEC_LSX_VEXTL_Q_D
+ UNSPEC_LSX_VSRLNI
+ UNSPEC_LSX_VSRLRNI
+ UNSPEC_LSX_VSSRLNI
+ UNSPEC_LSX_VSSRLNI2
+ UNSPEC_LSX_VSSRLRNI
+ UNSPEC_LSX_VSSRLRNI2
+ UNSPEC_LSX_VSRANI
+ UNSPEC_LSX_VSRARNI
+ UNSPEC_LSX_VSSRANI
+ UNSPEC_LSX_VSSRANI2
+ UNSPEC_LSX_VSSRARNI
+ UNSPEC_LSX_VSSRARNI2
+ UNSPEC_LSX_VPERMI
+])
+
+;; This attribute gives suffix for integers in VHMODE.
+(define_mode_attr dlsxfmt
+ [(V2DI "q")
+ (V4SI "d")
+ (V8HI "w")
+ (V16QI "h")])
+
+(define_mode_attr dlsxfmt_u
+ [(V2DI "qu")
+ (V4SI "du")
+ (V8HI "wu")
+ (V16QI "hu")])
+
+(define_mode_attr d2lsxfmt
+ [(V4SI "q")
+ (V8HI "d")
+ (V16QI "w")])
+
+(define_mode_attr d2lsxfmt_u
+ [(V4SI "qu")
+ (V8HI "du")
+ (V16QI "wu")])
+
+;; The attribute gives two double modes for vector modes.
+(define_mode_attr VD2MODE
+ [(V4SI "V2DI")
+ (V8HI "V2DI")
+ (V16QI "V4SI")])
+
+;; All vector modes with 128 bits.
+(define_mode_iterator LSX [V2DF V4SF V2DI V4SI V8HI V16QI])
+
+;; Same as LSX. Used by vcond to iterate two modes.
+(define_mode_iterator LSX_2 [V2DF V4SF V2DI V4SI V8HI V16QI])
+
+;; Only used for vilvh and splitting insert_d and copy_{u,s}.d.
+(define_mode_iterator LSX_D [V2DI V2DF])
+
+;; Only used for copy_{u,s}.w and vilvh.
+(define_mode_iterator LSX_W [V4SI V4SF])
+
+;; Only integer modes.
+(define_mode_iterator ILSX [V2DI V4SI V8HI V16QI])
+
+;; As ILSX but excludes V16QI.
+(define_mode_iterator ILSX_DWH [V2DI V4SI V8HI])
+
+;; As LSX but excludes V16QI.
+(define_mode_iterator LSX_DWH [V2DF V4SF V2DI V4SI V8HI])
+
+;; As ILSX but excludes V2DI.
+(define_mode_iterator ILSX_WHB [V4SI V8HI V16QI])
+
+;; Only integer modes equal or larger than a word.
+(define_mode_iterator ILSX_DW [V2DI V4SI])
+
+;; Only integer modes smaller than a word.
+(define_mode_iterator ILSX_HB [V8HI V16QI])
+
+;;;; Only integer modes for fixed-point madd_q/maddr_q.
+;;(define_mode_iterator ILSX_WH [V4SI V8HI])
+
+;; Only floating-point modes.
+(define_mode_iterator FLSX [V2DF V4SF])
+
+;; Only used for immediate set shuffle elements instruction.
+(define_mode_iterator LSX_WHB_W [V4SI V8HI V16QI V4SF])
+
+;; The attribute gives the integer vector mode with same size.
+(define_mode_attr VIMODE
+ [(V2DF "V2DI")
+ (V4SF "V4SI")
+ (V2DI "V2DI")
+ (V4SI "V4SI")
+ (V8HI "V8HI")
+ (V16QI "V16QI")])
+
+;; The attribute gives half modes for vector modes.
+(define_mode_attr VHMODE
+ [(V8HI "V16QI")
+ (V4SI "V8HI")
+ (V2DI "V4SI")])
+
+;; The attribute gives double modes for vector modes.
+(define_mode_attr VDMODE
+ [(V2DI "V2DI")
+ (V4SI "V2DI")
+ (V8HI "V4SI")
+ (V16QI "V8HI")])
+
+;; The attribute gives half modes with same number of elements for vector modes.
+(define_mode_attr VTRUNCMODE
+ [(V8HI "V8QI")
+ (V4SI "V4HI")
+ (V2DI "V2SI")])
+
+;; Double-sized Vector MODE with same elemet type. "Vector, Enlarged-MODE"
+(define_mode_attr VEMODE
+ [(V4SF "V8SF")
+ (V4SI "V8SI")
+ (V2DI "V4DI")
+ (V2DF "V4DF")])
+
+;; This attribute gives the mode of the result for "vpickve2gr_b, copy_u_b" etc.
+(define_mode_attr VRES
+ [(V2DF "DF")
+ (V4SF "SF")
+ (V2DI "DI")
+ (V4SI "SI")
+ (V8HI "SI")
+ (V16QI "SI")])
+
+;; Only used with LSX_D iterator.
+(define_mode_attr lsx_d
+ [(V2DI "reg_or_0")
+ (V2DF "register")])
+
+;; This attribute gives the integer vector mode with same size.
+(define_mode_attr mode_i
+ [(V2DF "v2di")
+ (V4SF "v4si")
+ (V2DI "v2di")
+ (V4SI "v4si")
+ (V8HI "v8hi")
+ (V16QI "v16qi")])
+
+;; This attribute gives suffix for LSX instructions.
+(define_mode_attr lsxfmt
+ [(V2DF "d")
+ (V4SF "w")
+ (V2DI "d")
+ (V4SI "w")
+ (V8HI "h")
+ (V16QI "b")])
+
+;; This attribute gives suffix for LSX instructions.
+(define_mode_attr lsxfmt_u
+ [(V2DF "du")
+ (V4SF "wu")
+ (V2DI "du")
+ (V4SI "wu")
+ (V8HI "hu")
+ (V16QI "bu")])
+
+;; This attribute gives suffix for integers in VHMODE.
+(define_mode_attr hlsxfmt
+ [(V2DI "w")
+ (V4SI "h")
+ (V8HI "b")])
+
+;; This attribute gives suffix for integers in VHMODE.
+(define_mode_attr hlsxfmt_u
+ [(V2DI "wu")
+ (V4SI "hu")
+ (V8HI "bu")])
+
+;; This attribute gives define_insn suffix for LSX instructions that need
+;; distinction between integer and floating point.
+(define_mode_attr lsxfmt_f
+ [(V2DF "d_f")
+ (V4SF "w_f")
+ (V2DI "d")
+ (V4SI "w")
+ (V8HI "h")
+ (V16QI "b")])
+
+(define_mode_attr flsxfmt_f
+ [(V2DF "d_f")
+ (V4SF "s_f")
+ (V2DI "d")
+ (V4SI "w")
+ (V8HI "h")
+ (V16QI "b")])
+
+(define_mode_attr flsxfmt
+ [(V2DF "d")
+ (V4SF "s")
+ (V2DI "d")
+ (V4SI "s")])
+
+(define_mode_attr flsxfrint
+ [(V2DF "d")
+ (V4SF "s")])
+
+(define_mode_attr ilsxfmt
+ [(V2DF "l")
+ (V4SF "w")])
+
+(define_mode_attr ilsxfmt_u
+ [(V2DF "lu")
+ (V4SF "wu")])
+
+;; This is used to form an immediate operand constraint using
+;; "const_<indeximm>_operand".
+(define_mode_attr indeximm
+ [(V2DF "0_or_1")
+ (V4SF "0_to_3")
+ (V2DI "0_or_1")
+ (V4SI "0_to_3")
+ (V8HI "uimm3")
+ (V16QI "uimm4")])
+
+;; This attribute represents bitmask needed for vec_merge using
+;; "const_<bitmask>_operand".
+(define_mode_attr bitmask
+ [(V2DF "exp_2")
+ (V4SF "exp_4")
+ (V2DI "exp_2")
+ (V4SI "exp_4")
+ (V8HI "exp_8")
+ (V16QI "exp_16")])
+
+;; This attribute is used to form an immediate operand constraint using
+;; "const_<bitimm>_operand".
+(define_mode_attr bitimm
+ [(V16QI "uimm3")
+ (V8HI "uimm4")
+ (V4SI "uimm5")
+ (V2DI "uimm6")])
+
+
+(define_int_iterator FRINT_S [UNSPEC_LSX_VFRINTRP_S
+ UNSPEC_LSX_VFRINTRZ_S
+ UNSPEC_LSX_VFRINT
+ UNSPEC_LSX_VFRINTRM_S])
+
+(define_int_iterator FRINT_D [UNSPEC_LSX_VFRINTRP_D
+ UNSPEC_LSX_VFRINTRZ_D
+ UNSPEC_LSX_VFRINT
+ UNSPEC_LSX_VFRINTRM_D])
+
+(define_int_attr frint_pattern_s
+ [(UNSPEC_LSX_VFRINTRP_S "ceil")
+ (UNSPEC_LSX_VFRINTRZ_S "btrunc")
+ (UNSPEC_LSX_VFRINT "rint")
+ (UNSPEC_LSX_VFRINTRM_S "floor")])
+
+(define_int_attr frint_pattern_d
+ [(UNSPEC_LSX_VFRINTRP_D "ceil")
+ (UNSPEC_LSX_VFRINTRZ_D "btrunc")
+ (UNSPEC_LSX_VFRINT "rint")
+ (UNSPEC_LSX_VFRINTRM_D "floor")])
+
+(define_int_attr frint_suffix
+ [(UNSPEC_LSX_VFRINTRP_S "rp")
+ (UNSPEC_LSX_VFRINTRP_D "rp")
+ (UNSPEC_LSX_VFRINTRZ_S "rz")
+ (UNSPEC_LSX_VFRINTRZ_D "rz")
+ (UNSPEC_LSX_VFRINT "")
+ (UNSPEC_LSX_VFRINTRM_S "rm")
+ (UNSPEC_LSX_VFRINTRM_D "rm")])
+
+(define_expand "vec_init<mode><unitmode>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand:LSX 1 "")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vector_init (operands[0], operands[1]);
+ DONE;
+})
+
+;; vpickev pattern with implicit type conversion.
+(define_insn "vec_pack_trunc_<mode>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (vec_concat:<VHMODE>
+ (truncate:<VTRUNCMODE>
+ (match_operand:ILSX_DWH 1 "register_operand" "f"))
+ (truncate:<VTRUNCMODE>
+ (match_operand:ILSX_DWH 2 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vpickev.<hlsxfmt>\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "<MODE>")])
+
+(define_expand "vec_unpacks_hi_v4sf"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_dup 2))))]
+ "ISA_HAS_LSX"
+{
+ operands[2] = loongarch_lsx_vec_parallel_const_half (V4SFmode,
+ true/*high_p*/);
+})
+
+(define_expand "vec_unpacks_lo_v4sf"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_dup 2))))]
+ "ISA_HAS_LSX"
+{
+ operands[2] = loongarch_lsx_vec_parallel_const_half (V4SFmode,
+ false/*high_p*/);
+})
+
+(define_expand "vec_unpacks_hi_<mode>"
+ [(match_operand:<VDMODE> 0 "register_operand")
+ (match_operand:ILSX_WHB 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_unpack (operands, false/*unsigned_p*/, true/*high_p*/);
+ DONE;
+})
+
+(define_expand "vec_unpacks_lo_<mode>"
+ [(match_operand:<VDMODE> 0 "register_operand")
+ (match_operand:ILSX_WHB 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_unpack (operands, false/*unsigned_p*/, false/*high_p*/);
+ DONE;
+})
+
+(define_expand "vec_unpacku_hi_<mode>"
+ [(match_operand:<VDMODE> 0 "register_operand")
+ (match_operand:ILSX_WHB 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_unpack (operands, true/*unsigned_p*/, true/*high_p*/);
+ DONE;
+})
+
+(define_expand "vec_unpacku_lo_<mode>"
+ [(match_operand:<VDMODE> 0 "register_operand")
+ (match_operand:ILSX_WHB 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_unpack (operands, true/*unsigned_p*/, false/*high_p*/);
+ DONE;
+})
+
+(define_expand "vec_extract<mode><unitmode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:ILSX 1 "register_operand")
+ (match_operand 2 "const_<indeximm>_operand")]
+ "ISA_HAS_LSX"
+{
+ if (<UNITMODE>mode == QImode || <UNITMODE>mode == HImode)
+ {
+ rtx dest1 = gen_reg_rtx (SImode);
+ emit_insn (gen_lsx_vpickve2gr_<lsxfmt> (dest1, operands[1], operands[2]));
+ emit_move_insn (operands[0],
+ gen_lowpart (<UNITMODE>mode, dest1));
+ }
+ else
+ emit_insn (gen_lsx_vpickve2gr_<lsxfmt> (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_expand "vec_extract<mode><unitmode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:FLSX 1 "register_operand")
+ (match_operand 2 "const_<indeximm>_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx temp;
+ HOST_WIDE_INT val = INTVAL (operands[2]);
+
+ if (val == 0)
+ temp = operands[1];
+ else
+ {
+ rtx n = GEN_INT (val * GET_MODE_SIZE (<UNITMODE>mode));
+ temp = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_lsx_vbsrl_<lsxfmt_f> (temp, operands[1], n));
+ }
+ emit_insn (gen_lsx_vec_extract_<lsxfmt_f> (operands[0], temp));
+ DONE;
+})
+
+(define_insn_and_split "lsx_vec_extract_<lsxfmt_f>"
+ [(set (match_operand:<UNITMODE> 0 "register_operand" "=f")
+ (vec_select:<UNITMODE>
+ (match_operand:FLSX 1 "register_operand" "f")
+ (parallel [(const_int 0)])))]
+ "ISA_HAS_LSX"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (match_dup 1))]
+{
+ operands[1] = gen_rtx_REG (<UNITMODE>mode, REGNO (operands[1]));
+}
+ [(set_attr "move_type" "fmove")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_expand "vec_set<mode>"
+ [(match_operand:ILSX 0 "register_operand")
+ (match_operand:<UNITMODE> 1 "reg_or_0_operand")
+ (match_operand 2 "const_<indeximm>_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx index = GEN_INT (1 << INTVAL (operands[2]));
+ emit_insn (gen_lsx_vinsgr2vr_<lsxfmt> (operands[0], operands[1],
+ operands[0], index));
+ DONE;
+})
+
+(define_expand "vec_set<mode>"
+ [(match_operand:FLSX 0 "register_operand")
+ (match_operand:<UNITMODE> 1 "register_operand")
+ (match_operand 2 "const_<indeximm>_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx index = GEN_INT (1 << INTVAL (operands[2]));
+ emit_insn (gen_lsx_vextrins_<lsxfmt_f>_scalar (operands[0], operands[1],
+ operands[0], index));
+ DONE;
+})
+
+(define_expand "vec_cmp<mode><mode_i>"
+ [(set (match_operand:<VIMODE> 0 "register_operand")
+ (match_operator 1 ""
+ [(match_operand:LSX 2 "register_operand")
+ (match_operand:LSX 3 "register_operand")]))]
+ "ISA_HAS_LSX"
+{
+ bool ok = loongarch_expand_vec_cmp (operands);
+ gcc_assert (ok);
+ DONE;
+})
+
+(define_expand "vec_cmpu<ILSX:mode><mode_i>"
+ [(set (match_operand:<VIMODE> 0 "register_operand")
+ (match_operator 1 ""
+ [(match_operand:ILSX 2 "register_operand")
+ (match_operand:ILSX 3 "register_operand")]))]
+ "ISA_HAS_LSX"
+{
+ bool ok = loongarch_expand_vec_cmp (operands);
+ gcc_assert (ok);
+ DONE;
+})
+
+(define_expand "vcondu<LSX:mode><ILSX:mode>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand:LSX 1 "reg_or_m1_operand")
+ (match_operand:LSX 2 "reg_or_0_operand")
+ (match_operator 3 ""
+ [(match_operand:ILSX 4 "register_operand")
+ (match_operand:ILSX 5 "register_operand")])]
+ "ISA_HAS_LSX
+ && (GET_MODE_NUNITS (<LSX:MODE>mode) == GET_MODE_NUNITS (<ILSX:MODE>mode))"
+{
+ loongarch_expand_vec_cond_expr (<LSX:MODE>mode, <LSX:VIMODE>mode, operands);
+ DONE;
+})
+
+(define_expand "vcond<LSX:mode><LSX_2:mode>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand:LSX 1 "reg_or_m1_operand")
+ (match_operand:LSX 2 "reg_or_0_operand")
+ (match_operator 3 ""
+ [(match_operand:LSX_2 4 "register_operand")
+ (match_operand:LSX_2 5 "register_operand")])]
+ "ISA_HAS_LSX
+ && (GET_MODE_NUNITS (<LSX:MODE>mode) == GET_MODE_NUNITS (<LSX_2:MODE>mode))"
+{
+ loongarch_expand_vec_cond_expr (<LSX:MODE>mode, <LSX:VIMODE>mode, operands);
+ DONE;
+})
+
+(define_expand "vcond_mask_<ILSX:mode><ILSX:mode>"
+ [(match_operand:ILSX 0 "register_operand")
+ (match_operand:ILSX 1 "reg_or_m1_operand")
+ (match_operand:ILSX 2 "reg_or_0_operand")
+ (match_operand:ILSX 3 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_cond_mask_expr (<ILSX:MODE>mode,
+ <ILSX:VIMODE>mode, operands);
+ DONE;
+})
+
+(define_insn "lsx_vinsgr2vr_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (vec_merge:ILSX
+ (vec_duplicate:ILSX
+ (match_operand:<UNITMODE> 1 "reg_or_0_operand" "rJ"))
+ (match_operand:ILSX 2 "register_operand" "0")
+ (match_operand 3 "const_<bitmask>_operand" "")))]
+ "ISA_HAS_LSX"
+{
+ if (!TARGET_64BIT && (<MODE>mode == V2DImode || <MODE>mode == V2DFmode))
+ return "#";
+ else
+ return "vinsgr2vr.<lsxfmt>\t%w0,%z1,%y3";
+}
+ [(set_attr "type" "simd_insert")
+ (set_attr "mode" "<MODE>")])
+
+(define_split
+ [(set (match_operand:LSX_D 0 "register_operand")
+ (vec_merge:LSX_D
+ (vec_duplicate:LSX_D
+ (match_operand:<UNITMODE> 1 "<LSX_D:lsx_d>_operand"))
+ (match_operand:LSX_D 2 "register_operand")
+ (match_operand 3 "const_<bitmask>_operand")))]
+ "reload_completed && ISA_HAS_LSX && !TARGET_64BIT"
+ [(const_int 0)]
+{
+ loongarch_split_lsx_insert_d (operands[0], operands[2], operands[3], operands[1]);
+ DONE;
+})
+
+(define_insn "lsx_vextrins_<lsxfmt_f>_internal"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_merge:LSX
+ (vec_duplicate:LSX
+ (vec_select:<UNITMODE>
+ (match_operand:LSX 1 "register_operand" "f")
+ (parallel [(const_int 0)])))
+ (match_operand:LSX 2 "register_operand" "0")
+ (match_operand 3 "const_<bitmask>_operand" "")))]
+ "ISA_HAS_LSX"
+ "vextrins.<lsxfmt>\t%w0,%w1,%y3<<4"
+ [(set_attr "type" "simd_insert")
+ (set_attr "mode" "<MODE>")])
+
+;; Operand 3 is a scalar.
+(define_insn "lsx_vextrins_<lsxfmt_f>_scalar"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (vec_merge:FLSX
+ (vec_duplicate:FLSX
+ (match_operand:<UNITMODE> 1 "register_operand" "f"))
+ (match_operand:FLSX 2 "register_operand" "0")
+ (match_operand 3 "const_<bitmask>_operand" "")))]
+ "ISA_HAS_LSX"
+ "vextrins.<lsxfmt>\t%w0,%w1,%y3<<4"
+ [(set_attr "type" "simd_insert")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vpickve2gr_<lsxfmt><u>"
+ [(set (match_operand:<VRES> 0 "register_operand" "=r")
+ (any_extend:<VRES>
+ (vec_select:<UNITMODE>
+ (match_operand:ILSX_HB 1 "register_operand" "f")
+ (parallel [(match_operand 2 "const_<indeximm>_operand" "")]))))]
+ "ISA_HAS_LSX"
+ "vpickve2gr.<lsxfmt><u>\t%0,%w1,%2"
+ [(set_attr "type" "simd_copy")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vpickve2gr_<lsxfmt_f><u>"
+ [(set (match_operand:<UNITMODE> 0 "register_operand" "=r")
+ (any_extend:<UNITMODE>
+ (vec_select:<UNITMODE>
+ (match_operand:LSX_W 1 "register_operand" "f")
+ (parallel [(match_operand 2 "const_<indeximm>_operand" "")]))))]
+ "ISA_HAS_LSX"
+ "vpickve2gr.<lsxfmt><u>\t%0,%w1,%2"
+ [(set_attr "type" "simd_copy")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn_and_split "lsx_vpickve2gr_du"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (vec_select:DI
+ (match_operand:V2DI 1 "register_operand" "f")
+ (parallel [(match_operand 2 "const_0_or_1_operand" "")])))]
+ "ISA_HAS_LSX"
+{
+ if (TARGET_64BIT)
+ return "vpickve2gr.du\t%0,%w1,%2";
+ else
+ return "#";
+}
+ "reload_completed && ISA_HAS_LSX && !TARGET_64BIT"
+ [(const_int 0)]
+{
+ loongarch_split_lsx_copy_d (operands[0], operands[1], operands[2],
+ gen_lsx_vpickve2gr_wu);
+ DONE;
+}
+ [(set_attr "type" "simd_copy")
+ (set_attr "mode" "V2DI")])
+
+(define_insn_and_split "lsx_vpickve2gr_<lsxfmt_f>"
+ [(set (match_operand:<UNITMODE> 0 "register_operand" "=r")
+ (vec_select:<UNITMODE>
+ (match_operand:LSX_D 1 "register_operand" "f")
+ (parallel [(match_operand 2 "const_<indeximm>_operand" "")])))]
+ "ISA_HAS_LSX"
+{
+ if (TARGET_64BIT)
+ return "vpickve2gr.<lsxfmt>\t%0,%w1,%2";
+ else
+ return "#";
+}
+ "reload_completed && ISA_HAS_LSX && !TARGET_64BIT"
+ [(const_int 0)]
+{
+ loongarch_split_lsx_copy_d (operands[0], operands[1], operands[2],
+ gen_lsx_vpickve2gr_w);
+ DONE;
+}
+ [(set_attr "type" "simd_copy")
+ (set_attr "mode" "<MODE>")])
+
+
+(define_expand "abs<mode>2"
+ [(match_operand:ILSX 0 "register_operand" "=f")
+ (abs:ILSX (match_operand:ILSX 1 "register_operand" "f"))]
+ "ISA_HAS_LSX"
+{
+ if (ISA_HAS_LSX)
+ {
+ emit_insn (gen_vabs<mode>2 (operands[0], operands[1]));
+ DONE;
+ }
+ else
+ {
+ rtx reg = gen_reg_rtx (<MODE>mode);
+ emit_move_insn (reg, CONST0_RTX (<MODE>mode));
+ emit_insn (gen_lsx_vadda_<lsxfmt> (operands[0], operands[1], reg));
+ DONE;
+ }
+})
+
+(define_expand "neg<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand")
+ (neg:ILSX (match_operand:ILSX 1 "register_operand")))]
+ "ISA_HAS_LSX"
+{
+ emit_insn (gen_vneg<mode>2 (operands[0], operands[1]));
+ DONE;
+})
+
+(define_expand "neg<mode>2"
+ [(set (match_operand:FLSX 0 "register_operand")
+ (neg:FLSX (match_operand:FLSX 1 "register_operand")))]
+ "ISA_HAS_LSX"
+{
+ rtx reg = gen_reg_rtx (<MODE>mode);
+ emit_move_insn (reg, CONST0_RTX (<MODE>mode));
+ emit_insn (gen_sub<mode>3 (operands[0], reg, operands[1]));
+ DONE;
+})
+
+(define_expand "lsx_vrepli<mode>"
+ [(match_operand:ILSX 0 "register_operand")
+ (match_operand 1 "const_imm10_operand")]
+ "ISA_HAS_LSX"
+{
+ if (<MODE>mode == V16QImode)
+ operands[1] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]),
+ <UNITMODE>mode));
+ emit_move_insn (operands[0],
+ loongarch_gen_const_int_vector (<MODE>mode, INTVAL (operands[1])));
+ DONE;
+})
+
+(define_expand "vec_perm<mode>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand:LSX 1 "register_operand")
+ (match_operand:LSX 2 "register_operand")
+ (match_operand:LSX 3 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ loongarch_expand_vec_perm (operands[0], operands[1],
+ operands[2], operands[3]);
+ DONE;
+})
+
+(define_insn "lsx_vshuf_<lsxfmt_f>"
+ [(set (match_operand:LSX_DWH 0 "register_operand" "=f")
+ (unspec:LSX_DWH [(match_operand:LSX_DWH 1 "register_operand" "0")
+ (match_operand:LSX_DWH 2 "register_operand" "f")
+ (match_operand:LSX_DWH 3 "register_operand" "f")]
+ UNSPEC_LSX_VSHUF))]
+ "ISA_HAS_LSX"
+ "vshuf.<lsxfmt>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_sld")
+ (set_attr "mode" "<MODE>")])
+
+(define_expand "mov<mode>"
+ [(set (match_operand:LSX 0)
+ (match_operand:LSX 1))]
+ "ISA_HAS_LSX"
+{
+ if (loongarch_legitimize_move (<MODE>mode, operands[0], operands[1]))
+ DONE;
+})
+
+(define_expand "movmisalign<mode>"
+ [(set (match_operand:LSX 0)
+ (match_operand:LSX 1))]
+ "ISA_HAS_LSX"
+{
+ if (loongarch_legitimize_move (<MODE>mode, operands[0], operands[1]))
+ DONE;
+})
+
+(define_insn "mov<mode>_lsx"
+ [(set (match_operand:LSX 0 "nonimmediate_operand" "=f,f,R,*r,*f")
+ (match_operand:LSX 1 "move_operand" "fYGYI,R,f,*f,*r"))]
+ "ISA_HAS_LSX"
+{ return loongarch_output_move (operands[0], operands[1]); }
+ [(set_attr "type" "simd_move,simd_load,simd_store,simd_copy,simd_insert")
+ (set_attr "mode" "<MODE>")])
+
+(define_split
+ [(set (match_operand:LSX 0 "nonimmediate_operand")
+ (match_operand:LSX 1 "move_operand"))]
+ "reload_completed && ISA_HAS_LSX
+ && loongarch_split_move_insn_p (operands[0], operands[1])"
+ [(const_int 0)]
+{
+ loongarch_split_move_insn (operands[0], operands[1], curr_insn);
+ DONE;
+})
+
+;; Offset load
+(define_expand "lsx_ld_<lsxfmt_f>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand 1 "pmode_register_operand")
+ (match_operand 2 "aq10<lsxfmt>_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx addr = plus_constant (GET_MODE (operands[1]), operands[1],
+ INTVAL (operands[2]));
+ loongarch_emit_move (operands[0], gen_rtx_MEM (<MODE>mode, addr));
+ DONE;
+})
+
+;; Offset store
+(define_expand "lsx_st_<lsxfmt_f>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand 1 "pmode_register_operand")
+ (match_operand 2 "aq10<lsxfmt>_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx addr = plus_constant (GET_MODE (operands[1]), operands[1],
+ INTVAL (operands[2]));
+ loongarch_emit_move (gen_rtx_MEM (<MODE>mode, addr), operands[0]);
+ DONE;
+})
+
+;; Integer operations
+(define_insn "add<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f,f")
+ (plus:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_ximm5_operand" "f,Unv5,Uuv5")))]
+ "ISA_HAS_LSX"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "vadd.<lsxfmt>\t%w0,%w1,%w2";
+ case 1:
+ {
+ HOST_WIDE_INT val = INTVAL (CONST_VECTOR_ELT (operands[2], 0));
+
+ operands[2] = GEN_INT (-val);
+ return "vsubi.<lsxfmt_u>\t%w0,%w1,%d2";
+ }
+ case 2:
+ return "vaddi.<lsxfmt_u>\t%w0,%w1,%E2";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr "alu_type" "simd_add")
+ (set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "sub<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (minus:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm5_operand" "f,Uuv5")))]
+ "ISA_HAS_LSX"
+ "@
+ vsub.<lsxfmt>\t%w0,%w1,%w2
+ vsubi.<lsxfmt_u>\t%w0,%w1,%E2"
+ [(set_attr "alu_type" "simd_add")
+ (set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "mul<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (mult:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vmul.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_mul")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vmadd_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (plus:ILSX (mult:ILSX (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand:ILSX 3 "register_operand" "f"))
+ (match_operand:ILSX 1 "register_operand" "0")))]
+ "ISA_HAS_LSX"
+ "vmadd.<lsxfmt>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_mul")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vmsub_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (minus:ILSX (match_operand:ILSX 1 "register_operand" "0")
+ (mult:ILSX (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand:ILSX 3 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vmsub.<lsxfmt>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_mul")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "div<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (div:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+{ return loongarch_lsx_output_division ("vdiv.<lsxfmt>\t%w0,%w1,%w2", operands); }
+ [(set_attr "type" "simd_div")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "udiv<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (udiv:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+{ return loongarch_lsx_output_division ("vdiv.<lsxfmt_u>\t%w0,%w1,%w2", operands); }
+ [(set_attr "type" "simd_div")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "mod<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (mod:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+{ return loongarch_lsx_output_division ("vmod.<lsxfmt>\t%w0,%w1,%w2", operands); }
+ [(set_attr "type" "simd_div")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "umod<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (umod:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+{ return loongarch_lsx_output_division ("vmod.<lsxfmt_u>\t%w0,%w1,%w2", operands); }
+ [(set_attr "type" "simd_div")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "xor<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f,f")
+ (xor:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+ "ISA_HAS_LSX"
+ "@
+ vxor.v\t%w0,%w1,%w2
+ vbitrevi.%v0\t%w0,%w1,%V2
+ vxori.b\t%w0,%w1,%B2"
+ [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "ior<mode>3"
+ [(set (match_operand:LSX 0 "register_operand" "=f,f,f")
+ (ior:LSX
+ (match_operand:LSX 1 "register_operand" "f,f,f")
+ (match_operand:LSX 2 "reg_or_vector_same_val_operand" "f,YC,Urv8")))]
+ "ISA_HAS_LSX"
+ "@
+ vor.v\t%w0,%w1,%w2
+ vbitseti.%v0\t%w0,%w1,%V2
+ vori.b\t%w0,%w1,%B2"
+ [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "and<mode>3"
+ [(set (match_operand:LSX 0 "register_operand" "=f,f,f")
+ (and:LSX
+ (match_operand:LSX 1 "register_operand" "f,f,f")
+ (match_operand:LSX 2 "reg_or_vector_same_val_operand" "f,YZ,Urv8")))]
+ "ISA_HAS_LSX"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "vand.v\t%w0,%w1,%w2";
+ case 1:
+ {
+ rtx elt0 = CONST_VECTOR_ELT (operands[2], 0);
+ unsigned HOST_WIDE_INT val = ~UINTVAL (elt0);
+ operands[2] = loongarch_gen_const_int_vector (<MODE>mode, val & (-val));
+ return "vbitclri.%v0\t%w0,%w1,%V2";
+ }
+ case 2:
+ return "vandi.b\t%w0,%w1,%B2";
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "simd_logic,simd_bit,simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "one_cmpl<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (not:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vnor.v\t%w0,%w1,%w1"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "TI")])
+
+(define_insn "vlshr<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (lshiftrt:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm6_operand" "f,Uuv6")))]
+ "ISA_HAS_LSX"
+ "@
+ vsrl.<lsxfmt>\t%w0,%w1,%w2
+ vsrli.<lsxfmt>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vashr<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (ashiftrt:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm6_operand" "f,Uuv6")))]
+ "ISA_HAS_LSX"
+ "@
+ vsra.<lsxfmt>\t%w0,%w1,%w2
+ vsrai.<lsxfmt>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vashl<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (ashift:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm6_operand" "f,Uuv6")))]
+ "ISA_HAS_LSX"
+ "@
+ vsll.<lsxfmt>\t%w0,%w1,%w2
+ vslli.<lsxfmt>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+;; Floating-point operations
+(define_insn "add<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (plus:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfadd.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "sub<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (minus:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfsub.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "mul<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (mult:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfmul.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fmul")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "div<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (div:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfdiv.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fdiv")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "fma<mode>4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (fma:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")
+ (match_operand:FLSX 3 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfmadd.<flsxfmt>\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "fnma<mode>4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (fma:FLSX (neg:FLSX (match_operand:FLSX 1 "register_operand" "f"))
+ (match_operand:FLSX 2 "register_operand" "f")
+ (match_operand:FLSX 3 "register_operand" "0")))]
+ "ISA_HAS_LSX"
+ "vfnmsub.<flsxfmt>\t%w0,%w1,%w2,%w0"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "sqrt<mode>2"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (sqrt:FLSX (match_operand:FLSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfsqrt.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fdiv")
+ (set_attr "mode" "<MODE>")])
+
+;; Built-in functions
+(define_insn "lsx_vadda_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (plus:ILSX (abs:ILSX (match_operand:ILSX 1 "register_operand" "f"))
+ (abs:ILSX (match_operand:ILSX 2 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vadda.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "ssadd<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (ss_plus:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vsadd.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "usadd<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (us_plus:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vsadd.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vabsd_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_ABSD_S))]
+ "ISA_HAS_LSX"
+ "vabsd.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vabsd_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VABSD_U))]
+ "ISA_HAS_LSX"
+ "vabsd.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vavg_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VAVG_S))]
+ "ISA_HAS_LSX"
+ "vavg.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vavg_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VAVG_U))]
+ "ISA_HAS_LSX"
+ "vavg.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vavgr_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VAVGR_S))]
+ "ISA_HAS_LSX"
+ "vavgr.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vavgr_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VAVGR_U))]
+ "ISA_HAS_LSX"
+ "vavgr.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitclr_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VBITCLR))]
+ "ISA_HAS_LSX"
+ "vbitclr.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitclri_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VBITCLRI))]
+ "ISA_HAS_LSX"
+ "vbitclri.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitrev_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VBITREV))]
+ "ISA_HAS_LSX"
+ "vbitrev.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitrevi_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_lsx_branch_operand" "")]
+ UNSPEC_LSX_VBITREVI))]
+ "ISA_HAS_LSX"
+ "vbitrevi.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitsel_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (ior:ILSX (and:ILSX (not:ILSX
+ (match_operand:ILSX 3 "register_operand" "f"))
+ (match_operand:ILSX 1 "register_operand" "f"))
+ (and:ILSX (match_dup 3)
+ (match_operand:ILSX 2 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vbitsel.v\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_bitmov")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitseli_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (ior:V16QI (and:V16QI (not:V16QI
+ (match_operand:V16QI 1 "register_operand" "0"))
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (and:V16QI (match_dup 1)
+ (match_operand:V16QI 3 "const_vector_same_val_operand" "Urv8"))))]
+ "ISA_HAS_LSX"
+ "vbitseli.b\t%w0,%w2,%B3"
+ [(set_attr "type" "simd_bitmov")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vbitset_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VBITSET))]
+ "ISA_HAS_LSX"
+ "vbitset.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbitseti_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VBITSETI))]
+ "ISA_HAS_LSX"
+ "vbitseti.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_code_iterator ICC [eq le leu lt ltu])
+
+(define_code_attr icc
+ [(eq "eq")
+ (le "le")
+ (leu "le")
+ (lt "lt")
+ (ltu "lt")])
+
+(define_code_attr icci
+ [(eq "eqi")
+ (le "lei")
+ (leu "lei")
+ (lt "lti")
+ (ltu "lti")])
+
+(define_code_attr cmpi
+ [(eq "s")
+ (le "s")
+ (leu "u")
+ (lt "s")
+ (ltu "u")])
+
+(define_code_attr cmpi_1
+ [(eq "")
+ (le "")
+ (leu "u")
+ (lt "")
+ (ltu "u")])
+
+(define_insn "lsx_vs<ICC:icc>_<ILSX:lsxfmt><ICC:cmpi_1>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (ICC:ILSX
+ (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_<ICC:cmpi>imm5_operand" "f,U<ICC:cmpi>v5")))]
+ "ISA_HAS_LSX"
+ "@
+ vs<ICC:icc>.<ILSX:lsxfmt><ICC:cmpi_1>\t%w0,%w1,%w2
+ vs<ICC:icci>.<ILSX:lsxfmt><ICC:cmpi_1>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfclass_<flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFCLASS))]
+ "ISA_HAS_LSX"
+ "vfclass.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fclass")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfcmp_caf_<flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VFCMP_CAF))]
+ "ISA_HAS_LSX"
+ "vfcmp.caf.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcmp")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfcmp_cune_<FLSX:flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VFCMP_CUNE))]
+ "ISA_HAS_LSX"
+ "vfcmp.cune.<FLSX:flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcmp")
+ (set_attr "mode" "<MODE>")])
+
+(define_code_iterator vfcond [unordered ordered eq ne le lt uneq unle unlt])
+
+(define_code_attr fcc
+ [(unordered "cun")
+ (ordered "cor")
+ (eq "ceq")
+ (ne "cne")
+ (uneq "cueq")
+ (unle "cule")
+ (unlt "cult")
+ (le "cle")
+ (lt "clt")])
+
+(define_int_iterator FSC_UNS [UNSPEC_LSX_VFCMP_SAF UNSPEC_LSX_VFCMP_SUN UNSPEC_LSX_VFCMP_SOR
+ UNSPEC_LSX_VFCMP_SEQ UNSPEC_LSX_VFCMP_SNE UNSPEC_LSX_VFCMP_SUEQ
+ UNSPEC_LSX_VFCMP_SUNE UNSPEC_LSX_VFCMP_SULE UNSPEC_LSX_VFCMP_SULT
+ UNSPEC_LSX_VFCMP_SLE UNSPEC_LSX_VFCMP_SLT])
+
+(define_int_attr fsc
+ [(UNSPEC_LSX_VFCMP_SAF "saf")
+ (UNSPEC_LSX_VFCMP_SUN "sun")
+ (UNSPEC_LSX_VFCMP_SOR "sor")
+ (UNSPEC_LSX_VFCMP_SEQ "seq")
+ (UNSPEC_LSX_VFCMP_SNE "sne")
+ (UNSPEC_LSX_VFCMP_SUEQ "sueq")
+ (UNSPEC_LSX_VFCMP_SUNE "sune")
+ (UNSPEC_LSX_VFCMP_SULE "sule")
+ (UNSPEC_LSX_VFCMP_SULT "sult")
+ (UNSPEC_LSX_VFCMP_SLE "sle")
+ (UNSPEC_LSX_VFCMP_SLT "slt")])
+
+(define_insn "lsx_vfcmp_<vfcond:fcc>_<FLSX:flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (vfcond:<VIMODE> (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfcmp.<vfcond:fcc>.<FLSX:flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcmp")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfcmp_<fsc>_<FLSX:flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")]
+ FSC_UNS))]
+ "ISA_HAS_LSX"
+ "vfcmp.<fsc>.<FLSX:flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcmp")
+ (set_attr "mode" "<MODE>")])
+
+(define_mode_attr fint
+ [(V4SF "v4si")
+ (V2DF "v2di")])
+
+(define_mode_attr FINTCNV
+ [(V4SF "I2S")
+ (V2DF "I2D")])
+
+(define_mode_attr FINTCNV_2
+ [(V4SF "S2I")
+ (V2DF "D2I")])
+
+(define_insn "float<fint><FLSX:mode>2"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (float:FLSX (match_operand:<VIMODE> 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vffint.<flsxfmt>.<ilsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV>")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "floatuns<fint><FLSX:mode>2"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unsigned_float:FLSX
+ (match_operand:<VIMODE> 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vffint.<flsxfmt>.<ilsxfmt_u>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV>")
+ (set_attr "mode" "<MODE>")])
+
+(define_mode_attr FFQ
+ [(V4SF "V8HI")
+ (V2DF "V4SI")])
+
+(define_insn "lsx_vreplgr2vr_<lsxfmt_f>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (vec_duplicate:ILSX
+ (match_operand:<UNITMODE> 1 "reg_or_0_operand" "r,J")))]
+ "ISA_HAS_LSX"
+{
+ if (which_alternative == 1)
+ return "ldi.<lsxfmt>\t%w0,0";
+
+ if (!TARGET_64BIT && (<MODE>mode == V2DImode || <MODE>mode == V2DFmode))
+ return "#";
+ else
+ return "vreplgr2vr.<lsxfmt>\t%w0,%z1";
+}
+ [(set_attr "type" "simd_fill")
+ (set_attr "mode" "<MODE>")])
+
+(define_split
+ [(set (match_operand:LSX_D 0 "register_operand")
+ (vec_duplicate:LSX_D
+ (match_operand:<UNITMODE> 1 "register_operand")))]
+ "reload_completed && ISA_HAS_LSX && !TARGET_64BIT"
+ [(const_int 0)]
+{
+ loongarch_split_lsx_fill_d (operands[0], operands[1]);
+ DONE;
+})
+
+(define_insn "logb<mode>2"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFLOGB))]
+ "ISA_HAS_LSX"
+ "vflogb.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_flog2")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "smax<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (smax:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfmax.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fminmax")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfmaxa_<flsxfmt>"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (if_then_else:FLSX
+ (gt (abs:FLSX (match_operand:FLSX 1 "register_operand" "f"))
+ (abs:FLSX (match_operand:FLSX 2 "register_operand" "f")))
+ (match_dup 1)
+ (match_dup 2)))]
+ "ISA_HAS_LSX"
+ "vfmaxa.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fminmax")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "smin<mode>3"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (smin:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfmin.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fminmax")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfmina_<flsxfmt>"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (if_then_else:FLSX
+ (lt (abs:FLSX (match_operand:FLSX 1 "register_operand" "f"))
+ (abs:FLSX (match_operand:FLSX 2 "register_operand" "f")))
+ (match_dup 1)
+ (match_dup 2)))]
+ "ISA_HAS_LSX"
+ "vfmina.<flsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fminmax")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfrecip_<flsxfmt>"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRECIP))]
+ "ISA_HAS_LSX"
+ "vfrecip.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fdiv")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfrint_<flsxfmt>"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINT))]
+ "ISA_HAS_LSX"
+ "vfrint.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfrsqrt_<flsxfmt>"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRSQRT))]
+ "ISA_HAS_LSX"
+ "vfrsqrt.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fdiv")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vftint_s_<ilsxfmt>_<flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINT_S))]
+ "ISA_HAS_LSX"
+ "vftint.<ilsxfmt>.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV_2>")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vftint_u_<ilsxfmt_u>_<flsxfmt>"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINT_U))]
+ "ISA_HAS_LSX"
+ "vftint.<ilsxfmt_u>.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV_2>")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "fix_trunc<FLSX:mode><mode_i>2"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (fix:<VIMODE> (match_operand:FLSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vftintrz.<ilsxfmt>.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV_2>")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "fixuns_trunc<FLSX:mode><mode_i>2"
+ [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+ (unsigned_fix:<VIMODE> (match_operand:FLSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vftintrz.<ilsxfmt_u>.<flsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "cnv_mode" "<FINTCNV_2>")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vh<optab>w_h<u>_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (addsub:V8HI
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))))]
+ "ISA_HAS_LSX"
+ "vh<optab>w.h<u>.b<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vh<optab>w_w<u>_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (addsub:V4SI
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))))]
+ "ISA_HAS_LSX"
+ "vh<optab>w.w<u>.h<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vh<optab>w_d<u>_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (addsub:V2DI
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)])))
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)])))))]
+ "ISA_HAS_LSX"
+ "vh<optab>w.d<u>.w<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vpackev_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 16)
+ (const_int 2) (const_int 18)
+ (const_int 4) (const_int 20)
+ (const_int 6) (const_int 22)
+ (const_int 8) (const_int 24)
+ (const_int 10) (const_int 26)
+ (const_int 12) (const_int 28)
+ (const_int 14) (const_int 30)])))]
+ "ISA_HAS_LSX"
+ "vpackev.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vpackev_h"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 8)
+ (const_int 2) (const_int 10)
+ (const_int 4) (const_int 12)
+ (const_int 6) (const_int 14)])))]
+ "ISA_HAS_LSX"
+ "vpackev.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vpackev_w"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (vec_select:V4SI
+ (vec_concat:V8SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (match_operand:V4SI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 4)
+ (const_int 2) (const_int 6)])))]
+ "ISA_HAS_LSX"
+ "vpackev.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vpackev_w_f"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_select:V4SF
+ (vec_concat:V8SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 4)
+ (const_int 2) (const_int 6)])))]
+ "ISA_HAS_LSX"
+ "vpackev.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vilvh_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 8) (const_int 24)
+ (const_int 9) (const_int 25)
+ (const_int 10) (const_int 26)
+ (const_int 11) (const_int 27)
+ (const_int 12) (const_int 28)
+ (const_int 13) (const_int 29)
+ (const_int 14) (const_int 30)
+ (const_int 15) (const_int 31)])))]
+ "ISA_HAS_LSX"
+ "vilvh.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vilvh_h"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 4) (const_int 12)
+ (const_int 5) (const_int 13)
+ (const_int 6) (const_int 14)
+ (const_int 7) (const_int 15)])))]
+ "ISA_HAS_LSX"
+ "vilvh.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_mode_attr vilvh_suffix
+ [(V4SI "") (V4SF "_f")
+ (V2DI "") (V2DF "_f")])
+
+(define_insn "lsx_vilvh_w<vilvh_suffix>"
+ [(set (match_operand:LSX_W 0 "register_operand" "=f")
+ (vec_select:LSX_W
+ (vec_concat:<VEMODE>
+ (match_operand:LSX_W 1 "register_operand" "f")
+ (match_operand:LSX_W 2 "register_operand" "f"))
+ (parallel [(const_int 2) (const_int 6)
+ (const_int 3) (const_int 7)])))]
+ "ISA_HAS_LSX"
+ "vilvh.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vilvh_d<vilvh_suffix>"
+ [(set (match_operand:LSX_D 0 "register_operand" "=f")
+ (vec_select:LSX_D
+ (vec_concat:<VEMODE>
+ (match_operand:LSX_D 1 "register_operand" "f")
+ (match_operand:LSX_D 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 3)])))]
+ "ISA_HAS_LSX"
+ "vilvh.d\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vpackod_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 17)
+ (const_int 3) (const_int 19)
+ (const_int 5) (const_int 21)
+ (const_int 7) (const_int 23)
+ (const_int 9) (const_int 25)
+ (const_int 11) (const_int 27)
+ (const_int 13) (const_int 29)
+ (const_int 15) (const_int 31)])))]
+ "ISA_HAS_LSX"
+ "vpackod.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vpackod_h"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 9)
+ (const_int 3) (const_int 11)
+ (const_int 5) (const_int 13)
+ (const_int 7) (const_int 15)])))]
+ "ISA_HAS_LSX"
+ "vpackod.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vpackod_w"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (vec_select:V4SI
+ (vec_concat:V8SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (match_operand:V4SI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 5)
+ (const_int 3) (const_int 7)])))]
+ "ISA_HAS_LSX"
+ "vpackod.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vpackod_w_f"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_select:V4SF
+ (vec_concat:V8SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 5)
+ (const_int 3) (const_int 7)])))]
+ "ISA_HAS_LSX"
+ "vpackod.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vilvl_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 16)
+ (const_int 1) (const_int 17)
+ (const_int 2) (const_int 18)
+ (const_int 3) (const_int 19)
+ (const_int 4) (const_int 20)
+ (const_int 5) (const_int 21)
+ (const_int 6) (const_int 22)
+ (const_int 7) (const_int 23)])))]
+ "ISA_HAS_LSX"
+ "vilvl.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vilvl_h"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 8)
+ (const_int 1) (const_int 9)
+ (const_int 2) (const_int 10)
+ (const_int 3) (const_int 11)])))]
+ "ISA_HAS_LSX"
+ "vilvl.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vilvl_w"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (vec_select:V4SI
+ (vec_concat:V8SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (match_operand:V4SI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 4)
+ (const_int 1) (const_int 5)])))]
+ "ISA_HAS_LSX"
+ "vilvl.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vilvl_w_f"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_select:V4SF
+ (vec_concat:V8SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 4)
+ (const_int 1) (const_int 5)])))]
+ "ISA_HAS_LSX"
+ "vilvl.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vilvl_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (vec_select:V2DI
+ (vec_concat:V4DI
+ (match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)])))]
+ "ISA_HAS_LSX"
+ "vilvl.d\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vilvl_d_f"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (vec_select:V2DF
+ (vec_concat:V4DF
+ (match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)])))]
+ "ISA_HAS_LSX"
+ "vilvl.d\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "smax<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (smax:ILSX (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_simm5_operand" "f,Usv5")))]
+ "ISA_HAS_LSX"
+ "@
+ vmax.<lsxfmt>\t%w0,%w1,%w2
+ vmaxi.<lsxfmt>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "umax<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (umax:ILSX (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm5_operand" "f,Uuv5")))]
+ "ISA_HAS_LSX"
+ "@
+ vmax.<lsxfmt_u>\t%w0,%w1,%w2
+ vmaxi.<lsxfmt_u>\t%w0,%w1,%B2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "smin<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (smin:ILSX (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_simm5_operand" "f,Usv5")))]
+ "ISA_HAS_LSX"
+ "@
+ vmin.<lsxfmt>\t%w0,%w1,%w2
+ vmini.<lsxfmt>\t%w0,%w1,%E2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "umin<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (umin:ILSX (match_operand:ILSX 1 "register_operand" "f,f")
+ (match_operand:ILSX 2 "reg_or_vector_same_uimm5_operand" "f,Uuv5")))]
+ "ISA_HAS_LSX"
+ "@
+ vmin.<lsxfmt_u>\t%w0,%w1,%w2
+ vmini.<lsxfmt_u>\t%w0,%w1,%B2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vclo_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (clz:ILSX (not:ILSX (match_operand:ILSX 1 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vclo.<lsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "clz<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (clz:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vclz.<lsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_nor_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f,f")
+ (and:ILSX (not:ILSX (match_operand:ILSX 1 "register_operand" "f,f"))
+ (not:ILSX (match_operand:ILSX 2 "reg_or_vector_same_val_operand" "f,Urv8"))))]
+ "ISA_HAS_LSX"
+ "@
+ vnor.v\t%w0,%w1,%w2
+ vnori.b\t%w0,%w1,%B2"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vpickev_b"
+[(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)
+ (const_int 16) (const_int 18)
+ (const_int 20) (const_int 22)
+ (const_int 24) (const_int 26)
+ (const_int 28) (const_int 30)])))]
+ "ISA_HAS_LSX"
+ "vpickev.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vpickev_h"
+[(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))]
+ "ISA_HAS_LSX"
+ "vpickev.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vpickev_w"
+[(set (match_operand:V4SI 0 "register_operand" "=f")
+ (vec_select:V4SI
+ (vec_concat:V8SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (match_operand:V4SI 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))]
+ "ISA_HAS_LSX"
+ "vpickev.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vpickev_w_f"
+[(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_select:V4SF
+ (vec_concat:V8SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f"))
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))]
+ "ISA_HAS_LSX"
+ "vpickev.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vpickod_b"
+[(set (match_operand:V16QI 0 "register_operand" "=f")
+ (vec_select:V16QI
+ (vec_concat:V32QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)
+ (const_int 17) (const_int 19)
+ (const_int 21) (const_int 23)
+ (const_int 25) (const_int 27)
+ (const_int 29) (const_int 31)])))]
+ "ISA_HAS_LSX"
+ "vpickod.b\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vpickod_h"
+[(set (match_operand:V8HI 0 "register_operand" "=f")
+ (vec_select:V8HI
+ (vec_concat:V16HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (match_operand:V8HI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))]
+ "ISA_HAS_LSX"
+ "vpickod.h\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vpickod_w"
+[(set (match_operand:V4SI 0 "register_operand" "=f")
+ (vec_select:V4SI
+ (vec_concat:V8SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (match_operand:V4SI 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))]
+ "ISA_HAS_LSX"
+ "vpickod.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vpickod_w_f"
+[(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_select:V4SF
+ (vec_concat:V8SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f"))
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))]
+ "ISA_HAS_LSX"
+ "vpickod.w\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_permute")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "popcount<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (popcount:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vpcnt.<lsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_pcnt")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsat_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSAT_S))]
+ "ISA_HAS_LSX"
+ "vsat.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_sat")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsat_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSAT_U))]
+ "ISA_HAS_LSX"
+ "vsat.<lsxfmt_u>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_sat")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vshuf4i_<lsxfmt_f>"
+ [(set (match_operand:LSX_WHB_W 0 "register_operand" "=f")
+ (vec_select:LSX_WHB_W
+ (match_operand:LSX_WHB_W 1 "register_operand" "f")
+ (match_operand 2 "par_const_vector_shf_set_operand" "")))]
+ "ISA_HAS_LSX"
+{
+ HOST_WIDE_INT val = 0;
+ unsigned int i;
+
+ /* We convert the selection to an immediate. */
+ for (i = 0; i < 4; i++)
+ val |= INTVAL (XVECEXP (operands[2], 0, i)) << (2 * i);
+
+ operands[2] = GEN_INT (val);
+ return "vshuf4i.<lsxfmt>\t%w0,%w1,%X2";
+}
+ [(set_attr "type" "simd_shf")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrar_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRAR))]
+ "ISA_HAS_LSX"
+ "vsrar.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrari_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSRARI))]
+ "ISA_HAS_LSX"
+ "vsrari.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrlr_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRLR))]
+ "ISA_HAS_LSX"
+ "vsrlr.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrlri_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSRLRI))]
+ "ISA_HAS_LSX"
+ "vsrlri.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssub_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (ss_minus:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vssub.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssub_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (us_minus:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vssub.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vreplve_<lsxfmt_f>"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_duplicate:LSX
+ (vec_select:<UNITMODE>
+ (match_operand:LSX 1 "register_operand" "f")
+ (parallel [(match_operand:SI 2 "register_operand" "r")]))))]
+ "ISA_HAS_LSX"
+ "vreplve.<lsxfmt>\t%w0,%w1,%z2"
+ [(set_attr "type" "simd_splat")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vreplvei_<lsxfmt_f>"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_duplicate:LSX
+ (vec_select:<UNITMODE>
+ (match_operand:LSX 1 "register_operand" "f")
+ (parallel [(match_operand 2 "const_<indeximm>_operand" "")]))))]
+ "ISA_HAS_LSX"
+ "vreplvei.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_splat")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vreplvei_<lsxfmt_f>_scalar"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_duplicate:LSX
+ (match_operand:<UNITMODE> 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vreplvei.<lsxfmt>\t%w0,%w1,0"
+ [(set_attr "type" "simd_splat")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfcvt_h_s"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (unspec:V8HI [(match_operand:V4SF 1 "register_operand" "f")
+ (match_operand:V4SF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFCVT))]
+ "ISA_HAS_LSX"
+ "vfcvt.h.s\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vfcvt_s_d"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFCVT))]
+ "ISA_HAS_LSX"
+ "vfcvt.s.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "vec_pack_trunc_v2df"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (vec_concat:V4SF
+ (float_truncate:V2SF (match_operand:V2DF 1 "register_operand" "f"))
+ (float_truncate:V2SF (match_operand:V2DF 2 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vfcvt.s.d\t%w0,%w2,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfcvth_s_h"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V8HI 1 "register_operand" "f")]
+ UNSPEC_LSX_VFCVTH))]
+ "ISA_HAS_LSX"
+ "vfcvth.s.h\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfcvth_d_s"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (parallel [(const_int 2) (const_int 3)]))))]
+ "ISA_HAS_LSX"
+ "vfcvth.d.s\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vfcvtl_s_h"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V8HI 1 "register_operand" "f")]
+ UNSPEC_LSX_VFCVTL))]
+ "ISA_HAS_LSX"
+ "vfcvtl.s.h\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfcvtl_d_s"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_operand:V4SF 1 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 1)]))))]
+ "ISA_HAS_LSX"
+ "vfcvtl.d.s\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DF")])
+
+(define_code_attr lsxbr
+ [(eq "bz")
+ (ne "bnz")])
+
+(define_code_attr lsxeq_v
+ [(eq "eqz")
+ (ne "nez")])
+
+(define_code_attr lsxne_v
+ [(eq "nez")
+ (ne "eqz")])
+
+(define_code_attr lsxeq
+ [(eq "anyeqz")
+ (ne "allnez")])
+
+(define_code_attr lsxne
+ [(eq "allnez")
+ (ne "anyeqz")])
+
+(define_insn "lsx_<lsxbr>_<lsxfmt_f>"
+ [(set (pc) (if_then_else
+ (equality_op
+ (unspec:SI [(match_operand:LSX 1 "register_operand" "f")]
+ UNSPEC_LSX_BRANCH)
+ (match_operand:SI 2 "const_0_operand"))
+ (label_ref (match_operand 0))
+ (pc)))
+ (clobber (match_scratch:FCC 3 "=z"))]
+ "ISA_HAS_LSX"
+{
+ return loongarch_output_conditional_branch (insn, operands,
+ "vset<lsxeq>.<lsxfmt>\t%Z3%w1\n\tbcnez\t%Z3%0",
+ "vset<lsxne>.<lsxfmt>\t%Z3%w1\n\tbcnez\t%Z3%0");
+}
+ [(set_attr "type" "simd_branch")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_<lsxbr>_v_<lsxfmt_f>"
+ [(set (pc) (if_then_else
+ (equality_op
+ (unspec:SI [(match_operand:LSX 1 "register_operand" "f")]
+ UNSPEC_LSX_BRANCH_V)
+ (match_operand:SI 2 "const_0_operand"))
+ (label_ref (match_operand 0))
+ (pc)))
+ (clobber (match_scratch:FCC 3 "=z"))]
+ "ISA_HAS_LSX"
+{
+ return loongarch_output_conditional_branch (insn, operands,
+ "vset<lsxeq_v>.v\t%Z3%w1\n\tbcnez\t%Z3%0",
+ "vset<lsxne_v>.v\t%Z3%w1\n\tbcnez\t%Z3%0");
+}
+ [(set_attr "type" "simd_branch")
+ (set_attr "mode" "TI")])
+
+;; vec_concate
+(define_expand "vec_concatv2di"
+ [(set (match_operand:V2DI 0 "register_operand")
+ (vec_concat:V2DI
+ (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "register_operand")))]
+ "ISA_HAS_LSX"
+{
+ emit_insn (gen_lsx_vinsgr2vr_d (operands[0], operands[1],
+ operands[0], GEN_INT (0)));
+ emit_insn (gen_lsx_vinsgr2vr_d (operands[0], operands[2],
+ operands[0], GEN_INT (1)));
+ DONE;
+})
+
+
+(define_insn "vandn<mode>3"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (and:LSX (not:LSX (match_operand:LSX 1 "register_operand" "f"))
+ (match_operand:LSX 2 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vandn.v\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vabs<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (abs:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vsigncov.<lsxfmt>\t%w0,%w1,%w1"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vneg<mode>2"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (neg:ILSX (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vneg.<lsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vmuh_s_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VMUH_S))]
+ "ISA_HAS_LSX"
+ "vmuh.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vmuh_u_<lsxfmt_u>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VMUH_U))]
+ "ISA_HAS_LSX"
+ "vmuh.<lsxfmt_u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vextw_s_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTW_S))]
+ "ISA_HAS_LSX"
+ "vextw_s.d\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vextw_u_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTW_U))]
+ "ISA_HAS_LSX"
+ "vextw_u.d\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vsllwil_s_<dlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VDMODE> 0 "register_operand" "=f")
+ (unspec:<VDMODE> [(match_operand:ILSX_WHB 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSLLWIL_S))]
+ "ISA_HAS_LSX"
+ "vsllwil.<dlsxfmt>.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsllwil_u_<dlsxfmt_u>_<lsxfmt_u>"
+ [(set (match_operand:<VDMODE> 0 "register_operand" "=f")
+ (unspec:<VDMODE> [(match_operand:ILSX_WHB 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSLLWIL_U))]
+ "ISA_HAS_LSX"
+ "vsllwil.<dlsxfmt_u>.<lsxfmt_u>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsran_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRAN))]
+ "ISA_HAS_LSX"
+ "vsran.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssran_s_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRAN_S))]
+ "ISA_HAS_LSX"
+ "vssran.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssran_u_<hlsxfmt_u>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRAN_U))]
+ "ISA_HAS_LSX"
+ "vssran.<hlsxfmt_u>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrain_<hlsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSRAIN))]
+ "ISA_HAS_LSX"
+ "vsrain.<hlsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+;; FIXME: bitimm
+(define_insn "lsx_vsrains_s_<hlsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSRAINS_S))]
+ "ISA_HAS_LSX"
+ "vsrains_s.<hlsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+;; FIXME: bitimm
+(define_insn "lsx_vsrains_u_<hlsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")]
+ UNSPEC_LSX_VSRAINS_U))]
+ "ISA_HAS_LSX"
+ "vsrains_u.<hlsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrarn_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRARN))]
+ "ISA_HAS_LSX"
+ "vsrarn.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrarn_s_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRARN_S))]
+ "ISA_HAS_LSX"
+ "vssrarn.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrarn_u_<hlsxfmt_u>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRARN_U))]
+ "ISA_HAS_LSX"
+ "vssrarn.<hlsxfmt_u>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrln_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRLN))]
+ "ISA_HAS_LSX"
+ "vsrln.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrln_u_<hlsxfmt_u>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRLN_U))]
+ "ISA_HAS_LSX"
+ "vssrln.<hlsxfmt_u>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrlrn_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSRLRN))]
+ "ISA_HAS_LSX"
+ "vsrlrn.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrlrn_u_<hlsxfmt_u>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRLRN_U))]
+ "ISA_HAS_LSX"
+ "vssrlrn.<hlsxfmt_u>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfrstpi_<lsxfmt>"
+ [(set (match_operand:ILSX_HB 0 "register_operand" "=f")
+ (unspec:ILSX_HB [(match_operand:ILSX_HB 1 "register_operand" "0")
+ (match_operand:ILSX_HB 2 "register_operand" "f")
+ (match_operand 3 "const_uimm5_operand" "")]
+ UNSPEC_LSX_VFRSTPI))]
+ "ISA_HAS_LSX"
+ "vfrstpi.<lsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vfrstp_<lsxfmt>"
+ [(set (match_operand:ILSX_HB 0 "register_operand" "=f")
+ (unspec:ILSX_HB [(match_operand:ILSX_HB 1 "register_operand" "0")
+ (match_operand:ILSX_HB 2 "register_operand" "f")
+ (match_operand:ILSX_HB 3 "register_operand" "f")]
+ UNSPEC_LSX_VFRSTP))]
+ "ISA_HAS_LSX"
+ "vfrstp.<lsxfmt>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vshuf4i_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand")]
+ UNSPEC_LSX_VSHUF4I))]
+ "ISA_HAS_LSX"
+ "vshuf4i.d\t%w0,%w2,%3"
+ [(set_attr "type" "simd_sld")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vbsrl_<lsxfmt_f>"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (unspec:LSX [(match_operand:LSX 1 "register_operand" "f")
+ (match_operand 2 "const_uimm5_operand" "")]
+ UNSPEC_LSX_VBSRL_V))]
+ "ISA_HAS_LSX"
+ "vbsrl.v\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vbsll_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_uimm5_operand" "")]
+ UNSPEC_LSX_VBSLL_V))]
+ "ISA_HAS_LSX"
+ "vbsll.v\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vextrins_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VEXTRINS))]
+ "ISA_HAS_LSX"
+ "vextrins.<lsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vmskltz_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VMSKLTZ))]
+ "ISA_HAS_LSX"
+ "vmskltz.<lsxfmt>\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsigncov_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VSIGNCOV))]
+ "ISA_HAS_LSX"
+ "vsigncov.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_expand "copysign<mode>3"
+ [(set (match_dup 4)
+ (and:FLSX
+ (not:FLSX (match_dup 3))
+ (match_operand:FLSX 1 "register_operand")))
+ (set (match_dup 5)
+ (and:FLSX (match_dup 3)
+ (match_operand:FLSX 2 "register_operand")))
+ (set (match_operand:FLSX 0 "register_operand")
+ (ior:FLSX (match_dup 4) (match_dup 5)))]
+ "ISA_HAS_LSX"
+{
+ operands[3] = loongarch_build_signbit_mask (<MODE>mode, 1, 0);
+
+ operands[4] = gen_reg_rtx (<MODE>mode);
+ operands[5] = gen_reg_rtx (<MODE>mode);
+})
+
+(define_insn "absv2df2"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (abs:V2DF (match_operand:V2DF 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vbitclri.d\t%w0,%w1,63"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "absv4sf2"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (abs:V4SF (match_operand:V4SF 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vbitclri.w\t%w0,%w1,31"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "vfmadd<mode>4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (fma:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")
+ (match_operand:FLSX 3 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vfmadd.<flsxfmt>\t%w0,%w1,$w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "fms<mode>4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (fma:FLSX (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")
+ (neg:FLSX (match_operand:FLSX 3 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vfmsub.<flsxfmt>\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vfnmsub<mode>4_nmsub4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (neg:FLSX
+ (fma:FLSX
+ (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")
+ (neg:FLSX (match_operand:FLSX 3 "register_operand" "f")))))]
+ "ISA_HAS_LSX"
+ "vfnmsub.<flsxfmt>\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+
+(define_insn "vfnmadd<mode>4_nmadd4"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (neg:FLSX
+ (fma:FLSX
+ (match_operand:FLSX 1 "register_operand" "f")
+ (match_operand:FLSX 2 "register_operand" "f")
+ (match_operand:FLSX 3 "register_operand" "f"))))]
+ "ISA_HAS_LSX"
+ "vfnmadd.<flsxfmt>\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vftintrne_w_s"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRNE))]
+ "ISA_HAS_LSX"
+ "vftintrne.w.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrne_l_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRNE))]
+ "ISA_HAS_LSX"
+ "vftintrne.l.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftintrp_w_s"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRP))]
+ "ISA_HAS_LSX"
+ "vftintrp.w.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrp_l_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRP))]
+ "ISA_HAS_LSX"
+ "vftintrp.l.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftintrm_w_s"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRM))]
+ "ISA_HAS_LSX"
+ "vftintrm.w.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrm_l_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRM))]
+ "ISA_HAS_LSX"
+ "vftintrm.l.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftint_w_d"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFTINT_W_D))]
+ "ISA_HAS_LSX"
+ "vftint.w.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vffint_s_l"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VFFINT_S_L))]
+ "ISA_HAS_LSX"
+ "vffint.s.l\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vftintrz_w_d"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRZ_W_D))]
+ "ISA_HAS_LSX"
+ "vftintrz.w.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftintrp_w_d"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRP_W_D))]
+ "ISA_HAS_LSX"
+ "vftintrp.w.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftintrm_w_d"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRM_W_D))]
+ "ISA_HAS_LSX"
+ "vftintrm.w.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftintrne_w_d"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
+ (match_operand:V2DF 2 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRNE_W_D))]
+ "ISA_HAS_LSX"
+ "vftintrne.w.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vftinth_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTH_L_H))]
+ "ISA_HAS_LSX"
+ "vftinth.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintl_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTL_L_S))]
+ "ISA_HAS_LSX"
+ "vftintl.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vffinth_d_w"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V4SI 1 "register_operand" "f")]
+ UNSPEC_LSX_VFFINTH_D_W))]
+ "ISA_HAS_LSX"
+ "vffinth.d.w\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vffintl_d_w"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V4SI 1 "register_operand" "f")]
+ UNSPEC_LSX_VFFINTL_D_W))]
+ "ISA_HAS_LSX"
+ "vffintl.d.w\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vftintrzh_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRZH_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrzh.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrzl_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRZL_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrzl.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrph_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRPH_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrph.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrpl_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRPL_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrpl.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrmh_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRMH_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrmh.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrml_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRML_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrml.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrneh_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRNEH_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrneh.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vftintrnel_l_s"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFTINTRNEL_L_S))]
+ "ISA_HAS_LSX"
+ "vftintrnel.l.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfrintrne_s"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRNE_S))]
+ "ISA_HAS_LSX"
+ "vfrintrne.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfrintrne_d"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRNE_D))]
+ "ISA_HAS_LSX"
+ "vfrintrne.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vfrintrz_s"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRZ_S))]
+ "ISA_HAS_LSX"
+ "vfrintrz.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfrintrz_d"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRZ_D))]
+ "ISA_HAS_LSX"
+ "vfrintrz.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vfrintrp_s"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRP_S))]
+ "ISA_HAS_LSX"
+ "vfrintrp.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfrintrp_d"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRP_D))]
+ "ISA_HAS_LSX"
+ "vfrintrp.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+(define_insn "lsx_vfrintrm_s"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRM_S))]
+ "ISA_HAS_LSX"
+ "vfrintrm.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "lsx_vfrintrm_d"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINTRM_D))]
+ "ISA_HAS_LSX"
+ "vfrintrm.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+;; Vector versions of the floating-point frint patterns.
+;; Expands to btrunc, ceil, floor, rint.
+(define_insn "<FRINT_S:frint_pattern_s>v4sf2"
+ [(set (match_operand:V4SF 0 "register_operand" "=f")
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
+ FRINT_S))]
+ "ISA_HAS_LSX"
+ "vfrint<FRINT_S:frint_suffix>.s\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V4SF")])
+
+(define_insn "<FRINT_D:frint_pattern_d>v2df2"
+ [(set (match_operand:V2DF 0 "register_operand" "=f")
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
+ FRINT_D))]
+ "ISA_HAS_LSX"
+ "vfrint<FRINT_D:frint_suffix>.d\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "V2DF")])
+
+;; Expands to round.
+(define_insn "round<mode>2"
+ [(set (match_operand:FLSX 0 "register_operand" "=f")
+ (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
+ UNSPEC_LSX_VFRINT))]
+ "ISA_HAS_LSX"
+ "vfrint.<flsxfrint>\t%w0,%w1"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+;; Offset load and broadcast
+(define_expand "lsx_vldrepl_<lsxfmt_f>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand 1 "pmode_register_operand")
+ (match_operand 2 "aq12<lsxfmt>_operand")]
+ "ISA_HAS_LSX"
+{
+ emit_insn (gen_lsx_vldrepl_<lsxfmt_f>_insn
+ (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "lsx_vldrepl_<lsxfmt_f>_insn"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_duplicate:LSX
+ (mem:<UNITMODE> (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand 2 "aq12<lsxfmt>_operand")))))]
+ "ISA_HAS_LSX"
+{
+ return "vldrepl.<lsxfmt>\t%w0,%1,%2";
+}
+ [(set_attr "type" "simd_load")
+ (set_attr "mode" "<MODE>")
+ (set_attr "length" "4")])
+
+(define_insn "lsx_vldrepl_<lsxfmt_f>_insn_0"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (vec_duplicate:LSX
+ (mem:<UNITMODE> (match_operand:DI 1 "register_operand" "r"))))]
+ "ISA_HAS_LSX"
+{
+ return "vldrepl.<lsxfmt>\t%w0,%1,0";
+}
+ [(set_attr "type" "simd_load")
+ (set_attr "mode" "<MODE>")
+ (set_attr "length" "4")])
+
+;; Offset store by sel
+(define_expand "lsx_vstelm_<lsxfmt_f>"
+ [(match_operand:LSX 0 "register_operand")
+ (match_operand 3 "const_<indeximm>_operand")
+ (match_operand 2 "aq8<lsxfmt>_operand")
+ (match_operand 1 "pmode_register_operand")]
+ "ISA_HAS_LSX"
+{
+ emit_insn (gen_lsx_vstelm_<lsxfmt_f>_insn
+ (operands[1], operands[2], operands[0], operands[3]));
+ DONE;
+})
+
+(define_insn "lsx_vstelm_<lsxfmt_f>_insn"
+ [(set (mem:<UNITMODE> (plus:DI (match_operand:DI 0 "register_operand" "r")
+ (match_operand 1 "aq8<lsxfmt>_operand")))
+ (vec_select:<UNITMODE>
+ (match_operand:LSX 2 "register_operand" "f")
+ (parallel [(match_operand 3 "const_<indeximm>_operand" "")])))]
+
+ "ISA_HAS_LSX"
+{
+ return "vstelm.<lsxfmt>\t%w2,%0,%1,%3";
+}
+ [(set_attr "type" "simd_store")
+ (set_attr "mode" "<MODE>")
+ (set_attr "length" "4")])
+
+;; Offset is "0"
+(define_insn "lsx_vstelm_<lsxfmt_f>_insn_0"
+ [(set (mem:<UNITMODE> (match_operand:DI 0 "register_operand" "r"))
+ (vec_select:<UNITMODE>
+ (match_operand:LSX 1 "register_operand" "f")
+ (parallel [(match_operand:SI 2 "const_<indeximm>_operand")])))]
+ "ISA_HAS_LSX"
+{
+ return "vstelm.<lsxfmt>\t%w1,%0,0,%2";
+}
+ [(set_attr "type" "simd_store")
+ (set_attr "mode" "<MODE>")
+ (set_attr "length" "4")])
+
+(define_expand "lsx_vld"
+ [(match_operand:V16QI 0 "register_operand")
+ (match_operand 1 "pmode_register_operand")
+ (match_operand 2 "aq12b_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx addr = plus_constant (GET_MODE (operands[1]), operands[1],
+ INTVAL (operands[2]));
+ loongarch_emit_move (operands[0], gen_rtx_MEM (V16QImode, addr));
+ DONE;
+})
+
+(define_expand "lsx_vst"
+ [(match_operand:V16QI 0 "register_operand")
+ (match_operand 1 "pmode_register_operand")
+ (match_operand 2 "aq12b_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx addr = plus_constant (GET_MODE (operands[1]), operands[1],
+ INTVAL (operands[2]));
+ loongarch_emit_move (gen_rtx_MEM (V16QImode, addr), operands[0]);
+ DONE;
+})
+
+(define_insn "lsx_vssrln_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRLN))]
+ "ISA_HAS_LSX"
+ "vssrln.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+
+(define_insn "lsx_vssrlrn_<hlsxfmt>_<lsxfmt>"
+ [(set (match_operand:<VHMODE> 0 "register_operand" "=f")
+ (unspec:<VHMODE> [(match_operand:ILSX_DWH 1 "register_operand" "f")
+ (match_operand:ILSX_DWH 2 "register_operand" "f")]
+ UNSPEC_LSX_VSSRLRN))]
+ "ISA_HAS_LSX"
+ "vssrlrn.<hlsxfmt>.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "vorn<mode>3"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (ior:ILSX (not:ILSX (match_operand:ILSX 2 "register_operand" "f"))
+ (match_operand:ILSX 1 "register_operand" "f")))]
+ "ISA_HAS_LSX"
+ "vorn.v\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_logic")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vldi"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand 1 "const_imm13_operand")]
+ UNSPEC_LSX_VLDI))]
+ "ISA_HAS_LSX"
+{
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ if (val < 0)
+ {
+ HOST_WIDE_INT modeVal = (val & 0xf00) >> 8;
+ if (modeVal < 13)
+ return "vldi\t%w0,%1";
+ else
+ sorry ("imm13 only support 0000 ~ 1100 in bits 9 ~ 12 when bit '13' is 1");
+ return "#";
+ }
+ else
+ return "vldi\t%w0,%1";
+}
+ [(set_attr "type" "simd_load")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vshuf_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "f")
+ (match_operand:V16QI 2 "register_operand" "f")
+ (match_operand:V16QI 3 "register_operand" "f")]
+ UNSPEC_LSX_VSHUF_B))]
+ "ISA_HAS_LSX"
+ "vshuf.b\t%w0,%w1,%w2,%w3"
+ [(set_attr "type" "simd_shf")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vldx"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (unspec:V16QI [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "reg_or_0_operand" "rJ")]
+ UNSPEC_LSX_VLDX))]
+ "ISA_HAS_LSX"
+{
+ return "vldx\t%w0,%1,%z2";
+}
+ [(set_attr "type" "simd_load")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vstx"
+ [(set (mem:V16QI (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "reg_or_0_operand" "rJ")))
+ (unspec: V16QI [(match_operand:V16QI 0 "register_operand" "f")]
+ UNSPEC_LSX_VSTX))]
+
+ "ISA_HAS_LSX"
+{
+ return "vstx\t%w0,%1,%z2";
+}
+ [(set_attr "type" "simd_store")
+ (set_attr "mode" "DI")])
+
+(define_insn "lsx_vextl_qu_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTL_QU_DU))]
+ "ISA_HAS_LSX"
+ "vextl.qu.du\t%w0,%w1"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vseteqz_v"
+ [(set (match_operand:FCC 0 "register_operand" "=z")
+ (eq:FCC
+ (unspec:SI [(match_operand:V16QI 1 "register_operand" "f")]
+ UNSPEC_LSX_VSETEQZ_V)
+ (match_operand:SI 2 "const_0_operand")))]
+ "ISA_HAS_LSX"
+{
+ return "vseteqz.v\t%0,%1";
+}
+ [(set_attr "type" "simd_fcmp")
+ (set_attr "mode" "FCC")])
+
+;; Vector reduction operation
+(define_expand "reduc_plus_scal_v2di"
+ [(match_operand:DI 0 "register_operand")
+ (match_operand:V2DI 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (V2DImode);
+ emit_insn (gen_lsx_vhaddw_q_d (tmp, operands[1], operands[1]));
+ emit_insn (gen_vec_extractv2didi (operands[0], tmp, const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_plus_scal_v4si"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:V4SI 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (V2DImode);
+ rtx tmp1 = gen_reg_rtx (V2DImode);
+ emit_insn (gen_lsx_vhaddw_d_w (tmp, operands[1], operands[1]));
+ emit_insn (gen_lsx_vhaddw_q_d (tmp1, tmp, tmp));
+ emit_insn (gen_vec_extractv4sisi (operands[0], gen_lowpart (V4SImode,tmp1),
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_plus_scal_<mode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:FLSX 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_add<mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_<optab>_scal_<mode>"
+ [(any_bitwise:<UNITMODE>
+ (match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:ILSX 1 "register_operand"))]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_<optab><mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_smax_scal_<mode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:LSX 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_smax<mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_smin_scal_<mode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:LSX 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_smin<mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_umax_scal_<mode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:ILSX 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_umax<mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_expand "reduc_umin_scal_<mode>"
+ [(match_operand:<UNITMODE> 0 "register_operand")
+ (match_operand:ILSX 1 "register_operand")]
+ "ISA_HAS_LSX"
+{
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ loongarch_expand_vector_reduc (gen_umin<mode>3, tmp, operands[1]);
+ emit_insn (gen_vec_extract<mode><unitmode> (operands[0], tmp,
+ const0_rtx));
+ DONE;
+})
+
+(define_insn "lsx_v<optab>wev_d_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (addsubmul:V2DI
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)])))
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.d.w<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_v<optab>wev_w_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (addsubmul:V4SI
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.w.h<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_v<optab>wev_h_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (addsubmul:V8HI
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.h.b<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_v<optab>wod_d_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (addsubmul:V2DI
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)])))
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.d.w<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_v<optab>wod_w_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (addsubmul:V4SI
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.w.h<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_v<optab>wod_h_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (addsubmul:V8HI
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.h.b<u>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_v<optab>wev_d_wu_w"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (addmul:V2DI
+ (zero_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)])))
+ (sign_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.d.wu.w\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_v<optab>wev_w_hu_h"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (addmul:V4SI
+ (zero_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))
+ (sign_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.w.hu.h\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_v<optab>wev_h_bu_b"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (addmul:V8HI
+ (zero_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))
+ (sign_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wev.h.bu.b\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_v<optab>wod_d_wu_w"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (addmul:V2DI
+ (zero_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)])))
+ (sign_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.d.wu.w\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_v<optab>wod_w_hu_h"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (addmul:V4SI
+ (zero_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))
+ (sign_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.w.hu.h\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_v<optab>wod_h_bu_b"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (addmul:V8HI
+ (zero_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))
+ (sign_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))))]
+ "ISA_HAS_LSX"
+ "v<optab>wod.h.bu.b\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vaddwev_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWEV))]
+ "ISA_HAS_LSX"
+ "vaddwev.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vaddwev_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWEV2))]
+ "ISA_HAS_LSX"
+ "vaddwev.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vaddwod_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWOD))]
+ "ISA_HAS_LSX"
+ "vaddwod.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vaddwod_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWOD2))]
+ "ISA_HAS_LSX"
+ "vaddwod.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsubwev_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VSUBWEV))]
+ "ISA_HAS_LSX"
+ "vsubwev.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsubwev_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VSUBWEV2))]
+ "ISA_HAS_LSX"
+ "vsubwev.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsubwod_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VSUBWOD))]
+ "ISA_HAS_LSX"
+ "vsubwod.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsubwod_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VSUBWOD2))]
+ "ISA_HAS_LSX"
+ "vsubwod.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vaddwev_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWEV3))]
+ "ISA_HAS_LSX"
+ "vaddwev.q.du.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vaddwod_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADDWOD3))]
+ "ISA_HAS_LSX"
+ "vaddwod.q.du.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwev_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWEV3))]
+ "ISA_HAS_LSX"
+ "vmulwev.q.du.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwod_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWOD3))]
+ "ISA_HAS_LSX"
+ "vmulwod.q.du.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwev_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWEV))]
+ "ISA_HAS_LSX"
+ "vmulwev.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwev_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWEV2))]
+ "ISA_HAS_LSX"
+ "vmulwev.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwod_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWOD))]
+ "ISA_HAS_LSX"
+ "vmulwod.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmulwod_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VMULWOD2))]
+ "ISA_HAS_LSX"
+ "vmulwod.q.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vhaddw_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VHADDW_Q_D))]
+ "ISA_HAS_LSX"
+ "vhaddw.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vhaddw_qu_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VHADDW_QU_DU))]
+ "ISA_HAS_LSX"
+ "vhaddw.qu.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vhsubw_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VHSUBW_Q_D))]
+ "ISA_HAS_LSX"
+ "vhsubw.q.d\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vhsubw_qu_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VHSUBW_QU_DU))]
+ "ISA_HAS_LSX"
+ "vhsubw.qu.du\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwev_d_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (plus:V2DI
+ (match_operand:V2DI 1 "register_operand" "0")
+ (mult:V2DI
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)])))
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.d.w<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwev_w_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (plus:V4SI
+ (match_operand:V4SI 1 "register_operand" "0")
+ (mult:V4SI
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.w.h<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vmaddwev_h_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (plus:V8HI
+ (match_operand:V8HI 1 "register_operand" "0")
+ (mult:V8HI
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.h.b<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vmaddwod_d_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (plus:V2DI
+ (match_operand:V2DI 1 "register_operand" "0")
+ (mult:V2DI
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)])))
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.d.w<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwod_w_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (plus:V4SI
+ (match_operand:V4SI 1 "register_operand" "0")
+ (mult:V4SI
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.w.h<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vmaddwod_h_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (plus:V8HI
+ (match_operand:V8HI 1 "register_operand" "0")
+ (mult:V8HI
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.h.b<u>\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vmaddwev_d_wu_w"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (plus:V2DI
+ (match_operand:V2DI 1 "register_operand" "0")
+ (mult:V2DI
+ (zero_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)])))
+ (sign_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.d.wu.w\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwev_w_hu_h"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (plus:V4SI
+ (match_operand:V4SI 1 "register_operand" "0")
+ (mult:V4SI
+ (zero_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)])))
+ (sign_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.w.hu.h\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vmaddwev_h_bu_b"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (plus:V8HI
+ (match_operand:V8HI 1 "register_operand" "0")
+ (mult:V8HI
+ (zero_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "%f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)])))
+ (sign_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 3 "register_operand" "f")
+ (parallel [(const_int 0) (const_int 2)
+ (const_int 4) (const_int 6)
+ (const_int 8) (const_int 10)
+ (const_int 12) (const_int 14)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwev.h.bu.b\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vmaddwod_d_wu_w"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (plus:V2DI
+ (match_operand:V2DI 1 "register_operand" "0")
+ (mult:V2DI
+ (zero_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)])))
+ (sign_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.d.wu.w\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwod_w_hu_h"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (plus:V4SI
+ (match_operand:V4SI 1 "register_operand" "0")
+ (mult:V4SI
+ (zero_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)])))
+ (sign_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.w.hu.h\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vmaddwod_h_bu_b"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (plus:V8HI
+ (match_operand:V8HI 1 "register_operand" "0")
+ (mult:V8HI
+ (zero_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 2 "register_operand" "%f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)])))
+ (sign_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 3 "register_operand" "f")
+ (parallel [(const_int 1) (const_int 3)
+ (const_int 5) (const_int 7)
+ (const_int 9) (const_int 11)
+ (const_int 13) (const_int 15)]))))))]
+ "ISA_HAS_LSX"
+ "vmaddwod.h.bu.b\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_fmadd")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vmaddwev_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWEV))]
+ "ISA_HAS_LSX"
+ "vmaddwev.q.d\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwod_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWOD))]
+ "ISA_HAS_LSX"
+ "vmaddwod.q.d\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwev_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWEV2))]
+ "ISA_HAS_LSX"
+ "vmaddwev.q.du\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwod_q_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWOD2))]
+ "ISA_HAS_LSX"
+ "vmaddwod.q.du\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwev_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWEV3))]
+ "ISA_HAS_LSX"
+ "vmaddwev.q.du.d\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmaddwod_q_du_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0")
+ (match_operand:V2DI 2 "register_operand" "f")
+ (match_operand:V2DI 3 "register_operand" "f")]
+ UNSPEC_LSX_VMADDWOD3))]
+ "ISA_HAS_LSX"
+ "vmaddwod.q.du.d\t%w0,%w2,%w3"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vrotr_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
+ (match_operand:ILSX 2 "register_operand" "f")]
+ UNSPEC_LSX_VROTR))]
+ "ISA_HAS_LSX"
+ "vrotr.<lsxfmt>\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vadd_q"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VADD_Q))]
+ "ISA_HAS_LSX"
+ "vadd.q\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsub_q"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")
+ (match_operand:V2DI 2 "register_operand" "f")]
+ UNSPEC_LSX_VSUB_Q))]
+ "ISA_HAS_LSX"
+ "vsub.q\t%w0,%w1,%w2"
+ [(set_attr "type" "simd_int_arith")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vmskgez_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "f")]
+ UNSPEC_LSX_VMSKGEZ))]
+ "ISA_HAS_LSX"
+ "vmskgez.b\t%w0,%w1"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vmsknz_b"
+ [(set (match_operand:V16QI 0 "register_operand" "=f")
+ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "f")]
+ UNSPEC_LSX_VMSKNZ))]
+ "ISA_HAS_LSX"
+ "vmsknz.b\t%w0,%w1"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "V16QI")])
+
+(define_insn "lsx_vexth_h<u>_b<u>"
+ [(set (match_operand:V8HI 0 "register_operand" "=f")
+ (any_extend:V8HI
+ (vec_select:V8QI
+ (match_operand:V16QI 1 "register_operand" "f")
+ (parallel [(const_int 8) (const_int 9)
+ (const_int 10) (const_int 11)
+ (const_int 12) (const_int 13)
+ (const_int 14) (const_int 15)]))))]
+ "ISA_HAS_LSX"
+ "vexth.h<u>.b<u>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V8HI")])
+
+(define_insn "lsx_vexth_w<u>_h<u>"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (any_extend:V4SI
+ (vec_select:V4HI
+ (match_operand:V8HI 1 "register_operand" "f")
+ (parallel [(const_int 4) (const_int 5)
+ (const_int 6) (const_int 7)]))))]
+ "ISA_HAS_LSX"
+ "vexth.w<u>.h<u>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V4SI")])
+
+(define_insn "lsx_vexth_d<u>_w<u>"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (any_extend:V2DI
+ (vec_select:V2SI
+ (match_operand:V4SI 1 "register_operand" "f")
+ (parallel [(const_int 2) (const_int 3)]))))]
+ "ISA_HAS_LSX"
+ "vexth.d<u>.w<u>\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vexth_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTH_Q_D))]
+ "ISA_HAS_LSX"
+ "vexth.q.d\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vexth_qu_du"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTH_QU_DU))]
+ "ISA_HAS_LSX"
+ "vexth.qu.du\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vrotri_<lsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (rotatert:ILSX (match_operand:ILSX 1 "register_operand" "f")
+ (match_operand 2 "const_<bitimm>_operand" "")))]
+ "ISA_HAS_LSX"
+ "vrotri.<lsxfmt>\t%w0,%w1,%2"
+ [(set_attr "type" "simd_shf")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vextl_q_d"
+ [(set (match_operand:V2DI 0 "register_operand" "=f")
+ (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "f")]
+ UNSPEC_LSX_VEXTL_Q_D))]
+ "ISA_HAS_LSX"
+ "vextl.q.d\t%w0,%w1"
+ [(set_attr "type" "simd_fcvt")
+ (set_attr "mode" "V2DI")])
+
+(define_insn "lsx_vsrlni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSRLNI))]
+ "ISA_HAS_LSX"
+ "vsrlni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrlrni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSRLRNI))]
+ "ISA_HAS_LSX"
+ "vsrlrni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrlni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRLNI))]
+ "ISA_HAS_LSX"
+ "vssrlni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrlni_<lsxfmt_u>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRLNI2))]
+ "ISA_HAS_LSX"
+ "vssrlni.<lsxfmt_u>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrlrni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRLRNI))]
+ "ISA_HAS_LSX"
+ "vssrlrni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrlrni_<lsxfmt_u>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRLRNI2))]
+ "ISA_HAS_LSX"
+ "vssrlrni.<lsxfmt_u>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrani_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSRANI))]
+ "ISA_HAS_LSX"
+ "vsrani.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vsrarni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSRARNI))]
+ "ISA_HAS_LSX"
+ "vsrarni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrani_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRANI))]
+ "ISA_HAS_LSX"
+ "vssrani.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrani_<lsxfmt_u>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRANI2))]
+ "ISA_HAS_LSX"
+ "vssrani.<lsxfmt_u>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrarni_<lsxfmt>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRARNI))]
+ "ISA_HAS_LSX"
+ "vssrarni.<lsxfmt>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vssrarni_<lsxfmt_u>_<dlsxfmt>"
+ [(set (match_operand:ILSX 0 "register_operand" "=f")
+ (unspec:ILSX [(match_operand:ILSX 1 "register_operand" "0")
+ (match_operand:ILSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VSSRARNI2))]
+ "ISA_HAS_LSX"
+ "vssrarni.<lsxfmt_u>.<dlsxfmt>\t%w0,%w2,%3"
+ [(set_attr "type" "simd_shift")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "lsx_vpermi_w"
+ [(set (match_operand:V4SI 0 "register_operand" "=f")
+ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0")
+ (match_operand:V4SI 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VPERMI))]
+ "ISA_HAS_LSX"
+ "vpermi.w\t%w0,%w2,%3"
+ [(set_attr "type" "simd_bit")
+ (set_attr "mode" "V4SI")])