https://github.com/kito-cheng created https://github.com/llvm/llvm-project/pull/154906
Extract ManualCodegen blocks from riscv_vector.td to dedicated helper functions in RISCV.cpp to improve compilation times and code organization. This refactoring: - Reduces riscv_vector_builtin_cg.inc from ~70,000 lines to ~30,000 lines - Extracts lots of ManualCodegen blocks into helper functions in RISCV.cpp - Moves complex code generation logic from TableGen to C++ - Marks extracted functions with LLVM_ATTRIBUTE_NOINLINE to prevent excessive inlining in EmitRISCVBuiltinExpr's large switch statement, which would cause compilation time to increase significantly Performance Impact on AMD Ryzen 9 3950X 16-Core with SSD (Release build) with GCC 11: Before: real 0m22.577s, user 0m0.498s, sys 0m0.152s After: real 1m4.560s, user 0m0.529s, sys 0m0.175s Which reduced around 65% of compilation time. During this refactoring, I also found few more opportunities to optimize and simplify the code generation logic, but I think leave to next PR since it already change a lot of code. Fix #88368 >From 28d711631005958ba1efe80dcfdeb9010397cf19 Mon Sep 17 00:00:00 2001 From: Kito Cheng <kito.ch...@sifive.com> Date: Thu, 21 Aug 2025 17:55:14 +0800 Subject: [PATCH] [RISCV] Refactor RVV builtin code generation for reduce compilation time Extract ManualCodegen blocks from riscv_vector.td to dedicated helper functions in RISCV.cpp to improve compilation times and code organization. This refactoring: - Reduces riscv_vector_builtin_cg.inc from ~70,000 lines to ~30,000 lines - Extracts 35+ ManualCodegen blocks into 32 helper functions - Moves complex code generation logic from TableGen to C++ - Marks extracted functions with LLVM_ATTRIBUTE_NOINLINE to prevent excessive inlining in EmitRISCVBuiltinExpr's large switch statement, which would cause compilation time to increase significantly Performance Impact on AMD Ryzen 9 3950X 16-Core with SSD (Release build) with GCC 11: Before: real 0m22.577s, user 0m0.498s, sys 0m0.152s After: real 1m4.560s, user 0m0.529s, sys 0m0.175s Which reduced around 65% of compilation time. During this refactoring, I also found few more opportunities to optimize and simplify the code generation logic, but I think leave to next PR since it already change a lot of code. Fix #88368 --- clang/include/clang/Basic/riscv_vector.td | 762 ++-------------- clang/lib/CodeGen/TargetBuiltins/RISCV.cpp | 956 ++++++++++++++++++++- 2 files changed, 1029 insertions(+), 689 deletions(-) diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index c1de2bfe4243d..cc5ab38f8f960 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -56,34 +56,8 @@ multiclass RVVVLEFFBuiltin<list<string> types> { 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(), Ops[2]->getType()}; - } else { - if (PolicyAttrs & RVV_VTA) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - IntrinsicTypes = {ResultType, Ops[3]->getType(), Ops[1]->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; - } + return emitRVVVLEFFBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = types in { def : RVVBuiltin<"v", "vPCePz", type>; @@ -139,17 +113,8 @@ multiclass RVVIndexedLoad<string op> { 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[1]->getType(), Ops[3]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()}; + return emitRVVVSEMaskBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { class RVVVSEMaskBuiltin : RVVBuiltin<"m", "0PUem", "c"> { let Name = "vsm_v"; @@ -177,17 +142,8 @@ multiclass RVVVSSEBuiltin<list<string> types> { 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[1]->getType(), Ops[4]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; + return emitRVVVSSEBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = types in { def : RVVBuiltin<"v", "0Petv", type>; @@ -202,17 +158,8 @@ 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[1]->getType(), Ops[2]->getType(), Ops[4]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[3]->getType()}; + return emitRVVIndexedStoreBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach type = TypeList in { foreach eew_list = EEWList[0-2] in { @@ -367,28 +314,8 @@ multiclass RVVPseudoUnaryBuiltin<string IR, string type_range> { 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; - } + return emitRVVPseudoUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; } @@ -400,32 +327,8 @@ multiclass RVVPseudoVNotBuiltin<string IR, string type_range> { 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; - } + return emitRVVPseudoVNotBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; def : RVVBuiltin<"Uv", "UvUv", type_range>; @@ -437,13 +340,8 @@ multiclass RVVPseudoMaskBuiltin<string IR, string type_range> { IRName = IR, HasMasked = false, ManualCodegen = [{ - { - // op1, vl - IntrinsicTypes = {ResultType, - Ops[1]->getType()}; - Ops.insert(Ops.begin() + 1, Ops[0]); - break; - } + return emitRVVPseudoMaskBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"m", "mm", type_range>; } @@ -455,28 +353,8 @@ multiclass RVVPseudoVFUnaryBuiltin<string IR, string type_range> { 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; - } + return emitRVVPseudoVFUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { def : RVVBuiltin<"v", "vv", type_range>; } @@ -490,33 +368,8 @@ multiclass RVVPseudoVWCVTBuiltin<string IR, string MName, string type_range, 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>(Ops[1]->getType())->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; - } + return emitRVVPseudoVWCVTBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach s_p = suffixes_prototypes in { def : RVVBuiltin<s_p[0], s_p[1], type_range>; @@ -532,32 +385,8 @@ multiclass RVVPseudoVNCVTBuiltin<string IR, string MName, string type_range, 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; - } + return emitRVVPseudoVNCVTBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach s_p = suffixes_prototypes in { def : RVVBuiltin<s_p[0], s_p[1], type_range>; @@ -575,17 +404,8 @@ 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); - } + return emitRVVVlenbBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { def vlenb : RVVBuiltin<"", "u", "i">; @@ -660,7 +480,10 @@ let HasBuiltinAlias = false, HasMasked = false, MaskedPolicyScheme = NonePolicy, Log2LMUL = [0], - ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type + ManualCodegen = [{ + return emitRVVVsetvliBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); + }] in // Set XLEN type { def vsetvli : RVVBuiltin<"", "zzKzKz", "i">; def vsetvlimax : RVVBuiltin<"", "zKzKz", "i">; @@ -720,35 +543,10 @@ multiclass RVVUnitStridedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[0]->getType(), Ops.back()->getType()}; - else - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()}; - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if (NoPassthru) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } - }] in { + return emitRVVUnitStridedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, + IsMasked, SegInstSEW); + }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCe", type>; if !not(IsFloat<type>.val) then { @@ -776,29 +574,10 @@ multiclass RVVUnitStridedSegStoreTuple<string op> { NF = nf, HasMaskedOffOperand = false, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, v_tuple, vl) - // Intrinsic: (tuple, ptr, mask, vl, SegInstSEW) - // Unmasked - // Builtin: (ptr, v_tuple, vl) - // Intrinsic: (tuple, ptr, vl, SegInstSEW) - - if (IsMasked) - std::swap(Ops[0], Ops[2]); - else - std::swap(Ops[0], Ops[1]); - - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[3]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()}; - - break; - } - }] in { + return emitRVVUnitStridedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, + IsMasked, SegInstSEW); + }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pe" # T # "v", type>; if !not(IsFloat<type>.val) then { @@ -825,47 +604,9 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> { MaskedIRName = op # nf # "ff_mask", NF = nf, ManualCodegen = [{ - { - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType(), Ops[0]->getType()}; - else - IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()}; - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if (NoPassthru) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - Value *NewVL = Ops[2]; - Ops.erase(Ops.begin() + 2); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - - llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); - // Get alignment from the new vl operand - clang::CharUnits Align = - CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType()); - - llvm::Value *ReturnTuple = Builder.CreateExtractValue(LoadValue, 0); - - // Store new_vl - llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1); - Builder.CreateStore(V, Address(NewVL, V->getType(), Align)); - - if (ReturnValue.isNull()) - return ReturnTuple; - else - return Builder.CreateStore(ReturnTuple, ReturnValue.getValue()); - } + return emitRVVUnitStridedSegLoadFFTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCePz", type>; @@ -893,34 +634,9 @@ multiclass RVVStridedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType(), Ops[0]->getType()}; - else - IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()}; - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if (NoPassthru) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); - - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } + return emitRVVStridedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCet", type>; @@ -950,27 +666,9 @@ multiclass RVVStridedSegStoreTuple<string op> { HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, stride, v_tuple, vl) - // Intrinsic: (tuple, ptr, stride, mask, vl, SegInstSEW) - // Unmasked - // Builtin: (ptr, stride, v_tuple, vl) - // Intrinsic: (tuple, ptr, stride, vl, SegInstSEW) - - if (IsMasked) - std::swap(Ops[0], Ops[3]); - else - std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); - - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType(), Ops[3]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; - break; - } + return emitRVVStridedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pet" # T # "v", type>; @@ -993,37 +691,9 @@ multiclass RVVIndexedSegLoadTuple<string op> { MaskedIRName = op # nf # "_mask", NF = nf, ManualCodegen = [{ - { - bool NoPassthru = - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | - (!IsMasked && (PolicyAttrs & RVV_VTA)); - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - if (NoPassthru) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {ResultType, Ops[1]->getType(), - Ops[2]->getType(), - Ops[3]->getType(), - Ops[4]->getType()}; - else - IntrinsicTypes = {ResultType, Ops[1]->getType(), - Ops[2]->getType(), - Ops[3]->getType()}; - llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); - llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); - - if (ReturnValue.isNull()) - return LoadValue; - else - return Builder.CreateStore(LoadValue, ReturnValue.getValue()); - } + return emitRVVIndexedSegLoadTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", T # "vPCe" # eew_type # "Uv", type>; @@ -1049,29 +719,9 @@ multiclass RVVIndexedSegStoreTuple<string op> { HasMaskedOffOperand = false, MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - // Masked - // Builtin: (mask, ptr, index, v_tuple, vl) - // Intrinsic: (tuple, ptr, index, mask, vl, SegInstSEW) - // Unmasked - // Builtin: (ptr, index, v_tuple, vl) - // Intrinsic: (tuple, ptr, index, vl, SegInstSEW) - - if (IsMasked) - std::swap(Ops[0], Ops[3]); - else - std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); - - Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); - - if (IsMasked) - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), - Ops[3]->getType(), Ops[4]->getType()}; - else - IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), - Ops[3]->getType()}; - break; - } + return emitRVVIndexedSegStoreTupleBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); }] in { defvar T = "(Tuple:" # nf # ")"; def : RVVBuiltin<T # "v", "0Pe" # eew_type # "Uv" # T # "v", type>; @@ -1312,25 +962,8 @@ 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) - - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()}; - break; + return emitRVVAveragingBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); } }] in { // 12.2. Vector Single-Width Averaging Add and Subtract @@ -1349,26 +982,8 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy) - - bool HasMaskedOff = !( - (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || - (!IsMasked && PolicyAttrs & RVV_VTA)); - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), - Ops.back()->getType()}; - break; + return emitRVVNarrowingClipBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { // 12.5. Vector Narrowing Fixed-Point Clip Instructions @@ -1392,31 +1007,8 @@ enum __RISCV_FRM { 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) - - 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); - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()}; - break; + return emitRVVFloatingPointBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = true in { @@ -1453,32 +1045,9 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, op1, round_mode, vl) - // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) - - 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); - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), - Ops.back()->getType()}; - break; + return emitRVVWideningFloatingPointBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); } }] in { let HasFRMRoundModeOp = true in { @@ -1520,24 +1089,8 @@ let ManualCodegen = [{ let UnMaskedPolicyScheme = HasPolicyOperand in { let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy) - // Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy) - - bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), - Ops.back()->getType()}; - - break; + return emitRVVFMABuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1564,24 +1117,8 @@ let ManualCodegen = [{ let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, policy) - // Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, vl, policy) - - bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 4); - - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), - Ops.back()->getType()}; - - break; + return emitRVVWideningFMABuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1619,31 +1156,8 @@ let ManualCodegen = [{ let UnMaskedPolicyScheme = HasPassthruOperand in { let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, round_mode, vl) - // Masked: (passthru, op0, mask, frm, vl, policy) - - 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); - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops.back()->getType()}; - break; + return emitRVVFloatingUnaryBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1805,30 +1319,8 @@ def vfwcvtbf16_f_f_v : RVVConvBuiltin<"Fw", "Fwv", "y", "vfwcvtbf16_f">; let ManualCodegen = [{ { - // LLVM intrinsic - // Unmasked: (passthru, op0, frm, vl) - // Masked: (passthru, op0, mask, frm, vl, policy) - 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); - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - if (IsMasked) - Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()}; - break; + return emitRVVFloatingConvBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -1994,28 +1486,9 @@ 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) - - 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); - - if (!HasRoundModeOp) - Ops.insert(Ops.end() - 1, ConstantInt::get(Ops.back()->getType(), 7)); // frm - - if (IsMasked) - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); - - if (!HasMaskedOff) - Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); - - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()}; - break; + return emitRVVFloatingReductionBuiltin( + this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked, + SegInstSEW); } }] in { let HasFRMRoundModeOp = 1 in { @@ -2173,37 +1646,8 @@ let HasMasked = false, 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); + return emitRVVReinterpretBuiltin(this, E, ReturnValue, ResultType, ID, + Ops, PolicyAttrs, IsMasked, SegInstSEW); }] in { // Reinterpret between different type under the same SEW and LMUL def vreinterpret_i_u : RVVBuiltin<"Uvv", "vUv", "csil", "v">; @@ -2329,25 +1773,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { let Name = "vget_v", MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - auto *VecTy = cast<ScalableVectorType>(ResultType); - if (auto *OpVecTy = dyn_cast<ScalableVectorType>(Ops[0]->getType())) { - unsigned MaxIndex = OpVecTy->getMinNumElements() / VecTy->getMinNumElements(); - assert(isPowerOf2_32(MaxIndex)); - // Mask to only valid indices. - 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]); - } - - return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_extract, - {ResultType, Ops[0]->getType()}, - {Ops[0], Builder.CreateTrunc(Ops[1], - Builder.getInt32Ty())}); - } + return emitRVVGetBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach dst_lmul = ["(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in { def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilxfdy", dst_lmul # "v">; @@ -2362,25 +1789,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { let Name = "vset_v", MaskedPolicyScheme = NonePolicy, ManualCodegen = [{ - { - if (auto *ResVecTy = dyn_cast<ScalableVectorType>(ResultType)) { - auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType()); - unsigned MaxIndex = ResVecTy->getMinNumElements() / VecTy->getMinNumElements(); - assert(isPowerOf2_32(MaxIndex)); - // Mask to only valid indices. - 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]); - } - - return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert, - {ResultType, Ops[2]->getType()}, - {Ops[0], Ops[2], - Builder.CreateTrunc(Ops[1],Builder.getInt32Ty())}); - } + return emitRVVSetBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in { def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfdy">; @@ -2398,26 +1808,8 @@ let HasMasked = false, HasVL = false, IRName = "" in { MaskedPolicyScheme = NonePolicy, SupportOverloading = false, ManualCodegen = [{ - { - llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType); - auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType()); - for (unsigned I = 0, N = Ops.size(); I < N; ++I) { - if (isa<ScalableVectorType>(ResultType)) { - llvm::Value *Idx = ConstantInt::get(Builder.getInt64Ty(), - VecTy->getMinNumElements() * I); - ReturnVector = - Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx); - } else { - llvm::Value *Idx = ConstantInt::get(Builder.getInt32Ty(), I); - ReturnVector = - Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert, - {ResultType, Ops[I]->getType()}, - {ReturnVector, Ops[I], Idx}); - } - - } - return ReturnVector; - } + return emitRVVCreateBuiltin(this, E, ReturnValue, ResultType, ID, Ops, + PolicyAttrs, IsMasked, SegInstSEW); }] in { // Since the vcreate_v uses LFixedLog2LMUL, setting the Log2LMUL to [-3] can diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp index b08a0588c5ac1..30a1a217ac64a 100644 --- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp @@ -20,6 +20,958 @@ using namespace clang; using namespace CodeGen; using namespace llvm; +// The 0th bit simulates the `vta` of RVV +// The 1st bit simulates the `vma` of RVV +static constexpr unsigned RVV_VTA = 0x1; +static constexpr unsigned RVV_VMA = 0x2; + +// RISC-V Vector builtin helper functions are marked NOINLINE to prevent +// excessive inlining in CodeGenFunction::EmitRISCVBuiltinExpr's large switch +// statement, which would significantly increase compilation time. +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVVLEFFBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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(), Ops[2]->getType()}; + } else { + if (PolicyAttrs & RVV_VTA) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + IntrinsicTypes = {ResultType, Ops[3]->getType(), Ops[1]->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; +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVVSSEBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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[1]->getType(), Ops[4]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedStoreBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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[1]->getType(), Ops[2]->getType(), + Ops[4]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVPseudoUnaryBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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()}; + } + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVPseudoVNotBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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()}; + } + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVPseudoMaskBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // op1, vl + IntrinsicTypes = {ResultType, Ops[1]->getType()}; + Ops.insert(Ops.begin() + 1, Ops[0]); + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVPseudoVFUnaryBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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]); + } + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVPseudoVWCVTBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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>(Ops[1]->getType())->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()}; + } + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVPseudoVNCVTBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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()}; + } + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVVlenbBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + LLVMContext &Context = CGM.getLLVMContext(); + llvm::MDBuilder MDHelper(Context); + llvm::Metadata *OpsMD[] = {llvm::MDString::get(Context, "vlenb")}; + llvm::MDNode *RegName = llvm::MDNode::get(Context, OpsMD); + llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName); + llvm::Function *F = + CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF->SizeTy}); + return Builder.CreateCall(F, Metadata); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVVsetvliBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes = {ResultType}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVVSEMaskBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + 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[1]->getType(), Ops[3]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegLoadTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + bool NoPassthru = + (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | + (!IsMasked && (PolicyAttrs & RVV_VTA)); + unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; + if (IsMasked) + IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[0]->getType(), + Ops.back()->getType()}; + else + IntrinsicTypes = {ResultType, Ops[Offset]->getType(), + Ops.back()->getType()}; + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + if (NoPassthru) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); + if (ReturnValue.isNull()) + return LoadValue; + else + return Builder.CreateStore(LoadValue, ReturnValue.getValue()); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegStoreTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // Masked + // Builtin: (mask, ptr, v_tuple, vl) + // Intrinsic: (tuple, ptr, mask, vl, SegInstSEW) + // Unmasked + // Builtin: (ptr, v_tuple, vl) + // Intrinsic: (tuple, ptr, vl, SegInstSEW) + if (IsMasked) + std::swap(Ops[0], Ops[2]); + else + std::swap(Ops[0], Ops[1]); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + if (IsMasked) + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegLoadFFTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + bool NoPassthru = + (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | + (!IsMasked && (PolicyAttrs & RVV_VTA)); + unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; + if (IsMasked) + IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType(), + Ops[0]->getType()}; + else + IntrinsicTypes = {ResultType, Ops.back()->getType(), + Ops[Offset]->getType()}; + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + if (NoPassthru) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + Value *NewVL = Ops[2]; + Ops.erase(Ops.begin() + 2); + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); + // Get alignment from the new vl operand + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType()); + llvm::Value *ReturnTuple = Builder.CreateExtractValue(LoadValue, 0); + // Store new_vl + llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1); + Builder.CreateStore(V, Address(NewVL, V->getType(), Align)); + if (ReturnValue.isNull()) + return ReturnTuple; + else + return Builder.CreateStore(ReturnTuple, ReturnValue.getValue()); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVStridedSegLoadTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + bool NoPassthru = + (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | + (!IsMasked && (PolicyAttrs & RVV_VTA)); + unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; + if (IsMasked) + IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType(), + Ops[0]->getType()}; + else + IntrinsicTypes = {ResultType, Ops[Offset]->getType(), + Ops.back()->getType()}; + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + if (NoPassthru) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); + if (ReturnValue.isNull()) + return LoadValue; + else + return Builder.CreateStore(LoadValue, ReturnValue.getValue()); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVStridedSegStoreTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // Masked + // Builtin: (mask, ptr, stride, v_tuple, vl) + // Intrinsic: (tuple, ptr, stride, mask, vl, SegInstSEW) + // Unmasked + // Builtin: (ptr, stride, v_tuple, vl) + // Intrinsic: (tuple, ptr, stride, vl, SegInstSEW) + if (IsMasked) + std::swap(Ops[0], Ops[3]); + else + std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + if (IsMasked) + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType(), + Ops[3]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVAveragingBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, op1, round_mode, vl) + // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, + // policy) + + bool HasMaskedOff = + !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || + (!IsMasked && PolicyAttrs & RVV_VTA)); + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVNarrowingClipBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, op1, round_mode, vl) + // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, + // policy) + + bool HasMaskedOff = + !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) || + (!IsMasked && PolicyAttrs & RVV_VTA)); + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), + Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingPointBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, op1, round_mode, vl) + // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) + + 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); + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVWideningFloatingPointBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, op1, round_mode, vl) + // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) + + 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); + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), + Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedSegLoadTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + + bool NoPassthru = + (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) | + (!IsMasked && (PolicyAttrs & RVV_VTA)); + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + if (NoPassthru) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + + if (IsMasked) + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType(), Ops[4]->getType()}; + else + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + llvm::Value *LoadValue = Builder.CreateCall(F, Ops, ""); + + if (ReturnValue.isNull()) + return LoadValue; + else + return Builder.CreateStore(LoadValue, ReturnValue.getValue()); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedSegStoreTupleBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // Masked + // Builtin: (mask, ptr, index, v_tuple, vl) + // Intrinsic: (tuple, ptr, index, mask, vl, SegInstSEW) + // Unmasked + // Builtin: (ptr, index, v_tuple, vl) + // Intrinsic: (tuple, ptr, index, vl, SegInstSEW) + + if (IsMasked) + std::swap(Ops[0], Ops[3]); + else + std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); + + Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW)); + + if (IsMasked) + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType(), Ops[4]->getType()}; + else + IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), + Ops[3]->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVFMABuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, + // vl, policy) + // Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, + // vl, policy) + + bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()}; + + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVWideningFMABuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl, + // policy) Masked: (vector_in, vector_in/scalar_in, vector_in, mask, frm, + // vl, policy) + + bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5; + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 4); + + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(), + Ops.back()->getType()}; + + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingUnaryBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, round_mode, vl) + // Masked: (passthru, op0, mask, frm, vl, policy) + + 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); + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingConvBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, frm, vl) + // Masked: (passthru, op0, mask, frm, vl, policy) + 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); + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + if (IsMasked) + Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingReductionBuiltin( + CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::Type *ResultType, Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes; + // LLVM intrinsic + // Unmasked: (passthru, op0, op1, round_mode, vl) + // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy) + + 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); + + if (!HasRoundModeOp) + Ops.insert(Ops.end() - 1, + ConstantInt::get(Ops.back()->getType(), 7)); // frm + + if (IsMasked) + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2); + + if (!HasMaskedOff) + Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); + + IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Ops, ""); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVReinterpretBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto &CGM = CGF->CGM; + + 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(CGF->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(CGF->Int64Ty, 0)); + return Builder.CreateBitCast(Boolean64Val, ResultType); + } + } + return Builder.CreateBitCast(Ops[0], ResultType); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVGetBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + auto *VecTy = cast<ScalableVectorType>(ResultType); + if (auto *OpVecTy = dyn_cast<ScalableVectorType>(Ops[0]->getType())) { + unsigned MaxIndex = + OpVecTy->getMinNumElements() / VecTy->getMinNumElements(); + assert(isPowerOf2_32(MaxIndex)); + // Mask to only valid indices. + 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]); + } + + return Builder.CreateIntrinsic( + Intrinsic::riscv_tuple_extract, {ResultType, Ops[0]->getType()}, + {Ops[0], Builder.CreateTrunc(Ops[1], Builder.getInt32Ty())}); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVSetBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + if (auto *ResVecTy = dyn_cast<ScalableVectorType>(ResultType)) { + auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType()); + unsigned MaxIndex = + ResVecTy->getMinNumElements() / VecTy->getMinNumElements(); + assert(isPowerOf2_32(MaxIndex)); + // Mask to only valid indices. + 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]); + } + + return Builder.CreateIntrinsic( + Intrinsic::riscv_tuple_insert, {ResultType, Ops[2]->getType()}, + {Ops[0], Ops[2], Builder.CreateTrunc(Ops[1], Builder.getInt32Ty())}); +} + +static LLVM_ATTRIBUTE_NOINLINE Value * +emitRVVCreateBuiltin(CodeGenFunction *CGF, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Type *ResultType, + Intrinsic::ID ID, SmallVector<Value *, 4> Ops, + int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) { + auto &Builder = CGF->Builder; + llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType); + auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType()); + for (unsigned I = 0, N = Ops.size(); I < N; ++I) { + if (isa<ScalableVectorType>(ResultType)) { + llvm::Value *Idx = ConstantInt::get(Builder.getInt64Ty(), + VecTy->getMinNumElements() * I); + ReturnVector = + Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx); + } else { + llvm::Value *Idx = ConstantInt::get(Builder.getInt32Ty(), I); + ReturnVector = Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert, + {ResultType, Ops[I]->getType()}, + {ReturnVector, Ops[I], Idx}); + } + } + return ReturnVector; +} + Value *CodeGenFunction::EmitRISCVCpuInit() { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {VoidPtrTy}, false); llvm::FunctionCallee Func = @@ -180,10 +1132,6 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, } Intrinsic::ID ID = Intrinsic::not_intrinsic; - // The 0th bit simulates the `vta` of RVV - // The 1st bit simulates the `vma` of RVV - constexpr unsigned RVV_VTA = 0x1; - constexpr unsigned RVV_VMA = 0x2; int PolicyAttrs = 0; bool IsMasked = false; // This is used by segment load/store to determine it's llvm type. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits