;; Machine Description for LARCH Loongson SX ASE
;;
;; Copyright (C) 2018-2024 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
;; .
;;
(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_VFCLASS
UNSPEC_LSX_VFCVT
UNSPEC_LSX_VFCVTH
UNSPEC_LSX_VFCVTL
UNSPEC_LSX_VFLOGB
UNSPEC_LSX_VFRECIP
UNSPEC_LSX_VFRECIPE
UNSPEC_LSX_VFRINT
UNSPEC_LSX_VFRSQRT
UNSPEC_LSX_VFRSQRTE
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_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_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_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_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
UNSPEC_LSX_VILVL_INTERNAL
UNSPEC_LSX_VREPLVEI_MIRROR
])
;; 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])
;; 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 used for immediate set shuffle elements instruction.
(define_mode_iterator LSX_WHB_W [V4SI V8HI V16QI V4SF])
;; 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__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__operand".
(define_mode_attr bitmask
[(V2DF "exp_2")
(V4SF "exp_4")
(V2DI "exp_2")
(V4SI "exp_4")
(V8HI "exp_8")
(V16QI "exp_16")])
(define_expand "vec_init"
[(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_"
[(set (match_operand: 0 "register_operand" "=f")
(vec_concat:
(truncate:
(match_operand:ILSX_DWH 1 "register_operand" "f"))
(truncate:
(match_operand:ILSX_DWH 2 "register_operand" "f"))))]
"ISA_HAS_LSX"
"vpickev.\t%w0,%w2,%w1"
[(set_attr "type" "simd_permute")
(set_attr "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_"
[(match_operand: 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_"
[(match_operand: 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_"
[(match_operand: 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_"
[(match_operand: 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"
[(match_operand: 0 "register_operand")
(match_operand:ILSX 1 "register_operand")
(match_operand 2 "const__operand")]
"ISA_HAS_LSX"
{
if (mode == QImode || mode == HImode)
{
rtx dest1 = gen_reg_rtx (SImode);
emit_insn (gen_lsx_vpickve2gr_ (dest1, operands[1], operands[2]));
emit_move_insn (operands[0],
gen_lowpart (mode, dest1));
}
else
emit_insn (gen_lsx_vpickve2gr_ (operands[0], operands[1], operands[2]));
DONE;
})
(define_expand "vec_extract"
[(match_operand: 0 "register_operand")
(match_operand:FLSX 1 "register_operand")
(match_operand 2 "const__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 (mode));
temp = gen_reg_rtx (mode);
emit_insn (gen_lsx_vbsrl_ (temp, operands[1], n));
}
emit_insn (gen_lsx_vec_extract_ (operands[0], temp));
DONE;
})
(define_insn_and_split "lsx_vec_extract_"
[(set (match_operand: 0 "register_operand" "=f")
(vec_select:
(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 (mode, REGNO (operands[1]));
}
[(set_attr "move_type" "fmove")
(set_attr "mode" "")])
(define_expand "vec_set"
[(match_operand:ILSX 0 "register_operand")
(match_operand: 1 "reg_or_0_operand")
(match_operand 2 "const__operand")]
"ISA_HAS_LSX"
{
rtx index = GEN_INT (1 << INTVAL (operands[2]));
emit_insn (gen_lsx_vinsgr2vr_ (operands[0], operands[1],
operands[0], index));
DONE;
})
(define_expand "vec_set"
[(match_operand:FLSX 0 "register_operand")
(match_operand: 1 "register_operand")
(match_operand 2 "const__operand")]
"ISA_HAS_LSX"
{
rtx index = GEN_INT (1 << INTVAL (operands[2]));
emit_insn (gen_lsx_vextrins__scalar (operands[0], operands[1],
operands[0], index));
DONE;
})
(define_expand "vec_cmp"
[(set (match_operand: 0 "register_operand")
(match_operator 1 ""
[(match_operand:LSX 2 "register_operand")
(match_operand:LSX 3 "register_operand")]))]
"ISA_HAS_LSX"
{
loongarch_expand_vec_cmp (operands);
DONE;
})
(define_expand "vec_cmpu"
[(set (match_operand: 0 "register_operand")
(match_operator 1 ""
[(match_operand:ILSX 2 "register_operand")
(match_operand:ILSX 3 "register_operand")]))]
"ISA_HAS_LSX"
{
loongarch_expand_vec_cmp (operands);
DONE;
})
(define_expand "vcondu"
[(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 (mode) == GET_MODE_NUNITS (mode))"
{
loongarch_expand_vec_cond_expr (mode, mode, operands);
DONE;
})
(define_expand "vcond"
[(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 (mode) == GET_MODE_NUNITS (mode))"
{
loongarch_expand_vec_cond_expr (mode, mode, operands);
DONE;
})
(define_expand "vcond_mask_"
[(match_operand:LSX 0 "register_operand")
(match_operand:LSX 1 "reg_or_m1_operand")
(match_operand:LSX 2 "reg_or_0_operand")
(match_operand: 3 "register_operand")]
"ISA_HAS_LSX"
{
loongarch_expand_vec_cond_mask_expr (mode,
mode, operands);
DONE;
})
(define_insn "lsx_vinsgr2vr_"
[(set (match_operand:ILSX 0 "register_operand" "=f")
(vec_merge:ILSX
(vec_duplicate:ILSX
(match_operand: 1 "reg_or_0_operand" "rJ"))
(match_operand:ILSX 2 "register_operand" "0")
(match_operand 3 "const__operand" "")))]
"ISA_HAS_LSX"
{
return "vinsgr2vr.\t%w0,%z1,%y3";
}
[(set_attr "type" "simd_insert")
(set_attr "mode" "")])
(define_insn "lsx_vextrins__internal"
[(set (match_operand:LSX 0 "register_operand" "=f")
(vec_merge:LSX
(vec_duplicate:LSX
(vec_select:
(match_operand:LSX 1 "register_operand" "f")
(parallel [(const_int 0)])))
(match_operand:LSX 2 "register_operand" "0")
(match_operand 3 "const__operand" "")))]
"ISA_HAS_LSX"
"vextrins.\t%w0,%w1,%y3<<4"
[(set_attr "type" "simd_insert")
(set_attr "mode" "")])
;; Operand 3 is a scalar.
(define_insn "lsx_vextrins__scalar"
[(set (match_operand:FLSX 0 "register_operand" "=f")
(vec_merge:FLSX
(vec_duplicate:FLSX
(match_operand: 1 "register_operand" "f"))
(match_operand:FLSX 2 "register_operand" "0")
(match_operand 3 "const__operand" "")))]
"ISA_HAS_LSX"
"vextrins.\t%w0,%w1,%y3<<4"
[(set_attr "type" "simd_insert")
(set_attr "mode" "")])
(define_insn "lsx_vpickve2gr_"
[(set (match_operand: 0 "register_operand" "=r")
(any_extend:
(vec_select:
(match_operand:ILSX_HB 1 "register_operand" "f")
(parallel [(match_operand 2 "const__operand" "")]))))]
"ISA_HAS_LSX"
"vpickve2gr.\t%0,%w1,%2"
[(set_attr "type" "simd_copy")
(set_attr "mode" "")])
(define_insn "lsx_vpickve2gr_"
[(set (match_operand: 0 "register_operand" "=r")
(any_extend:
(vec_select:
(match_operand:LSX_W 1 "register_operand" "f")
(parallel [(match_operand 2 "const__operand" "")]))))]
"ISA_HAS_LSX"
"vpickve2gr.\t%0,%w1,%2"
[(set_attr "type" "simd_copy")
(set_attr "mode" "")])
(define_insn "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"
"vpickve2gr.du\t%0,%w1,%2"
[(set_attr "type" "simd_copy")
(set_attr "mode" "V2DI")])
(define_insn "lsx_vpickve2gr_"
[(set (match_operand: 0 "register_operand" "=r")
(vec_select:
(match_operand:LSX_D 1 "register_operand" "f")
(parallel [(match_operand 2 "const__operand" "")])))]
"ISA_HAS_LSX"
"vpickve2gr.\t%0,%w1,%2"
[(set_attr "type" "simd_copy")
(set_attr "mode" "")])
(define_expand "neg2"
[(set (match_operand:ILSX 0 "register_operand")
(neg:ILSX (match_operand:ILSX 1 "register_operand")))]
"ISA_HAS_LSX"
{
emit_insn (gen_vneg2 (operands[0], operands[1]));
DONE;
})
(define_expand "lsx_vrepli"
[(match_operand:ILSX 0 "register_operand")
(match_operand 1 "const_imm10_operand")]
"ISA_HAS_LSX"
{
if (mode == V16QImode)
operands[1] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]),
mode));
emit_move_insn (operands[0],
loongarch_gen_const_int_vector (mode, INTVAL (operands[1])));
DONE;
})
(define_expand "vec_perm"
[(match_operand:LSX 0 "register_operand")
(match_operand:LSX 1 "register_operand")
(match_operand:LSX 2 "register_operand")
(match_operand: 3 "register_operand")]
"ISA_HAS_LSX"
{
loongarch_expand_vec_perm (operands[0], operands[1],
operands[2], operands[3]);
DONE;
})
(define_insn "lsx_vshuf_"
[(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.\t%w0,%w2,%w3"
[(set_attr "type" "simd_sld")
(set_attr "mode" "")])
(define_expand "mov"
[(set (match_operand:LSX 0)
(match_operand:LSX 1))]
"ISA_HAS_LSX"
{
if (loongarch_legitimize_move (mode, operands[0], operands[1]))
DONE;
})
(define_expand "movmisalign"
[(set (match_operand:LSX 0)
(match_operand:LSX 1))]
"ISA_HAS_LSX"
{
if (loongarch_legitimize_move (mode, operands[0], operands[1]))
DONE;
})
(define_insn "mov_lsx"
[(set (match_operand:LSX 0 "nonimmediate_operand" "=f,f,R,*r,*f,*r")
(match_operand:LSX 1 "move_operand" "fYGYI,R,f,*f,*r,*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,simd_copy")
(set_attr "mode" "")])
(define_split
[(set (match_operand:LSX 0 "nonimmediate_operand")
(match_operand:LSX 1 "move_operand"))]
"reload_completed && ISA_HAS_LSX
&& loongarch_split_move_p (operands[0], operands[1])"
[(const_int 0)]
{
loongarch_split_move (operands[0], operands[1]);
DONE;
})
;; Integer operations
(define_insn "add3"
[(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.\t%w0,%w1,%w2";
case 1:
{
HOST_WIDE_INT val = INTVAL (CONST_VECTOR_ELT (operands[2], 0));
operands[2] = GEN_INT (-val);
return "vsubi.\t%w0,%w1,%d2";
}
case 2:
return "vaddi.\t%w0,%w1,%E2";
default:
gcc_unreachable ();
}
}
[(set_attr "alu_type" "simd_add")
(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "sub3"
[(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.\t%w0,%w1,%w2
vsubi.\t%w0,%w1,%E2"
[(set_attr "alu_type" "simd_add")
(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "mul3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_mul")
(set_attr "mode" "")])
(define_insn "lsx_vmadd_"
[(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.\t%w0,%w2,%w3"
[(set_attr "type" "simd_mul")
(set_attr "mode" "")])
(define_insn "lsx_vmsub_"
[(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.\t%w0,%w2,%w3"
[(set_attr "type" "simd_mul")
(set_attr "mode" "")])
(define_insn "div3"
[(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.\t%w0,%w1,%w2", operands); }
[(set_attr "type" "simd_div")
(set_attr "mode" "")])
(define_insn "udiv3"
[(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.\t%w0,%w1,%w2", operands); }
[(set_attr "type" "simd_div")
(set_attr "mode" "")])
(define_insn "mod3"
[(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.\t%w0,%w1,%w2", operands); }
[(set_attr "type" "simd_div")
(set_attr "mode" "")])
(define_insn "umod3"
[(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.\t%w0,%w1,%w2", operands); }
[(set_attr "type" "simd_div")
(set_attr "mode" "")])
(define_insn "xor3"
[(set (match_operand:LSX 0 "register_operand" "=f,f,f")
(xor: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"
"@
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" "")])
(define_insn "ior3"
[(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" "")])
(define_insn "and3"
[(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, 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" "")])
(define_insn "one_cmpl2"
[(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 "vlshr3"
[(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.\t%w0,%w1,%w2
vsrli.\t%w0,%w1,%E2"
[(set_attr "type" "simd_shift")
(set_attr "mode" "")])
(define_insn "vashr3"
[(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.\t%w0,%w1,%w2
vsrai.\t%w0,%w1,%E2"
[(set_attr "type" "simd_shift")
(set_attr "mode" "")])
(define_insn "vashl3"
[(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.\t%w0,%w1,%w2
vslli.\t%w0,%w1,%E2"
[(set_attr "type" "simd_shift")
(set_attr "mode" "")])
;; Floating-point operations
(define_insn "add3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_fadd")
(set_attr "mode" "")])
(define_insn "sub3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_fadd")
(set_attr "mode" "")])
(define_insn "mul3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_fmul")
(set_attr "mode" "")])
(define_expand "div3"
[(set (match_operand:FLSX 0 "register_operand")
(div:FLSX (match_operand:FLSX 1 "reg_or_vecotr_1_operand")
(match_operand:FLSX 2 "register_operand")))]
"ISA_HAS_LSX"
{
if (mode == V4SFmode
&& TARGET_RECIP_VEC_DIV
&& optimize_insn_for_speed_p ()
&& flag_finite_math_only && !flag_trapping_math
&& flag_unsafe_math_optimizations)
{
loongarch_emit_swdivsf (operands[0], operands[1],
operands[2], V4SFmode);
DONE;
}
})
(define_insn "*div3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_fdiv")
(set_attr "mode" "")])
(define_insn "fma4"
[(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.\t%w0,%w1,%w2,%w3"
[(set_attr "type" "simd_fmadd")
(set_attr "mode" "")])
(define_insn "fnma4"
[(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.\t%w0,%w1,%w2,%w0"
[(set_attr "type" "simd_fmadd")
(set_attr "mode" "")])
(define_expand "sqrt2"
[(set (match_operand:FLSX 0 "register_operand")
(sqrt:FLSX (match_operand:FLSX 1 "register_operand")))]
"ISA_HAS_LSX"
{
if (mode == V4SFmode
&& TARGET_RECIP_VEC_SQRT
&& flag_unsafe_math_optimizations
&& optimize_insn_for_speed_p ()
&& flag_finite_math_only && !flag_trapping_math)
{
loongarch_emit_swrsqrtsf (operands[0], operands[1], V4SFmode, 0);
DONE;
}
})
(define_insn "*sqrt2"
[(set (match_operand:FLSX 0 "register_operand" "=f")
(sqrt:FLSX (match_operand:FLSX 1 "register_operand" "f")))]
"ISA_HAS_LSX"
"vfsqrt.\t%w0,%w1"
[(set_attr "type" "simd_fdiv")
(set_attr "mode" "")])
;; Built-in functions
(define_insn "lsx_vadda_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "ssadd3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "usadd3"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vabsd_s_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vabsd_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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vavg_s_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vavg_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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vavgr_s_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vavgr_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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_int_arith")
(set_attr "mode" "")])
(define_insn "lsx_vbitclr_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_bit")
(set_attr "mode" "")])
(define_insn "lsx_vbitclri_"
[(set (match_operand:ILSX 0 "register_operand" "=f")
(unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
(match_operand 2 "const__operand" "")]
UNSPEC_LSX_VBITCLRI))]
"ISA_HAS_LSX"
"vbitclri.\t%w0,%w1,%2"
[(set_attr "type" "simd_bit")
(set_attr "mode" "")])
(define_insn "lsx_vbitrev_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_bit")
(set_attr "mode" "")])
(define_insn "lsx_vbitrevi_"
[(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.\t%w0,%w1,%2"
[(set_attr "type" "simd_bit")
(set_attr "mode" "")])
(define_insn "lsx_vbitsel_"
[(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" "")])
(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_"
[(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.\t%w0,%w1,%w2"
[(set_attr "type" "simd_bit")
(set_attr "mode" "")])
(define_insn "lsx_vbitseti_"
[(set (match_operand:ILSX 0 "register_operand" "=f")
(unspec:ILSX [(match_operand:ILSX 1 "register_operand" "f")
(match_operand 2 "const__operand" "")]
UNSPEC_LSX_VBITSETI))]
"ISA_HAS_LSX"
"vbitseti.\t%w0,%w1,%2"
[(set_attr "type" "simd_bit")
(set_attr "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_