Author: Brandon Wu Date: 2025-03-03T12:39:35+08:00 New Revision: c804e86f558a42f328946331af391d700747fa90
URL: https://github.com/llvm/llvm-project/commit/c804e86f558a42f328946331af391d700747fa90 DIFF: https://github.com/llvm/llvm-project/commit/c804e86f558a42f328946331af391d700747fa90.diff LOG: [RISCV][VLS] Support RISCV VLS calling convention (#100346) This patch adds a function attribute `riscv_vls_cc` for RISCV VLS calling convention which takes 0 or 1 argument, the argument is the `ABI_VLEN` which is the `VLEN` for passing the fixed-vector arguments, it wraps the argument as a scalable vector(VLA) using the `ABI_VLEN` and uses the corresponding mechanism to handle it. The range of `ABI_VLEN` is [32, 65536], if not specified, the default value is 128. Here is an example of VLS argument passing: Non-VLS call: ``` void original_call(__attribute__((vector_size(16))) int arg) {} => define void @original_call(i128 noundef %arg) { entry: ... ret void } ``` VLS call: ``` void __attribute__((riscv_vls_cc(256))) vls_call(__attribute__((vector_size(16))) int arg) {} => define riscv_vls_cc void @vls_call(<vscale x 1 x i32> %arg) { entry: ... ret void } } ``` The first Non-VLS call passes generic vector argument of 16 bytes by flattened integer. On the contrary, the VLS call uses `ABI_VLEN=256` which wraps the vector to <vscale x 1 x i32> where the number of scalable vector elements is calaulated by: `ORIG_ELTS * RVV_BITS_PER_BLOCK / ABI_VLEN`. Note: ORIG_ELTS = Vector Size / Type Size = 128 / 32 = 4. PsABI PR: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418 C-API PR: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/68 Added: llvm/test/Assembler/riscv_vls_cc.ll Modified: clang/include/clang-c/Index.h clang/include/clang/AST/Type.h clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/Specifiers.h clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/Type.cpp clang/lib/AST/TypePrinter.cpp clang/lib/Basic/Targets/RISCV.cpp clang/lib/CodeGen/CGCall.cpp clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/Targets/RISCV.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaType.cpp clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp clang/test/CodeGen/RISCV/riscv-vector-callingconv.c clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp clang/tools/libclang/CXType.cpp llvm/include/llvm/AsmParser/LLToken.h llvm/include/llvm/BinaryFormat/Dwarf.def llvm/include/llvm/IR/CallingConv.h llvm/lib/AsmParser/LLLexer.cpp llvm/lib/AsmParser/LLParser.cpp llvm/lib/IR/AsmWriter.cpp llvm/lib/Target/RISCV/RISCVISelLowering.cpp llvm/test/Bitcode/compatibility.ll Removed: ################################################################################ diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 3a511de553ad4..c50410dc365b6 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3061,6 +3061,18 @@ enum CXCallingConv { CXCallingConv_M68kRTD = 19, CXCallingConv_PreserveNone = 20, CXCallingConv_RISCVVectorCall = 21, + CXCallingConv_RISCVVLSCall_32 = 22, + CXCallingConv_RISCVVLSCall_64 = 23, + CXCallingConv_RISCVVLSCall_128 = 24, + CXCallingConv_RISCVVLSCall_256 = 25, + CXCallingConv_RISCVVLSCall_512 = 26, + CXCallingConv_RISCVVLSCall_1024 = 27, + CXCallingConv_RISCVVLSCall_2048 = 28, + CXCallingConv_RISCVVLSCall_4096 = 29, + CXCallingConv_RISCVVLSCall_8192 = 30, + CXCallingConv_RISCVVLSCall_16384 = 31, + CXCallingConv_RISCVVLSCall_32768 = 32, + CXCallingConv_RISCVVLSCall_65536 = 33, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index c3ff7ebd88516..3cd2be2d2170a 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1946,7 +1946,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// Extra information which affects how the function is called, like /// regparm and the calling convention. LLVM_PREFERRED_TYPE(CallingConv) - unsigned ExtInfo : 13; + unsigned ExtInfo : 14; /// The ref-qualifier associated with a \c FunctionProtoType. /// @@ -4438,19 +4438,16 @@ class FunctionType : public Type { // Type::FunctionTypeBitfields::ExtInfo as well. // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall| - // |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 | 12 | + // |0 .. 5| 6 | 7 | 8 |9 .. 11| 12 | 13 | // // regparm is either 0 (no regparm attribute) or the regparm value+1. - enum { CallConvMask = 0x1F }; - enum { NoReturnMask = 0x20 }; - enum { ProducesResultMask = 0x40 }; - enum { NoCallerSavedRegsMask = 0x80 }; - enum { - RegParmMask = 0x700, - RegParmOffset = 8 - }; - enum { NoCfCheckMask = 0x800 }; - enum { CmseNSCallMask = 0x1000 }; + enum { CallConvMask = 0x3F }; + enum { NoReturnMask = 0x40 }; + enum { ProducesResultMask = 0x80 }; + enum { NoCallerSavedRegsMask = 0x100 }; + enum { RegParmMask = 0xe00, RegParmOffset = 9 }; + enum { NoCfCheckMask = 0x1000 }; + enum { CmseNSCallMask = 0x2000 }; uint16_t Bits = CC_C; ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {} diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 80a51c92cc520..458747a1f7155 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3316,6 +3316,14 @@ def RISCVVectorCC: DeclOrTypeAttr, TargetSpecificAttr<TargetRISCV> { let Documentation = [RISCVVectorCCDocs]; } +def RISCVVLSCC: DeclOrTypeAttr, TargetSpecificAttr<TargetRISCV> { + let Spellings = [CXX11<"riscv", "vls_cc">, + C23<"riscv", "vls_cc">, + Clang<"riscv_vls_cc">]; + let Args = [UnsignedArgument<"VectorWidth", /*opt*/1>]; + let Documentation = [RISCVVLSCCDocs]; +} + def Target : InheritableAttr { let Spellings = [GCC<"target">]; let Args = [StringArgument<"featuresStr">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index d6d43df44fb21..24f795628a763 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6214,6 +6214,17 @@ them if they use them. }]; } +def RISCVVLSCCDocs : Documentation { + let Category = DocCatCallingConvs; + let Heading = "riscv::vls_cc, riscv_vls_cc, clang::riscv_vls_cc"; + let Content = [{ +The ``riscv_vls_cc`` attribute can be applied to a function. Functions +declared with this attribute will utilize the standard fixed-length vector +calling convention variant instead of the default calling convention defined by +the ABI. This variant aims to pass fixed-length vectors via vector registers, +if possible, rather than through general-purpose registers.}]; +} + def PreferredNameDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 9c089908fdc13..491badcc804e7 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -276,30 +276,43 @@ namespace clang { /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { - CC_C, // __attribute__((cdecl)) - CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall, // __attribute__((fastcall)) - CC_X86ThisCall, // __attribute__((thiscall)) - CC_X86VectorCall, // __attribute__((vectorcall)) - CC_X86Pascal, // __attribute__((pascal)) - CC_Win64, // __attribute__((ms_abi)) - CC_X86_64SysV, // __attribute__((sysv_abi)) - CC_X86RegCall, // __attribute__((regcall)) - CC_AAPCS, // __attribute__((pcs("aapcs"))) - CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) - CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) - CC_SpirFunction, // default for OpenCL functions on SPIR target - CC_OpenCLKernel, // inferred for OpenCL kernels - CC_Swift, // __attribute__((swiftcall)) - CC_SwiftAsync, // __attribute__((swiftasynccall)) - CC_PreserveMost, // __attribute__((preserve_most)) - CC_PreserveAll, // __attribute__((preserve_all)) - CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) - CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) - CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) - CC_M68kRTD, // __attribute__((m68k_rtd)) - CC_PreserveNone, // __attribute__((preserve_none)) - CC_RISCVVectorCall, // __attribute__((riscv_vector_cc)) + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86VectorCall, // __attribute__((vectorcall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_Win64, // __attribute__((ms_abi)) + CC_X86_64SysV, // __attribute__((sysv_abi)) + CC_X86RegCall, // __attribute__((regcall)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + CC_SpirFunction, // default for OpenCL functions on SPIR target + CC_OpenCLKernel, // inferred for OpenCL kernels + CC_Swift, // __attribute__((swiftcall)) + CC_SwiftAsync, // __attribute__((swiftasynccall)) + CC_PreserveMost, // __attribute__((preserve_most)) + CC_PreserveAll, // __attribute__((preserve_all)) + CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) + CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) + CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) + CC_M68kRTD, // __attribute__((m68k_rtd)) + CC_PreserveNone, // __attribute__((preserve_none)) + CC_RISCVVectorCall, // __attribute__((riscv_vector_cc)) + CC_RISCVVLSCall_32, // __attribute__((riscv_vls_cc(32))) + CC_RISCVVLSCall_64, // __attribute__((riscv_vls_cc(64))) + CC_RISCVVLSCall_128, // __attribute__((riscv_vls_cc)) or + // __attribute__((riscv_vls_cc(128))) + CC_RISCVVLSCall_256, // __attribute__((riscv_vls_cc(256))) + CC_RISCVVLSCall_512, // __attribute__((riscv_vls_cc(512))) + CC_RISCVVLSCall_1024, // __attribute__((riscv_vls_cc(1024))) + CC_RISCVVLSCall_2048, // __attribute__((riscv_vls_cc(2048))) + CC_RISCVVLSCall_4096, // __attribute__((riscv_vls_cc(4096))) + CC_RISCVVLSCall_8192, // __attribute__((riscv_vls_cc(8192))) + CC_RISCVVLSCall_16384, // __attribute__((riscv_vls_cc(16384))) + CC_RISCVVLSCall_32768, // __attribute__((riscv_vls_cc(32768))) + CC_RISCVVLSCall_65536, // __attribute__((riscv_vls_cc(65536))) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 4a090118c3d7b..b6ba36784f38a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3489,6 +3489,20 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_M68kRTD: case CC_PreserveNone: case CC_RISCVVectorCall: +#define CC_VLS_CASE(ABI_VLEN) case CC_RISCVVLSCall_##ABI_VLEN: + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE // FIXME: we should be mangling all of the above. return ""; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 8c11ec2e1fe24..1ddc2d1f492af 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3559,6 +3559,21 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_PreserveNone: return "preserve_none"; // clang-format off case CC_RISCVVectorCall: return "riscv_vector_cc"; +#define CC_VLS_CASE(ABI_VLEN) \ + case CC_RISCVVLSCall_##ABI_VLEN: return "riscv_vls_cc(" #ABI_VLEN ")"; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE // clang-format on } @@ -4226,6 +4241,7 @@ bool AttributedType::isCallingConv() const { case attr::M68kRTD: case attr::PreserveNone: case attr::RISCVVectorCC: + case attr::RISCVVLSCC: return true; } llvm_unreachable("invalid attr kind"); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 31695374cb52b..8762cc7b1e4e1 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1136,6 +1136,23 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_RISCVVectorCall: OS << "__attribute__((riscv_vector_cc))"; break; +#define CC_VLS_CASE(ABI_VLEN) \ + case CC_RISCVVLSCall_##ABI_VLEN: \ + OS << "__attribute__((riscv_vls_cc" #ABI_VLEN "))"; \ + break; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE } } @@ -2064,6 +2081,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::RISCVVectorCC: OS << "riscv_vector_cc"; break; + case attr::RISCVVLSCC: + OS << "riscv_vls_cc"; + break; case attr::NoDeref: OS << "noderef"; break; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index dff990d15dd62..fad698d985af7 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -559,6 +559,18 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { return CCCR_Warning; case CC_C: case CC_RISCVVectorCall: + case CC_RISCVVLSCall_32: + case CC_RISCVVLSCall_64: + case CC_RISCVVLSCall_128: + case CC_RISCVVLSCall_256: + case CC_RISCVVLSCall_512: + case CC_RISCVVLSCall_1024: + case CC_RISCVVLSCall_2048: + case CC_RISCVVLSCall_4096: + case CC_RISCVVLSCall_8192: + case CC_RISCVVLSCall_16384: + case CC_RISCVVLSCall_32768: + case CC_RISCVVLSCall_65536: return CCCR_OK; } } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 916455bc69393..bfcbc273dbda7 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -77,6 +77,22 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { // clang-format off case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall; // clang-format on +#define CC_VLS_CASE(ABI_VLEN) \ + case CC_RISCVVLSCall_##ABI_VLEN: \ + return llvm::CallingConv::RISCV_VLSCall_##ABI_VLEN; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE } } @@ -266,6 +282,29 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, if (D->hasAttr<RISCVVectorCCAttr>()) return CC_RISCVVectorCall; + if (RISCVVLSCCAttr *PCS = D->getAttr<RISCVVLSCCAttr>()) { + switch (PCS->getVectorWidth()) { + default: + llvm_unreachable("Invalid RISC-V VLS ABI VLEN"); +#define CC_VLS_CASE(ABI_VLEN) \ + case ABI_VLEN: \ + return CC_RISCVVLSCall_##ABI_VLEN; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE + } + } + return CC_C; } @@ -3234,6 +3273,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, } } + // Struct of fixed-length vectors and struct of array of fixed-length + // vector in VLS calling convention are coerced to vector tuple + // type(represented as TargetExtType) and scalable vector type + // respectively, they're no longer handled as struct. + if (ArgI.isDirect() && isa<llvm::StructType>(ConvertType(Ty)) && + (isa<llvm::TargetExtType>(ArgI.getCoerceToType()) || + isa<llvm::ScalableVectorType>(ArgI.getCoerceToType()))) { + ArgVals.push_back(ParamValue::forDirect(AI)); + break; + } + llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType()); Address Alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg), diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 46ad11e64c4d5..f4d4a36f9669c 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1593,6 +1593,21 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_PreserveNone; case CC_RISCVVectorCall: return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; +#define CC_VLS_CASE(ABI_VLEN) case CC_RISCVVLSCall_##ABI_VLEN: + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE + return llvm::dwarf::DW_CC_LLVM_RISCVVLSCall; } return 0; } diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index aa5fb6329c1c1..109fa1f9ee521 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -8,6 +8,7 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" +#include "llvm/TargetParser/RISCVTargetParser.h" using namespace clang; using namespace clang::CodeGen; @@ -34,6 +35,9 @@ class RISCVABIInfo : public DefaultABIInfo { llvm::Type *&Field2Ty, CharUnits &Field2Off) const; + bool detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, + llvm::Type *&VLSType) const; + public: RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, bool EABI) @@ -45,8 +49,8 @@ class RISCVABIInfo : public DefaultABIInfo { void computeInfo(CGFunctionInfo &FI) const override; ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, - int &ArgFPRsLeft) const; - ABIArgInfo classifyReturnType(QualType RetTy) const; + int &ArgFPRsLeft, unsigned ABIVLen) const; + ABIArgInfo classifyReturnType(QualType RetTy, unsigned ABIVLen) const; RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; @@ -62,7 +66,7 @@ class RISCVABIInfo : public DefaultABIInfo { llvm::Type *Field2Ty, CharUnits Field2Off) const; - ABIArgInfo coerceVLSVector(QualType Ty) const; + ABIArgInfo coerceVLSVector(QualType Ty, unsigned ABIVLen = 0) const; using ABIInfo::appendAttributeMangling; void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, @@ -111,9 +115,32 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, } void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { + unsigned ABIVLen; + switch (FI.getExtInfo().getCC()) { + default: + ABIVLen = 0; + break; +#define CC_VLS_CASE(ABI_VLEN) \ + case CallingConv::CC_RISCVVLSCall_##ABI_VLEN: \ + ABIVLen = ABI_VLEN; \ + break; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE + } QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(RetTy); + FI.getReturnInfo() = classifyReturnType(RetTy, ABIVLen); // IsRetIndirect is true if classifyArgumentType indicated the value should // be passed indirect, or if the type size is a scalar greater than 2*XLen @@ -139,8 +166,8 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { int ArgNum = 0; for (auto &ArgInfo : FI.arguments()) { bool IsFixed = ArgNum < NumFixedArgs; - ArgInfo.info = - classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); + ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, + ArgFPRsLeft, ABIVLen); ArgNum++; } } @@ -359,9 +386,158 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); } +bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, + llvm::Type *&VLSType) const { + // No riscv_vls_cc attribute. + if (ABIVLen == 1) + return false; + + // Legal struct for VLS calling convention should fulfill following rules: + // 1. Struct element should be either "homogeneous fixed-length vectors" or "a + // fixed-length vector array". + // 2. Number of struct elements or array elements should be greater or equal + // to 1 and less or equal to 8 + // 3. Total number of vector registers needed should not exceed 8. + // + // Examples: Assume ABI_VLEN = 128. + // These are legal structs: + // a. Structs with 1~8 "same" fixed-length vectors, e.g. + // struct { + // __attribute__((vector_size(16))) int a; + // __attribute__((vector_size(16))) int b; + // } + // + // b. Structs with "single" fixed-length vector array with lengh 1~8, e.g. + // struct { + // __attribute__((vector_size(16))) int a[3]; + // } + // These are illegal structs: + // a. Structs with 9 fixed-length vectors, e.g. + // struct { + // __attribute__((vector_size(16))) int a; + // __attribute__((vector_size(16))) int b; + // __attribute__((vector_size(16))) int c; + // __attribute__((vector_size(16))) int d; + // __attribute__((vector_size(16))) int e; + // __attribute__((vector_size(16))) int f; + // __attribute__((vector_size(16))) int g; + // __attribute__((vector_size(16))) int h; + // __attribute__((vector_size(16))) int i; + // } + // + // b. Structs with "multiple" fixed-length vector array, e.g. + // struct { + // __attribute__((vector_size(16))) int a[2]; + // __attribute__((vector_size(16))) int b[2]; + // } + // + // c. Vector registers needed exceeds 8, e.g. + // struct { + // // Registers needed for single fixed-length element: + // // 64 * 8 / ABI_VLEN = 4 + // __attribute__((vector_size(64))) int a; + // __attribute__((vector_size(64))) int b; + // __attribute__((vector_size(64))) int c; + // __attribute__((vector_size(64))) int d; + // } + // + // Struct of 1 fixed-length vector is passed as a scalable vector. + // Struct of >1 fixed-length vectors are passed as vector tuple. + // Struct of 1 array of fixed-length vectors is passed as a scalable vector. + // Otherwise, pass the struct indirectly. + + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty))) { + unsigned NumElts = STy->getStructNumElements(); + if (NumElts > 8) + return false; + + auto *FirstEltTy = STy->getElementType(0); + if (!STy->containsHomogeneousTypes()) + return false; + + // Check structure of fixed-length vectors and turn them into vector tuple + // type if legal. + if (auto *FixedVecTy = dyn_cast<llvm::FixedVectorType>(FirstEltTy)) { + if (NumElts == 1) { + // Handle single fixed-length vector. + VLSType = llvm::ScalableVectorType::get( + FixedVecTy->getElementType(), + llvm::divideCeil(FixedVecTy->getNumElements() * + llvm::RISCV::RVVBitsPerBlock, + ABIVLen)); + // Check registers needed <= 8. + return llvm::divideCeil( + FixedVecTy->getNumElements() * + FixedVecTy->getElementType()->getScalarSizeInBits(), + ABIVLen) <= 8; + } + // LMUL + // = fixed-length vector size / ABIVLen + // = 8 * I8EltCount / RVVBitsPerBlock + // => + // I8EltCount + // = (fixed-length vector size * RVVBitsPerBlock) / (ABIVLen * 8) + unsigned I8EltCount = llvm::divideCeil( + FixedVecTy->getNumElements() * + FixedVecTy->getElementType()->getScalarSizeInBits() * + llvm::RISCV::RVVBitsPerBlock, + ABIVLen * 8); + VLSType = llvm::TargetExtType::get( + getVMContext(), "riscv.vector.tuple", + llvm::ScalableVectorType::get(llvm::Type::getInt8Ty(getVMContext()), + I8EltCount), + NumElts); + // Check registers needed <= 8. + return NumElts * + llvm::divideCeil( + FixedVecTy->getNumElements() * + FixedVecTy->getElementType()->getScalarSizeInBits(), + ABIVLen) <= + 8; + } + + // If elements are not fixed-length vectors, it should be an array. + if (NumElts != 1) + return false; + + // Check array of fixed-length vector and turn it into scalable vector type + // if legal. + if (auto *ArrTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) { + unsigned NumArrElt = ArrTy->getNumElements(); + if (NumArrElt > 8) + return false; + + auto *ArrEltTy = dyn_cast<llvm::FixedVectorType>(ArrTy->getElementType()); + if (!ArrEltTy) + return false; + + // LMUL + // = NumArrElt * fixed-length vector size / ABIVLen + // = fixed-length vector elt size * ScalVecNumElts / RVVBitsPerBlock + // => + // ScalVecNumElts + // = (NumArrElt * fixed-length vector size * RVVBitsPerBlock) / + // (ABIVLen * fixed-length vector elt size) + // = NumArrElt * num fixed-length vector elt * RVVBitsPerBlock / + // ABIVLen + unsigned ScalVecNumElts = llvm::divideCeil( + NumArrElt * ArrEltTy->getNumElements() * llvm::RISCV::RVVBitsPerBlock, + ABIVLen); + VLSType = llvm::ScalableVectorType::get(ArrEltTy->getElementType(), + ScalVecNumElts); + // Check registers needed <= 8. + return llvm::divideCeil( + ScalVecNumElts * + ArrEltTy->getElementType()->getScalarSizeInBits(), + llvm::RISCV::RVVBitsPerBlock) <= 8; + } + } + return false; +} + // Fixed-length RVV vectors are represented as scalable vectors in function // args/return and must be coerced from fixed vectors. -ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const { +ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const { assert(Ty->isVectorType() && "expected vector type!"); const auto *VT = Ty->castAs<VectorType>(); @@ -385,23 +561,56 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty) const { NumElts *= 8; break; default: - assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData && + assert((VT->getVectorKind() == VectorKind::Generic || + VT->getVectorKind() == VectorKind::RVVFixedLengthData) && "Unexpected vector kind"); EltType = CGT.ConvertType(VT->getElementType()); } - // The MinNumElts is simplified from equation: - // NumElts / VScale = - // (EltSize * NumElts / (VScale * RVVBitsPerBlock)) - // * (RVVBitsPerBlock / EltSize) - llvm::ScalableVectorType *ResType = - llvm::ScalableVectorType::get(EltType, NumElts / VScale->first); + llvm::ScalableVectorType *ResType; + + if (ABIVLen == 0) { + // The MinNumElts is simplified from equation: + // NumElts / VScale = + // (EltSize * NumElts / (VScale * RVVBitsPerBlock)) + // * (RVVBitsPerBlock / EltSize) + ResType = llvm::ScalableVectorType::get(EltType, NumElts / VScale->first); + } else { + // Check registers needed <= 8. + if ((EltType->getScalarSizeInBits() * NumElts / ABIVLen) > 8) + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); + + // Generic vector + // The number of elements needs to be at least 1. + ResType = llvm::ScalableVectorType::get( + EltType, + llvm::divideCeil(NumElts * llvm::RISCV::RVVBitsPerBlock, ABIVLen)); + + // If the corresponding extension is not supported, just make it an i8 + // vector with same LMUL. + const TargetInfo &TI = getContext().getTargetInfo(); + if ((EltType->isHalfTy() && !TI.hasFeature("zvfhmin")) || + (EltType->isBFloatTy() && !TI.hasFeature("zvfbfmin")) || + (EltType->isFloatTy() && !TI.hasFeature("zve32f")) || + (EltType->isDoubleTy() && !TI.hasFeature("zve64d")) || + (EltType->isIntegerTy(64) && !TI.hasFeature("zve64x")) || + EltType->isIntegerTy(128)) { + // The number of elements needs to be at least 1. + ResType = llvm::ScalableVectorType::get( + llvm::Type::getInt8Ty(getVMContext()), + llvm::divideCeil(EltType->getScalarSizeInBits() * NumElts * + llvm::RISCV::RVVBitsPerBlock, + 8 * ABIVLen)); + } + } + return ABIArgInfo::getDirect(ResType); } ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, - int &ArgFPRsLeft) const { + int &ArgFPRsLeft, + unsigned ABIVLen) const { assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); @@ -458,6 +667,12 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, } } + if (IsFixed && Ty->isStructureOrClassType()) { + llvm::Type *VLSType = nullptr; + if (detectVLSCCEligibleStruct(Ty, ABIVLen, VLSType)) + return ABIArgInfo::getDirect(VLSType); + } + uint64_t NeededAlign = getContext().getTypeAlign(Ty); // Determine the number of GPRs needed to pass the current argument // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" @@ -501,13 +716,22 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, return ABIArgInfo::getDirect(); } - if (const VectorType *VT = Ty->getAs<VectorType>()) + // TODO: _BitInt is not handled yet in VLS calling convention since _BitInt + // ABI is also not merged yet in RISC-V: + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/419 + if (const VectorType *VT = Ty->getAs<VectorType>(); + VT && !VT->getElementType()->isBitIntType()) { if (VT->getVectorKind() == VectorKind::RVVFixedLengthData || VT->getVectorKind() == VectorKind::RVVFixedLengthMask || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) return coerceVLSVector(Ty); + if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 0) + // Generic vector without riscv_vls_cc should fall through and pass by + // reference. + return coerceVLSVector(Ty, ABIVLen); + } // Aggregates which are <= 2*XLen will be passed in registers if possible, // so coerce to integers. @@ -532,7 +756,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, /*ByVal=*/false); } -ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, + unsigned ABIVLen) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -541,8 +766,8 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { // The rules for return and argument types are the same, so defer to // classifyArgumentType. - return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, - ArgFPRsLeft); + return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, ArgFPRsLeft, + ABIVLen); } RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 942259b57c88b..5785cf5eec3c5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5206,6 +5206,25 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { case ParsedAttr::AT_RISCVVectorCC: D->addAttr(::new (S.Context) RISCVVectorCCAttr(S.Context, AL)); return; + case ParsedAttr::AT_RISCVVLSCC: { + // If the riscv_abi_vlen doesn't have any argument, default ABI_VLEN is 128. + unsigned VectorLength = 128; + if (AL.getNumArgs() && + !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), VectorLength)) + return; + if (VectorLength < 32 || VectorLength > 65536) { + S.Diag(AL.getLoc(), diag::err_argument_invalid_range) + << VectorLength << 32 << 65536; + return; + } + if (!llvm::isPowerOf2_64(VectorLength)) { + S.Diag(AL.getLoc(), diag::err_argument_not_power_of_2); + return; + } + + D->addAttr(::new (S.Context) RISCVVLSCCAttr(S.Context, AL, VectorLength)); + return; + } default: llvm_unreachable("unexpected attribute kind"); } @@ -5325,10 +5344,19 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, return false; } - unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; - if (!Attrs.checkExactlyNumArgs(*this, ReqArgs)) { - Attrs.setInvalid(); - return true; + if (Attrs.getKind() == ParsedAttr::AT_RISCVVLSCC) { + // riscv_vls_cc only accepts 0 or 1 argument. + if (!Attrs.checkAtLeastNumArgs(*this, 0) || + !Attrs.checkAtMostNumArgs(*this, 1)) { + Attrs.setInvalid(); + return true; + } + } else { + unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; + if (!Attrs.checkExactlyNumArgs(*this, ReqArgs)) { + Attrs.setInvalid(); + return true; + } } // TODO: diagnose uses of these conventions on the wrong target. @@ -5413,6 +5441,30 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_RISCVVectorCC: CC = CC_RISCVVectorCall; break; + case ParsedAttr::AT_RISCVVLSCC: { + // If the riscv_abi_vlen doesn't have any argument, we set set it to default + // value 128. + unsigned ABIVLen = 128; + if (Attrs.getNumArgs() && + !checkUInt32Argument(Attrs, Attrs.getArgAsExpr(0), ABIVLen)) { + Attrs.setInvalid(); + return true; + } + if (Attrs.getNumArgs() && (ABIVLen < 32 || ABIVLen > 65536)) { + Attrs.setInvalid(); + Diag(Attrs.getLoc(), diag::err_argument_invalid_range) + << ABIVLen << 32 << 65536; + return true; + } + if (!llvm::isPowerOf2_64(ABIVLen)) { + Attrs.setInvalid(); + Diag(Attrs.getLoc(), diag::err_argument_not_power_of_2); + return true; + } + CC = static_cast<CallingConv>(CallingConv::CC_RISCVVLSCall_32 + + llvm::Log2_64(ABIVLen) - 5); + break; + } default: llvm_unreachable("unexpected attribute kind"); } @@ -7271,6 +7323,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_M68kRTD: case ParsedAttr::AT_PreserveNone: case ParsedAttr::AT_RISCVVectorCC: + case ParsedAttr::AT_RISCVVLSCC: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_Suppress: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 60096eebfdb6f..11943c0b53591 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -143,7 +143,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_PreserveAll: \ case ParsedAttr::AT_M68kRTD: \ case ParsedAttr::AT_PreserveNone: \ - case ParsedAttr::AT_RISCVVectorCC + case ParsedAttr::AT_RISCVVectorCC: \ + case ParsedAttr::AT_RISCVVLSCC // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -7629,6 +7630,20 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr<PreserveNoneAttr>(Ctx, Attr); case ParsedAttr::AT_RISCVVectorCC: return createSimpleAttr<RISCVVectorCCAttr>(Ctx, Attr); + case ParsedAttr::AT_RISCVVLSCC: { + // If the riscv_abi_vlen doesn't have any argument, we set set it to default + // value 128. + unsigned ABIVLen = 128; + if (Attr.getNumArgs()) { + std::optional<llvm::APSInt> MaybeABIVLen = + Attr.getArgAsExpr(0)->getIntegerConstantExpr(Ctx); + if (!MaybeABIVLen) + llvm_unreachable("Invalid RISC-V ABI VLEN"); + ABIVLen = MaybeABIVLen->getZExtValue(); + } + + return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, ABIVLen); + } } llvm_unreachable("unexpected attribute kind!"); } diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c index 072d8a863d457..3044d91f1c31c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -1,6 +1,8 @@ // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -triple riscv64 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +zve32x \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ZVE32X %s // RUN: %clang_cc1 -std=c23 -triple riscv64 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s @@ -32,3 +34,161 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { __riscv_vse32_v_i32m1(base, val, vl); return ret; } + +// CHECK-LLVM: define dso_local void @test_vls_no_cc(i128 noundef %arg.coerce) +void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen(<vscale x 2 x i32> noundef %arg.coerce) +void __attribute__((riscv_vls_cc)) test_vls_default_abi_vlen(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23(<vscale x 2 x i32> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 8 x i8> noundef %arg.coerce) +void __attribute__((riscv_vls_cc)) test_vls_default_abi_vlen_unsupported_feature(__attribute__((vector_size(16))) _Float16 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature(__attribute__((vector_size(16))) _Float16 arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature_zve32x(<vscale x 8 x i8> noundef %arg.coerce) +void __attribute__((riscv_vls_cc)) test_vls_default_abi_vlen_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature_no_zve64x(<vscale x 8 x i8> noundef %arg.coerce) +void __attribute__((riscv_vls_cc)) test_vls_default_abi_vlen_unsupported_feature_no_zve64x(__attribute__((vector_size(16))) uint64_t arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature_no_zve64x(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature_no_zve64x(__attribute__((vector_size(16))) uint64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_vls_256_abi_vlen(<vscale x 1 x i32> noundef %arg.coerce) +void __attribute__((riscv_vls_cc(256))) test_vls_256_abi_vlen(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_vls_256_abi_vlen_c23(<vscale x 1 x i32> noundef %arg.coerce) +[[riscv::vls_cc(256)]] void test_vls_256_abi_vlen_c23(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @test_vls_least_element(<vscale x 1 x i32> noundef %arg.coerce) +void __attribute__((riscv_vls_cc(1024))) test_vls_least_element(__attribute__((vector_size(8))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @test_vls_least_element_c23(<vscale x 1 x i32> noundef %arg.coerce) +[[riscv::vls_cc(1024)]] void test_vls_least_element_c23(__attribute__((vector_size(8))) int arg) {} + + +struct st_i32x4 { + __attribute__((vector_size(16))) int i32; +}; + +struct st_i32x4_arr1 { + __attribute__((vector_size(16))) int i32[1]; +}; + +struct st_i32x4_arr4 { + __attribute__((vector_size(16))) int i32[4]; +}; + +struct st_i32x4_arr8 { + __attribute__((vector_size(16))) int i32[8]; +}; + + +struct st_i32x4x2 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; +}; + +struct st_i32x8x2 { + __attribute__((vector_size(32))) int i32_1; + __attribute__((vector_size(32))) int i32_2; +}; + +struct st_i32x64x2 { + __attribute__((vector_size(256))) int i32_1; + __attribute__((vector_size(256))) int i32_2; +}; + +struct st_i32x4x3 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; +}; + +struct st_i32x4x8 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; + __attribute__((vector_size(16))) int i32_4; + __attribute__((vector_size(16))) int i32_5; + __attribute__((vector_size(16))) int i32_6; + __attribute__((vector_size(16))) int i32_7; + __attribute__((vector_size(16))) int i32_8; +}; + +struct st_i32x4x9 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; + __attribute__((vector_size(16))) int i32_4; + __attribute__((vector_size(16))) int i32_5; + __attribute__((vector_size(16))) int i32_6; + __attribute__((vector_size(16))) int i32_7; + __attribute__((vector_size(16))) int i32_8; + __attribute__((vector_size(16))) int i32_9; +}; + +typedef int __attribute__((vector_size(256))) int32x64_t; + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_too_large(ptr noundef %0) +void __attribute__((riscv_vls_cc)) test_too_large(int32x64_t arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_too_large_256(<vscale x 16 x i32> noundef %arg.coerce) +void __attribute__((riscv_vls_cc(256))) test_too_large_256(int32x64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4(<vscale x 2 x i32> %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4(struct st_i32x4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_256(<vscale x 1 x i32> %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4_256(struct st_i32x4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr1(<vscale x 2 x i32> %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr1_256(<vscale x 1 x i32> %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4(<vscale x 8 x i32> %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256(<vscale x 4 x i32> %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8(<vscale x 16 x i32> %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256(<vscale x 8 x i32> %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x2(struct st_i32x4x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x2_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 2) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x2_256(struct st_i32x4x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x8x2(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x8x2(struct st_i32x8x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x8x2_256(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x8x2_256(struct st_i32x8x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x64x2(ptr noundef %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x64x2(struct st_i32x64x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x64x2_256(ptr noundef %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x64x2_256(struct st_i32x64x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x3(target("riscv.vector.tuple", <vscale x 8 x i8>, 3) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x3(struct st_i32x4x3 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x3_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 3) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x3_256(struct st_i32x4x3 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x8(struct st_i32x4x8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x8_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x8_256(struct st_i32x4x8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x9(ptr noundef %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x9(struct st_i32x4x9 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x9_256(ptr noundef %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x9_256(struct st_i32x4x9 arg) {} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp index c01aeb21f6757..594bfe159b28c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -1,6 +1,8 @@ // REQUIRES: riscv-registered-target // RUN: %clang_cc1 -std=c++11 -triple riscv64 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s +// RUN: %clang_cc1 -std=c++11 -triple riscv64 -target-feature +zve32x \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ZVE32X %s #include <riscv_vector.h> @@ -30,3 +32,143 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { __riscv_vse32_v_i32m1(base, val, vl); return ret; } + +// CHECK-LLVM: define dso_local void @_Z14test_vls_no_ccDv4_i(i128 noundef %arg.coerce) +void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z25test_vls_default_abi_vlenDv4_i(<vscale x 2 x i32> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature(__attribute__((vector_size(16))) _Float16 arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} + +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @_Z55test_vls_default_abi_vlen_unsupported_feature_no_zve64xDv2_m(<vscale x 8 x i8> noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature_no_zve64x(__attribute__((vector_size(16))) uint64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z21test_vls_256_abi_vlenDv4_i(<vscale x 1 x i32> noundef %arg.coerce) +[[riscv::vls_cc(256)]] void test_vls_256_abi_vlen(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @_Z22test_vls_least_elementDv2_i(<vscale x 1 x i32> noundef %arg.coerce) +[[riscv::vls_cc(1024)]] void test_vls_least_element(__attribute__((vector_size(8))) int arg) {} + + +struct st_i32x4 { + __attribute__((vector_size(16))) int i32; +}; + +struct st_i32x4_arr1 { + __attribute__((vector_size(16))) int i32[1]; +}; + +struct st_i32x4_arr4 { + __attribute__((vector_size(16))) int i32[4]; +}; + +struct st_i32x4_arr8 { + __attribute__((vector_size(16))) int i32[8]; +}; + + +struct st_i32x4x2 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; +}; + +struct st_i32x8x2 { + __attribute__((vector_size(32))) int i32_1; + __attribute__((vector_size(32))) int i32_2; +}; + +struct st_i32x64x2 { + __attribute__((vector_size(256))) int i32_1; + __attribute__((vector_size(256))) int i32_2; +}; + +struct st_i32x4x3 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; +}; + +struct st_i32x4x8 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; + __attribute__((vector_size(16))) int i32_4; + __attribute__((vector_size(16))) int i32_5; + __attribute__((vector_size(16))) int i32_6; + __attribute__((vector_size(16))) int i32_7; + __attribute__((vector_size(16))) int i32_8; +}; + +struct st_i32x4x9 { + __attribute__((vector_size(16))) int i32_1; + __attribute__((vector_size(16))) int i32_2; + __attribute__((vector_size(16))) int i32_3; + __attribute__((vector_size(16))) int i32_4; + __attribute__((vector_size(16))) int i32_5; + __attribute__((vector_size(16))) int i32_6; + __attribute__((vector_size(16))) int i32_7; + __attribute__((vector_size(16))) int i32_8; + __attribute__((vector_size(16))) int i32_9; +}; + +typedef int __attribute__((vector_size(256))) int32x64_t; + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z14test_too_largeDv64_i(ptr noundef %0) +[[riscv::vls_cc]] void test_too_large(int32x64_t arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z18test_too_large_256Dv64_i(<vscale x 16 x i32> noundef %arg.coerce) +[[riscv::vls_cc(256)]] void test_too_large_256(int32x64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z13test_st_i32x48st_i32x4(<vscale x 2 x i32> %arg) +[[riscv::vls_cc]] void test_st_i32x4(struct st_i32x4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z17test_st_i32x4_2568st_i32x4(<vscale x 1 x i32> %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_256(struct st_i32x4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr113st_i32x4_arr1(<vscale x 2 x i32> %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1(<vscale x 1 x i32> %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4(<vscale x 8 x i32> %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4(<vscale x 4 x i32> %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8(<vscale x 16 x i32> %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8(<vscale x 8 x i32> %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg) +[[riscv::vls_cc]] void test_st_i32x4x2(struct st_i32x4x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x2_25610st_i32x4x2(target("riscv.vector.tuple", <vscale x 4 x i8>, 2) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x2_256(struct st_i32x4x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x8x210st_i32x8x2(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %arg) +[[riscv::vls_cc]] void test_st_i32x8x2(struct st_i32x8x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x8x2_25610st_i32x8x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x8x2_256(struct st_i32x8x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z16test_st_i32x64x211st_i32x64x2(ptr noundef %arg) +[[riscv::vls_cc]] void test_st_i32x64x2(struct st_i32x64x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z20test_st_i32x64x2_25611st_i32x64x2(ptr noundef %arg) +[[riscv::vls_cc(256)]] void test_st_i32x64x2_256(struct st_i32x64x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x310st_i32x4x3(target("riscv.vector.tuple", <vscale x 8 x i8>, 3) %arg) +[[riscv::vls_cc]] void test_st_i32x4x3(struct st_i32x4x3 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x3_25610st_i32x4x3(target("riscv.vector.tuple", <vscale x 4 x i8>, 3) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x3_256(struct st_i32x4x3 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x810st_i32x4x8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg) +[[riscv::vls_cc]] void test_st_i32x4x8(struct st_i32x4x8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x8_25610st_i32x4x8(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x8_256(struct st_i32x4x8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x910st_i32x4x9(ptr noundef %arg) +[[riscv::vls_cc]] void test_st_i32x4x9(struct st_i32x4x9 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x9_25610st_i32x4x9(ptr noundef %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x9_256(struct st_i32x4x9 arg) {} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c index 5c35901799b42..6a71d1a9db81f 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c @@ -15,3 +15,21 @@ void __attribute__((riscv_vector_cc)) test_no_attribute(int x) { } // expected-e void test_no_attribute2(int); // expected-note {{previous declaration is here}} [[riscv::vector_cc]] void test_no_attribute2(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}} + +__attribute__((riscv_vls_cc)) int var_vls; // expected-warning {{'riscv_vls_cc' only applies to function types; type here is 'int'}} + +__attribute__((riscv_vls_cc)) void func_vls(); +__attribute__((riscv_vls_cc(1))) void func_vls_invalid(); // expected-error {{argument value 1 is outside the valid range [32, 65536]}} +__attribute__((riscv_vls_cc(129))) void func_vls_invalid(); // expected-error {{argument should be a power of 2}} + +void test_vls_no_attribute(int); // expected-note {{previous declaration is here}} +void __attribute__((riscv_vls_cc)) test_vls_no_attribute(int x) { } // expected-error {{function declared 'riscv_vls_cc(128)' here was previously declared without calling convention}} + +[[riscv::vls_cc]] int var2_vls; // expected-warning {{'vls_cc' only applies to function types; type here is 'int'}} + +[[riscv::vls_cc]] void func2_vls(); +[[riscv::vls_cc(1)]] void func_vls_invalid2(); // expected-error {{argument value 1 is outside the valid range [32, 65536]}} +[[riscv::vls_cc(129)]] void func_vls_invalid2(); // expected-error {{argument should be a power of 2}} + +void test_vls_no_attribute2(int); // expected-note {{previous declaration is here}} +[[riscv::vls_cc]] void test_vls_no_attribute2(int x) { } // expected-error {{function declared 'riscv_vls_cc(128)' here was previously declared without calling convention}} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp index 264bb7d9ad7c0..f041b0d36529c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp @@ -33,3 +33,21 @@ void test_lambda2() { [[riscv::vector_cc]] auto lambda = []() { // expected-warning {{'vector_cc' only applies to function types; type here is 'auto'}} }; } + +[[riscv::vls_cc]] int var_vls; // expected-warning {{'vls_cc' only applies to function types; type here is 'int'}} + +[[riscv::vls_cc]] void func_vls(); +[[riscv::vls_cc(1)]] void func_invalid_vls(); // expected-error {{argument value 1 is outside the valid range [32, 65536]}} +[[riscv::vls_cc(129)]] void func_invalid_vls(); // expected-error {{argument should be a power of 2}} + +void test_no_attribute_vls(int); // expected-note {{previous declaration is here}} +[[riscv::vls_cc]] void test_no_attribute_vls(int x) { } // expected-error {{function declared 'riscv_vls_cc(128)' here was previously declared without calling convention}} + +class test_cc_vls { + [[riscv::vls_cc]] void member_func(); +}; + +void test_lambda_vls() { + [[riscv::vls_cc]] auto lambda = []() { // expected-warning {{'vls_cc' only applies to function types; type here is 'auto'}} + }; +} diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index 5da87c6f4aa9c..f4227fd030734 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -701,6 +701,18 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(M68kRTD); TCALLINGCONV(PreserveNone); TCALLINGCONV(RISCVVectorCall); + TCALLINGCONV(RISCVVLSCall_32); + TCALLINGCONV(RISCVVLSCall_64); + TCALLINGCONV(RISCVVLSCall_128); + TCALLINGCONV(RISCVVLSCall_256); + TCALLINGCONV(RISCVVLSCall_512); + TCALLINGCONV(RISCVVLSCall_1024); + TCALLINGCONV(RISCVVLSCall_2048); + TCALLINGCONV(RISCVVLSCall_4096); + TCALLINGCONV(RISCVVLSCall_8192); + TCALLINGCONV(RISCVVLSCall_16384); + TCALLINGCONV(RISCVVLSCall_32768); + TCALLINGCONV(RISCVVLSCall_65536); case CC_SpirFunction: return CXCallingConv_Unexposed; case CC_AMDGPUKernelCall: return CXCallingConv_Unexposed; case CC_OpenCLKernel: return CXCallingConv_Unexposed; diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index a53d471f70271..81b9929b1fab8 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -185,6 +185,7 @@ enum Kind { kw_m68k_rtdcc, kw_graalcc, kw_riscv_vector_cc, + kw_riscv_vls_cc, // Attributes: kw_attributes, diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index 724a14ccc7aea..e52324a8ebc12 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -1126,6 +1126,7 @@ HANDLE_DW_CC(0xcc, LLVM_M68kRTD) HANDLE_DW_CC(0xcd, LLVM_PreserveNone) HANDLE_DW_CC(0xce, LLVM_RISCVVectorCall) HANDLE_DW_CC(0xcf, LLVM_SwiftTail) +HANDLE_DW_CC(0xd0, LLVM_RISCVVLSCall) // From GCC source code (include/dwarf2.h): This DW_CC_ value is not currently // generated by any toolchain. It is used internally to GDB to indicate OpenCL // C functions that have been compiled with the IBM XL C for OpenCL compiler and diff --git a/llvm/include/llvm/IR/CallingConv.h b/llvm/include/llvm/IR/CallingConv.h index 55e32028e3ed0..7897aabb6c1a9 100644 --- a/llvm/include/llvm/IR/CallingConv.h +++ b/llvm/include/llvm/IR/CallingConv.h @@ -270,6 +270,20 @@ namespace CallingConv { /// Preserve X1-X15, X19-X29, SP, Z0-Z31, P0-P15. AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1 = 111, + /// Calling convention used for RISC-V V-extension fixed vectors. + RISCV_VLSCall_32 = 112, + RISCV_VLSCall_64 = 113, + RISCV_VLSCall_128 = 114, + RISCV_VLSCall_256 = 115, + RISCV_VLSCall_512 = 116, + RISCV_VLSCall_1024 = 117, + RISCV_VLSCall_2048 = 118, + RISCV_VLSCall_4096 = 119, + RISCV_VLSCall_8192 = 120, + RISCV_VLSCall_16384 = 121, + RISCV_VLSCall_32768 = 122, + RISCV_VLSCall_65536 = 123, + /// The highest possible ID. Must be some 2^k - 1. MaxID = 1023 }; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index c867a68518e4d..fd0a50d25e714 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -683,6 +683,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(m68k_rtdcc); KEYWORD(graalcc); KEYWORD(riscv_vector_cc); + KEYWORD(riscv_vls_cc); KEYWORD(cc); KEYWORD(c); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 690e92a0f2afc..777bf5f7bb386 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2215,6 +2215,7 @@ void LLParser::parseOptionalDLLStorageClass(unsigned &Res) { /// ::= 'm68k_rtdcc' /// ::= 'graalcc' /// ::= 'riscv_vector_cc' +/// ::= 'riscv_vls_cc' /// ::= 'cc' UINT /// bool LLParser::parseOptionalCallingConv(unsigned &CC) { @@ -2291,6 +2292,37 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) { case lltok::kw_riscv_vector_cc: CC = CallingConv::RISCV_VectorCall; break; + case lltok::kw_riscv_vls_cc: + // Default ABI_VLEN + CC = CallingConv::RISCV_VLSCall_128; + Lex.Lex(); + if (!EatIfPresent(lltok::lparen)) + break; + uint32_t ABIVlen; + if (parseUInt32(ABIVlen) || !EatIfPresent(lltok::rparen)) + return true; + switch (ABIVlen) { + default: + return tokError("unknown RISC-V ABI VLEN"); +#define CC_VLS_CASE(ABIVlen) \ + case ABIVlen: \ + CC = CallingConv::RISCV_VLSCall_##ABIVlen; \ + break; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE + } + return false; case lltok::kw_cc: { Lex.Lex(); return parseUInt32(CC); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index a52c4d88ac836..238898c3b2e2f 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -376,6 +376,23 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::RISCV_VectorCall: Out << "riscv_vector_cc"; break; +#define CC_VLS_CASE(ABI_VLEN) \ + case CallingConv::RISCV_VLSCall_##ABI_VLEN: \ + Out << "riscv_vls_cc(" #ABI_VLEN ")"; \ + break; + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE } } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 4e6b3a224b79b..1719b362aeee9 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -20759,6 +20759,20 @@ SDValue RISCVTargetLowering::LowerFormalArguments( case CallingConv::SPIR_KERNEL: case CallingConv::GRAAL: case CallingConv::RISCV_VectorCall: +#define CC_VLS_CASE(ABI_VLEN) case CallingConv::RISCV_VLSCall_##ABI_VLEN: + CC_VLS_CASE(32) + CC_VLS_CASE(64) + CC_VLS_CASE(128) + CC_VLS_CASE(256) + CC_VLS_CASE(512) + CC_VLS_CASE(1024) + CC_VLS_CASE(2048) + CC_VLS_CASE(4096) + CC_VLS_CASE(8192) + CC_VLS_CASE(16384) + CC_VLS_CASE(32768) + CC_VLS_CASE(65536) +#undef CC_VLS_CASE break; case CallingConv::GHC: if (Subtarget.hasStdExtE()) diff --git a/llvm/test/Assembler/riscv_vls_cc.ll b/llvm/test/Assembler/riscv_vls_cc.ll new file mode 100644 index 0000000000000..bfe1def3fc3be --- /dev/null +++ b/llvm/test/Assembler/riscv_vls_cc.ll @@ -0,0 +1,122 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; CHECK: define riscv_vls_cc(32) void @no_args_32() { +define riscv_vls_cc(32) void @no_args_32() { + ret void +} + +; CHECK: define riscv_vls_cc(64) void @no_args_64() { +define riscv_vls_cc(64) void @no_args_64() { + ret void +} + +; CHECK: define riscv_vls_cc(128) void @no_args_128() { +define riscv_vls_cc(128) void @no_args_128() { + ret void +} + +; CHECK: define riscv_vls_cc(256) void @no_args_256() { +define riscv_vls_cc(256) void @no_args_256() { + ret void +} + +; CHECK: define riscv_vls_cc(512) void @no_args_512() { +define riscv_vls_cc(512) void @no_args_512() { + ret void +} + +; CHECK: define riscv_vls_cc(1024) void @no_args_1024() { +define riscv_vls_cc(1024) void @no_args_1024() { + ret void +} + +; CHECK: define riscv_vls_cc(2048) void @no_args_2048() { +define riscv_vls_cc(2048) void @no_args_2048() { + ret void +} + +; CHECK: define riscv_vls_cc(4096) void @no_args_4096() { +define riscv_vls_cc(4096) void @no_args_4096() { + ret void +} + +; CHECK: define riscv_vls_cc(8192) void @no_args_8192() { +define riscv_vls_cc(8192) void @no_args_8192() { + ret void +} + +; CHECK: define riscv_vls_cc(16384) void @no_args_16384() { +define riscv_vls_cc(16384) void @no_args_16384() { + ret void +} + +; CHECK: define riscv_vls_cc(32768) void @no_args_32768() { +define riscv_vls_cc(32768) void @no_args_32768() { + ret void +} + +; CHECK: define riscv_vls_cc(65536) void @no_args_65536() { +define riscv_vls_cc(65536) void @no_args_65536() { + ret void +} + +; CHECK: define riscv_vls_cc(32) void @byval_arg_32(ptr byval(i32) %0) { +define riscv_vls_cc(32) void @byval_arg_32(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(64) void @byval_arg_64(ptr byval(i32) %0) { +define riscv_vls_cc(64) void @byval_arg_64(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(128) void @byval_arg_128(ptr byval(i32) %0) { +define riscv_vls_cc(128) void @byval_arg_128(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(256) void @byval_arg_256(ptr byval(i32) %0) { +define riscv_vls_cc(256) void @byval_arg_256(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(512) void @byval_arg_512(ptr byval(i32) %0) { +define riscv_vls_cc(512) void @byval_arg_512(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(1024) void @byval_arg_1024(ptr byval(i32) %0) { +define riscv_vls_cc(1024) void @byval_arg_1024(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(2048) void @byval_arg_2048(ptr byval(i32) %0) { +define riscv_vls_cc(2048) void @byval_arg_2048(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(4096) void @byval_arg_4096(ptr byval(i32) %0) { +define riscv_vls_cc(4096) void @byval_arg_4096(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(8192) void @byval_arg_8192(ptr byval(i32) %0) { +define riscv_vls_cc(8192) void @byval_arg_8192(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(16384) void @byval_arg_16384(ptr byval(i32) %0) { +define riscv_vls_cc(16384) void @byval_arg_16384(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(32768) void @byval_arg_32768(ptr byval(i32) %0) { +define riscv_vls_cc(32768) void @byval_arg_32768(ptr byval(i32)) { + ret void +} + +; CHECK: define riscv_vls_cc(65536) void @byval_arg_65536(ptr byval(i32) %0) { +define riscv_vls_cc(65536) void @byval_arg_65536(ptr byval(i32)) { + ret void +} diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index 4a1f7ce1ee2a9..d9e594abcd50c 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -516,6 +516,54 @@ declare cc96 void @f.cc96() ; CHECK: declare amdgpu_es void @f.cc96() declare amdgpu_es void @f.amdgpu_es() ; CHECK: declare amdgpu_es void @f.amdgpu_es() +declare cc112 void @f.cc112() +; CHECK: declare riscv_vls_cc(32) void @f.cc112() +declare cc113 void @f.cc113() +; CHECK: declare riscv_vls_cc(64) void @f.cc113() +declare cc114 void @f.cc114() +; CHECK: declare riscv_vls_cc(128) void @f.cc114() +declare cc115 void @f.cc115() +; CHECK: declare riscv_vls_cc(256) void @f.cc115() +declare cc116 void @f.cc116() +; CHECK: declare riscv_vls_cc(512) void @f.cc116() +declare cc117 void @f.cc117() +; CHECK: declare riscv_vls_cc(1024) void @f.cc117() +declare cc118 void @f.cc118() +; CHECK: declare riscv_vls_cc(2048) void @f.cc118() +declare cc119 void @f.cc119() +; CHECK: declare riscv_vls_cc(4096) void @f.cc119() +declare cc120 void @f.cc120() +; CHECK: declare riscv_vls_cc(8192) void @f.cc120() +declare cc121 void @f.cc121() +; CHECK: declare riscv_vls_cc(16384) void @f.cc121() +declare cc122 void @f.cc122() +; CHECK: declare riscv_vls_cc(32768) void @f.cc122() +declare cc123 void @f.cc123() +; CHECK: declare riscv_vls_cc(65536) void @f.cc123() +declare riscv_vls_cc(32) void @riscv_vls_cc_32() +; CHECK: declare riscv_vls_cc(32) void @riscv_vls_cc_32() +declare riscv_vls_cc(64) void @riscv_vls_cc_64() +; CHECK: declare riscv_vls_cc(64) void @riscv_vls_cc_64() +declare riscv_vls_cc(128) void @riscv_vls_cc_128() +; CHECK: declare riscv_vls_cc(128) void @riscv_vls_cc_128() +declare riscv_vls_cc(256) void @riscv_vls_cc_256() +; CHECK: declare riscv_vls_cc(256) void @riscv_vls_cc_256() +declare riscv_vls_cc(512) void @riscv_vls_cc_512() +; CHECK: declare riscv_vls_cc(512) void @riscv_vls_cc_512() +declare riscv_vls_cc(1024) void @riscv_vls_cc_1024() +; CHECK: declare riscv_vls_cc(1024) void @riscv_vls_cc_1024() +declare riscv_vls_cc(2048) void @riscv_vls_cc_2048() +; CHECK: declare riscv_vls_cc(2048) void @riscv_vls_cc_2048() +declare riscv_vls_cc(4096) void @riscv_vls_cc_4096() +; CHECK: declare riscv_vls_cc(4096) void @riscv_vls_cc_4096() +declare riscv_vls_cc(8192) void @riscv_vls_cc_8192() +; CHECK: declare riscv_vls_cc(8192) void @riscv_vls_cc_8192() +declare riscv_vls_cc(16384) void @riscv_vls_cc_16384() +; CHECK: declare riscv_vls_cc(16384) void @riscv_vls_cc_16384() +declare riscv_vls_cc(32768) void @riscv_vls_cc_32768() +; CHECK: declare riscv_vls_cc(32768) void @riscv_vls_cc_32768() +declare riscv_vls_cc(65536) void @riscv_vls_cc_65536() +; CHECK: declare riscv_vls_cc(65536) void @riscv_vls_cc_65536() declare cc1023 void @f.cc1023() ; CHECK: declare cc1023 void @f.cc1023() _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits