aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td')
-rw-r--r--contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td2612
1 files changed, 2612 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td b/contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td
new file mode 100644
index 000000000000..8bde08105250
--- /dev/null
+++ b/contrib/llvm-project/clang/include/clang/Basic/riscv_vector.td
@@ -0,0 +1,2612 @@
+//==--- riscv_vector.td - RISC-V V-ext Builtin function list --------------===//
+//
+// 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 builtins for RISC-V V-extension. See:
+//
+// https://github.com/riscv/rvv-intrinsic-doc
+//
+//===----------------------------------------------------------------------===//
+
+include "riscv_vector_common.td"
+
+defvar TypeList = ["c","s","i","l","x","f","d"];
+defvar EEWList = [["8", "(Log2EEW:3)"],
+ ["16", "(Log2EEW:4)"],
+ ["32", "(Log2EEW:5)"],
+ ["64", "(Log2EEW:6)"]];
+
+class IsFloat<string type> {
+ bit val = !or(!eq(type, "x"), !eq(type, "f"), !eq(type, "d"));
+}
+
+let SupportOverloading = false,
+ MaskedPolicyScheme = NonePolicy in {
+ class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
+ let Name = "vlm_v";
+ let IRName = "vlm";
+ let HasMasked = false;
+ }
+}
+
+let SupportOverloading = false,
+ UnMaskedPolicyScheme = HasPassthruOperand in {
+ multiclass RVVVLEBuiltin<list<string> types> {
+ let Name = NAME # "_v",
+ IRName = "vle",
+ MaskedIRName ="vle_mask" in {
+ foreach type = types in {
+ def : RVVOutBuiltin<"v", "vPCe", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVOutBuiltin<"Uv", "UvPCUe", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVVLEFFBuiltin<list<string> types> {
+ let Name = NAME # "_v",
+ IRName = "vleff",
+ MaskedIRName = "vleff_mask",
+ SupportOverloading = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ // Move mask to right before vl.
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ IntrinsicTypes = {ResultType, Ops[4]->getType()};
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ IntrinsicTypes = {ResultType, Ops[3]->getType()};
+ }
+ Value *NewVL = Ops[2];
+ Ops.erase(Ops.begin() + 2);
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
+ llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0});
+ // Store new_vl.
+ clang::CharUnits Align;
+ if (IsMasked)
+ Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(E->getNumArgs()-2)->getType());
+ else
+ Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(1)->getType());
+ llvm::Value *Val = Builder.CreateExtractValue(LoadValue, {1});
+ Builder.CreateStore(Val, Address(NewVL, Val->getType(), Align));
+ return V;
+ }
+ }] in {
+ foreach type = types in {
+ def : RVVBuiltin<"v", "vPCePz", type>;
+ // Skip floating types for unsigned versions.
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<"Uv", "UvPCUePz", type>;
+ }
+ }
+ }
+}
+
+multiclass RVVVLSEBuiltin<list<string> types> {
+ let Name = NAME # "_v",
+ IRName = "vlse",
+ MaskedIRName ="vlse_mask",
+ SupportOverloading = false,
+ UnMaskedPolicyScheme = HasPassthruOperand in {
+ foreach type = types in {
+ def : RVVOutBuiltin<"v", "vPCet", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVOutBuiltin<"Uv", "UvPCUet", type>;
+ }
+ }
+ }
+}
+
+multiclass RVVIndexedLoad<string op> {
+ let UnMaskedPolicyScheme = HasPassthruOperand in {
+ foreach type = TypeList in {
+ foreach eew_list = EEWList[0-2] in {
+ defvar eew = eew_list[0];
+ defvar eew_type = eew_list[1];
+ let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask",
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>) in {
+ def: RVVOutOp1Builtin<"v", "vPCe" # eew_type # "Uv", type>;
+ if !not(IsFloat<type>.val) then {
+ def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew_type # "Uv", type>;
+ }
+ }
+ }
+ defvar eew64 = "64";
+ defvar eew64_type = "(Log2EEW:6)";
+ let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin", "RV64"],
+ ["RV64"]) in {
+ def: RVVOutOp1Builtin<"v", "vPCe" # eew64_type # "Uv", type>;
+ if !not(IsFloat<type>.val) then {
+ def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew64_type # "Uv", type>;
+ }
+ }
+ }
+ }
+}
+
+let HasMaskedOffOperand = false,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ if (IsMasked) {
+ // Builtin: (mask, ptr, value, vl). Intrinsic: (value, ptr, mask, vl)
+ std::swap(Ops[0], Ops[2]);
+ } else {
+ // Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl)
+ std::swap(Ops[0], Ops[1]);
+ }
+ if (IsMasked)
+ IntrinsicTypes = {Ops[0]->getType(), Ops[3]->getType()};
+ else
+ IntrinsicTypes = {Ops[0]->getType(), Ops[2]->getType()};
+ }] in {
+ class RVVVSEMaskBuiltin : RVVBuiltin<"m", "0PUem", "c"> {
+ let Name = "vsm_v";
+ let IRName = "vsm";
+ let HasMasked = false;
+ }
+ multiclass RVVVSEBuiltin<list<string> types> {
+ let Name = NAME # "_v",
+ IRName = "vse",
+ MaskedIRName = "vse_mask" in {
+ foreach type = types in {
+ def : RVVBuiltin<"v", "0Pev", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<"Uv", "0PUeUv", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVVSSEBuiltin<list<string> types> {
+ let Name = NAME # "_v",
+ IRName = "vsse",
+ MaskedIRName = "vsse_mask",
+ HasMaskedOffOperand = false,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ if (IsMasked) {
+ // Builtin: (mask, ptr, stride, value, vl). Intrinsic: (value, ptr, stride, mask, vl)
+ std::swap(Ops[0], Ops[3]);
+ } else {
+ // Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
+ std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
+ }
+ if (IsMasked)
+ IntrinsicTypes = {Ops[0]->getType(), Ops[4]->getType()};
+ else
+ IntrinsicTypes = {Ops[0]->getType(), Ops[3]->getType()};
+ }] in {
+ foreach type = types in {
+ def : RVVBuiltin<"v", "0Petv", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<"Uv", "0PUetUv", type>;
+ }
+ }
+ }
+}
+
+multiclass RVVIndexedStore<string op> {
+ let HasMaskedOffOperand = false,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ if (IsMasked) {
+ // Builtin: (mask, ptr, index, value, vl). Intrinsic: (value, ptr, index, mask, vl)
+ std::swap(Ops[0], Ops[3]);
+ } else {
+ // Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl)
+ std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
+ }
+ if (IsMasked)
+ IntrinsicTypes = {Ops[0]->getType(), Ops[2]->getType(), Ops[4]->getType()};
+ else
+ IntrinsicTypes = {Ops[0]->getType(), Ops[2]->getType(), Ops[3]->getType()};
+ }] in {
+ foreach type = TypeList in {
+ foreach eew_list = EEWList[0-2] in {
+ defvar eew = eew_list[0];
+ defvar eew_type = eew_list[1];
+ let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask",
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>) in {
+ def : RVVBuiltin<"v", "0Pe" # eew_type # "Uvv", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<"Uv", "0PUe" # eew_type # "UvUv", type>;
+ }
+ }
+ }
+ defvar eew64 = "64";
+ defvar eew64_type = "(Log2EEW:6)";
+ let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin", "RV64"],
+ ["RV64"]) in {
+ def : RVVBuiltin<"v", "0Pe" # eew64_type # "Uvv", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<"Uv", "0PUe" # eew64_type # "UvUv", type>;
+ }
+ }
+ }
+ }
+}
+
+defvar NFList = [2, 3, 4, 5, 6, 7, 8];
+/*
+A segment load builtin has different variants.
+
+Therefore a segment unit-stride load builtin can have 4 variants,
+1. When unmasked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Ptr, VL)
+2. When masked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Mask, Ptr, VL)
+3. When unmasked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, VL)
+4. When masked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Mask, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, VL)
+
+Other variants of segment load builtin share the same structure, but they
+have their own extra parameter.
+
+The segment unit-stride fault-only-first load builtin has a 'NewVL'
+operand after the 'Ptr' operand.
+1. When unmasked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Ptr, NewVL, VL)
+2. When masked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Mask, Ptr, NewVL, VL)
+3. When unmasked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, NewVL, VL)
+4. When masked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Mask, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, NewVL, VL)
+
+The segment strided load builtin has a 'Stride' operand after the 'Ptr'
+operand.
+1. When unmasked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Ptr, Stride, VL)
+2. When masked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Mask, Ptr, Stride, VL)
+3. When unmasked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, Stride, VL)
+4. When masked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Mask, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, Stride, VL)
+
+The segment indexed load builtin has a 'Idx' operand after the 'Ptr' operand.
+1. When unmasked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Ptr, Idx, VL)
+2. When masked and the policies are all specified as agnostic:
+(Address0, ..., Address{NF - 1}, Mask, Ptr, Idx, VL)
+3. When unmasked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, Idx, VL)
+4. When masked and one of the policies is specified as undisturbed:
+(Address0, ..., Address{NF - 1}, Mask, Maskedoff0, ..., Maskedoff{NF - 1},
+ Ptr, Idx, VL)
+
+Segment load intrinsics has different variants similar to their builtins.
+
+Segment unit-stride load intrinsic,
+ Masked: (Vector0, ..., Vector{NF - 1}, Ptr, Mask, VL, Policy)
+ Unmasked: (Vector0, ..., Vector{NF - 1}, Ptr, VL)
+Segment unit-stride fault-only-first load intrinsic,
+ Masked: (Vector0, ..., Vector{NF - 1}, Ptr, Mask, VL, Policy)
+ Unmasked: (Vector0, ..., Vector{NF - 1}, Ptr, VL)
+Segment strided load intrinsic,
+ Masked: (Vector0, ..., Vector{NF - 1}, Ptr, Stride, Mask, VL, Policy)
+ Unmasked: (Vector0, ..., Vector{NF - 1}, Ptr, Stride, VL)
+Segment indexed load intrinsic,
+ Masked: (Vector0, ..., Vector{NF - 1}, Ptr, Index, Mask, VL, Policy)
+ Unmasked: (Vector0, ..., Vector{NF - 1}, Ptr, Index, VL)
+
+The Vector(s) is poison when the policy behavior allows us to not care
+about any masked-off elements.
+*/
+
+class PVString<int nf, bit signed> {
+ string S =
+ !cond(!eq(nf, 2): !if(signed, "PvPv", "PUvPUv"),
+ !eq(nf, 3): !if(signed, "PvPvPv", "PUvPUvPUv"),
+ !eq(nf, 4): !if(signed, "PvPvPvPv", "PUvPUvPUvPUv"),
+ !eq(nf, 5): !if(signed, "PvPvPvPvPv", "PUvPUvPUvPUvPUv"),
+ !eq(nf, 6): !if(signed, "PvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUv"),
+ !eq(nf, 7): !if(signed, "PvPvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUvPUv"),
+ !eq(nf, 8): !if(signed, "PvPvPvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUvPUvPUv"));
+}
+
+class VString<int nf, bit signed> {
+ string S = !cond(!eq(nf, 2): !if(signed, "vv", "UvUv"),
+ !eq(nf, 3): !if(signed, "vvv", "UvUvUv"),
+ !eq(nf, 4): !if(signed, "vvvv", "UvUvUvUv"),
+ !eq(nf, 5): !if(signed, "vvvvv", "UvUvUvUvUv"),
+ !eq(nf, 6): !if(signed, "vvvvvv", "UvUvUvUvUvUv"),
+ !eq(nf, 7): !if(signed, "vvvvvvv", "UvUvUvUvUvUvUv"),
+ !eq(nf, 8): !if(signed, "vvvvvvvv", "UvUvUvUvUvUvUvUv"));
+}
+
+
+class FixedVString<int fixed_lmul, int num, string vec> {
+ string V = "(LFixedLog2LMUL:" # fixed_lmul # ")" # vec;
+ string S = !interleave(!listsplat(V, num), "");
+}
+
+multiclass RVVNonTupleVCreateBuiltin<int dst_lmul, list<int> src_lmul_list> {
+ defvar dst_v = FixedVString<dst_lmul, 1, "v">.V;
+ defvar dst_uv = FixedVString<dst_lmul, 1, "Uv">.V;
+ foreach src_lmul = src_lmul_list in {
+ defvar num = !shl(1, !sub(dst_lmul, src_lmul));
+
+ defvar src_v = FixedVString<src_lmul, num, "v">.V;
+ defvar src_s = FixedVString<src_lmul, num, "v">.S;
+ def vcreate # src_v # dst_v : RVVBuiltin<src_v # dst_v,
+ dst_v # src_s,
+ "csilxfd", dst_v>;
+
+ defvar src_uv = FixedVString<src_lmul, num, "Uv">.V;
+ defvar src_us = FixedVString<src_lmul, num, "Uv">.S;
+ def vcreate_u # src_uv # dst_uv : RVVBuiltin<src_uv # dst_uv,
+ dst_uv # src_us,
+ "csil", dst_uv>;
+ }
+}
+
+multiclass RVVPseudoUnaryBuiltin<string IR, string type_range> {
+ let Name = NAME,
+ IRName = IR,
+ MaskedIRName = IR # "_mask",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ }
+ auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
+ Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
+
+ if (IsMasked) {
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ // maskedoff, op1, op2, mask, vl, policy
+ IntrinsicTypes = {ResultType, ElemTy, Ops[4]->getType()};
+ } else {
+ // passthru, op1, op2, vl
+ IntrinsicTypes = {ResultType, ElemTy, Ops[3]->getType()};
+ }
+ break;
+ }
+ }] in {
+ def : RVVBuiltin<"v", "vv", type_range>;
+ }
+}
+
+multiclass RVVPseudoVNotBuiltin<string IR, string type_range> {
+ let Name = NAME,
+ IRName = IR,
+ MaskedIRName = IR # "_mask",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ }
+ auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
+ Ops.insert(Ops.begin() + 2,
+ llvm::Constant::getAllOnesValue(ElemTy));
+ if (IsMasked) {
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ // maskedoff, op1, po2, mask, vl, policy
+ IntrinsicTypes = {ResultType,
+ ElemTy,
+ Ops[4]->getType()};
+ } else {
+ // passthru, op1, op2, vl
+ IntrinsicTypes = {ResultType,
+ ElemTy,
+ Ops[3]->getType()};
+ }
+ break;
+ }
+ }] in {
+ def : RVVBuiltin<"v", "vv", type_range>;
+ def : RVVBuiltin<"Uv", "UvUv", type_range>;
+ }
+}
+
+multiclass RVVPseudoMaskBuiltin<string IR, string type_range> {
+ let Name = NAME,
+ IRName = IR,
+ HasMasked = false,
+ ManualCodegen = [{
+ {
+ // op1, vl
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType()};
+ Ops.insert(Ops.begin() + 1, Ops[0]);
+ break;
+ }
+ }] in {
+ def : RVVBuiltin<"m", "mm", type_range>;
+ }
+}
+
+multiclass RVVPseudoVFUnaryBuiltin<string IR, string type_range> {
+ let Name = NAME,
+ IRName = IR,
+ MaskedIRName = IR # "_mask",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ Ops.insert(Ops.begin() + 2, Ops[1]);
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ // maskedoff, op1, op2, mask, vl
+ IntrinsicTypes = {ResultType,
+ Ops[2]->getType(),
+ Ops.back()->getType()};
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ // op1, po2, vl
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType(), Ops[2]->getType()};
+ Ops.insert(Ops.begin() + 2, Ops[1]);
+ break;
+ }
+ break;
+ }
+ }] in {
+ def : RVVBuiltin<"v", "vv", type_range>;
+ }
+}
+
+multiclass RVVPseudoVWCVTBuiltin<string IR, string MName, string type_range,
+ list<list<string>> suffixes_prototypes> {
+ let Name = NAME,
+ OverloadedName = MName,
+ IRName = IR,
+ MaskedIRName = IR # "_mask",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ }
+ auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
+ Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
+ if (IsMasked) {
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ // maskedoff, op1, op2, mask, vl, policy
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType(),
+ ElemTy,
+ Ops[4]->getType()};
+ } else {
+ // passtru, op1, op2, vl
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType(),
+ ElemTy,
+ Ops[3]->getType()};
+ }
+ break;
+ }
+ }] in {
+ foreach s_p = suffixes_prototypes in {
+ def : RVVBuiltin<s_p[0], s_p[1], type_range>;
+ }
+ }
+}
+
+multiclass RVVPseudoVNCVTBuiltin<string IR, string MName, string type_range,
+ list<list<string>> suffixes_prototypes> {
+ let Name = NAME,
+ OverloadedName = MName,
+ IRName = IR,
+ MaskedIRName = IR # "_mask",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ ManualCodegen = [{
+ {
+ if (IsMasked) {
+ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
+ if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ } else {
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ }
+ Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(Ops.back()->getType()));
+ if (IsMasked) {
+ Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+ // maskedoff, op1, xlen, mask, vl
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType(),
+ Ops[4]->getType(),
+ Ops[4]->getType()};
+ } else {
+ // passthru, op1, xlen, vl
+ IntrinsicTypes = {ResultType,
+ Ops[1]->getType(),
+ Ops[3]->getType(),
+ Ops[3]->getType()};
+ }
+ break;
+ }
+ }] in {
+ foreach s_p = suffixes_prototypes in {
+ def : RVVBuiltin<s_p[0], s_p[1], type_range>;
+ }
+ }
+}
+
+let HeaderCode =
+[{
+#define __riscv_vlenb() __builtin_rvv_vlenb()
+}] in
+def vlenb_macro: RVVHeader;
+
+let HasBuiltinAlias = false, HasVL = false, HasMasked = false,
+ UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy,
+ Log2LMUL = [0], IRName = "",
+ ManualCodegen = [{
+ {
+ LLVMContext &Context = CGM.getLLVMContext();
+ llvm::MDBuilder MDHelper(Context);
+
+ llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "vlenb")};
+ llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
+ llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
+ llvm::Function *F =
+ CGM.getIntrinsic(llvm::Intrinsic::read_register, {SizeTy});
+ return Builder.CreateCall(F, Metadata);
+ }
+ }] in
+{
+ def vlenb : RVVBuiltin<"", "u", "i">;
+}
+
+// 6. Configuration-Setting Instructions
+// 6.1. vsetvli/vsetvl instructions
+
+// vsetvl/vsetvlmax are a macro because they require constant integers in SEW
+// and LMUL.
+let HeaderCode =
+[{
+#define __riscv_vsetvl_e8mf4(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 6)
+#define __riscv_vsetvl_e8mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 7)
+#define __riscv_vsetvl_e8m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 0)
+#define __riscv_vsetvl_e8m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 1)
+#define __riscv_vsetvl_e8m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 2)
+#define __riscv_vsetvl_e8m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 3)
+
+#define __riscv_vsetvl_e16mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 7)
+#define __riscv_vsetvl_e16m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 0)
+#define __riscv_vsetvl_e16m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 1)
+#define __riscv_vsetvl_e16m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 2)
+#define __riscv_vsetvl_e16m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 3)
+
+#define __riscv_vsetvl_e32m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 0)
+#define __riscv_vsetvl_e32m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 1)
+#define __riscv_vsetvl_e32m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 2)
+#define __riscv_vsetvl_e32m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 3)
+
+#if __riscv_v_elen >= 64
+#define __riscv_vsetvl_e8mf8(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 5)
+#define __riscv_vsetvl_e16mf4(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 6)
+#define __riscv_vsetvl_e32mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 7)
+
+#define __riscv_vsetvl_e64m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 0)
+#define __riscv_vsetvl_e64m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 1)
+#define __riscv_vsetvl_e64m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 2)
+#define __riscv_vsetvl_e64m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 3)
+#endif
+
+#define __riscv_vsetvlmax_e8mf4() __builtin_rvv_vsetvlimax(0, 6)
+#define __riscv_vsetvlmax_e8mf2() __builtin_rvv_vsetvlimax(0, 7)
+#define __riscv_vsetvlmax_e8m1() __builtin_rvv_vsetvlimax(0, 0)
+#define __riscv_vsetvlmax_e8m2() __builtin_rvv_vsetvlimax(0, 1)
+#define __riscv_vsetvlmax_e8m4() __builtin_rvv_vsetvlimax(0, 2)
+#define __riscv_vsetvlmax_e8m8() __builtin_rvv_vsetvlimax(0, 3)
+
+#define __riscv_vsetvlmax_e16mf2() __builtin_rvv_vsetvlimax(1, 7)
+#define __riscv_vsetvlmax_e16m1() __builtin_rvv_vsetvlimax(1, 0)
+#define __riscv_vsetvlmax_e16m2() __builtin_rvv_vsetvlimax(1, 1)
+#define __riscv_vsetvlmax_e16m4() __builtin_rvv_vsetvlimax(1, 2)
+#define __riscv_vsetvlmax_e16m8() __builtin_rvv_vsetvlimax(1, 3)
+
+#define __riscv_vsetvlmax_e32m1() __builtin_rvv_vsetvlimax(2, 0)
+#define __riscv_vsetvlmax_e32m2() __builtin_rvv_vsetvlimax(2, 1)
+#define __riscv_vsetvlmax_e32m4() __builtin_rvv_vsetvlimax(2, 2)
+#define __riscv_vsetvlmax_e32m8() __builtin_rvv_vsetvlimax(2, 3)
+
+#if __riscv_v_elen >= 64
+#define __riscv_vsetvlmax_e8mf8() __builtin_rvv_vsetvlimax(0, 5)
+#define __riscv_vsetvlmax_e16mf4() __builtin_rvv_vsetvlimax(1, 6)
+#define __riscv_vsetvlmax_e32mf2() __builtin_rvv_vsetvlimax(2, 7)
+
+#define __riscv_vsetvlmax_e64m1() __builtin_rvv_vsetvlimax(3, 0)
+#define __riscv_vsetvlmax_e64m2() __builtin_rvv_vsetvlimax(3, 1)
+#define __riscv_vsetvlmax_e64m4() __builtin_rvv_vsetvlimax(3, 2)
+#define __riscv_vsetvlmax_e64m8() __builtin_rvv_vsetvlimax(3, 3)
+#endif
+
+}] in
+def vsetvl_macro: RVVHeader;
+
+let HasBuiltinAlias = false,
+ HasVL = false,
+ HasMasked = false,
+ MaskedPolicyScheme = NonePolicy,
+ Log2LMUL = [0],
+ ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type
+{
+ def vsetvli : RVVBuiltin<"", "zzKzKz", "i">;
+ def vsetvlimax : RVVBuiltin<"", "zKzKz", "i">;
+}
+
+// 7. Vector Loads and Stores
+// 7.4. Vector Unit-Stride Instructions
+def vlm: RVVVLEMaskBuiltin;
+defm vle8: RVVVLEBuiltin<["c"]>;
+defm vle16: RVVVLEBuiltin<["s"]>;
+let Name = "vle16_v", RequiredFeatures = ["Zvfhmin"] in
+ defm vle16_h: RVVVLEBuiltin<["x"]>;
+defm vle32: RVVVLEBuiltin<["i","f"]>;
+defm vle64: RVVVLEBuiltin<["l","d"]>;
+
+def vsm : RVVVSEMaskBuiltin;
+defm vse8 : RVVVSEBuiltin<["c"]>;
+defm vse16: RVVVSEBuiltin<["s"]>;
+let Name = "vse16_v", RequiredFeatures = ["Zvfhmin"] in
+ defm vse16_h: RVVVSEBuiltin<["x"]>;
+defm vse32: RVVVSEBuiltin<["i","f"]>;
+defm vse64: RVVVSEBuiltin<["l","d"]>;
+
+// 7.5. Vector Strided Instructions
+defm vlse8: RVVVLSEBuiltin<["c"]>;
+defm vlse16: RVVVLSEBuiltin<["s"]>;
+let Name = "vlse16_v", RequiredFeatures = ["Zvfhmin"] in
+ defm vlse16_h: RVVVLSEBuiltin<["x"]>;
+defm vlse32: RVVVLSEBuiltin<["i","f"]>;
+defm vlse64: RVVVLSEBuiltin<["l","d"]>;
+
+defm vsse8 : RVVVSSEBuiltin<["c"]>;
+defm vsse16: RVVVSSEBuiltin<["s"]>;
+let Name = "vsse16_v", RequiredFeatures = ["Zvfhmin"] in
+ defm vsse16_h: RVVVSSEBuiltin<["x"]>;
+defm vsse32: RVVVSSEBuiltin<["i","f"]>;
+defm vsse64: RVVVSSEBuiltin<["l","d"]>;
+
+// 7.6. Vector Indexed Instructions
+defm : RVVIndexedLoad<"vluxei">;
+defm : RVVIndexedLoad<"vloxei">;
+
+defm : RVVIndexedStore<"vsuxei">;
+defm : RVVIndexedStore<"vsoxei">;
+
+// 7.7. Unit-stride Fault-Only-First Loads
+defm vle8ff: RVVVLEFFBuiltin<["c"]>;
+defm vle16ff: RVVVLEFFBuiltin<["s"]>;
+let Name = "vle16ff_v", RequiredFeatures = ["Zvfhmin"] in
+ defm vle16ff: RVVVLEFFBuiltin<["x"]>;
+defm vle32ff: RVVVLEFFBuiltin<["i", "f"]>;
+defm vle64ff: RVVVLEFFBuiltin<["l", "d"]>;
+
+multiclass RVVUnitStridedSegLoadTuple<string op> {
+ foreach type = TypeList in {
+ defvar eew = !cond(!eq(type, "c") : "8",
+ !eq(type, "s") : "16",
+ !eq(type, "i") : "32",
+ !eq(type, "l") : "64",
+ !eq(type, "x") : "16",
+ !eq(type, "f") : "32",
+ !eq(type, "d") : "64");
+ foreach nf = NFList in {
+ let Name = op # nf # "e" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ llvm::Type *ElementVectorType = cast<StructType>(ResultType)->elements()[0];
+ IntrinsicTypes = {ElementVectorType, Ops.back()->getType()};
+ SmallVector<llvm::Value*, 12> Operands;
+
+ bool NoPassthru =
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
+ (!IsMasked && (PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
+
+ if (NoPassthru) { // Push poison into passthru
+ Operands.append(NF, llvm::PoisonValue::get(ElementVectorType));
+ } else { // Push intrinsics operands into passthru
+ llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
+ for (unsigned I = 0; I < NF; ++I)
+ Operands.push_back(Builder.CreateExtractValue(PassthruOperand, {I}));
+ }
+
+ Operands.push_back(Ops[Offset]); // Ptr
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 1]); // VL
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+
+ llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
+ if (ReturnValue.isNull())
+ return LoadValue;
+ else
+ return Builder.CreateStore(LoadValue, ReturnValue.getValue());
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", T # "vPCe", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", T # "UvPCUe", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVUnitStridedSegStoreTuple<string op> {
+ foreach type = TypeList in {
+ defvar eew = !cond(!eq(type, "c") : "8",
+ !eq(type, "s") : "16",
+ !eq(type, "i") : "32",
+ !eq(type, "l") : "64",
+ !eq(type, "x") : "16",
+ !eq(type, "f") : "32",
+ !eq(type, "d") : "64");
+ foreach nf = NFList in {
+ let Name = op # nf # "e" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ HasMaskedOffOperand = false,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ // Masked
+ // Builtin: (mask, ptr, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, mask, vl)
+ // Unmasked
+ // Builtin: (ptr, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, vl)
+ unsigned Offset = IsMasked ? 1 : 0;
+ llvm::Value *VTupleOperand = Ops[Offset + 1];
+
+ SmallVector<llvm::Value*, 12> Operands;
+ for (unsigned I = 0; I < NF; ++I) {
+ llvm::Value *V = Builder.CreateExtractValue(VTupleOperand, {I});
+ Operands.push_back(V);
+ }
+ Operands.push_back(Ops[Offset]); // Ptr
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 2]); // VL
+
+ IntrinsicTypes = {Operands[0]->getType(), Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", "0Pe" # T # "v", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", "0PUe" # T # "Uv", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVUnitStridedSegLoadFFTuple<string op> {
+ foreach type = TypeList in {
+ defvar eew = !cond(!eq(type, "c") : "8",
+ !eq(type, "s") : "16",
+ !eq(type, "i") : "32",
+ !eq(type, "l") : "64",
+ !eq(type, "x") : "16",
+ !eq(type, "f") : "32",
+ !eq(type, "d") : "64");
+ foreach nf = NFList in {
+ let Name = op # nf # "e" # eew # "ff_v",
+ IRName = op # nf # "ff",
+ MaskedIRName = op # nf # "ff_mask",
+ NF = nf,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ llvm::Type *ElementVectorType = cast<StructType>(ResultType)->elements()[0];
+ IntrinsicTypes = {ElementVectorType, Ops.back()->getType()};
+ SmallVector<llvm::Value*, 12> Operands;
+
+ bool NoPassthru =
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
+ (!IsMasked && (PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
+
+ if (NoPassthru) { // Push poison into passthru
+ Operands.append(NF, llvm::PoisonValue::get(ElementVectorType));
+ } else { // Push intrinsics operands into passthru
+ llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
+ for (unsigned I = 0; I < NF; ++I)
+ Operands.push_back(Builder.CreateExtractValue(PassthruOperand, {I}));
+ }
+
+ Operands.push_back(Ops[Offset]); // Ptr
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 2]); // vl
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+
+ llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
+ // Get alignment from the new vl operand
+ clang::CharUnits Align =
+ CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
+
+ llvm::Value *ReturnTuple = llvm::PoisonValue::get(ResultType);
+ for (unsigned I = 0; I < NF; ++I) {
+ llvm::Value *V = Builder.CreateExtractValue(LoadValue, {I});
+ ReturnTuple = Builder.CreateInsertValue(ReturnTuple, V, {I});
+ }
+
+ // Store new_vl
+ llvm::Value *V = Builder.CreateExtractValue(LoadValue, {NF});
+ Builder.CreateStore(V, Address(Ops[Offset + 1], V->getType(), Align));
+
+ if (ReturnValue.isNull())
+ return ReturnTuple;
+ else
+ return Builder.CreateStore(ReturnTuple, ReturnValue.getValue());
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", T # "vPCePz", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", T # "UvPCUePz", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVStridedSegLoadTuple<string op> {
+ foreach type = TypeList in {
+ defvar eew = !cond(!eq(type, "c") : "8",
+ !eq(type, "s") : "16",
+ !eq(type, "i") : "32",
+ !eq(type, "l") : "64",
+ !eq(type, "x") : "16",
+ !eq(type, "f") : "32",
+ !eq(type, "d") : "64");
+ foreach nf = NFList in {
+ let Name = op # nf # "e" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ llvm::Type *ElementVectorType = cast<StructType>(ResultType)->elements()[0];
+ IntrinsicTypes = {ElementVectorType, Ops.back()->getType()};
+ SmallVector<llvm::Value*, 12> Operands;
+
+ bool NoPassthru =
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
+ (!IsMasked && (PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
+
+ if (NoPassthru) { // Push poison into passthru
+ Operands.append(NF, llvm::PoisonValue::get(ElementVectorType));
+ } else { // Push intrinsics operands into passthru
+ llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
+ for (unsigned I = 0; I < NF; ++I)
+ Operands.push_back(Builder.CreateExtractValue(PassthruOperand, {I}));
+ }
+
+ Operands.push_back(Ops[Offset]); // Ptr
+ Operands.push_back(Ops[Offset + 1]); // Stride
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 2]); // VL
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
+
+ if (ReturnValue.isNull())
+ return LoadValue;
+ else
+ return Builder.CreateStore(LoadValue, ReturnValue.getValue());
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", T # "vPCet", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", T # "UvPCUet", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVStridedSegStoreTuple<string op> {
+ foreach type = TypeList in {
+ defvar eew = !cond(!eq(type, "c") : "8",
+ !eq(type, "s") : "16",
+ !eq(type, "i") : "32",
+ !eq(type, "l") : "64",
+ !eq(type, "x") : "16",
+ !eq(type, "f") : "32",
+ !eq(type, "d") : "64");
+ foreach nf = NFList in {
+ let Name = op # nf # "e" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ HasMaskedOffOperand = false,
+ MaskedPolicyScheme = NonePolicy,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ // Masked
+ // Builtin: (mask, ptr, stride, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, stride, mask, vl)
+ // Unmasked
+ // Builtin: (ptr, stride, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, stride, vl)
+ unsigned Offset = IsMasked ? 1 : 0;
+ llvm::Value *VTupleOperand = Ops[Offset + 2];
+
+ SmallVector<llvm::Value*, 12> Operands;
+ for (unsigned I = 0; I < NF; ++I) {
+ llvm::Value *V = Builder.CreateExtractValue(VTupleOperand, {I});
+ Operands.push_back(V);
+ }
+ Operands.push_back(Ops[Offset]); // Ptr
+ Operands.push_back(Ops[Offset + 1]); // Stride
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 3]); // VL
+
+ IntrinsicTypes = {Operands[0]->getType(), Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", "0Pet" # T # "v", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", "0PUet" # T # "Uv", type>;
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVIndexedSegLoadTuple<string op> {
+ foreach type = TypeList in {
+ foreach eew_info = EEWList in {
+ defvar eew = eew_info[0];
+ defvar eew_type = eew_info[1];
+ foreach nf = NFList in {
+ let Name = op # nf # "ei" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ llvm::Type *ElementVectorType = cast<StructType>(ResultType)->elements()[0];
+ IntrinsicTypes = {ElementVectorType, Ops.back()->getType()};
+ SmallVector<llvm::Value*, 12> Operands;
+
+ bool NoPassthru =
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
+ (!IsMasked && (PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
+
+ if (NoPassthru) { // Push poison into passthru
+ Operands.append(NF, llvm::PoisonValue::get(ElementVectorType));
+ } else { // Push intrinsics operands into passthru
+ llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
+ for (unsigned I = 0; I < NF; ++I)
+ Operands.push_back(Builder.CreateExtractValue(PassthruOperand, {I}));
+ }
+
+ Operands.push_back(Ops[Offset]); // Ptr
+ Operands.push_back(Ops[Offset + 1]); // Idx
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 2]); // VL
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ElementVectorType, Ops[Offset + 1]->getType(),
+ Ops.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
+
+ if (ReturnValue.isNull())
+ return LoadValue;
+ else
+ return Builder.CreateStore(LoadValue, ReturnValue.getValue());
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", T # "vPCe" # eew_type # "Uv", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", T # "UvPCUe" # eew_type # "Uv", type>;
+ }
+ }
+ }
+ }
+ }
+}
+
+multiclass RVVIndexedSegStoreTuple<string op> {
+ foreach type = TypeList in {
+ foreach eew_info = EEWList in {
+ defvar eew = eew_info[0];
+ defvar eew_type = eew_info[1];
+ foreach nf = NFList in {
+ let Name = op # nf # "ei" # eew # "_v",
+ IRName = op # nf,
+ MaskedIRName = op # nf # "_mask",
+ NF = nf,
+ HasMaskedOffOperand = false,
+ MaskedPolicyScheme = NonePolicy,
+ RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
+ []<string>),
+ ManualCodegen = [{
+ {
+ // Masked
+ // Builtin: (mask, ptr, index, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, index, mask, vl)
+ // Unmasked
+ // Builtin: (ptr, index, v_tuple, vl)
+ // Intrinsic: (val0, val1, ..., ptr, index, vl)
+ unsigned Offset = IsMasked ? 1 : 0;
+ llvm::Value *VTupleOperand = Ops[Offset + 2];
+
+ SmallVector<llvm::Value*, 12> Operands;
+ for (unsigned I = 0; I < NF; ++I) {
+ llvm::Value *V = Builder.CreateExtractValue(VTupleOperand, {I});
+ Operands.push_back(V);
+ }
+ Operands.push_back(Ops[Offset]); // Ptr
+ Operands.push_back(Ops[Offset + 1]); // Idx
+ if (IsMasked)
+ Operands.push_back(Ops[0]);
+ Operands.push_back(Ops[Offset + 3]); // VL
+
+ IntrinsicTypes = {Operands[0]->getType(), Ops[Offset + 1]->getType(),
+ Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+ }] in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", "0Pe" # eew_type # "Uv" # T # "v", type>;
+ if !not(IsFloat<type>.val) then {
+ def : RVVBuiltin<T # "Uv", "0PUe" # eew_type # "Uv" # T # "Uv", type>;
+ }
+ }
+ }
+ }
+ }
+}
+
+// 7.8 Vector Load/Store Segment Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand,
+ IsTuple = true in {
+ defm : RVVUnitStridedSegLoadTuple<"vlseg">;
+ defm : RVVUnitStridedSegLoadFFTuple<"vlseg">;
+ defm : RVVStridedSegLoadTuple<"vlsseg">;
+ defm : RVVIndexedSegLoadTuple<"vluxseg">;
+ defm : RVVIndexedSegLoadTuple<"vloxseg">;
+}
+
+let UnMaskedPolicyScheme = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
+ IsTuple = true in {
+defm : RVVUnitStridedSegStoreTuple<"vsseg">;
+defm : RVVStridedSegStoreTuple<"vssseg">;
+defm : RVVIndexedSegStoreTuple<"vsuxseg">;
+defm : RVVIndexedSegStoreTuple<"vsoxseg">;
+}
+
+// 11. Vector Integer Arithmetic Instructions
+// 11.1. Vector Single-Width Integer Add and Subtract
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vadd : RVVIntBinBuiltinSet;
+defm vsub : RVVIntBinBuiltinSet;
+defm vrsub : RVVOutOp1BuiltinSet<"vrsub", "csil",
+ [["vx", "v", "vve"],
+ ["vx", "Uv", "UvUvUe"]]>;
+}
+defm vneg_v : RVVPseudoUnaryBuiltin<"vrsub", "csil">;
+
+// 11.2. Vector Widening Integer Add/Subtract
+// Widening unsigned integer add/subtract, 2*SEW = SEW +/- SEW
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vwaddu : RVVUnsignedWidenBinBuiltinSet;
+defm vwsubu : RVVUnsignedWidenBinBuiltinSet;
+// Widening signed integer add/subtract, 2*SEW = SEW +/- SEW
+defm vwadd : RVVSignedWidenBinBuiltinSet;
+defm vwsub : RVVSignedWidenBinBuiltinSet;
+// Widening unsigned integer add/subtract, 2*SEW = 2*SEW +/- SEW
+defm vwaddu : RVVUnsignedWidenOp0BinBuiltinSet;
+defm vwsubu : RVVUnsignedWidenOp0BinBuiltinSet;
+// Widening signed integer add/subtract, 2*SEW = 2*SEW +/- SEW
+defm vwadd : RVVSignedWidenOp0BinBuiltinSet;
+defm vwsub : RVVSignedWidenOp0BinBuiltinSet;
+}
+defm vwcvtu_x_x_v : RVVPseudoVWCVTBuiltin<"vwaddu", "vwcvtu_x", "csi",
+ [["Uw", "UwUv"]]>;
+defm vwcvt_x_x_v : RVVPseudoVWCVTBuiltin<"vwadd", "vwcvt_x", "csi",
+ [["w", "wv"]]>;
+
+// 11.3. Vector Integer Extension
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ def vsext_vf2 : RVVIntExt<"vsext", "w", "wv", "csi">;
+ def vzext_vf2 : RVVIntExt<"vzext", "Uw", "UwUv", "csi">;
+}
+let Log2LMUL = [-3, -2, -1, 0, 1] in {
+ def vsext_vf4 : RVVIntExt<"vsext", "q", "qv", "cs">;
+ def vzext_vf4 : RVVIntExt<"vzext", "Uq", "UqUv", "cs">;
+}
+let Log2LMUL = [-3, -2, -1, 0] in {
+ def vsext_vf8 : RVVIntExt<"vsext", "o", "ov", "c">;
+ def vzext_vf8 : RVVIntExt<"vzext", "Uo", "UoUv", "c">;
+}
+}
+
+// 11.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
+ let UnMaskedPolicyScheme = HasPassthruOperand in {
+ defm vadc : RVVCarryinBuiltinSet;
+ defm vsbc : RVVCarryinBuiltinSet;
+ }
+ defm vmadc : RVVCarryOutInBuiltinSet<"vmadc_carry_in">;
+ defm vmadc : RVVIntMaskOutBuiltinSet;
+ defm vmsbc : RVVCarryOutInBuiltinSet<"vmsbc_borrow_in">;
+ defm vmsbc : RVVIntMaskOutBuiltinSet;
+}
+
+// 11.5. Vector Bitwise Logical Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vand : RVVIntBinBuiltinSet;
+defm vxor : RVVIntBinBuiltinSet;
+defm vor : RVVIntBinBuiltinSet;
+}
+defm vnot_v : RVVPseudoVNotBuiltin<"vxor", "csil">;
+
+// 11.6. Vector Single-Width Shift Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vsll : RVVShiftBuiltinSet;
+defm vsrl : RVVUnsignedShiftBuiltinSet;
+defm vsra : RVVSignedShiftBuiltinSet;
+
+// 11.7. Vector Narrowing Integer Right Shift Instructions
+defm vnsrl : RVVUnsignedNShiftBuiltinSet;
+defm vnsra : RVVSignedNShiftBuiltinSet;
+}
+defm vncvt_x_x_w : RVVPseudoVNCVTBuiltin<"vnsrl", "vncvt_x", "csi",
+ [["v", "vw"],
+ ["Uv", "UvUw"]]>;
+
+// 11.8. Vector Integer Compare Instructions
+let MaskedPolicyScheme = HasPassthruOperand,
+ HasTailPolicy = false in {
+defm vmseq : RVVIntMaskOutBuiltinSet;
+defm vmsne : RVVIntMaskOutBuiltinSet;
+defm vmsltu : RVVUnsignedMaskOutBuiltinSet;
+defm vmslt : RVVSignedMaskOutBuiltinSet;
+defm vmsleu : RVVUnsignedMaskOutBuiltinSet;
+defm vmsle : RVVSignedMaskOutBuiltinSet;
+defm vmsgtu : RVVUnsignedMaskOutBuiltinSet;
+defm vmsgt : RVVSignedMaskOutBuiltinSet;
+defm vmsgeu : RVVUnsignedMaskOutBuiltinSet;
+defm vmsge : RVVSignedMaskOutBuiltinSet;
+}
+
+// 11.9. Vector Integer Min/Max Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vminu : RVVUnsignedBinBuiltinSet;
+defm vmin : RVVSignedBinBuiltinSet;
+defm vmaxu : RVVUnsignedBinBuiltinSet;
+defm vmax : RVVSignedBinBuiltinSet;
+
+// 11.10. Vector Single-Width Integer Multiply Instructions
+defm vmul : RVVIntBinBuiltinSet;
+defm vmulh : RVVSignedBinBuiltinSet;
+defm vmulhu : RVVUnsignedBinBuiltinSet;
+defm vmulhsu : RVVOutOp1BuiltinSet<"vmulhsu", "csil",
+ [["vv", "v", "vvUv"],
+ ["vx", "v", "vvUe"]]>;
+
+// 11.11. Vector Integer Divide Instructions
+defm vdivu : RVVUnsignedBinBuiltinSet;
+defm vdiv : RVVSignedBinBuiltinSet;
+defm vremu : RVVUnsignedBinBuiltinSet;
+defm vrem : RVVSignedBinBuiltinSet;
+}
+
+// 11.12. Vector Widening Integer Multiply Instructions
+let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vwmul : RVVOutOp0Op1BuiltinSet<"vwmul", "csi",
+ [["vv", "w", "wvv"],
+ ["vx", "w", "wve"]]>;
+defm vwmulu : RVVOutOp0Op1BuiltinSet<"vwmulu", "csi",
+ [["vv", "Uw", "UwUvUv"],
+ ["vx", "Uw", "UwUvUe"]]>;
+defm vwmulsu : RVVOutOp0Op1BuiltinSet<"vwmulsu", "csi",
+ [["vv", "w", "wvUv"],
+ ["vx", "w", "wvUe"]]>;
+}
+
+// 11.13. Vector Single-Width Integer Multiply-Add Instructions
+let UnMaskedPolicyScheme = HasPolicyOperand in {
+defm vmacc : RVVIntTerBuiltinSet;
+defm vnmsac : RVVIntTerBuiltinSet;
+defm vmadd : RVVIntTerBuiltinSet;
+defm vnmsub : RVVIntTerBuiltinSet;
+
+// 11.14. Vector Widening Integer Multiply-Add Instructions
+let HasMaskedOffOperand = false,
+ Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+defm vwmaccu : RVVOutOp1Op2BuiltinSet<"vwmaccu", "csi",
+ [["vv", "Uw", "UwUwUvUv"],
+ ["vx", "Uw", "UwUwUeUv"]]>;
+defm vwmacc : RVVOutOp1Op2BuiltinSet<"vwmacc", "csi",
+ [["vv", "w", "wwvv"],
+ ["vx", "w", "wwev"]]>;
+defm vwmaccsu : RVVOutOp1Op2BuiltinSet<"vwmaccsu", "csi",
+ [["vv", "w", "wwvUv"],
+ ["vx", "w", "wweUv"]]>;
+defm vwmaccus : RVVOutOp1Op2BuiltinSet<"vwmaccus", "csi",
+ [["vx", "w", "wwUev"]]>;
+}
+}
+
+// 11.15. Vector Integer Merge Instructions
+// C/C++ Operand: (mask, op1, op2, vl), Intrinsic: (passthru, op1, op2, mask, vl)
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ // insert poison passthru
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
+ }] in {
+ defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "csil",
+ [["vvm", "v", "vvvm"],
+ ["vxm", "v", "vvem"],
+ ["vvm", "Uv", "UvUvUvm"],
+ ["vxm", "Uv", "UvUvUem"]]>;
+}
+
+// 11.16. Vector Integer Move Instructions
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = NonePolicy,
+ OverloadedName = "vmv_v" in {
+ defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csil",
+ [["v", "Uv", "UvUv"]]>;
+ defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csilfd",
+ [["v", "v", "vv"]]>;
+ let RequiredFeatures = ["Zvfhmin"] in
+ defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "x",
+ [["v", "v", "vv"]]>;
+ let SupportOverloading = false in
+ defm vmv_v : RVVOutBuiltinSet<"vmv_v_x", "csil",
+ [["x", "v", "ve"],
+ ["x", "Uv", "UvUe"]]>;
+}
+
+// 12. Vector Fixed-Point Arithmetic Instructions
+let HeaderCode =
+[{
+enum __RISCV_VXRM {
+ __RISCV_VXRM_RNU = 0,
+ __RISCV_VXRM_RNE = 1,
+ __RISCV_VXRM_RDN = 2,
+ __RISCV_VXRM_ROD = 3,
+};
+}] in
+def vxrm_enum : RVVHeader;
+
+// 12.1. Vector Single-Width Saturating Add and Subtract
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vsaddu : RVVUnsignedBinBuiltinSet;
+defm vsadd : RVVSignedBinBuiltinSet;
+defm vssubu : RVVUnsignedBinBuiltinSet;
+defm vssub : RVVSignedBinBuiltinSet;
+
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ Operands.push_back(Ops[Offset + 2]); // vxrm
+ Operands.push_back(Ops[Offset + 3]); // vl
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(), Ops.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ // 12.2. Vector Single-Width Averaging Add and Subtract
+ defm vaaddu : RVVUnsignedBinBuiltinSetRoundingMode;
+ defm vaadd : RVVSignedBinBuiltinSetRoundingMode;
+ defm vasubu : RVVUnsignedBinBuiltinSetRoundingMode;
+ defm vasub : RVVSignedBinBuiltinSetRoundingMode;
+
+ // 12.3. Vector Single-Width Fractional Multiply with Rounding and Saturation
+ defm vsmul : RVVSignedBinBuiltinSetRoundingMode;
+
+ // 12.4. Vector Single-Width Scaling Shift Instructions
+ defm vssrl : RVVUnsignedShiftBuiltinSetRoundingMode;
+ defm vssra : RVVSignedShiftBuiltinSetRoundingMode;
+}
+
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ Operands.push_back(Ops[Offset + 2]); // vxrm
+ Operands.push_back(Ops[Offset + 3]); // vl
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
+ Ops.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ // 12.5. Vector Narrowing Fixed-Point Clip Instructions
+ defm vnclipu : RVVUnsignedNShiftBuiltinSetRoundingMode;
+ defm vnclip : RVVSignedNShiftBuiltinSetRoundingMode;
+}
+}
+
+// 13. Vector Floating-Point Instructions
+let HeaderCode =
+[{
+enum __RISCV_FRM {
+ __RISCV_FRM_RNE = 0,
+ __RISCV_FRM_RTZ = 1,
+ __RISCV_FRM_RDN = 2,
+ __RISCV_FRM_RUP = 3,
+ __RISCV_FRM_RMM = 4,
+};
+}] in def frm_enum : RVVHeader;
+
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ bool HasRoundModeOp = IsMasked ?
+ (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
+ (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
+
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 2]); // frm
+ Operands.push_back(Ops[Offset + 3]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ }
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(),
+ Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = true in {
+ // 13.2. Vector Single-Width Floating-Point Add/Subtract Instructions
+ defm vfadd : RVVFloatingBinBuiltinSetRoundingMode;
+ defm vfsub : RVVFloatingBinBuiltinSetRoundingMode;
+ defm vfrsub : RVVFloatingBinVFBuiltinSetRoundingMode;
+
+ // 13.3. Vector Widening Floating-Point Add/Subtract Instructions
+ // Widening FP add/subtract, 2*SEW = 2*SEW +/- SEW
+ defm vfwadd : RVVFloatingWidenOp0BinBuiltinSetRoundingMode;
+ defm vfwsub : RVVFloatingWidenOp0BinBuiltinSetRoundingMode;
+
+ // 13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions
+ defm vfmul : RVVFloatingBinBuiltinSetRoundingMode;
+ defm vfdiv : RVVFloatingBinBuiltinSetRoundingMode;
+ defm vfrdiv : RVVFloatingBinVFBuiltinSetRoundingMode;
+ }
+ // 13.2. Vector Single-Width Floating-Point Add/Subtract Instructions
+ defm vfadd : RVVFloatingBinBuiltinSet;
+ defm vfsub : RVVFloatingBinBuiltinSet;
+ defm vfrsub : RVVFloatingBinVFBuiltinSet;
+
+ // 13.3. Vector Widening Floating-Point Add/Subtract Instructions
+ // Widening FP add/subtract, 2*SEW = 2*SEW +/- SEW
+ defm vfwadd : RVVFloatingWidenOp0BinBuiltinSet;
+ defm vfwsub : RVVFloatingWidenOp0BinBuiltinSet;
+
+ // 13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions
+ defm vfmul : RVVFloatingBinBuiltinSet;
+ defm vfdiv : RVVFloatingBinBuiltinSet;
+ defm vfrdiv : RVVFloatingBinVFBuiltinSet;
+}
+
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ bool HasRoundModeOp = IsMasked ?
+ (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
+ (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
+
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 2]); // frm
+ Operands.push_back(Ops[Offset + 3]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ }
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
+ Ops.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = true in {
+ // 13.3. Vector Widening Floating-Point Add/Subtract Instructions
+ // Widening FP add/subtract, 2*SEW = SEW +/- SEW
+ defm vfwadd : RVVFloatingWidenBinBuiltinSetRoundingMode;
+ defm vfwsub : RVVFloatingWidenBinBuiltinSetRoundingMode;
+
+ // 13.5. Vector Widening Floating-Point Multiply
+ let Log2LMUL = [-2, -1, 0, 1, 2] in {
+ defm vfwmul : RVVOutOp0Op1BuiltinSet<"vfwmul", "xf",
+ [["vv", "w", "wvvu"],
+ ["vf", "w", "wveu"]]>;
+ }
+ }
+ // 13.3. Vector Widening Floating-Point Add/Subtract Instructions
+ // Widening FP add/subtract, 2*SEW = SEW +/- SEW
+ defm vfwadd : RVVFloatingWidenBinBuiltinSet;
+ defm vfwsub : RVVFloatingWidenBinBuiltinSet;
+
+ // 13.5. Vector Widening Floating-Point Multiply
+ let Log2LMUL = [-2, -1, 0, 1, 2] in {
+ defm vfwmul : RVVOutOp0Op1BuiltinSet<"vfwmul", "xf",
+ [["vv", "w", "wvv"],
+ ["vf", "w", "wve"]]>;
+ }
+}
+}
+
+
+let UnMaskedPolicyScheme = HasPolicyOperand in {
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
+
+ unsigned Offset = IsMasked ? 2 : 1;
+
+ Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 2]); // frm
+ Operands.push_back(Ops[Offset + 3]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ }
+
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
+ Operands.back()->getType()};
+
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = 1 in {
+ // 13.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
+ defm vfmacc : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfnmacc : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfmsac : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfnmsac : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfmadd : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfnmadd : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfmsub : RVVFloatingTerBuiltinSetRoundingMode;
+ defm vfnmsub : RVVFloatingTerBuiltinSetRoundingMode;
+ }
+ // 13.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
+ defm vfmacc : RVVFloatingTerBuiltinSet;
+ defm vfnmacc : RVVFloatingTerBuiltinSet;
+ defm vfmsac : RVVFloatingTerBuiltinSet;
+ defm vfnmsac : RVVFloatingTerBuiltinSet;
+ defm vfmadd : RVVFloatingTerBuiltinSet;
+ defm vfnmadd : RVVFloatingTerBuiltinSet;
+ defm vfmsub : RVVFloatingTerBuiltinSet;
+ defm vfnmsub : RVVFloatingTerBuiltinSet;
+}
+
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
+
+ unsigned Offset = IsMasked ? 2 : 1;
+
+ Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 2]); // frm
+ Operands.push_back(Ops[Offset + 3]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ }
+
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
+ Operands.back()->getType()};
+
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = 1 in {
+ // 13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions
+ defm vfwmacc : RVVFloatingWidenTerBuiltinSetRoundingMode;
+ defm vfwnmacc : RVVFloatingWidenTerBuiltinSetRoundingMode;
+ defm vfwmsac : RVVFloatingWidenTerBuiltinSetRoundingMode;
+ defm vfwnmsac : RVVFloatingWidenTerBuiltinSetRoundingMode;
+ }
+ // 13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions
+ defm vfwmacc : RVVFloatingWidenTerBuiltinSet;
+ defm vfwnmacc : RVVFloatingWidenTerBuiltinSet;
+ defm vfwmsac : RVVFloatingWidenTerBuiltinSet;
+ defm vfwnmsac : RVVFloatingWidenTerBuiltinSet;
+}
+
+}
+
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, round_mode, vl)
+ // Masked: (passthru, op0, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ bool HasRoundModeOp = IsMasked ?
+ (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
+ (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
+
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 1]); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 1]); // vl
+ }
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = 1 in {
+ // 13.8. Vector Floating-Point Square-Root Instruction
+ defm vfsqrt : RVVOutBuiltinSet<"vfsqrt", "xfd", [["v", "v", "vvu"]]>;
+
+ // 13.10. Vector Floating-Point Reciprocal Estimate Instruction
+ defm vfrec7 : RVVOutBuiltinSet<"vfrec7", "xfd", [["v", "v", "vvu"]]>;
+ }
+ // 13.8. Vector Floating-Point Square-Root Instruction
+ defm vfsqrt : RVVOutBuiltinSet<"vfsqrt", "xfd", [["v", "v", "vv"]]>;
+
+ // 13.10. Vector Floating-Point Reciprocal Estimate Instruction
+ defm vfrec7 : RVVOutBuiltinSet<"vfrec7", "xfd", [["v", "v", "vv"]]>;
+}
+
+// 13.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction
+def vfrsqrt7 : RVVFloatingUnaryVVBuiltin;
+
+// 13.11. Vector Floating-Point MIN/MAX Instructions
+defm vfmin : RVVFloatingBinBuiltinSet;
+defm vfmax : RVVFloatingBinBuiltinSet;
+
+// 13.12. Vector Floating-Point Sign-Injection Instructions
+defm vfsgnj : RVVFloatingBinBuiltinSet;
+defm vfsgnjn : RVVFloatingBinBuiltinSet;
+defm vfsgnjx : RVVFloatingBinBuiltinSet;
+}
+defm vfneg_v : RVVPseudoVFUnaryBuiltin<"vfsgnjn", "xfd">;
+defm vfabs_v : RVVPseudoVFUnaryBuiltin<"vfsgnjx", "xfd">;
+
+// 13.13. Vector Floating-Point Compare Instructions
+let MaskedPolicyScheme = HasPassthruOperand,
+ HasTailPolicy = false in {
+defm vmfeq : RVVFloatingMaskOutBuiltinSet;
+defm vmfne : RVVFloatingMaskOutBuiltinSet;
+defm vmflt : RVVFloatingMaskOutBuiltinSet;
+defm vmfle : RVVFloatingMaskOutBuiltinSet;
+defm vmfgt : RVVFloatingMaskOutBuiltinSet;
+defm vmfge : RVVFloatingMaskOutBuiltinSet;
+}
+
+// 13.14. Vector Floating-Point Classify Instruction
+let Name = "vfclass_v", UnMaskedPolicyScheme = HasPassthruOperand in
+ def vfclass : RVVOp0Builtin<"Uv", "Uvv", "xfd">;
+
+// 13.15. Vector Floating-Point Merge Instruction
+// C/C++ Operand: (mask, op1, op2, vl), Builtin: (op1, op2, mask, vl)
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ // insert poison passthru
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
+ }] in {
+ defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "fd",
+ [["vvm", "v", "vvvm"]]>;
+ let RequiredFeatures = ["Zvfhmin"] in
+ defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "x",
+ [["vvm", "v", "vvvm"]]>;
+ defm vfmerge : RVVOutOp1BuiltinSet<"vfmerge", "xfd",
+ [["vfm", "v", "vvem"]]>;
+}
+
+// 13.16. Vector Floating-Point Move Instruction
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ SupportOverloading = false,
+ MaskedPolicyScheme = NonePolicy,
+ OverloadedName = "vfmv_v" in
+ defm vfmv_v : RVVOutBuiltinSet<"vfmv_v_f", "xfd",
+ [["f", "v", "ve"]]>;
+
+// 13.17. Single-Width Floating-Point/Integer Type-Convert Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+def vfcvt_rtz_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_rtz_xu">;
+def vfcvt_rtz_x_f_v : RVVConvToSignedBuiltin<"vfcvt_rtz_x">;
+
+// 13.18. Widening Floating-Point/Integer Type-Convert Instructions
+let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ def vfwcvt_rtz_xu_f_v : RVVConvToWidenUnsignedBuiltin<"vfwcvt_rtz_xu">;
+ def vfwcvt_rtz_x_f_v : RVVConvToWidenSignedBuiltin<"vfwcvt_rtz_x">;
+ def vfwcvt_f_xu_v : RVVConvBuiltin<"Fw", "FwUv", "csi", "vfwcvt_f">;
+ def vfwcvt_f_x_v : RVVConvBuiltin<"Fw", "Fwv", "csi", "vfwcvt_f">;
+ def vfwcvt_f_f_v : RVVConvBuiltin<"w", "wv", "f", "vfwcvt_f">;
+ let RequiredFeatures = ["Zvfhmin"] in
+ def vfwcvt_f_f_v_fp16 : RVVConvBuiltin<"w", "wv", "x", "vfwcvt_f"> {
+ let Name = "vfwcvt_f_f_v";
+ let IRName = "vfwcvt_f_f_v";
+ let MaskedIRName = "vfwcvt_f_f_v_mask";
+ }
+}
+
+// 13.19. Narrowing Floating-Point/Integer Type-Convert Instructions
+let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ def vfncvt_rtz_xu_f_w : RVVConvToNarrowingUnsignedBuiltin<"vfncvt_rtz_xu">;
+ def vfncvt_rtz_x_f_w : RVVConvToNarrowingSignedBuiltin<"vfncvt_rtz_x">;
+ def vfncvt_rod_f_f_w : RVVConvBuiltin<"v", "vw", "xf", "vfncvt_rod_f">;
+}
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, frm, vl)
+ // Masked: (passthru, op0, mask, frm, vl, policy)
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ bool HasRoundModeOp = IsMasked ?
+ (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
+ (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
+
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 1]); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 1]); // vl
+ }
+
+ if (IsMasked)
+ Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
+ Operands.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = 1 in {
+ // 14.17. Single-Width Floating-Point/Integer Type-Convert Instructions
+ let OverloadedName = "vfcvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfcvt_x_f_v", "xfd", [["Iv", "Ivvu"]]>;
+ let OverloadedName = "vfcvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfcvt_xu_f_v", "xfd", [["Uv", "Uvvu"]]>;
+ let OverloadedName = "vfcvt_f" in {
+ defm :
+ RVVConvBuiltinSet<"vfcvt_f_x_v", "sil", [["Fv", "Fvvu"]]>;
+ defm :
+ RVVConvBuiltinSet<"vfcvt_f_xu_v", "sil", [["Fv", "FvUvu"]]>;
+ }
+
+ // 13.18. Widening Floating-Point/Integer Type-Convert Instructions
+ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ let OverloadedName = "vfwcvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfwcvt_x_f_v", "xf", [["Iw", "Iwvu"]]>;
+ let OverloadedName = "vfwcvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfwcvt_xu_f_v", "xf", [["Uw", "Uwvu"]]>;
+ }
+ // 13.19. Narrowing Floating-Point/Integer Type-Convert Instructions
+ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ let OverloadedName = "vfncvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfncvt_x_f_w", "csi", [["Iv", "IvFwu"]]>;
+ let OverloadedName = "vfncvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfncvt_xu_f_w", "csi", [["Uv", "UvFwu"]]>;
+ let OverloadedName = "vfncvt_f" in {
+ defm :
+ RVVConvBuiltinSet<"vfncvt_f_x_w", "csi", [["Fv", "Fvwu"]]>;
+ defm :
+ RVVConvBuiltinSet<"vfncvt_f_xu_w", "csi", [["Fv", "FvUwu"]]>;
+ }
+ let OverloadedName = "vfncvt_f" in {
+ defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "f", [["v", "vwu"]]>;
+ let RequiredFeatures = ["Zvfhmin"] in
+ defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "x", [["v", "vwu"]]>;
+ }
+ }
+ }
+
+ // 13.17. Single-Width Floating-Point/Integer Type-Convert Instructions
+ let OverloadedName = "vfcvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfcvt_x_f_v", "xfd", [["Iv", "Ivv"]]>;
+ let OverloadedName = "vfcvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfcvt_xu_f_v", "xfd", [["Uv", "Uvv"]]>;
+ let OverloadedName = "vfcvt_f" in {
+ defm :
+ RVVConvBuiltinSet<"vfcvt_f_x_v", "sil", [["Fv", "Fvv"]]>;
+ defm :
+ RVVConvBuiltinSet<"vfcvt_f_xu_v", "sil", [["Fv", "FvUv"]]>;
+ }
+
+ // 13.18. Widening Floating-Point/Integer Type-Convert Instructions
+ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ let OverloadedName = "vfwcvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfwcvt_x_f_v", "xf", [["Iw", "Iwv"]]>;
+ let OverloadedName = "vfwcvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfwcvt_xu_f_v", "xf", [["Uw", "Uwv"]]>;
+ }
+ // 13.19. Narrowing Floating-Point/Integer Type-Convert Instructions
+ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
+ let OverloadedName = "vfncvt_x" in
+ defm :
+ RVVConvBuiltinSet<"vfncvt_x_f_w", "csi", [["Iv", "IvFw"]]>;
+ let OverloadedName = "vfncvt_xu" in
+ defm :
+ RVVConvBuiltinSet<"vfncvt_xu_f_w", "csi", [["Uv", "UvFw"]]>;
+ let OverloadedName = "vfncvt_f" in {
+ defm :
+ RVVConvBuiltinSet<"vfncvt_f_x_w", "csi", [["Fv", "Fvw"]]>;
+ defm :
+ RVVConvBuiltinSet<"vfncvt_f_xu_w", "csi", [["Fv", "FvUw"]]>;
+ }
+ let OverloadedName = "vfncvt_f" in {
+ defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "f", [["v", "vw"]]>;
+ let RequiredFeatures = ["Zvfhmin"] in
+ defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "x", [["v", "vw"]]>;
+ }
+ }
+}
+}
+
+// 14. Vector Reduction Operations
+// 14.1. Vector Single-Width Integer Reduction Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = HasPassthruOperand,
+ HasMaskPolicy = false in {
+defm vredsum : RVVIntReductionBuiltinSet;
+defm vredmaxu : RVVUnsignedReductionBuiltin;
+defm vredmax : RVVSignedReductionBuiltin;
+defm vredminu : RVVUnsignedReductionBuiltin;
+defm vredmin : RVVSignedReductionBuiltin;
+defm vredand : RVVIntReductionBuiltinSet;
+defm vredor : RVVIntReductionBuiltinSet;
+defm vredxor : RVVIntReductionBuiltinSet;
+
+// 14.2. Vector Widening Integer Reduction Instructions
+// Vector Widening Integer Reduction Operations
+let HasMaskedOffOperand = true in {
+ defm vwredsum : RVVOutOp0BuiltinSet<"vwredsum", "csi",
+ [["vs", "vSw", "SwvSw"]]>;
+ defm vwredsumu : RVVOutOp0BuiltinSet<"vwredsumu", "csi",
+ [["vs", "UvUSw", "USwUvUSw"]]>;
+}
+
+// 14.3. Vector Single-Width Floating-Point Reduction Instructions
+defm vfredmax : RVVFloatingReductionBuiltin;
+defm vfredmin : RVVFloatingReductionBuiltin;
+let ManualCodegen = [{
+ {
+ // LLVM intrinsic
+ // Unmasked: (passthru, op0, op1, round_mode, vl)
+ // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
+
+ SmallVector<llvm::Value*, 7> Operands;
+ bool HasMaskedOff = !(
+ (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
+ (!IsMasked && PolicyAttrs & RVV_VTA));
+ bool HasRoundModeOp = IsMasked ?
+ (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
+ (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
+
+ unsigned Offset = IsMasked ?
+ (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
+
+ if (!HasMaskedOff)
+ Operands.push_back(llvm::PoisonValue::get(ResultType));
+ else
+ Operands.push_back(Ops[IsMasked ? 1 : 0]);
+
+ Operands.push_back(Ops[Offset]); // op0
+ Operands.push_back(Ops[Offset + 1]); // op1
+
+ if (IsMasked)
+ Operands.push_back(Ops[0]); // mask
+
+ if (HasRoundModeOp) {
+ Operands.push_back(Ops[Offset + 2]); // frm
+ Operands.push_back(Ops[Offset + 3]); // vl
+ } else {
+ Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
+ Operands.push_back(Ops[Offset + 2]); // vl
+ }
+
+ IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
+ Ops.back()->getType()};
+ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
+ return Builder.CreateCall(F, Operands, "");
+ }
+}] in {
+ let HasFRMRoundModeOp = 1 in {
+ // 14.3. Vector Single-Width Floating-Point Reduction Instructions
+ defm vfredusum : RVVFloatingReductionBuiltinRoundingMode;
+ defm vfredosum : RVVFloatingReductionBuiltinRoundingMode;
+
+ // 14.4. Vector Widening Floating-Point Reduction Instructions
+ defm vfwredusum : RVVFloatingWidenReductionBuiltinRoundingMode;
+ defm vfwredosum : RVVFloatingWidenReductionBuiltinRoundingMode;
+ }
+ // 14.3. Vector Single-Width Floating-Point Reduction Instructions
+ defm vfredusum : RVVFloatingReductionBuiltin;
+ defm vfredosum : RVVFloatingReductionBuiltin;
+
+ // 14.4. Vector Widening Floating-Point Reduction Instructions
+ defm vfwredusum : RVVFloatingWidenReductionBuiltin;
+ defm vfwredosum : RVVFloatingWidenReductionBuiltin;
+}
+}
+
+// 15. Vector Mask Instructions
+// 15.1. Vector Mask-Register Logical Instructions
+def vmand : RVVMaskBinBuiltin;
+def vmnand : RVVMaskBinBuiltin;
+def vmandn : RVVMaskBinBuiltin;
+def vmxor : RVVMaskBinBuiltin;
+def vmor : RVVMaskBinBuiltin;
+def vmnor : RVVMaskBinBuiltin;
+def vmorn : RVVMaskBinBuiltin;
+def vmxnor : RVVMaskBinBuiltin;
+// pseudoinstructions
+def vmclr : RVVMaskNullaryBuiltin;
+def vmset : RVVMaskNullaryBuiltin;
+defm vmmv_m : RVVPseudoMaskBuiltin<"vmand", "c">;
+defm vmnot_m : RVVPseudoMaskBuiltin<"vmnand", "c">;
+
+let MaskedPolicyScheme = NonePolicy in {
+// 15.2. Vector count population in mask vcpop.m
+def vcpop : RVVMaskOp0Builtin<"um">;
+
+// 15.3. vfirst find-first-set mask bit
+def vfirst : RVVMaskOp0Builtin<"lm">;
+}
+
+let MaskedPolicyScheme = HasPassthruOperand,
+ HasTailPolicy = false in {
+// 15.4. vmsbf.m set-before-first mask bit
+def vmsbf : RVVMaskUnaryBuiltin;
+
+// 15.5. vmsif.m set-including-first mask bit
+def vmsif : RVVMaskUnaryBuiltin;
+
+// 15.6. vmsof.m set-only-first mask bit
+def vmsof : RVVMaskUnaryBuiltin;
+}
+
+let UnMaskedPolicyScheme = HasPassthruOperand, SupportOverloading = false in {
+ // 15.8. Vector Iota Instruction
+ defm viota : RVVOutBuiltinSet<"viota", "csil", [["m", "Uv", "Uvm"]]>;
+
+ // 15.9. Vector Element Index Instruction
+ defm vid : RVVOutBuiltinSet<"vid", "csil", [["v", "v", "v"],
+ ["v", "Uv", "Uv"]]>;
+}
+
+// 16. Vector Permutation Instructions
+// 16.1. Integer Scalar Move Instructions
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
+ let HasVL = false, OverloadedName = "vmv_x" in
+ defm vmv_x : RVVOp0BuiltinSet<"vmv_x_s", "csil",
+ [["s", "ve", "ev"],
+ ["s", "UvUe", "UeUv"]]>;
+ let OverloadedName = "vmv_s",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ SupportOverloading = false in
+ defm vmv_s : RVVOutBuiltinSet<"vmv_s_x", "csil",
+ [["x", "v", "ve"],
+ ["x", "Uv", "UvUe"]]>;
+}
+
+// 16.2. Floating-Point Scalar Move Instructions
+let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
+ let HasVL = false, OverloadedName = "vfmv_f" in
+ defm vfmv_f : RVVOp0BuiltinSet<"vfmv_f_s", "xfd",
+ [["s", "ve", "ev"]]>;
+ let OverloadedName = "vfmv_s",
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ SupportOverloading = false in
+ defm vfmv_s : RVVOutBuiltinSet<"vfmv_s_f", "xfd",
+ [["f", "v", "ve"],
+ ["x", "Uv", "UvUe"]]>;
+}
+
+// 16.3. Vector Slide Instructions
+// 16.3.1. Vector Slideup Instructions
+defm vslideup : RVVSlideUpBuiltinSet;
+// 16.3.2. Vector Slidedown Instructions
+defm vslidedown : RVVSlideDownBuiltinSet;
+
+// 16.3.3. Vector Slide1up Instructions
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+defm vslide1up : RVVSlideOneBuiltinSet;
+defm vfslide1up : RVVFloatingBinVFBuiltinSet;
+
+// 16.3.4. Vector Slide1down Instruction
+defm vslide1down : RVVSlideOneBuiltinSet;
+defm vfslide1down : RVVFloatingBinVFBuiltinSet;
+
+// 16.4. Vector Register Gather Instructions
+// signed and floating type
+defm vrgather : RVVOutBuiltinSet<"vrgather_vv", "csilxfd",
+ [["vv", "v", "vvUv"]]>;
+defm vrgather : RVVOutBuiltinSet<"vrgather_vx", "csilxfd",
+ [["vx", "v", "vvz"]]>;
+defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csilxfd",
+ [["vv", "v", "vv(Log2EEW:4)Uv"]]>;
+// unsigned type
+defm vrgather : RVVOutBuiltinSet<"vrgather_vv", "csil",
+ [["vv", "Uv", "UvUvUv"]]>;
+defm vrgather : RVVOutBuiltinSet<"vrgather_vx", "csil",
+ [["vx", "Uv", "UvUvz"]]>;
+defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csil",
+ [["vv", "Uv", "UvUv(Log2EEW:4)Uv"]]>;
+}
+
+// 16.5. Vector Compress Instruction
+let HasMasked = false,
+ UnMaskedPolicyScheme = HasPassthruOperand,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ // insert poison passthru
+ if (PolicyAttrs & RVV_VTA)
+ Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
+ IntrinsicTypes = {ResultType, Ops.back()->getType()};
+ }] in {
+ // signed and floating type
+ defm vcompress : RVVOutBuiltinSet<"vcompress", "csilxfd",
+ [["vm", "v", "vvm"]]>;
+ // unsigned type
+ defm vcompress : RVVOutBuiltinSet<"vcompress", "csil",
+ [["vm", "Uv", "UvUvm"]]>;
+}
+
+// Miscellaneous
+let HasMasked = false, HasVL = false, IRName = "" in {
+ let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ if (ResultType->isIntOrIntVectorTy(1) ||
+ Ops[0]->getType()->isIntOrIntVectorTy(1)) {
+ assert(isa<ScalableVectorType>(ResultType) &&
+ isa<ScalableVectorType>(Ops[0]->getType()));
+
+ LLVMContext &Context = CGM.getLLVMContext();
+ ScalableVectorType *Boolean64Ty =
+ ScalableVectorType::get(llvm::Type::getInt1Ty(Context), 64);
+
+ if (ResultType->isIntOrIntVectorTy(1)) {
+ // Casting from m1 vector integer -> vector boolean
+ // Ex: <vscale x 8 x i8>
+ // --(bitcast)--------> <vscale x 64 x i1>
+ // --(vector_extract)-> <vscale x 8 x i1>
+ llvm::Value *BitCast = Builder.CreateBitCast(Ops[0], Boolean64Ty);
+ return Builder.CreateExtractVector(ResultType, BitCast,
+ ConstantInt::get(Int64Ty, 0));
+ } else {
+ // Casting from vector boolean -> m1 vector integer
+ // Ex: <vscale x 1 x i1>
+ // --(vector_insert)-> <vscale x 64 x i1>
+ // --(bitcast)-------> <vscale x 8 x i8>
+ llvm::Value *Boolean64Val =
+ Builder.CreateInsertVector(Boolean64Ty,
+ llvm::PoisonValue::get(Boolean64Ty),
+ Ops[0],
+ ConstantInt::get(Int64Ty, 0));
+ return Builder.CreateBitCast(Boolean64Val, ResultType);
+ }
+ }
+ return Builder.CreateBitCast(Ops[0], ResultType);
+ }] in {
+ // Reinterpret between different type under the same SEW and LMUL
+ def vreinterpret_i_u : RVVBuiltin<"Uvv", "vUv", "csil", "v">;
+ def vreinterpret_i_f : RVVBuiltin<"Fvv", "vFv", "il", "v">;
+ def vreinterpret_u_i : RVVBuiltin<"vUv", "Uvv", "csil", "Uv">;
+ def vreinterpret_u_f : RVVBuiltin<"FvUv", "UvFv", "il", "Uv">;
+ def vreinterpret_f_i : RVVBuiltin<"vFv", "Fvv", "il", "Fv">;
+ def vreinterpret_f_u : RVVBuiltin<"UvFv", "FvUv", "il", "Fv">;
+ let RequiredFeatures = ["Zvfhmin"] in {
+ def vreinterpret_i_h : RVVBuiltin<"Fvv", "vFv", "s", "v">;
+ def vreinterpret_u_h : RVVBuiltin<"FvUv", "UvFv", "s", "Uv">;
+ def vreinterpret_h_i : RVVBuiltin<"vFv", "Fvv", "s", "Fv">;
+ def vreinterpret_h_u : RVVBuiltin<"UvFv", "FvUv", "s", "Fv">;
+ }
+
+ // Reinterpret between different SEW under the same LMUL
+ foreach dst_sew = ["(FixedSEW:8)", "(FixedSEW:16)", "(FixedSEW:32)",
+ "(FixedSEW:64)"] in {
+ def vreinterpret_i_ # dst_sew : RVVBuiltin<"v" # dst_sew # "v",
+ dst_sew # "vv", "csil", dst_sew # "v">;
+ def vreinterpret_u_ # dst_sew : RVVBuiltin<"Uv" # dst_sew # "Uv",
+ dst_sew # "UvUv", "csil", dst_sew # "Uv">;
+ }
+
+ // Existing users of FixedSEW - the reinterpretation between different SEW
+ // and same LMUL has the implicit assumption that if FixedSEW is set to the
+ // given element width, then the type will be identified as invalid, thus
+ // skipping definition of reinterpret of SEW=8 to SEW=8. However this blocks
+ // our usage here of defining all possible combinations of a fixed SEW to
+ // any boolean. So we need to separately define SEW=8 here.
+ // Reinterpret from LMUL=1 integer type to vector boolean type
+ def vreintrepret_m1_b8_signed :
+ RVVBuiltin<"Svm",
+ "mSv",
+ "c", "m">;
+ def vreintrepret_m1_b8_usigned :
+ RVVBuiltin<"USvm",
+ "mUSv",
+ "c", "m">;
+
+ // Reinterpret from vector boolean type to LMUL=1 integer type
+ def vreintrepret_b8_m1_signed :
+ RVVBuiltin<"mSv",
+ "Svm",
+ "c", "Sv">;
+ def vreintrepret_b8_m1_usigned :
+ RVVBuiltin<"mUSv",
+ "USvm",
+ "c", "USv">;
+
+ foreach dst_sew = ["16", "32", "64"] in {
+ // Reinterpret from LMUL=1 integer type to vector boolean type
+ def vreinterpret_m1_b # dst_sew # _signed:
+ RVVBuiltin<"(FixedSEW:" # dst_sew # ")Svm",
+ "m(FixedSEW:" # dst_sew # ")Sv",
+ "c", "m">;
+ def vreinterpret_m1_b # dst_sew # _unsigned:
+ RVVBuiltin<"(FixedSEW:" # dst_sew # ")USvm",
+ "m(FixedSEW:" # dst_sew # ")USv",
+ "c", "m">;
+ // Reinterpret from vector boolean type to LMUL=1 integer type
+ def vreinterpret_b # dst_sew # _m1_signed:
+ RVVBuiltin<"m(FixedSEW:" # dst_sew # ")Sv",
+ "(FixedSEW:" # dst_sew # ")Svm",
+ "c", "(FixedSEW:" # dst_sew # ")Sv">;
+ def vreinterpret_b # dst_sew # _m1_unsigned:
+ RVVBuiltin<"m(FixedSEW:" # dst_sew # ")USv",
+ "(FixedSEW:" # dst_sew # ")USvm",
+ "c", "(FixedSEW:" # dst_sew # ")USv">;
+ }
+ }
+
+ let Name = "vundefined", SupportOverloading = false,
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ return llvm::PoisonValue::get(ResultType);
+ }] in {
+ def vundefined : RVVBuiltin<"v", "v", "csilxfd">;
+ def vundefined_u : RVVBuiltin<"Uv", "Uv", "csil">;
+
+ foreach nf = NFList in {
+ let NF = nf in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "v", T # "v", "csilxfd">;
+ def : RVVBuiltin<T # "Uv", T # "Uv", "csil">;
+ }
+ }
+
+ }
+
+ // LMUL truncation
+ // C/C++ Operand: VecTy, IR Operand: VecTy, Index
+ let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc",
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{ {
+ return Builder.CreateExtractVector(ResultType, Ops[0],
+ ConstantInt::get(Int64Ty, 0));
+ } }] in {
+ foreach dst_lmul = ["(SFixedLog2LMUL:-3)", "(SFixedLog2LMUL:-2)", "(SFixedLog2LMUL:-1)",
+ "(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in {
+ def vlmul_trunc # dst_lmul : RVVBuiltin<"v" # dst_lmul # "v",
+ dst_lmul # "vv", "csilxfd", dst_lmul # "v">;
+ def vlmul_trunc_u # dst_lmul : RVVBuiltin<"Uv" # dst_lmul # "Uv",
+ dst_lmul # "UvUv", "csil", dst_lmul # "Uv">;
+ }
+ }
+
+ // LMUL extension
+ // C/C++ Operand: SubVecTy, IR Operand: VecTy, SubVecTy, Index
+ let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext",
+ MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ return Builder.CreateInsertVector(ResultType,
+ llvm::PoisonValue::get(ResultType),
+ Ops[0], ConstantInt::get(Int64Ty, 0));
+ }] in {
+ foreach dst_lmul = ["(LFixedLog2LMUL:-2)", "(LFixedLog2LMUL:-1)", "(LFixedLog2LMUL:-0)",
+ "(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in {
+ def vlmul_ext # dst_lmul : RVVBuiltin<"v" # dst_lmul # "v",
+ dst_lmul # "vv", "csilxfd", dst_lmul # "v">;
+ def vlmul_ext_u # dst_lmul : RVVBuiltin<"Uv" # dst_lmul # "Uv",
+ dst_lmul # "UvUv", "csil", dst_lmul # "Uv">;
+ }
+ }
+
+ let Name = "vget_v", MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ {
+ if (isa<StructType>(Ops[0]->getType())) // For tuple type
+ // Extract value from index (operand 1) of vtuple (operand 0)
+ return Builder.CreateExtractValue(
+ Ops[0],
+ {(unsigned)cast<ConstantInt>(Ops[1])->getZExtValue()});
+ auto *VecTy = cast<ScalableVectorType>(ResultType);
+ auto *OpVecTy = cast<ScalableVectorType>(Ops[0]->getType());
+ // Mask to only valid indices.
+ unsigned MaxIndex = OpVecTy->getMinNumElements() / VecTy->getMinNumElements();
+ assert(isPowerOf2_32(MaxIndex));
+ Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
+ Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
+ Ops[1] = Builder.CreateMul(Ops[1],
+ ConstantInt::get(Ops[1]->getType(),
+ VecTy->getMinNumElements()));
+ return Builder.CreateExtractVector(ResultType, Ops[0], Ops[1]);
+ }
+ }] in {
+ foreach dst_lmul = ["(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in {
+ def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilxfd", dst_lmul # "v">;
+ def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "UvUvKz", "csil", dst_lmul # "Uv">;
+ }
+ foreach nf = NFList in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<T # "vv", "v" # T # "vKz", "csilxfd", "v">;
+ def : RVVBuiltin<T # "UvUv", "Uv" # T # "UvKz", "csil", "Uv">;
+ }
+ }
+
+ let Name = "vset_v", MaskedPolicyScheme = NonePolicy,
+ ManualCodegen = [{
+ {
+ if (isa<StructType>(ResultType)) // For tuple type
+ // Insert value (operand 2) into index (operand 1) of vtuple (operand 0)
+ return Builder.CreateInsertValue(
+ Ops[0], Ops[2],
+ {(unsigned)cast<ConstantInt>(Ops[1])->getZExtValue()});
+ auto *ResVecTy = cast<ScalableVectorType>(ResultType);
+ auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType());
+ // Mask to only valid indices.
+ unsigned MaxIndex = ResVecTy->getMinNumElements() / VecTy->getMinNumElements();
+ assert(isPowerOf2_32(MaxIndex));
+ Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
+ Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
+ Ops[1] = Builder.CreateMul(Ops[1],
+ ConstantInt::get(Ops[1]->getType(),
+ VecTy->getMinNumElements()));
+ return Builder.CreateInsertVector(ResultType, Ops[0], Ops[2], Ops[1]);
+ }
+ }] in {
+ foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in {
+ def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfd">;
+ def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "Uv" # dst_lmul #"UvKzUv", "csil">;
+ }
+ foreach nf = NFList in {
+ defvar T = "(Tuple:" # nf # ")";
+ def : RVVBuiltin<"v" # T # "v", T # "v" # T # "vKzv", "csilxfd">;
+ def : RVVBuiltin<"Uv" # T # "Uv", T # "Uv" # T # "UvKzUv", "csil">;
+ }
+ }
+
+ let Name = "vcreate_v",
+ UnMaskedPolicyScheme = NonePolicy,
+ MaskedPolicyScheme = NonePolicy,
+ SupportOverloading = false,
+ ManualCodegen = [{
+ {
+ if (isa<StructType>(ResultType)) {
+ unsigned NF = cast<StructType>(ResultType)->getNumElements();
+ llvm::Value *ReturnTuple = llvm::PoisonValue::get(ResultType);
+ for (unsigned I = 0; I < NF; ++I) {
+ ReturnTuple = Builder.CreateInsertValue(ReturnTuple, Ops[I], {I});
+ }
+ return ReturnTuple;
+ }
+ llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType);
+ auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType());
+ for (unsigned I = 0, N = Ops.size(); I < N; ++I) {
+ llvm::Value *Idx =
+ ConstantInt::get(Builder.getInt64Ty(),
+ VecTy->getMinNumElements() * I);
+ ReturnVector =
+ Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx);
+ }
+ return ReturnVector;
+ }
+ }] in {
+
+ defm : RVVNonTupleVCreateBuiltin<1, [0]>;
+ defm : RVVNonTupleVCreateBuiltin<2, [0, 1]>;
+ defm : RVVNonTupleVCreateBuiltin<3, [0, 1, 2]>;
+
+ foreach nf = NFList in {
+ let NF = nf in {
+ defvar T = "(Tuple:" # nf # ")";
+ defvar V = VString<nf, /*signed=*/true>.S;
+ defvar UV = VString<nf, /*signed=*/false>.S;
+ def : RVVBuiltin<T # "v", T # "v" # V, "csilxfd">;
+ def : RVVBuiltin<T # "Uv", T # "Uv" # UV, "csil">;
+ }
+ }
+ }
+}
+
+multiclass RVVOutBuiltinSetZvbb {
+ let OverloadedName = NAME in
+ defm "" : RVVOutBuiltinSet<NAME, "csil", [["v", "v", "vv"],
+ ["v", "Uv", "UvUv"]]>;
+}
+
+multiclass RVVOutBuiltinSetZvk<bit HasVV = 1, bit HasVS = 1> {
+ // vaesz only has 'vs' and vgmul only has 'vv' and they do not have ambiguous
+ // prototypes like other zvkned instructions (e.g. vaesdf), so we don't
+ // need to encode the operand mnemonics into its intrinsic function name.
+ if HasVV then {
+ defvar name = NAME # !if(!eq(NAME, "vgmul"), "", "_vv");
+ let OverloadedName = name in
+ defm "" : RVVOutBuiltinSet<NAME # "_vv", "i",
+ [["vv", "Uv", "UvUvUv"]]>;
+ }
+
+ if HasVS then {
+ foreach vs2_lmul = ["(SEFixedLog2LMUL:-1)", "(SEFixedLog2LMUL:0)",
+ "(SEFixedLog2LMUL:1)", "(SEFixedLog2LMUL:2)",
+ "(SEFixedLog2LMUL:3)"] in {
+ defvar name = NAME # !if(!eq(NAME, "vaesz"), "", "_vs");
+ let OverloadedName = name, IRName = NAME # "_vs", Name = NAME # "_vs",
+ IntrinsicTypes = [-1, 1] in
+ def NAME # vs2_lmul
+ : RVVBuiltin<vs2_lmul # "UvUv", "UvUv" # vs2_lmul # "Uv", "i">;
+ }
+ }
+}
+
+multiclass RVVOutOp2BuiltinSetVVZvk<string type_range = "i">
+ : RVVOutOp2BuiltinSet<NAME, type_range, [["vv", "Uv", "UvUvUvUv"]]>;
+
+multiclass RVVOutOp2BuiltinSetVIZvk<string type_range = "i">
+ : RVVOutOp2BuiltinSet<NAME, type_range, [["vi", "Uv", "UvUvUvKz"]]>;
+
+multiclass RVVSignedWidenBinBuiltinSetVwsll
+ : RVVWidenBuiltinSet<NAME, "csi",
+ [["vv", "Uw", "UwUvUv"],
+ ["vx", "Uw", "UwUvz"]]>;
+
+let UnMaskedPolicyScheme = HasPassthruOperand in {
+ // zvkb
+ let RequiredFeatures = ["Zvkb", "Experimental"] in {
+ defm vandn : RVVUnsignedBinBuiltinSet;
+ defm vbrev8 : RVVOutBuiltinSetZvbb;
+ defm vrev8 : RVVOutBuiltinSetZvbb;
+ defm vrol : RVVUnsignedShiftBuiltinSet;
+ defm vror : RVVUnsignedShiftBuiltinSet;
+ }
+
+ // zvbb
+ let RequiredFeatures = ["Zvbb", "Experimental"] in {
+ defm vbrev : RVVOutBuiltinSetZvbb;
+ defm vclz : RVVOutBuiltinSetZvbb;
+ defm vctz : RVVOutBuiltinSetZvbb;
+ defm vcpopv : RVVOutBuiltinSetZvbb;
+ let OverloadedName = "vwsll" in
+ defm vwsll : RVVSignedWidenBinBuiltinSetVwsll;
+ }
+
+ // zvbc
+ let RequiredFeatures = ["Zvbc", "Experimental"] in {
+ defm vclmul : RVVInt64BinBuiltinSet;
+ defm vclmulh : RVVInt64BinBuiltinSet;
+ }
+}
+
+let UnMaskedPolicyScheme = HasPolicyOperand, HasMasked = false in {
+ // zvkg
+ let RequiredFeatures = ["Zvkg", "Experimental"] in {
+ defm vghsh : RVVOutOp2BuiltinSetVVZvk;
+ defm vgmul : RVVOutBuiltinSetZvk<HasVV=1, HasVS=0>;
+ }
+
+ // zvkned
+ let RequiredFeatures = ["Zvkned", "Experimental"] in {
+ defm vaesdf : RVVOutBuiltinSetZvk;
+ defm vaesdm : RVVOutBuiltinSetZvk;
+ defm vaesef : RVVOutBuiltinSetZvk;
+ defm vaesem : RVVOutBuiltinSetZvk;
+ let UnMaskedPolicyScheme = HasPassthruOperand in
+ defm vaeskf1 : RVVOutOp1BuiltinSet<"vaeskf1", "i", [["vi", "Uv", "UvUvKz"]]>;
+ defm vaeskf2 : RVVOutOp2BuiltinSetVIZvk;
+ defm vaesz : RVVOutBuiltinSetZvk<HasVV=0>;
+ }
+
+ // zvknha
+ let RequiredFeatures = ["Zvknha", "Experimental"] in {
+ defm vsha2ch : RVVOutOp2BuiltinSetVVZvk<"i">;
+ defm vsha2cl : RVVOutOp2BuiltinSetVVZvk<"i">;
+ defm vsha2ms : RVVOutOp2BuiltinSetVVZvk<"i">;
+ }
+
+ // zvknhb
+ let RequiredFeatures = ["Zvknhb", "Experimental"] in {
+ defm vsha2ch : RVVOutOp2BuiltinSetVVZvk<"il">;
+ defm vsha2cl : RVVOutOp2BuiltinSetVVZvk<"il">;
+ defm vsha2ms : RVVOutOp2BuiltinSetVVZvk<"il">;
+ }
+
+ // zvksed
+ let RequiredFeatures = ["Zvksed", "Experimental"] in {
+ let UnMaskedPolicyScheme = HasPassthruOperand in
+ defm vsm4k : RVVOutOp1BuiltinSet<"vsm4k", "i", [["vi", "Uv", "UvUvKz"]]>;
+ defm vsm4r : RVVOutBuiltinSetZvk;
+ }
+
+ // zvksh
+ let RequiredFeatures = ["Zvksh", "Experimental"] in {
+ defm vsm3c : RVVOutOp2BuiltinSetVIZvk;
+ let UnMaskedPolicyScheme = HasPassthruOperand in
+ defm vsm3me : RVVOutOp1BuiltinSet<"vsm3me", "i", [["vv", "Uv", "UvUvUv"]]>;
+ }
+}