//===- arm_mve.td - ACLE intrinsic functions for MVE architecture ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the set of ACLE-specified source-level intrinsic // functions wrapping the MVE vector instruction set and scalar shift // operations. // // Refer to comments in arm_mve_defs.td for the infrastructure used in // here, and to MveEmitter.cpp for how those are used in turn to // generate code. // //===----------------------------------------------------------------------===// include "arm_mve_defs.td" let params = T.Usual in foreach n = [ 2, 4 ] in { def "vst"#n#"q": Intrinsic, MultiVector), (CustomCodegen<"VST24"> n:$NumVectors, "Intrinsic::arm_mve_vst"#n#"q":$IRIntr)>; def "vld"#n#"q": Intrinsic, (args CPtr), (CustomCodegen<"VLD24"> n:$NumVectors, "Intrinsic::arm_mve_vld"#n#"q":$IRIntr)>; } multiclass bit_op_fp { def "": Intrinsic; } multiclass bit_op_fp_with_inv { def "": Intrinsic; } let params = T.Signed in { def vqaddq: Intrinsic $a, $b)>; def vqsubq: Intrinsic $a, $b)>; let pnt = PNT_NType in { def vqaddq_n: Intrinsic:$b), (IRIntBase<"sadd_sat", [Vector]> $a, (splat $b))>; def vqsubq_n: Intrinsic:$b), (IRIntBase<"ssub_sat", [Vector]> $a, (splat $b))>; } } let params = T.Unsigned in { def vqaddq_u: Intrinsic $a, $b)>, NameOverride<"vqaddq">; def vqsubq_u: Intrinsic $a, $b)>, NameOverride<"vqsubq">; let pnt = PNT_NType in { def vqaddq_u_n: Intrinsic:$b), (IRIntBase<"uadd_sat", [Vector]> $a, (splat $b))>, NameOverride<"vqaddq_n">; def vqsubq_u_n: Intrinsic:$b), (IRIntBase<"usub_sat", [Vector]> $a, (splat $b))>, NameOverride<"vqsubq_n">; } } // Some intrinsics below are implemented not as IR fragments, but as // special-purpose IR intrinsics. This is because such a general form // (such as NEON uses) required a variable-width vector size, and we are // restricted to 128 bit. Although we can possibly get clever with lane // operations, the consequent IR representation would be very hard to // write sensibly. In particular, doubling a vector's width would be a // mess. Other intrinsics just don't translate nicely into IR. let params = T.Int in { def vaddq: Intrinsic; def vhaddq: Intrinsic $a, $b, (unsignedflag Scalar))>; def vrhaddq: Intrinsic $a, $b, (unsignedflag Scalar))>; def vandq: Intrinsic; def vbicq: Intrinsic; def veorq: Intrinsic; def vornq: Intrinsic; def vorrq: Intrinsic; def vsubq: Intrinsic; def vhsubq: Intrinsic $a, $b, (unsignedflag Scalar))>; def vmulq: Intrinsic; def vmulhq: Intrinsic $a, $b, (unsignedflag Scalar))>; def vrmulhq: Intrinsic $a, $b, (unsignedflag Scalar))>; def vmullbq_int: Intrinsic $a, $b, (unsignedflag Scalar), 0)>; def vmulltq_int: Intrinsic $a, $b, (unsignedflag Scalar), 1)>; let pnt = PNT_NType in { def vaddq_n: Intrinsic:$b), (add $a, (splat $b))>; def vsubq_n: Intrinsic:$b), (sub $a, (splat $b))>; def vmulq_n: Intrinsic:$b), (mul $a, (splat $b))>; def vhaddq_n: Intrinsic:$b), (IRInt<"vhadd", [Vector]> $a, (splat $b), (unsignedflag Scalar))>; def vhsubq_n: Intrinsic:$b), (IRInt<"vhsub", [Vector]> $a, (splat $b), (unsignedflag Scalar))>; } } let params = T.Signed in { def vqdmulhq: Intrinsic $a, $b)>; def vqrdmulhq: Intrinsic $a, $b)>; let pnt = PNT_NType in { def vqdmulhq_n: Intrinsic:$b), (IRInt<"vqdmulh", [Vector]> $a, (splat $b))>; def vqrdmulhq_n: Intrinsic:$b), (IRInt<"vqrdmulh", [Vector]> $a, (splat $b))>; } } let params = T.Poly, overrideKindLetter = "p" in { def vmullbq_poly: Intrinsic $a, $b, 0)>; def vmulltq_poly: Intrinsic $a, $b, 1)>; } let params = T.Float in { def vaddqf: Intrinsic, NameOverride<"vaddq">; defm vandqf: bit_op_fp, NameOverride<"vandq">; defm vbicqf: bit_op_fp_with_inv, NameOverride<"vbicq">; defm veorqf: bit_op_fp, NameOverride<"veorq">; defm vornqf: bit_op_fp_with_inv, NameOverride<"vornq">; defm vorrqf: bit_op_fp, NameOverride<"vorrq">; def vsubqf: Intrinsic, NameOverride<"vsubq">; def vmulqf: Intrinsic, NameOverride<"vmulq">; let pnt = PNT_NType in { def vaddqf_n: Intrinsic:$b), (fadd $a, (splat $b))>, NameOverride<"vaddq_n">; def vsubqf_n: Intrinsic:$b), (fsub $a, (splat $b))>, NameOverride<"vsubq_n">; def vmulqf_n: Intrinsic:$b), (fmul $a, (splat $b))>, NameOverride<"vmulq_n">; } } multiclass FMA { // FMS instructions are defined in the ArmARM as if they negate the // second multiply input. defvar m2_cg = !if(add, (id $m2), (fneg $m2)); defvar unpred_cg = (IRIntBase<"fma", [Vector]> $m1, m2_cg, $addend); defvar pred_cg = (IRInt<"fma_predicated", [Vector, Predicate]> $m1, m2_cg, $addend, $pred); def q: Intrinsic; def q_m: Intrinsic; // Only FMA has the vector/scalar variants, not FMS if add then let pnt = PNT_NType in { def q_n: Intrinsic:$m2_s), (seq (splat $m2_s):$m2, unpred_cg)>; def sq_n: Intrinsic:$addend_s), (seq (splat $addend_s):$addend, unpred_cg)>; def q_m_n: Intrinsic:$m2_s, Predicate:$pred), (seq (splat $m2_s):$m2, pred_cg)>; def sq_m_n: Intrinsic:$addend_s, Predicate:$pred), (seq (splat $addend_s):$addend, pred_cg)>; } } let params = T.Float in { defm vfma: FMA<1>; defm vfms: FMA<0>; } let params = T.Int, pnt = PNT_NType in { def vmlaq_n: Intrinsic< Vector, (args Vector:$addend, Vector:$m1, unpromoted:$m2_s), (add (mul $m1, (splat $m2_s)), $addend)>; def vmlasq_n: Intrinsic< Vector, (args Vector:$m1, Vector:$m2, unpromoted:$addend_s), (add (mul $m1, $m2), (splat $addend_s))>; def vmlaq_m_n: Intrinsic< Vector, (args Vector:$addend, Vector:$m1, Scalar:$m2_s, Predicate:$pred), (IRInt<"vmla_n_predicated", [Vector, Predicate]> $addend, $m1, $m2_s, $pred)>; def vmlasq_m_n: Intrinsic< Vector, (args Vector:$m1, Vector:$m2, Scalar:$addend_s, Predicate:$pred), (IRInt<"vmlas_n_predicated", [Vector, Predicate]> $m1, $m2, $addend_s, $pred)>; } multiclass VQDMLA { def hq_n: Intrinsic< Vector, (args Vector:$addend, Vector:$m1, Scalar:$m2_s), (IRInt $addend, $m1, $m2_s)>; def shq_n: Intrinsic< Vector, (args Vector:$m1, Vector:$m2, Scalar:$addend_s), (IRInt $m1, $m2, $addend_s)>; def hq_m_n: Intrinsic< Vector, (args Vector:$addend, Vector:$m1, Scalar:$m2_s, Predicate:$pred), (IRInt $addend, $m1, $m2_s, $pred)>; def shq_m_n: Intrinsic< Vector, (args Vector:$m1, Vector:$m2, Scalar:$addend_s, Predicate:$pred), (IRInt $m1, $m2, $addend_s, $pred)>; } let params = T.Signed, pnt = PNT_NType in { defm vqdmla: VQDMLA; defm vqrdmla: VQDMLA; } multiclass VQDMLAD { def "": Intrinsic $a, $b, $c, (u32 exchange), (u32 round), (u32 subtract))>; def _m: Intrinsic $a, $b, $c, (u32 exchange), (u32 round), (u32 subtract), $pred)>; } let params = T.Signed in { defm vqdmladhq: VQDMLAD<0, 0, 0>; defm vqdmladhxq: VQDMLAD<1, 0, 0>; defm vqdmlsdhq: VQDMLAD<0, 0, 1>; defm vqdmlsdhxq: VQDMLAD<1, 0, 1>; defm vqrdmladhq: VQDMLAD<0, 1, 0>; defm vqrdmladhxq: VQDMLAD<1, 1, 0>; defm vqrdmlsdhq: VQDMLAD<0, 1, 1>; defm vqrdmlsdhxq: VQDMLAD<1, 1, 1>; } let params = !listconcat(T.Int16, T.Int32) in { let pnt = PNT_None in { def vmvnq_n: Intrinsic; } defm vmvnq: IntrinsicMX; let pnt = PNT_NType in { def vbicq_n: Intrinsic; def vorrq_n: Intrinsic; } def vbicq_m_n: Intrinsic< Vector, (args Vector:$v, imm_simd_restrictive:$imm, Predicate:$pred), (select $pred, (and $v, (not (splat (Scalar $imm)))), $v)>; def vorrq_m_n: Intrinsic< Vector, (args Vector:$v, imm_simd_restrictive:$imm, Predicate:$pred), (select $pred, (or $v, (splat (Scalar $imm))), $v)>; } let params = T.Usual in { let pnt = PNT_None in def vdupq_n: Intrinsic:$s), (splat $s)>; defm vdupq: IntrinsicMX< Vector, (args unpromoted:$s, Predicate:$pred), (select $pred, (splat $s), $inactive), 1, "_n", PNT_NType, PNT_None>; } multiclass vxdup_mc { defvar UnpredInt = IRInt; defvar PredInt = IRInt; defvar UnpredIntCall = !con((UnpredInt $base), paramsOut); defvar PredIntCall = !con((PredInt $inactive, $base), paramsOut, (? $pred)); // Straightforward case with neither writeback nor predication let pnt = PNT_N in def q_n: Intrinsic; // Predicated form without writeback defm q: IntrinsicMX< Vector, !con((args u32:$base), paramsIn, (? Predicate:$pred)), (xval PredIntCall, 0), 1, "_n", PNT_NType, PNT_N>; // Writeback without predication let pnt = PNT_WB in def q_wb: Intrinsic< Vector, !con((args Ptr:$baseaddr), paramsIn), (seq (load $baseaddr):$base, UnpredIntCall:$pair, (store (xval $pair, 1), $baseaddr), (xval $pair, 0))>; // Both writeback and predicated defm q: IntrinsicMX< Vector, !con((args Ptr:$baseaddr), paramsIn, (? Predicate:$pred)), (seq (load $baseaddr):$base, PredIntCall:$pair, (store (xval $pair, 1), $baseaddr), (xval $pair, 0)), 1, "_wb", PNT_WBType, PNT_WB>; } let params = T.Unsigned in { defm vidup: vxdup_mc<(? imm_1248:$step), (? $step)>; defm vddup: vxdup_mc<(? imm_1248:$step), (? $step)>; defm viwdup: vxdup_mc<(? u32:$limit, imm_1248:$step), (? $limit, $step)>; defm vdwdup: vxdup_mc<(? u32:$limit, imm_1248:$step), (? $limit, $step)>; } let params = T.Int in { def vmvnq: Intrinsic; defm vmvnq: IntrinsicMX $a, $pred, $inactive)>; def vclzq: Intrinsic $a, (i1 0))>; defm vclzq: IntrinsicMX $a, $pred, $inactive)>; } let params = T.Signed in { def vclsq: Intrinsic $a)>; defm vclsq: IntrinsicMX $a, $pred, $inactive)>; def vnegq: Intrinsic; def vabsq: Intrinsic; def vqnegq: Intrinsic; def vqabsq: Intrinsic; foreach name = ["qneg", "qabs"] in { defm v#name#q: IntrinsicMX $a, $pred, $inactive), 0 /* no _x variant for saturating intrinsics */>; } } let params = !listconcat(T.Signed, T.Float) in { foreach name = ["neg", "abs"] in { defm v#name#q: IntrinsicMX $a, $pred, $inactive)>; } } let params = T.Float in { def vnegq_f: Intrinsic, NameOverride<"vnegq">; def vabsq_f: Intrinsic $a)>, NameOverride<"vabsq">; } // The bitcasting below is not overcomplicating the IR because while // Vector and UVector may be different vector types at the C level i.e. // vectors of same size signed/unsigned ints. Once they're lowered // to IR, they are just bit vectors with no sign at all, so the // bitcasts will be automatically elided by IRBuilder. multiclass predicated_bit_op_fp { def "": Intrinsic (bitcast $a, UVector), (bitcast $b, UVector), $pred, (bitcast $inactive, UVector)), Vector)>; } // Plain intrinsics let params = T.Usual in { def vabdq: Intrinsic $a, $b, (unsignedflag Scalar))>; } multiclass VectorVectorArithmetic { defm "" : IntrinsicMX< Vector, (args Vector:$a, Vector:$b, Predicate:$pred), !con((IRInt $a, $b), extraArgs, (? $pred, $inactive)), wantXVariant>; } multiclass VectorScalarArithmetic { defm "" : IntrinsicMXNameOverride< Vector, (args Vector:$a, unpromoted:$b, Predicate:$pred), !con((IRInt $a, (splat $b)), extraArgs, (? $pred, $inactive)), basename, wantXVariant, "_n", PNT_NType, PNT_NType>; } multiclass VectorVectorArithmeticBitcast { defm "" : IntrinsicMX (bitcast $a, UVector), (bitcast $b, UVector), $pred, (bitcast $inactive, UVector)), Vector)>; } // Predicated intrinsics let params = T.Usual in { defm vabdq : VectorVectorArithmetic<"abd_predicated", (? (unsignedflag Scalar))>; defm vaddq : VectorVectorArithmetic<"add_predicated">; defm vsubq : VectorVectorArithmetic<"sub_predicated">; defm vmulq : VectorVectorArithmetic<"mul_predicated">; defm vandq : VectorVectorArithmeticBitcast<"and_predicated">; defm vbicq : VectorVectorArithmeticBitcast<"bic_predicated">; defm veorq : VectorVectorArithmeticBitcast<"eor_predicated">; defm vornq : VectorVectorArithmeticBitcast<"orn_predicated">; defm vorrq : VectorVectorArithmeticBitcast<"orr_predicated">; defm : VectorScalarArithmetic<"add_predicated", "vaddq">; defm : VectorScalarArithmetic<"sub_predicated", "vsubq">; defm : VectorScalarArithmetic<"mul_predicated", "vmulq">; } multiclass DblVectorVectorArithmetic { defm "" : IntrinsicMX< DblVector, (args Vector:$a, Vector:$b, DblPredicate:$pred), !con((IRInt $a, $b), extraArgs, (? $pred, $inactive)), wantXVariant>; } multiclass DblVectorScalarArithmetic { defm "" : IntrinsicMXNameOverride< DblVector, (args Vector:$a, unpromoted:$b, DblPredicate:$pred), !con((IRInt $a, (splat $b)), extraArgs, (? $pred, $inactive)), basename, wantXVariant, "_n", PNT_NType, PNT_NType>; } // Predicated intrinsics - Int types only let params = T.Int in { defm vminq : VectorVectorArithmetic<"min_predicated", (? (unsignedflag Scalar))>; defm vmaxq : VectorVectorArithmetic<"max_predicated", (? (unsignedflag Scalar))>; defm vmulhq : VectorVectorArithmetic<"mulh_predicated", (? (unsignedflag Scalar))>; defm vrmulhq : VectorVectorArithmetic<"rmulh_predicated", (? (unsignedflag Scalar))>; defm vqaddq : VectorVectorArithmetic<"qadd_predicated", (? (unsignedflag Scalar)), 0>; defm vhaddq : VectorVectorArithmetic<"hadd_predicated", (? (unsignedflag Scalar))>; defm vrhaddq : VectorVectorArithmetic<"rhadd_predicated", (? (unsignedflag Scalar))>; defm vqsubq : VectorVectorArithmetic<"qsub_predicated", (? (unsignedflag Scalar)), 0>; defm vhsubq : VectorVectorArithmetic<"hsub_predicated", (? (unsignedflag Scalar))>; defm vmullbq_int : DblVectorVectorArithmetic<"mull_int_predicated", (? (unsignedflag Scalar), (u32 0))>; defm vmulltq_int : DblVectorVectorArithmetic<"mull_int_predicated", (? (unsignedflag Scalar), (u32 1))>; defm : VectorScalarArithmetic<"qadd_predicated", "vqaddq", (? (unsignedflag Scalar)), 0>; defm : VectorScalarArithmetic<"hadd_predicated", "vhaddq", (? (unsignedflag Scalar))>; defm : VectorScalarArithmetic<"qsub_predicated", "vqsubq", (? (unsignedflag Scalar)), 0>; defm : VectorScalarArithmetic<"hsub_predicated", "vhsubq", (? (unsignedflag Scalar))>; } let params = T.Signed in { defm vqdmulhq : VectorVectorArithmetic<"qdmulh_predicated", (?), 0>; defm vqrdmulhq : VectorVectorArithmetic<"qrdmulh_predicated", (?), 0>; def vminaq_m: Intrinsic $a, $b, $pred)>; def vmaxaq_m: Intrinsic $a, $b, $pred)>; defm : VectorScalarArithmetic<"qdmulh_predicated", "vqdmulhq", (?), 0>; defm : VectorScalarArithmetic<"qrdmulh_predicated", "vqrdmulhq", (?), 0>; } let params = T.Poly, overrideKindLetter = "p" in { defm vmullbq_poly : DblVectorVectorArithmetic<"mull_poly_predicated", (? (u32 0))>; defm vmulltq_poly : DblVectorVectorArithmetic<"mull_poly_predicated", (? (u32 1))>; } let params = [s16, s32] in { def vqdmullbq: Intrinsic $a, $b, 0)>; def vqdmulltq: Intrinsic $a, $b, 1)>; defm vqdmullbq: DblVectorVectorArithmetic<"vqdmull_predicated", (? (u32 0)), 0>; defm vqdmulltq: DblVectorVectorArithmetic<"vqdmull_predicated", (? (u32 1)), 0>; let pnt = PNT_NType in { def vqdmullbq_n: Intrinsic:$b), (IRInt<"vqdmull", [DblVector, Vector]> $a, (splat $b), 0)>; def vqdmulltq_n: Intrinsic:$b), (IRInt<"vqdmull", [DblVector, Vector]> $a, (splat $b), 1)>; } defm vqdmullbq_n: DblVectorScalarArithmetic<"vqdmull_predicated", "vqdmullbq", (? (u32 0)), 0>; defm vqdmulltq_n: DblVectorScalarArithmetic<"vqdmull_predicated", "vqdmulltq", (? (u32 1)), 0>; } // Predicated intrinsics - Float types only let params = T.Float in { defm vminnmq : VectorVectorArithmetic<"min_predicated", (? (u32 0))>; defm vmaxnmq : VectorVectorArithmetic<"max_predicated", (? (u32 0))>; def vminnmaq_m: Intrinsic $a, $b, $pred)>; def vmaxnmaq_m: Intrinsic $a, $b, $pred)>; } multiclass Reduction basetypes, bit needSign = 0, dag postCG = (seq (id $ret)), dag accArg = (args Accumulator:$prev), dag preCG = (seq)> { defvar intArgsBase = (? $prev, $vec); defvar intArgsUnpred = !con(intArgsBase, !if(needSign, (? (unsignedflag Scalar)), (?))); defvar intArgsPred = !con(intArgsUnpred, (? $pred)); defvar intUnpred = !setdagop(intArgsUnpred, IRInt); defvar intPred = !setdagop(intArgsPred, IRInt< basename#"_predicated", !listconcat(basetypes, [Predicate])>); def "": Intrinsic< Accumulator, !con(accArg, (args Vector:$vec)), !con(preCG, (seq intUnpred:$ret), postCG)>; def _p: Intrinsic< Accumulator, !con(accArg, (args Vector:$vec, Predicate:$pred)), !con(preCG, (seq intPred:$ret), postCG)>; } let params = T.Int in { defm vminvq: Reduction; defm vmaxvq: Reduction; } let params = T.Signed in { defm vminavq: Reduction; defm vmaxavq: Reduction; } let params = T.Float in { defm vminnmvq: Reduction; defm vmaxnmvq: Reduction; defm vminnmavq: Reduction; defm vmaxnmavq: Reduction; } foreach half = [ "b", "t" ] in { defvar halfconst = !ne(half, "b"); let params = [f32], pnt = PNT_None in { def vcvt#half#q_f16: Intrinsic< VecOf, (args VecOf:$inactive, Vector:$a), (IRInt<"vcvt_narrow"> $inactive, $a, halfconst)>; def vcvt#half#q_m_f16: Intrinsic< VecOf, (args VecOf:$inactive, Vector:$a, PredOf:$pred), (IRInt<"vcvt_narrow_predicated"> $inactive, $a, halfconst, $pred)>; } // params = [f32], pnt = PNT_None let params = [f16], pnt = PNT_None in { def vcvt#half#q_f32: Intrinsic, (args Vector:$a), (IRInt<"vcvt_widen"> $a, halfconst)>; defm vcvt#half#q: IntrinsicMX< VecOf, (args Vector:$a, PredOf:$pred), (IRInt<"vcvt_widen_predicated"> $inactive, $a, halfconst, $pred), 1, "_f32">; } // params = [f16], pnt = PNT_None } // loop over half = "b", "t" multiclass float_int_conversions { defvar FVector = VecOf; defvar IVector = VecOf; let params = [IScalar] in { let pnt = PNT_2Type in { def : Intrinsic, NameOverride<"vcvtq_" # FScalar>; } defm vcvtq: IntrinsicMX $a, (unsignedflag IScalar), $pred, $inactive), 1, "_" # FScalar, PNT_2Type, PNT_2Type>; } let params = [FScalar] in { let pnt = PNT_None in { def : Intrinsic, NameOverride<"vcvtq_" # IScalar>; foreach suffix = ["a","n","p","m"] in def : Intrinsic (unsignedflag IScalar), $a)>, NameOverride<"vcvt"#suffix#"q_" # IScalar>; } defm vcvtq: IntrinsicMX $a, (unsignedflag IScalar), $pred, $inactive), 1, "_" # IScalar, PNT_2Type, PNT_None>; foreach suffix = ["a","n","p","m"] in { defm "vcvt"#suffix#"q" : IntrinsicMX< IVector, (args FVector:$a, Predicate:$pred), (IRInt<"vcvt"#suffix#"_predicated", [IVector, FVector, Predicate]> (unsignedflag IScalar), $inactive, $a, $pred), 1, "_" # IScalar, PNT_2Type, PNT_None>; } } } defm "" : float_int_conversions; defm "" : float_int_conversions; defm "" : float_int_conversions; defm "" : float_int_conversions; multiclass vmovl { let params = [s8, u8, s16, u16] in { def "": Intrinsic; defm "": IntrinsicMX $a, (unsignedflag Scalar), top, $pred, $inactive)>; } } defm vmovlbq: vmovl<0>; defm vmovltq: vmovl<1>; multiclass vmovn { let params = [s16, u16, s32, u32] in { def "": Intrinsic; def _m: Intrinsic $inactive, $a, top, $pred)>; } } defm vmovntq: vmovn<1, (zip (vreinterpret $inactive, Vector), $a)>; defm vmovnbq: vmovn<0, (zip $a, (vreinterpret (vrev $inactive, (bitsize Scalar)), Vector))>; multiclass vqmovn { defvar RetVector = VecOf; let params = [s16, u16, s32, u32] in { def : Intrinsic< RetVector, (args RetVector:$inactive, Vector:$a), (IRInt<"vqmovn", [RetVector, Vector]> $inactive, $a, (unsignedflag RetScalar), (unsignedflag Scalar), top)>, NameOverride; def: Intrinsic< RetVector, (args RetVector:$inactive, Vector:$a, Predicate:$pred), (IRInt<"vqmovn_predicated", [RetVector, Vector, Predicate]> $inactive, $a, (unsignedflag RetScalar), (unsignedflag Scalar), top, $pred)>, NameOverride; } } let params = [s16, s32, u16, u32] in { defm vqmovntq: vqmovn<1, HalfScalar>; defm vqmovnbq: vqmovn<0, HalfScalar>; } let params = [s16, s32] in { defm vqmovuntq: vqmovn<1, UHalfScalar>; defm vqmovunbq: vqmovn<0, UHalfScalar>; } multiclass vrnd { let params = T.Float in { def "": Intrinsic; defm "": IntrinsicMX $a, $pred, $inactive)>; } } defm vrndq: vrnd, "z">; defm vrndmq: vrnd, "m">; defm vrndpq: vrnd, "p">; defm vrndaq: vrnd, "a">; defm vrndxq: vrnd, "x">; defm vrndnq: vrnd, "n">; multiclass compare_with_pred { // Make the predicated and unpredicated versions of a single comparison. def: Intrinsic cmp))>, NameOverride<"vcmp" # condname # "q" # suffix>; def: Intrinsic (and $inpred, cmp)))>, NameOverride<"vcmp" # condname # "q_m" # suffix>; } multiclass compare { // Make all four variants of a comparison: the vector/vector and // vector/scalar forms, each using compare_with_pred to make a // predicated and unpredicated version. defm: compare_with_pred; let pnt = PNT_NType in { defm: compare_with_pred:$sb), (cmpop $va, (splat $sb)), "_n">; } } let params = T.Int in { defm: compare<"eq", icmp_eq>; defm: compare<"ne", icmp_ne>; } let params = T.Signed in { defm: compare<"gt", icmp_sgt>; defm: compare<"ge", icmp_sge>; defm: compare<"lt", icmp_slt>; defm: compare<"le", icmp_sle>; } let params = T.Unsigned in { defm: compare<"hi", icmp_ugt>; defm: compare<"cs", icmp_uge>; } let params = T.Float in { defm: compare<"eq", fcmp_eq>; defm: compare<"ne", fcmp_ne>; defm: compare<"gt", fcmp_gt>; defm: compare<"ge", fcmp_ge>; defm: compare<"lt", fcmp_lt>; defm: compare<"le", fcmp_le>; } let params = T.Signed in { def vminq: Intrinsic; def vmaxq: Intrinsic; def vminaq: Intrinsic; def vmaxaq: Intrinsic; } let params = T.Unsigned in { def vminqu: Intrinsic, NameOverride<"vminq">; def vmaxqu: Intrinsic, NameOverride<"vmaxq">; } let params = T.Float in { def vminnmq: Intrinsic $a, $b)>; def vmaxnmq: Intrinsic $a, $b)>; def vminnmaq: Intrinsic (IRIntBase<"fabs", [Vector]> $a), (IRIntBase<"fabs", [Vector]> $b))>; def vmaxnmaq: Intrinsic (IRIntBase<"fabs", [Vector]> $a), (IRIntBase<"fabs", [Vector]> $b))>; } def vpselq: Intrinsic { let params = T.Usual; } def vpselq_64: Intrinsic< Vector, (args Vector:$t, Vector:$f, PredOf:$pred), (bitcast (select $pred, (bitcast $t, VecOf), (bitcast $f, VecOf)), Vector)>, NameOverride<"vpselq"> { let params = T.All64; } let params = [Void], pnt = PNT_None in { multiclass vctp { def "": Intrinsic (IRIntBase $val)))>; def _m: Intrinsic (and $inpred, (IRIntBase $val))))>; } defm vctp8q: vctp, "arm_mve_vctp8">; defm vctp16q: vctp, "arm_mve_vctp16">; defm vctp32q: vctp, "arm_mve_vctp32">; defm vctp64q: vctp, "arm_mve_vctp64">; def vpnot: Intrinsic, (args unpromoted>:$pred), (xor $pred, (u16 65535))>; } multiclass contiguous_load same_size, list wider> { // Intrinsics named with explicit memory and element sizes that match: // vldrbq_?8, vldrhq_?16, vldrwq_?32. let params = same_size, pnt = PNT_None in { def: Intrinsic>:$addr), (load (address (CPtr $addr), !srl(memtype.size,3)))>, NameOverride; def: Intrinsic>:$addr, Predicate:$pred), (IRIntBase<"masked_load", [Vector, CPtr]> (CPtr $addr), !srl(memtype.size,3), $pred, (zeroinit Vector))>, NameOverride; } // Synonyms for the above, with the generic name vld1q that just means // 'memory and element sizes match', and allows convenient polymorphism with // the memory and element types covariant. let params = same_size in { def: Intrinsic>:$addr), (load (address (CPtr $addr), !srl(memtype.size,3)))>, NameOverride<"vld1q">; def: Intrinsic>:$addr, Predicate:$pred), (IRIntBase<"masked_load", [Vector, CPtr]> (CPtr $addr), !srl(memtype.size,3), $pred, (zeroinit Vector))>, NameOverride<"vld1q_z">; } // Intrinsics with the memory size narrower than the vector element, so that // they load less than 128 bits of memory and sign/zero extend each loaded // value into a wider vector lane. let params = wider, pnt = PNT_None in { def: Intrinsic>:$addr), (extend (load (address (CPtr> $addr), !srl(memtype.size,3))), Vector, (unsignedflag Scalar))>, NameOverride; def: Intrinsic>:$addr, Predicate:$pred), (extend (IRIntBase<"masked_load", [NarrowedVecOf, CPtr>]> (CPtr> $addr), !srl(memtype.size,3), $pred, (zeroinit NarrowedVecOf)), Vector, (unsignedflag Scalar))>, NameOverride; } } defm: contiguous_load<"vldrbq", u8, T.All8, !listconcat(T.Int16, T.Int32)>; defm: contiguous_load<"vldrhq", u16, T.All16, T.Int32>; defm: contiguous_load<"vldrwq", u32, T.All32, []>; multiclass contiguous_store same_size, list wider> { // Intrinsics named with explicit memory and element sizes that match: // vstrbq_?8, vstrhq_?16, vstrwq_?32. let params = same_size in { def: Intrinsic>:$addr, Vector:$value), (store $value, (address (Ptr $addr), !srl(memtype.size,3)))>, NameOverride; def: Intrinsic>:$addr, Vector:$value, Predicate:$pred), (IRIntBase<"masked_store", [Vector, Ptr]> $value, (Ptr $addr), !srl(memtype.size,3), $pred)>, NameOverride; } // Synonyms for the above, with the generic name vst1q that just means // 'memory and element sizes match', and allows convenient polymorphism with // the memory and element types covariant. let params = same_size in { def: Intrinsic>:$addr, Vector:$value), (store $value, (address (Ptr $addr), !srl(memtype.size,3)))>, NameOverride<"vst1q">; def: Intrinsic>:$addr, Vector:$value, Predicate:$pred), (IRIntBase<"masked_store", [Vector, Ptr]> $value, (Ptr $addr), !srl(memtype.size,3), $pred)>, NameOverride<"vst1q_p">; } // Intrinsics with the memory size narrower than the vector element, so that // they store less than 128 bits of memory, truncating each vector lane into // a narrower value to store. let params = wider in { def: Intrinsic>:$addr, Vector:$value), (store (trunc $value, NarrowedVecOf), (address (Ptr> $addr), !srl(memtype.size,3)))>, NameOverride; def: Intrinsic>:$addr, Vector:$value, Predicate:$pred), (IRIntBase<"masked_store", [NarrowedVecOf, Ptr>]> (trunc $value, NarrowedVecOf), (Ptr> $addr), !srl(memtype.size,3), $pred)>, NameOverride; } } defm: contiguous_store<"vstrbq", u8, T.All8, !listconcat(T.Int16, T.Int32)>; defm: contiguous_store<"vstrhq", u16, T.All16, T.Int32>; defm: contiguous_store<"vstrwq", u32, T.All32, []>; multiclass gather_base types, int size> { let params = types, pnt = PNT_None in { def _gather_base: Intrinsic< Vector, (args UVector:$addr, imm_mem7bit:$offset), (IRInt<"vldr_gather_base", [Vector, UVector]> $addr, $offset)>; def _gather_base_z: Intrinsic< Vector, (args UVector:$addr, imm_mem7bit:$offset, Predicate:$pred), (IRInt<"vldr_gather_base_predicated", [Vector, UVector, Predicate]> $addr, $offset, $pred)>; def _gather_base_wb: Intrinsic< Vector, (args Ptr:$addr, imm_mem7bit:$offset), (seq (IRInt<"vldr_gather_base_wb", [Vector, UVector]> (load $addr), $offset):$pair, (store (xval $pair, 1), $addr), (xval $pair, 0))>; def _gather_base_wb_z: Intrinsic< Vector, (args Ptr:$addr, imm_mem7bit:$offset, Predicate:$pred), (seq (IRInt<"vldr_gather_base_wb_predicated", [Vector, UVector, Predicate]> (load $addr), $offset, $pred):$pair, (store (xval $pair, 1), $addr), (xval $pair, 0))>; } } defm vldrwq: gather_base; defm vldrdq: gather_base; multiclass scatter_base types, int size> { let params = types in { def _scatter_base: Intrinsic< Void, (args UVector:$addr, imm_mem7bit:$offset, Vector:$data), (IRInt<"vstr_scatter_base", [UVector, Vector]> $addr, $offset, $data)>; def _scatter_base_p: Intrinsic< Void, (args UVector:$addr, imm_mem7bit:$offset, Vector:$data, Predicate:$pred), (IRInt<"vstr_scatter_base_predicated", [UVector, Vector, Predicate]> $addr, $offset, $data, $pred)>; def _scatter_base_wb: Intrinsic< Void, (args Ptr:$addr, imm_mem7bit:$offset, Vector:$data), (seq (IRInt<"vstr_scatter_base_wb", [UVector, Vector]> (load $addr), $offset, $data):$wbaddr, (store $wbaddr, $addr))>; def _scatter_base_wb_p: Intrinsic< Void, (args Ptr:$addr, imm_mem7bit:$offset, Vector:$data, Predicate:$pred), (seq (IRInt<"vstr_scatter_base_wb_predicated", [UVector, Vector, Predicate]> (load $addr), $offset, $data, $pred):$wbaddr, (store $wbaddr, $addr))>; } } defm vstrwq: scatter_base; defm vstrdq: scatter_base; multiclass gather_offset_unshifted types, PrimitiveType memtype> { let params = types in { def _gather_offset: Intrinsic< Vector, (args CPtr>:$base, UVector:$offsets), (IRInt<"vldr_gather_offset", [Vector, CPtr>, UVector]> $base, $offsets, memtype.size, 0, (unsignedflag Scalar))>; def _gather_offset_z: Intrinsic< Vector, (args CPtr>:$base, UVector:$offsets, Predicate:$pred), (IRInt<"vldr_gather_offset_predicated", [Vector, CPtr>, UVector, Predicate]> $base, $offsets, memtype.size, 0, (unsignedflag Scalar), $pred)>; } } multiclass gather_offset_shifted types, PrimitiveType memtype, int shift> { let params = types in { def _gather_shifted_offset: Intrinsic< Vector, (args CPtr>:$base, UVector:$offsets), (IRInt<"vldr_gather_offset", [Vector, CPtr>, UVector]> $base, $offsets, memtype.size, shift, (unsignedflag Scalar))>; def _gather_shifted_offset_z: Intrinsic< Vector, (args CPtr>:$base, UVector:$offsets, Predicate:$pred), (IRInt<"vldr_gather_offset_predicated", [Vector, CPtr>, UVector, Predicate]> $base, $offsets, memtype.size, shift, (unsignedflag Scalar), $pred)>; } } multiclass gather_offset_both types, PrimitiveType memtype, int shift> { defm "": gather_offset_unshifted; defm "": gather_offset_shifted; } defm vldrbq: gather_offset_unshifted; defm vldrhq: gather_offset_both; defm vldrwq: gather_offset_both; defm vldrdq: gather_offset_both; multiclass scatter_offset_unshifted types, PrimitiveType memtype> { let params = types in { def _scatter_offset: Intrinsic< Void, (args Ptr>:$base, UVector:$offsets, Vector:$data), (IRInt<"vstr_scatter_offset", [Ptr>, UVector, Vector]> $base, $offsets, $data, memtype.size, 0)>; def _scatter_offset_p: Intrinsic< Void, (args Ptr>:$base, UVector:$offsets, Vector:$data, Predicate:$pred), (IRInt<"vstr_scatter_offset_predicated", [Ptr>, UVector, Vector, Predicate]> $base, $offsets, $data, memtype.size, 0, $pred)>; } } multiclass scatter_offset_shifted types, PrimitiveType memtype, int shift> { let params = types in { def _scatter_shifted_offset: Intrinsic< Void, (args Ptr>:$base, UVector:$offsets, Vector:$data), (IRInt<"vstr_scatter_offset", [Ptr>, UVector, Vector]> $base, $offsets, $data, memtype.size, shift)>; def _scatter_shifted_offset_p: Intrinsic< Void, (args Ptr>:$base, UVector:$offsets, Vector:$data, Predicate:$pred), (IRInt<"vstr_scatter_offset_predicated", [Ptr>, UVector, Vector, Predicate]> $base, $offsets, $data, memtype.size, shift, $pred)>; } } multiclass scatter_offset_both types, PrimitiveType memtype, int shift> { defm "": scatter_offset_unshifted; defm "": scatter_offset_shifted; } defm vstrbq: scatter_offset_unshifted; defm vstrhq: scatter_offset_both; defm vstrwq: scatter_offset_both; defm vstrdq: scatter_offset_both; let params = T.Int in { def vshlq_n: Intrinsic; defm vshlq: IntrinsicMX $v, $sh, $pred, $inactive), 1, "_n">; let pnt = PNT_NType in { def vshrq_n: Intrinsic; defm vshrq: IntrinsicMX $v, $sh, (unsignedflag Scalar), $pred, $inactive), 1, "_n">; } } let params = T.Int in { def vqshlq_n: Intrinsic $v, $sh, (unsignedflag Scalar))>; def vqshlq_m_n: Intrinsic $v, $sh, (unsignedflag Scalar), $pred, $inactive)>; let pnt = PNT_NType in { def vrshrq_n: Intrinsic $v, $sh, (unsignedflag Scalar))>; defm vrshrq: IntrinsicMX $v, $sh, (unsignedflag Scalar), $pred, $inactive), 1, "_n">; } } let params = T.Signed, pnt = PNT_NType in { def vqshluq_n: Intrinsic $v, $sh)>; def vqshluq_m_n: Intrinsic $v, $sh, $pred, $inactive)>; } multiclass vshll_imm { let params = !listconcat(T.Int8, T.Int16), pnt = PNT_NType in { def _n: Intrinsic $v, $sh, (unsignedflag Scalar), top)>; defm "": IntrinsicMX $v, $sh, (unsignedflag Scalar), top, $pred, $inactive), 1, "_n">; } } defm vshllbq : vshll_imm<0>; defm vshlltq : vshll_imm<1>; multiclass DyadicImmShift { defvar intparams = !if(!eq(outtype, Vector), [Vector], [outtype, Vector]); def q_n: Intrinsic< outtype, (args outtype:$a, Vector:$b, imm:$sh), !con((IRInt $a, $b, $sh), extraargs)>; def q_m_n: Intrinsic< outtype, (args outtype:$a, Vector:$b, imm:$sh, Predicate:$pred), !con((IRInt $a, $b, $sh), extraargs, (? $pred))>; } multiclass VSHRN { defm b: DyadicImmShift; defm t: DyadicImmShift; } let params = [s16, s32, u16, u32], pnt = PNT_NType in { defvar U = (unsignedflag Scalar); defm vshrn : VSHRN; defm vqshrn : VSHRN; defm vrshrn : VSHRN; defm vqrshrn : VSHRN; } let params = [s16, s32], pnt = PNT_NType in { defm vqshrun : VSHRN; defm vqrshrun : VSHRN; } let params = T.Int, pnt = PNT_NType in { defm vsli : DyadicImmShift; defm vsri : DyadicImmShift; } multiclass VSHL_non_imm { let pnt = pnt_scalar_unpred in { def scalarSuffix: Intrinsic< Vector, (args Vector:$in, s32:$sh), (IRInt<"vshl_scalar", [Vector]> $in, $sh, q, r, (unsignedflag Scalar))>; } def "_m" # scalarSuffix: Intrinsic< Vector, (args Vector:$in, s32:$sh, Predicate:$pred), (IRInt<"vshl_scalar_predicated", [Vector, Predicate]> $in, $sh, q, r, (unsignedflag Scalar), $pred)>; def "": Intrinsic< Vector, (args Vector:$in, SVector:$sh), (IRInt<"vshl_vector", [Vector, SVector]> $in, $sh, q, r, (unsignedflag Scalar))>; defm "": IntrinsicMX< Vector, (args Vector:$in, SVector:$sh, Predicate:$pred), (IRInt<"vshl_vector_predicated", [Vector, SVector, Predicate]> $in, $sh, q, r, (unsignedflag Scalar), $pred, $inactive), // The saturating shift intrinsics don't have an x variant, so we // set wantXVariant to 1 iff q == 0 !eq(q, 0)>; } let params = T.Int in { defm vshlq : VSHL_non_imm<"_r", 0, 0>; defm vqshlq : VSHL_non_imm<"_r", 1, 0>; defm vrshlq : VSHL_non_imm<"_n", 0, 1, PNT_NType>; defm vqrshlq : VSHL_non_imm<"_n", 1, 1, PNT_NType>; } // Base class for the scalar shift intrinsics. class ScalarShift: Intrinsic { let params = [Void]; let pnt = PNT_None; } // Subclass that includes the machinery to take a 64-bit input apart // into halves, retrieve the two halves of a shifted output as a pair, // and glue the pieces of the pair back into an i64 for output. class LongScalarShift: ScalarShift; // The family of saturating/rounding scalar shifts that take an // immediate shift count. They come in matched 32- and 64-bit pairs. multiclass ScalarSaturatingShiftImm { def "": ScalarShift $value, $sh)>; def l: LongScalarShift $lo, $hi, $sh)>; } defm uqshl: ScalarSaturatingShiftImm; defm urshr: ScalarSaturatingShiftImm; defm sqshl: ScalarSaturatingShiftImm; defm srshr: ScalarSaturatingShiftImm; // The family of saturating/rounding scalar shifts that take a // register shift count. They also have 32- and 64-bit forms, but the // 64-bit form also has a version that saturates to 48 bits, so the IR // intrinsic takes an extra saturation-type operand. multiclass ScalarSaturatingShiftReg { def "": ScalarShift $value, $sh)>; def l: LongScalarShift $lo, $hi, $sh, 64)>; def l_sat48: LongScalarShift $lo, $hi, $sh, 48)>; } defm uqrshl: ScalarSaturatingShiftReg; defm sqrshr: ScalarSaturatingShiftReg; // The intrinsics for LSLL and ASRL come in 64-bit versions only, with // no saturation count. def lsll: LongScalarShift $lo, $hi, $sh)>; def asrl: LongScalarShift $lo, $hi, $sh)>; multiclass vadcsbc { def q: Intrinsic:$carry), (seq (IRInt $a, $b, (shl (load $carry), 29)):$pair, (store (and 1, (lshr (xval $pair, 1), 29)), $carry), (xval $pair, 0))>; def iq: Intrinsic:$carry), (seq (IRInt $a, $b, 0):$pair, (store (and 1, (lshr (xval $pair, 1), 29)), $carry), (xval $pair, 0))>; def q_m: Intrinsic:$carry, Predicate:$pred), (seq (IRInt $inactive, $a, $b, (shl (load $carry), 29), $pred):$pair, (store (and 1, (lshr (xval $pair, 1), 29)), $carry), (xval $pair, 0))>; def iq_m: Intrinsic:$carry, Predicate:$pred), (seq (IRInt $inactive, $a, $b, 0, $pred):$pair, (store (and 1, (lshr (xval $pair, 1), 29)), $carry), (xval $pair, 0))>; } let params = T.Int32 in { defm vadc: vadcsbc; defm vsbc: vadcsbc; } let params = T.Int in { def vshlcq: Intrinsic< Vector, (args Vector:$v, Ptr:$ps, imm_1to32:$imm), (seq (load $ps):$s, (IRInt<"vshlc", [Vector]> $v, $s, $imm):$pair, (store (xval $pair, 0), $ps), (xval $pair, 1))>; def vshlcq_m: Intrinsic< Vector, (args Vector:$v, Ptr:$ps, imm_1to32:$imm, Predicate:$pred), (seq (load $ps):$s, (IRInt<"vshlc_predicated", [Vector, Predicate]> $v, $s, $imm, $pred):$pair, (store (xval $pair, 0), $ps), (xval $pair, 1))>; } multiclass VectorComplexAddPred { def "" : Intrinsic not_halving, angle, $a, $b)>; defm "" : IntrinsicMX not_halving, angle, $inactive, $a, $b, $pred)>; } multiclass VectorComplexMulPred { def "" : Intrinsic angle, $a, $b)>; defm "" : IntrinsicMX angle, $inactive, $a, $b, $pred)>; } multiclass VectorComplexMLAPred { def "" : Intrinsic angle, $a, $b, $c)>; def _m : Intrinsic angle, $a, $b, $c, $pred)>; } multiclass VectorComplexAddAngle { defm _rot90 : VectorComplexAddPred; defm _rot270 : VectorComplexAddPred; } multiclass VectorComplexMulAngle { defm "" : VectorComplexMulPred<(u32 0)>; defm _rot90 : VectorComplexMulPred<(u32 1)>; defm _rot180 : VectorComplexMulPred<(u32 2)>; defm _rot270 : VectorComplexMulPred<(u32 3)>; } multiclass VectorComplexMLAAngle { defm "" : VectorComplexMLAPred<(u32 0)>; defm _rot90 : VectorComplexMLAPred<(u32 1)>; defm _rot180 : VectorComplexMLAPred<(u32 2)>; defm _rot270 : VectorComplexMLAPred<(u32 3)>; } let params = T.Usual in defm vcaddq : VectorComplexAddAngle<(u32 1)>; let params = T.Signed in defm vhcaddq : VectorComplexAddAngle<(u32 0)>; let params = T.Float in { defm vcmulq : VectorComplexMulAngle; defm vcmlaq : VectorComplexMLAAngle; } multiclass MVEBinaryVectorHoriz32 { def xsuffix#"q" : Intrinsic (unsignedflag Scalar), subtract, exchange, (zeroinit Scalar32), $a, $b)>; def xsuffix#"q_p" : Intrinsic (unsignedflag Scalar), subtract, exchange, (zeroinit Scalar32), $a, $b, $pred)>; def "a"#xsuffix#"q" : Intrinsic (unsignedflag Scalar), subtract, exchange, $a, $b, $c)>; def "a"#xsuffix#"q_p" : Intrinsic (unsignedflag Scalar), subtract, exchange, $a, $b, $c, $pred)>; } class IntrSplit64 : Intrinsic; class IntrSplit64ZeroInit : Intrinsic; multiclass MVEBinaryVectorHoriz64Base { def xsuffix#"q" : IntrSplit64ZeroInit (unsignedflag Scalar), subtract, exchange, $lo, $hi, $a, $b)>; def xsuffix#"q_p" : IntrSplit64ZeroInit (unsignedflag Scalar), subtract, exchange, $lo, $hi, $a, $b, $pred)>; def "a"#xsuffix#"q" : IntrSplit64 (unsignedflag Scalar), subtract, exchange, $lo, $hi, $b, $c)>; def "a"#xsuffix#"q_p" : IntrSplit64 (unsignedflag Scalar), subtract, exchange, $lo, $hi, $b, $c, $pred)>; } multiclass MVEBinaryVectorHoriz64 { defm "" : MVEBinaryVectorHoriz64Base; } multiclass MVEBinaryVectorHoriz64R { defm "" : MVEBinaryVectorHoriz64Base; } multiclass VADDV { defvar accArg = !if(acc, (args Scalar:$acc), (args)); defvar predArg = !if(pred, (args Predicate:$pred), (args)); defvar intrinsic = !if(pred, IRInt, IRInt); defvar intCG = !con((intrinsic $v, (unsignedflag Scalar)), !if(pred, (? $pred), (?))); defvar accCG = !if(acc, (add intCG, $acc), intCG); def "": Intrinsic; } let params = T.Int in { defm vaddvq : VADDV<0, 0, "addv", Scalar32>; defm vaddvaq : VADDV<1, 0, "addv", Scalar32>; defm vaddvq_p : VADDV<0, 1, "addv", Scalar32>; defm vaddvaq_p : VADDV<1, 1, "addv", Scalar32>; } let params = [s32, u32] in { defm vaddlvq : VADDV<0, 0, "addlv", Scalar64>; defm vaddlvaq : VADDV<1, 0, "addlv", Scalar64>; defm vaddlvq_p : VADDV<0, 1, "addlv", Scalar64>; defm vaddlvaq_p : VADDV<1, 1, "addlv", Scalar64>; } let params = T.Int in { def vabavq : Intrinsic (unsignedflag Scalar), $a, $b, $c)>; def vabavq_p : Intrinsic (unsignedflag Scalar), $a, $b, $c, $pred)>; defm vmladav : MVEBinaryVectorHoriz32; } let params = T.Signed in { defm vmladav : MVEBinaryVectorHoriz32; defm vmlsdav : MVEBinaryVectorHoriz32; defm vmlsdav : MVEBinaryVectorHoriz32; } let params = [u16, s16, u32, s32] in defm vmlaldav : MVEBinaryVectorHoriz64; let params = [s16, s32] in { defm vmlaldav : MVEBinaryVectorHoriz64; defm vmlsldav : MVEBinaryVectorHoriz64; defm vmlsldav : MVEBinaryVectorHoriz64; } let params = T.Int32 in defm vrmlaldavh : MVEBinaryVectorHoriz64R; let params = [s32] in { defm vrmlaldavh : MVEBinaryVectorHoriz64R; defm vrmlsldavh : MVEBinaryVectorHoriz64R; defm vrmlsldavh : MVEBinaryVectorHoriz64R; } multiclass vrev_predicated { defm "" : IntrinsicMX $a, revsize, $pred, $inactive)>; } let params = T.All8 in { def vrev16q : Intrinsic; defm vrev16q: vrev_predicated<16>; } let params = !listconcat(T.All8, T.All16) in { def vrev32q : Intrinsic; defm vrev32q: vrev_predicated<32>; } let params = T.Usual in { def vrev64q : Intrinsic; defm vrev64q: vrev_predicated<64>; } foreach desttype = T.All in { // We want a vreinterpretq between every pair of supported vector types // _except_ that there shouldn't be one from a type to itself. let params = !filter(srctype, T.All, !ne(srctype, desttype)) in { def "vreinterpretq_" # desttype: Intrinsic< VecOf, (args Vector:$x), (vreinterpret $x, VecOf)>; } } let params = T.All in { let pnt = PNT_None in { def vcreateq: Intrinsic), $a, 0), $b, 1), Vector)>; def vuninitializedq: Intrinsic; } // This is the polymorphic form of vuninitializedq, which takes no type // suffix, but takes an _unevaluated_ vector parameter and returns an // uninitialized vector of the same vector type. // // This intrinsic has no _non_-polymorphic form exposed to the user. But each // separately typed version of it still has to have its own clang builtin id, // which can't be called vuninitializedq_u32 or similar because that would // collide with the explicit nullary versions above. So I'm calling them // vuninitializedq_polymorphic_u32 (and so on) for builtin id purposes; that // full name never appears in the header file due to the polymorphicOnly // flag, and the _polymorphic suffix is omitted from the shortened name by // the custom PolymorphicNameType here. let polymorphicOnly = 1, nonEvaluating = 1, pnt = PolymorphicNameType<1, "polymorphic"> in { def vuninitializedq_polymorphic: Intrinsic< Vector, (args Vector), (undef Vector)>; } def vgetq_lane: Intrinsic; def vsetq_lane: Intrinsic:$e, Vector:$v, imm_lane:$lane), (ielt_var $v, $e, $lane)>; } foreach desttype = !listconcat(T.Int16, T.Int32, T.Float) in { defvar is_dest_float = !eq(desttype.kind, "f"); defvar is_dest_unsigned = !eq(desttype.kind, "u"); // First immediate operand of the LLVM intrinsic defvar unsigned_flag = !cond(is_dest_float: (unsignedflag Scalar), is_dest_unsigned: V.True, true: V.False); // For float->int conversions _n and _x_n intrinsics are not polymorphic // because the signedness of the destination type cannot be inferred. defvar pnt_nx = !if(is_dest_float, PNT_2Type, PNT_None); let params = !if(is_dest_float, !if(!eq(desttype.size, 16), T.Int16, T.Int32), !if(!eq(desttype.size, 16), [f16], [f32])) in { let pnt = pnt_nx in def "vcvtq_n_"#desttype : Intrinsic, (args Vector:$a, imm_1toN:$b), (IRInt<"vcvt_fix", [VecOf, Vector]> unsigned_flag, $a, $b)>; defm "vcvtq" : IntrinsicMX, (args Vector:$a, imm_1toN:$b, Predicate:$p), (IRInt<"vcvt_fix_predicated", [VecOf, Vector, Predicate]> unsigned_flag, $inactive, $a, $b, $p), 1, "_n_"#desttype, PNT_2Type, pnt_nx>; } } let params = T.Usual in { let pnt = PNT_NType in def vbrsrq_n: Intrinsic $a, $b)>; defm vbrsrq : IntrinsicMX $inactive, $a, $b, $pred), 1, "_n", PNT_NType, PNT_NType>; }