From b838b5a6ca2cdf5d41fa96ee84ba3ef8757c9a67 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Sun, 21 Jul 2024 09:49:11 -0700 Subject: [PATCH 01/12] [RISCV][VLS] Support RISCV VLS calling convention 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( %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 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. --- clang/include/clang-c/Index.h | 1 + clang/include/clang/AST/Type.h | 26 +++++- clang/include/clang/AST/TypeProperties.td | 7 +- clang/include/clang/Basic/Attr.td | 8 ++ clang/include/clang/Basic/AttrDocs.td | 11 +++ clang/include/clang/Basic/CodeGenOptions.def | 3 + clang/include/clang/Basic/Specifiers.h | 1 + clang/include/clang/CodeGen/CGFunctionInfo.h | 9 +- clang/include/clang/Driver/Options.td | 5 +- clang/lib/AST/ASTContext.cpp | 2 + clang/lib/AST/ItaniumMangle.cpp | 1 + clang/lib/AST/Type.cpp | 2 + clang/lib/AST/TypePrinter.cpp | 6 ++ clang/lib/Basic/Targets/RISCV.cpp | 1 + clang/lib/CodeGen/CGCall.cpp | 5 + clang/lib/CodeGen/CGDebugInfo.cpp | 2 + clang/lib/CodeGen/CodeGenModule.cpp | 3 +- clang/lib/CodeGen/TargetInfo.h | 2 +- clang/lib/CodeGen/Targets/RISCV.cpp | 91 +++++++++++++------ clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 4 + clang/lib/Driver/ToolChains/Clang.cpp | 15 +++ clang/lib/Sema/SemaDeclAttr.cpp | 40 +++++++- clang/lib/Sema/SemaType.cpp | 26 +++++- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 40 ++++++++ .../riscv-vector-callingconv-llvm-ir.cpp | 22 +++++ .../CodeGen/RISCV/riscv-vector-callingconv.c | 18 ++++ .../RISCV/riscv-vector-callingconv.cpp | 18 ++++ clang/tools/libclang/CXType.cpp | 1 + llvm/include/llvm/AsmParser/LLToken.h | 1 + llvm/include/llvm/BinaryFormat/Dwarf.def | 1 + llvm/include/llvm/IR/CallingConv.h | 3 + llvm/lib/AsmParser/LLLexer.cpp | 1 + llvm/lib/AsmParser/LLParser.cpp | 4 + llvm/lib/IR/AsmWriter.cpp | 3 + llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 1 + llvm/test/Assembler/riscv_vls_cc.ll | 12 +++ llvm/test/Bitcode/compatibility.ll | 4 + 37 files changed, 358 insertions(+), 42 deletions(-) create mode 100644 llvm/test/Assembler/riscv_vls_cc.ll diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index aac5d1fa8aa2e..21a4863203b6e 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3053,6 +3053,7 @@ enum CXCallingConv { CXCallingConv_M68kRTD = 19, CXCallingConv_PreserveNone = 20, CXCallingConv_RISCVVectorCall = 21, + CXCallingConv_RISCVVLSCall = 22, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index f0fbacccc97bb..ccdcbfe14ff24 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 : 18; /// The ref-qualifier associated with a \c FunctionProtoType. /// @@ -4438,6 +4438,8 @@ class FunctionType : public Type { // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall| // |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 | 12 | + // |RISCV-ABI-VLEN| + // |13 .. 17| // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; @@ -4450,23 +4452,25 @@ class FunctionType : public Type { }; enum { NoCfCheckMask = 0x800 }; enum { CmseNSCallMask = 0x1000 }; - uint16_t Bits = CC_C; + enum { Log2RISCVABIVLenMask = 0x3E000, Log2RISCVABIVLenOffset = 13 }; + uint32_t Bits = CC_C; - ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} + ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs, bool NoCfCheck, - bool cmseNSCall) { + bool cmseNSCall, unsigned Log2RISCVABIVLen) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | (producesResult ? ProducesResultMask : 0) | (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | (NoCfCheck ? NoCfCheckMask : 0) | - (cmseNSCall ? CmseNSCallMask : 0); + (cmseNSCall ? CmseNSCallMask : 0) | + (Log2RISCVABIVLen << Log2RISCVABIVLenOffset); } // Constructor with all defaults. Use when for example creating a @@ -4493,6 +4497,10 @@ class FunctionType : public Type { CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } + unsigned getLog2RISCVABIVLen() const { + return (Bits & Log2RISCVABIVLenMask) >> Log2RISCVABIVLenOffset; + } + bool operator==(ExtInfo Other) const { return Bits == Other.Bits; } @@ -4548,6 +4556,11 @@ class FunctionType : public Type { return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } + ExtInfo withLog2RISCVABIVLen(unsigned Log2RISCVABIVLen) const { + return ExtInfo((Bits & ~Log2RISCVABIVLenMask) | + (Log2RISCVABIVLen << Log2RISCVABIVLenOffset)); + } + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } @@ -4657,6 +4670,9 @@ class FunctionType : public Type { bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } + unsigned getLog2RISCVABIVLen() const { + return getExtInfo().getLog2RISCVABIVLen(); + } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 6f1a76bd18fb5..d5f653013a9b8 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -313,6 +313,9 @@ let Class = FunctionType in { def : Property<"cmseNSCall", Bool> { let Read = [{ node->getExtInfo().getCmseNSCall() }]; } + def : Property<"Log2RISCVABIVLen", UInt32> { + let Read = [{ node->getExtInfo().getLog2RISCVABIVLen() }]; + } } let Class = FunctionNoProtoType in { @@ -320,7 +323,7 @@ let Class = FunctionNoProtoType in { auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, callingConvention, producesResult, noCallerSavedRegs, noCfCheck, - cmseNSCall); + cmseNSCall, Log2RISCVABIVLen); return ctx.getFunctionNoProtoType(returnType, extInfo); }]>; } @@ -363,7 +366,7 @@ let Class = FunctionProtoType in { auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, callingConvention, producesResult, noCallerSavedRegs, noCfCheck, - cmseNSCall); + cmseNSCall, Log2RISCVABIVLen); FunctionProtoType::ExtProtoInfo epi; epi.ExtInfo = extInfo; epi.Variadic = variadic; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 408d3adf370c8..be307b346620f 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3285,6 +3285,14 @@ def RISCVVectorCC: DeclOrTypeAttr, TargetSpecificAttr { let Documentation = [RISCVVectorCCDocs]; } +def RISCVVLSCC: DeclOrTypeAttr, TargetSpecificAttr { + 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 5e66e752512d0..1c98eb7c899d7 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6061,6 +6061,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/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 0f4ed13d5f3d8..1c14400e699f5 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -465,6 +465,9 @@ ENUM_CODEGENOPT(ZeroCallUsedRegs, llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind, /// non-deleting destructors. (No effect on Microsoft ABI.) CODEGENOPT(CtorDtorReturnThis, 1, 0) +/// Specify the VLEN for VLS calling convention. +CODEGENOPT(RISCVABIVLen, 17, 0) + /// FIXME: Make DebugOptions its own top-level .def file. #include "DebugOptions.def" diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 9c089908fdc13..d2df5a24da143 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -300,6 +300,7 @@ namespace clang { CC_M68kRTD, // __attribute__((m68k_rtd)) CC_PreserveNone, // __attribute__((preserve_none)) CC_RISCVVectorCall, // __attribute__((riscv_vector_cc)) + CC_RISCVVLSCall, // __attribute__((riscv_vls_cc)) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 9d785d878b61d..44ae2755a2ab0 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -625,6 +625,9 @@ class CGFunctionInfo final /// Log 2 of the maximum vector width. unsigned MaxVectorWidth : 4; + /// Log2 of ABI_VLEN used in RISCV VLS calling convention. + unsigned Log2RISCVABIVLen : 5; + RequiredArgs Required; /// The struct representing all arguments passed in memory. Only used when @@ -735,11 +738,13 @@ class CGFunctionInfo final bool getHasRegParm() const { return HasRegParm; } unsigned getRegParm() const { return RegParm; } + unsigned getLog2RISCVABIVLen() const { return Log2RISCVABIVLen; } + FunctionType::ExtInfo getExtInfo() const { return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), getASTCallingConvention(), isReturnsRetained(), isNoCallerSavedRegs(), isNoCfCheck(), - isCmseNSCall()); + isCmseNSCall(), getLog2RISCVABIVLen()); } CanQualType getReturnType() const { return getArgsBuffer()[0].type; } @@ -793,6 +798,7 @@ class CGFunctionInfo final ID.AddInteger(RegParm); ID.AddBoolean(NoCfCheck); ID.AddBoolean(CmseNSCall); + ID.AddInteger(Log2RISCVABIVLen); ID.AddInteger(Required.getOpaqueData()); ID.AddBoolean(HasExtParameterInfos); if (HasExtParameterInfos) { @@ -820,6 +826,7 @@ class CGFunctionInfo final ID.AddInteger(info.getRegParm()); ID.AddBoolean(info.getNoCfCheck()); ID.AddBoolean(info.getCmseNSCall()); + ID.AddInteger(info.getLog2RISCVABIVLen()); ID.AddInteger(required.getOpaqueData()); ID.AddBoolean(!paramInfos.empty()); if (!paramInfos.empty()) { diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 2721c1b5d8dc5..e1c4741a9ea6d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4992,7 +4992,10 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group, !eq(GlobalDocumentation.Program, "Flang") : "", true: " The value will be reflected in __riscv_v_fixed_vlen preprocessor define"), " (RISC-V only)")>; - +def mriscv_abi_vlen_EQ : Joined<["-"], "mriscv-abi-vlen=">, Group, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Specify the VLEN for VLS calling convention.">, + MarshallingInfoInt>; def munaligned_access : Flag<["-"], "munaligned-access">, Group, HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">; def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index be1dd29d46278..7d043068fa095 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11108,6 +11108,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return {}; if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck()) return {}; + if (lbaseInfo.getLog2RISCVABIVLen() != rbaseInfo.getLog2RISCVABIVLen()) + return {}; // When merging declarations, it's common for supplemental information like // attributes to only be present in one of the declarations, and we generally diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 1dd936cf4fb51..a63556c647af4 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3489,6 +3489,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_M68kRTD: case CC_PreserveNone: case CC_RISCVVectorCall: + case CC_RISCVVLSCall: // 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 caa0ac858a1be..3472972f6f106 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3561,6 +3561,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_PreserveNone: return "preserve_none"; // clang-format off case CC_RISCVVectorCall: return "riscv_vector_cc"; + case CC_RISCVVLSCall: return "riscv_vls_cc"; // clang-format on } @@ -4228,6 +4229,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 a850410ffc846..65d3b3108175d 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1136,6 +1136,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_RISCVVectorCall: OS << "__attribute__((riscv_vector_cc))"; break; + case CC_RISCVVLSCall: + OS << "__attribute__((riscv_vls_cc))"; + break; } } @@ -2064,6 +2067,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 db23b0c228338..ebced9da22e8c 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -516,6 +516,7 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { return CCCR_Warning; case CC_C: case CC_RISCVVectorCall: + case CC_RISCVVLSCall: return CCCR_OK; } } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index e0cf6ca69f0df..9e143c26fb47e 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -76,6 +76,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_PreserveNone: return llvm::CallingConv::PreserveNone; // clang-format off case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall; + case CC_RISCVVLSCall: return llvm::CallingConv::RISCV_VLSCall; // clang-format on } } @@ -266,6 +267,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, if (D->hasAttr()) return CC_RISCVVectorCall; + if (D->hasAttr()) + return CC_RISCVVLSCall; + return CC_C; } @@ -861,6 +865,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, bool instanceMethod, FI->HasExtParameterInfos = !paramInfos.empty(); FI->getArgsBuffer()[0].type = resultType; FI->MaxVectorWidth = 0; + FI->Log2RISCVABIVLen = info.getLog2RISCVABIVLen(); for (unsigned i = 0, e = argTypes.size(); i != e; ++i) FI->getArgsBuffer()[i + 1].type = argTypes[i]; for (unsigned i = 0, e = paramInfos.size(); i != e; ++i) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index f9cba414dcfe2..9d6fa7f98461b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1593,6 +1593,8 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_PreserveNone; case CC_RISCVVectorCall: return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; + case CC_RISCVVLSCall: + return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; } return 0; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index dfb51b11e1d85..30d455a5d509b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -231,7 +231,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { else if (ABIStr.ends_with("d")) ABIFLen = 64; bool EABI = ABIStr.ends_with("e"); - return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, EABI); + return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, + CodeGenOpts.RISCVABIVLen, EABI); } case llvm::Triple::systemz: { diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index ab3142bdea684..6dd4085bb5101 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -551,7 +551,7 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind, std::unique_ptr createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen, - bool EABI); + unsigned ABIVLen, bool EABI); std::unique_ptr createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM); diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 2b70f2bd3f38b..f4c37eee20c21 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; @@ -25,6 +26,7 @@ class RISCVABIInfo : public DefaultABIInfo { // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target // with soft float ABI has FLen==0). unsigned FLen; + unsigned ABIVLen; const int NumArgGPRs; const int NumArgFPRs; const bool EABI; @@ -36,17 +38,17 @@ class RISCVABIInfo : public DefaultABIInfo { public: RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, - bool EABI) - : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8), - NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} + unsigned ABIVLen, bool EABI) + : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), ABIVLen(ABIVLen), + NumArgGPRs(EABI ? 6 : 8), NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload it. 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 ArgABIVLen) const; + ABIArgInfo classifyReturnType(QualType RetTy, unsigned ArgABIVLen) const; RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; @@ -62,7 +64,7 @@ class RISCVABIInfo : public DefaultABIInfo { llvm::Type *Field2Ty, CharUnits Field2Off) const; - ABIArgInfo coerceVLSVector(QualType Ty) const; + ABIArgInfo coerceVLSVector(QualType Ty, unsigned ArgABIVLen = 0) const; using ABIInfo::appendAttributeMangling; void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, @@ -111,9 +113,13 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, } void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { + unsigned ArgABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen(); + if (ArgABIVLen == 1) + ArgABIVLen = ABIVLen; + QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(RetTy); + FI.getReturnInfo() = classifyReturnType(RetTy, ArgABIVLen); // 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 +145,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, ArgABIVLen); ArgNum++; } } @@ -361,7 +367,8 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( // 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 ArgABIVLen) const { assert(Ty->isVectorType() && "expected vector type!"); const auto *VT = Ty->castAs(); @@ -385,23 +392,48 @@ 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 (ArgABIVLen == 0) { + // The MinNumElts is simplified from equation: + // NumElts / VScale = + // (EltSize * NumElts / (VScale * RVVBitsPerBlock)) + // * (RVVBitsPerBlock / EltSize) + ResType = llvm::ScalableVectorType::get(EltType, NumElts / VScale->first); + } else { + // If the corresponding extension is not supported, just make it an i32 + // vector. + 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)) { + NumElts = NumElts * EltType->getScalarSizeInBits() / 32; + EltType = llvm::Type::getInt32Ty(getVMContext()); + } + + // Generic vector + // The number of element need to be at least 1. + ResType = llvm::ScalableVectorType::get( + EltType, + llvm::divideCeil(NumElts * llvm::RISCV::RVVBitsPerBlock, ArgABIVLen)); + } + return ABIArgInfo::getDirect(ResType); } ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, - int &ArgFPRsLeft) const { + int &ArgFPRsLeft, + unsigned ArgABIVLen) const { assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); @@ -498,13 +530,18 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, return ABIArgInfo::getDirect(); } - if (const VectorType *VT = Ty->getAs()) + if (const VectorType *VT = Ty->getAs()) { 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 && ArgABIVLen != 0) + // Generic vector without riscv_vls_cc should fall through and pass by + // reference. + return coerceVLSVector(Ty, ArgABIVLen); + } // Aggregates which are <= 2*XLen will be passed in registers if possible, // so coerce to integers. @@ -527,7 +564,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, + unsigned ArgABIVLen) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -536,8 +574,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, + ArgABIVLen); } RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, @@ -576,9 +614,9 @@ namespace { class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { public: RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, - unsigned FLen, bool EABI) + unsigned FLen, unsigned ABIVLen, bool EABI) : TargetCodeGenInfo( - std::make_unique(CGT, XLen, FLen, EABI)) { + std::make_unique(CGT, XLen, FLen, ABIVLen, EABI)) { SwiftInfo = std::make_unique(CGT, /*SwiftErrorInRegister=*/false); } @@ -610,7 +648,8 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { std::unique_ptr CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, - unsigned FLen, bool EABI) { + unsigned FLen, unsigned ABIVLen, + bool EABI) { return std::make_unique(CGM.getTypes(), XLen, FLen, - EABI); + ABIVLen, EABI); } diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 6935904a24edb..18da247b3eab4 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -95,6 +95,10 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, CPUFastVectorUnaligned = true; } + if (Arg *A = Args.getLastArg(options::OPT_mriscv_abi_vlen_EQ)) + Features.push_back( + Args.MakeArgString(Twine("+abi-vlen-") + A->getValue() + "b")); + // Handle features corresponding to "-ffixed-X" options #define RESERVE_REG(REG) \ if (Args.hasArg(options::OPT_ffixed_##REG)) \ diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 33f08cf28feca..3e83192ceebee 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2225,6 +2225,21 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, << A->getSpelling() << Val; } } + + if (Arg *A = Args.getLastArg(options::OPT_mriscv_abi_vlen_EQ)) { + StringRef ABIVLenStr = A->getValue(); + unsigned ABIVLen; + const Driver &D = getToolChain().getDriver(); + if (ABIVLenStr.getAsInteger(10, ABIVLen) || ABIVLen < 32 || + ABIVLen > 65536 || !llvm::isPowerOf2_64(ABIVLen)) { + D.Diag(diag::err_drv_invalid_value) + << A->getOption().getName() << ABIVLenStr; + return; + } + + CmdArgs.push_back( + Args.MakeArgString(Twine("-mriscv-abi-vlen=") + A->getValue())); + } } void Clang::AddSparcTargetArgs(const ArgList &Args, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c2d82b9aa9b32..31fe6e342ed0f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5013,6 +5013,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"); } @@ -5132,10 +5151,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 accept 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. @@ -5220,6 +5248,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_RISCVVectorCC: CC = CC_RISCVVectorCall; break; + case ParsedAttr::AT_RISCVVLSCC: + CC = CC_RISCVVLSCall; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -7075,6 +7106,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 2ccf5a8e1d6f3..9a58fcc2836bc 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 \ @@ -7617,6 +7618,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_RISCVVectorCC: return createSimpleAttr(Ctx, Attr); + case ParsedAttr::AT_RISCVVLSCC: + return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, /*dummy*/ 0); } llvm_unreachable("unexpected attribute kind!"); } @@ -8103,6 +8106,27 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, CallingConv CCOld = fn->getCallConv(); Attr *CCAttr = getCCTypeAttr(S.Context, attr); + if (attr.getKind() == ParsedAttr::AT_RISCVVLSCC) { + // If the riscv_abi_vlen doesn't have any argument, default ABI_VLEN is 128. + unsigned ABIVLen = 128; + if (attr.getNumArgs() && + !S.checkUInt32Argument(attr, attr.getArgAsExpr(0), ABIVLen)) + return false; + if (ABIVLen < 32 || ABIVLen > 65536) { + S.Diag(attr.getLoc(), diag::err_argument_invalid_range) + << ABIVLen << 32 << 65536; + return false; + } + if (!llvm::isPowerOf2_64(ABIVLen)) { + S.Diag(attr.getLoc(), diag::err_argument_not_power_of_2); + return false; + } + + auto EI = unwrapped.get()->getExtInfo().withLog2RISCVABIVLen( + llvm::Log2_64(ABIVLen)); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + } + if (CCOld != CC) { // Error out on when there's already an attribute on the type // and the CCs don't match. 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..8c205459db999 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -3,6 +3,10 @@ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s // RUN: %clang_cc1 -std=c23 -triple riscv64 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s +// RUN: %clang_cc1 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s +// RUN: %clang_cc1 -std=c23 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s #include @@ -32,3 +36,39 @@ 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) +// CHECK-LLVM-ABI-VLEN: define dso_local void @test_vls_no_cc( noundef %arg.coerce) +void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen( 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 void @test_vls_default_abi_vlen_c23( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23( 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 void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature(__attribute__((vector_size(16))) _Float16 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( 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 void @test_vls_256_abi_vlen_c23( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen_c23( 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 void @test_vls_least_element( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_least_element( 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 void @test_vls_least_element_c23( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_least_element_c23( noundef %arg.coerce) +[[riscv::vls_cc(1024)]] void test_vls_least_element_c23(__attribute__((vector_size(8))) int 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..9447e6fae0cea 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 -mriscv-abi-vlen=256 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s #include @@ -30,3 +32,23 @@ 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) +// CHECK-LLVM-ABI-VLEN: define dso_local void @_Z14test_vls_no_ccDv4_i( noundef %arg.coerce) +void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i( 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature(__attribute__((vector_size(16))) _Float16 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( 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 void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) +[[riscv::vls_cc(1024)]] void test_vls_least_element(__attribute__((vector_size(8))) int arg) {} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c index 5c35901799b42..da4819186f4e2 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]}} expected-warning {{'riscv_vls_cc' only applies to function types; type here is 'void (void)__attribute__((riscv_vls_cc))'}} +__attribute__((riscv_vls_cc(129))) void func_vls_invalid(); // expected-error {{argument should be a power of 2}} expected-warning {{'riscv_vls_cc' only applies to function types; type here is 'void (void)__attribute__((riscv_vls_cc))'}} + +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' 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]}} expected-warning {{'vls_cc' only applies to function types; type here is 'void (void)'}} +[[riscv::vls_cc(129)]] void func_vls_invalid2(); // expected-error {{argument should be a power of 2}} expected-warning {{'vls_cc' only applies to function types; type here is 'void (void)'}} + +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' 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..5e27c76d5307f 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]}} expected-warning {{'vls_cc' only applies to function types; type here is 'void ()'}} +[[riscv::vls_cc(129)]] void func_invalid_vls(); // expected-error {{argument should be a power of 2}} expected-warning {{'vls_cc' only applies to function types; type here is 'void ()'}} + +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' 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..65fa6fa254095 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -701,6 +701,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(M68kRTD); TCALLINGCONV(PreserveNone); TCALLINGCONV(RISCVVectorCall); + TCALLINGCONV(RISCVVLSCall); 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 7b47bc88ddb25..b079c27b09064 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 2bb84fbc864d8..a756bb88f8ef1 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -1120,6 +1120,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..bc3a75f2fe665 100644 --- a/llvm/include/llvm/IR/CallingConv.h +++ b/llvm/include/llvm/IR/CallingConv.h @@ -270,6 +270,9 @@ 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 = 112, + /// 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 5ea507c009bdc..f5468fdcb60b2 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 81d048b32e139..abf98f76b6a61 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2207,6 +2207,7 @@ void LLParser::parseOptionalDLLStorageClass(unsigned &Res) { /// ::= 'm68k_rtdcc' /// ::= 'graalcc' /// ::= 'riscv_vector_cc' +/// ::= 'riscv_vls_cc' /// ::= 'cc' UINT /// bool LLParser::parseOptionalCallingConv(unsigned &CC) { @@ -2283,6 +2284,9 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) { case lltok::kw_riscv_vector_cc: CC = CallingConv::RISCV_VectorCall; break; + case lltok::kw_riscv_vls_cc: + CC = CallingConv::RISCV_VLSCall; + break; case lltok::kw_cc: { Lex.Lex(); return parseUInt32(CC); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index a37a8901489cf..67a8e6260f1e3 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -368,6 +368,9 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::RISCV_VectorCall: Out << "riscv_vector_cc"; break; + case CallingConv::RISCV_VLSCall: + Out << "riscv_vls_cc"; + break; } } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b25cb128bce9f..96f51580d6ace 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -19901,6 +19901,7 @@ SDValue RISCVTargetLowering::LowerFormalArguments( case CallingConv::SPIR_KERNEL: case CallingConv::GRAAL: case CallingConv::RISCV_VectorCall: + case CallingConv::RISCV_VLSCall: 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..cc63e61ed6a1f --- /dev/null +++ b/llvm/test/Assembler/riscv_vls_cc.ll @@ -0,0 +1,12 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; CHECK: define riscv_vls_cc void @no_args() { +define riscv_vls_cc void @no_args() { + ret void +} + +; CHECK: define riscv_vls_cc void @byval_arg(ptr byval(i32) %0) { +define riscv_vls_cc void @byval_arg(ptr byval(i32)) { + ret void +} diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index a28156cdaa279..485508ca0013a 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -516,6 +516,10 @@ 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 void @f.cc112() +declare riscv_vls_cc void @riscv_vls_cc() +; CHECK: declare riscv_vls_cc void @riscv_vls_cc() declare cc1023 void @f.cc1023() ; CHECK: declare cc1023 void @f.cc1023() From 35039565c4e204ec1c6aa39834b46b72ea99cdaa Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Sat, 9 Nov 2024 18:58:14 -0800 Subject: [PATCH 02/12] fixup! [RISCV][VLS] Support RISCV VLS calling convention --- clang/lib/CodeGen/Targets/RISCV.cpp | 2 +- clang/lib/Sema/SemaDeclAttr.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index f4c37eee20c21..4762d82e982fd 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -421,7 +421,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, } // Generic vector - // The number of element need to be at least 1. + // The number of elements needs to be at least 1. ResType = llvm::ScalableVectorType::get( EltType, llvm::divideCeil(NumElts * llvm::RISCV::RVVBitsPerBlock, ArgABIVLen)); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 31fe6e342ed0f..4645c47f85b59 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5152,7 +5152,7 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, } if (Attrs.getKind() == ParsedAttr::AT_RISCVVLSCC) { - // riscv_vls_cc only accept 0 or 1 argument. + // riscv_vls_cc only accepts 0 or 1 argument. if (!Attrs.checkAtLeastNumArgs(*this, 0) || !Attrs.checkAtMostNumArgs(*this, 1)) { Attrs.setInvalid(); From a19954741b3ffd726d40ba430400002b99fae14b Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Tue, 3 Dec 2024 23:28:32 -0800 Subject: [PATCH 03/12] fixup! [RISCV][VLS] Support RISCV VLS calling convention --- clang/lib/CodeGen/Targets/RISCV.cpp | 13 +++++++--- clang/lib/Sema/SemaType.cpp | 7 ++--- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 26 ++++++++++++++----- .../riscv-vector-callingconv-llvm-ir.cpp | 16 +++++++++--- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 4762d82e982fd..6c96e6338cda2 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -114,8 +114,13 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { unsigned ArgABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen(); - if (ArgABIVLen == 1) + // If ArgABIVLen is default value(2), try to set it to the value passed by + // option if any, otherwise, set it to default value 128. + // Note that ArgABIVLen == 1 means vector_cc is not enabled. + if (ArgABIVLen == 2 && ABIVLen) ArgABIVLen = ABIVLen; + else if (ArgABIVLen == 2) + ArgABIVLen = 128; QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) @@ -416,8 +421,8 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, (EltType->isDoubleTy() && !TI.hasFeature("zve64d")) || (EltType->isIntegerTy(64) && !TI.hasFeature("zve64x")) || EltType->isIntegerTy(128)) { - NumElts = NumElts * EltType->getScalarSizeInBits() / 32; - EltType = llvm::Type::getInt32Ty(getVMContext()); + EltType = + llvm::Type::getIntNTy(getVMContext(), EltType->getScalarSizeInBits()); } // Generic vector @@ -537,7 +542,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) return coerceVLSVector(Ty); - if (VT->getVectorKind() == VectorKind::Generic && ArgABIVLen != 0) + if (VT->getVectorKind() == VectorKind::Generic && ArgABIVLen != 1) // Generic vector without riscv_vls_cc should fall through and pass by // reference. return coerceVLSVector(Ty, ArgABIVLen); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9a58fcc2836bc..f25b732b026f9 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8107,12 +8107,13 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, Attr *CCAttr = getCCTypeAttr(S.Context, attr); if (attr.getKind() == ParsedAttr::AT_RISCVVLSCC) { - // If the riscv_abi_vlen doesn't have any argument, default ABI_VLEN is 128. - unsigned ABIVLen = 128; + // If the riscv_abi_vlen doesn't have any argument, we set set it to 2 to + // differentiate from functions without attribute. + unsigned ABIVLen = 2; if (attr.getNumArgs() && !S.checkUInt32Argument(attr, attr.getArgAsExpr(0), ABIVLen)) return false; - if (ABIVLen < 32 || ABIVLen > 65536) { + if (ABIVLen != 2 && (ABIVLen < 32 || ABIVLen > 65536)) { S.Diag(attr.getLoc(), diag::err_argument_invalid_range) << ABIVLen << 32 << 65536; return false; 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 8c205459db999..0b06bede29dc7 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -1,10 +1,14 @@ // 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 // RUN: %clang_cc1 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s +// RUN: %clang_cc1 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +zve32x \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN-ZVE32X %s // RUN: %clang_cc1 -std=c23 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s @@ -38,25 +42,33 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { } // CHECK-LLVM: define dso_local void @test_vls_no_cc(i128 noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local void @test_vls_no_cc( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: 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 void @test_vls_default_abi_vlen( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen( 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 void @test_vls_default_abi_vlen_c23( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23( 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 void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature( 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 void @test_vls_default_abi_vlen_unsupported_feature_zve32x( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature_zve32x( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} + // CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( noundef %arg.coerce) // CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( noundef %arg.coerce) void __attribute__((riscv_vls_cc(256))) test_vls_256_abi_vlen(__attribute__((vector_size(16))) int 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 9447e6fae0cea..0b91f8b3877eb 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -1,8 +1,12 @@ // 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 // RUN: %clang_cc1 -std=c++11 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ // RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s +// RUN: %clang_cc1 -std=c++11 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +zve32x \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN-ZVE32X %s #include @@ -34,17 +38,21 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { } // CHECK-LLVM: define dso_local void @_Z14test_vls_no_ccDv4_i(i128 noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local void @_Z14test_vls_no_ccDv4_i( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: 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 void @_Z25test_vls_default_abi_vlenDv4_i( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i( 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( 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 void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) +// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) +[[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} + // CHECK-LLVM: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( noundef %arg.coerce) // CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( noundef %arg.coerce) [[riscv::vls_cc(256)]] void test_vls_256_abi_vlen(__attribute__((vector_size(16))) int arg) {} From 8c8ef947c40ef35643c64b17d7b4b2a4d1c3fef1 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Mon, 9 Dec 2024 10:04:07 -0800 Subject: [PATCH 04/12] fixup! [RISCV][VLS] Support RISCV VLS calling convention --- clang/lib/Sema/SemaType.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f25b732b026f9..f6f7cbb278f5d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8113,7 +8113,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, if (attr.getNumArgs() && !S.checkUInt32Argument(attr, attr.getArgAsExpr(0), ABIVLen)) return false; - if (ABIVLen != 2 && (ABIVLen < 32 || ABIVLen > 65536)) { + if (attr.getNumArgs() && (ABIVLen < 32 || ABIVLen > 65536)) { S.Diag(attr.getLoc(), diag::err_argument_invalid_range) << ABIVLen << 32 << 65536; return false; From 5190e0fae4f782c5744825d3dab9ae41647a2ed6 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Sun, 22 Dec 2024 23:10:58 -0800 Subject: [PATCH 05/12] fixup! Remove command line option --- clang/include/clang/Basic/CodeGenOptions.def | 3 -- clang/include/clang/Driver/Options.td | 4 -- clang/lib/CodeGen/CodeGenModule.cpp | 3 +- clang/lib/CodeGen/TargetInfo.h | 2 +- clang/lib/CodeGen/Targets/RISCV.cpp | 50 ++++++++----------- clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 4 -- clang/lib/Driver/ToolChains/Clang.cpp | 15 ------ clang/lib/Sema/SemaType.cpp | 6 +-- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 17 ------- .../riscv-vector-callingconv-llvm-ir.cpp | 10 ---- 10 files changed, 25 insertions(+), 89 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 1c14400e699f5..0f4ed13d5f3d8 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -465,9 +465,6 @@ ENUM_CODEGENOPT(ZeroCallUsedRegs, llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind, /// non-deleting destructors. (No effect on Microsoft ABI.) CODEGENOPT(CtorDtorReturnThis, 1, 0) -/// Specify the VLEN for VLS calling convention. -CODEGENOPT(RISCVABIVLen, 17, 0) - /// FIXME: Make DebugOptions its own top-level .def file. #include "DebugOptions.def" diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e1c4741a9ea6d..4a4900a0e3b6e 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4992,10 +4992,6 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group, !eq(GlobalDocumentation.Program, "Flang") : "", true: " The value will be reflected in __riscv_v_fixed_vlen preprocessor define"), " (RISC-V only)")>; -def mriscv_abi_vlen_EQ : Joined<["-"], "mriscv-abi-vlen=">, Group, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Specify the VLEN for VLS calling convention.">, - MarshallingInfoInt>; def munaligned_access : Flag<["-"], "munaligned-access">, Group, HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">; def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 30d455a5d509b..dfb51b11e1d85 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -231,8 +231,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { else if (ABIStr.ends_with("d")) ABIFLen = 64; bool EABI = ABIStr.ends_with("e"); - return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, - CodeGenOpts.RISCVABIVLen, EABI); + return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, EABI); } case llvm::Triple::systemz: { diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 6dd4085bb5101..ab3142bdea684 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -551,7 +551,7 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind, std::unique_ptr createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen, - unsigned ABIVLen, bool EABI); + bool EABI); std::unique_ptr createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM); diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 6c96e6338cda2..cff3f3c87214d 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -26,7 +26,6 @@ class RISCVABIInfo : public DefaultABIInfo { // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target // with soft float ABI has FLen==0). unsigned FLen; - unsigned ABIVLen; const int NumArgGPRs; const int NumArgFPRs; const bool EABI; @@ -38,8 +37,8 @@ class RISCVABIInfo : public DefaultABIInfo { public: RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, - unsigned ABIVLen, bool EABI) - : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), ABIVLen(ABIVLen), + bool EABI) + : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8), NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are @@ -47,8 +46,8 @@ class RISCVABIInfo : public DefaultABIInfo { void computeInfo(CGFunctionInfo &FI) const override; ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, - int &ArgFPRsLeft, unsigned ArgABIVLen) const; - ABIArgInfo classifyReturnType(QualType RetTy, unsigned ArgABIVLen) 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; @@ -64,7 +63,7 @@ class RISCVABIInfo : public DefaultABIInfo { llvm::Type *Field2Ty, CharUnits Field2Off) const; - ABIArgInfo coerceVLSVector(QualType Ty, unsigned ArgABIVLen = 0) const; + ABIArgInfo coerceVLSVector(QualType Ty, unsigned ABIVLen = 0) const; using ABIInfo::appendAttributeMangling; void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, @@ -113,18 +112,10 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, } void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { - unsigned ArgABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen(); - // If ArgABIVLen is default value(2), try to set it to the value passed by - // option if any, otherwise, set it to default value 128. - // Note that ArgABIVLen == 1 means vector_cc is not enabled. - if (ArgABIVLen == 2 && ABIVLen) - ArgABIVLen = ABIVLen; - else if (ArgABIVLen == 2) - ArgABIVLen = 128; - + unsigned ABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen(); QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(RetTy, ArgABIVLen); + 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 @@ -151,7 +142,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { for (auto &ArgInfo : FI.arguments()) { bool IsFixed = ArgNum < NumFixedArgs; ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, - ArgFPRsLeft, ArgABIVLen); + ArgFPRsLeft, ABIVLen); ArgNum++; } } @@ -373,7 +364,7 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( // 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, - unsigned ArgABIVLen) const { + unsigned ABIVLen) const { assert(Ty->isVectorType() && "expected vector type!"); const auto *VT = Ty->castAs(); @@ -405,7 +396,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, llvm::ScalableVectorType *ResType; - if (ArgABIVLen == 0) { + if (ABIVLen == 0) { // The MinNumElts is simplified from equation: // NumElts / VScale = // (EltSize * NumElts / (VScale * RVVBitsPerBlock)) @@ -429,7 +420,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, // The number of elements needs to be at least 1. ResType = llvm::ScalableVectorType::get( EltType, - llvm::divideCeil(NumElts * llvm::RISCV::RVVBitsPerBlock, ArgABIVLen)); + llvm::divideCeil(NumElts * llvm::RISCV::RVVBitsPerBlock, ABIVLen)); } return ABIArgInfo::getDirect(ResType); @@ -438,7 +429,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, int &ArgFPRsLeft, - unsigned ArgABIVLen) const { + unsigned ABIVLen) const { assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); @@ -542,10 +533,10 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) return coerceVLSVector(Ty); - if (VT->getVectorKind() == VectorKind::Generic && ArgABIVLen != 1) + if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 1) // Generic vector without riscv_vls_cc should fall through and pass by // reference. - return coerceVLSVector(Ty, ArgABIVLen); + return coerceVLSVector(Ty, ABIVLen); } // Aggregates which are <= 2*XLen will be passed in registers if possible, @@ -570,7 +561,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, } ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, - unsigned ArgABIVLen) const { + unsigned ABIVLen) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -580,7 +571,7 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, // The rules for return and argument types are the same, so defer to // classifyArgumentType. return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, ArgFPRsLeft, - ArgABIVLen); + ABIVLen); } RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, @@ -619,9 +610,9 @@ namespace { class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { public: RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, - unsigned FLen, unsigned ABIVLen, bool EABI) + unsigned FLen, bool EABI) : TargetCodeGenInfo( - std::make_unique(CGT, XLen, FLen, ABIVLen, EABI)) { + std::make_unique(CGT, XLen, FLen, EABI)) { SwiftInfo = std::make_unique(CGT, /*SwiftErrorInRegister=*/false); } @@ -653,8 +644,7 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { std::unique_ptr CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, - unsigned FLen, unsigned ABIVLen, - bool EABI) { + unsigned FLen, bool EABI) { return std::make_unique(CGM.getTypes(), XLen, FLen, - ABIVLen, EABI); + EABI); } diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 18da247b3eab4..6935904a24edb 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -95,10 +95,6 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, CPUFastVectorUnaligned = true; } - if (Arg *A = Args.getLastArg(options::OPT_mriscv_abi_vlen_EQ)) - Features.push_back( - Args.MakeArgString(Twine("+abi-vlen-") + A->getValue() + "b")); - // Handle features corresponding to "-ffixed-X" options #define RESERVE_REG(REG) \ if (Args.hasArg(options::OPT_ffixed_##REG)) \ diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3e83192ceebee..33f08cf28feca 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2225,21 +2225,6 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, << A->getSpelling() << Val; } } - - if (Arg *A = Args.getLastArg(options::OPT_mriscv_abi_vlen_EQ)) { - StringRef ABIVLenStr = A->getValue(); - unsigned ABIVLen; - const Driver &D = getToolChain().getDriver(); - if (ABIVLenStr.getAsInteger(10, ABIVLen) || ABIVLen < 32 || - ABIVLen > 65536 || !llvm::isPowerOf2_64(ABIVLen)) { - D.Diag(diag::err_drv_invalid_value) - << A->getOption().getName() << ABIVLenStr; - return; - } - - CmdArgs.push_back( - Args.MakeArgString(Twine("-mriscv-abi-vlen=") + A->getValue())); - } } void Clang::AddSparcTargetArgs(const ArgList &Args, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f6f7cbb278f5d..88e47fd5f8249 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8107,9 +8107,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, Attr *CCAttr = getCCTypeAttr(S.Context, attr); if (attr.getKind() == ParsedAttr::AT_RISCVVLSCC) { - // If the riscv_abi_vlen doesn't have any argument, we set set it to 2 to - // differentiate from functions without attribute. - unsigned ABIVLen = 2; + // If the riscv_abi_vlen doesn't have any argument, we set set it to default + // value 128. + unsigned ABIVLen = 128; if (attr.getNumArgs() && !S.checkUInt32Argument(attr, attr.getArgAsExpr(0), ABIVLen)) return false; 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 0b06bede29dc7..3cb1fa0407d8a 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -5,12 +5,6 @@ // 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 -// RUN: %clang_cc1 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ -// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s -// RUN: %clang_cc1 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +zve32x \ -// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN-ZVE32X %s -// RUN: %clang_cc1 -std=c23 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ -// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s #include @@ -42,45 +36,34 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { } // CHECK-LLVM: define dso_local void @test_vls_no_cc(i128 noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: 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 void @test_vls_default_abi_vlen( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen( 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 void @test_vls_default_abi_vlen_c23( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23( 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 void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature( 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 void @test_vls_default_abi_vlen_unsupported_feature_zve32x( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature_zve32x( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) [[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} // CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( 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 void @test_vls_256_abi_vlen_c23( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen_c23( 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 void @test_vls_least_element( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_least_element( 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 void @test_vls_least_element_c23( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_least_element_c23( noundef %arg.coerce) [[riscv::vls_cc(1024)]] void test_vls_least_element_c23(__attribute__((vector_size(8))) int 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 0b91f8b3877eb..4265e129c2fdb 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -3,10 +3,6 @@ // 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 -// RUN: %clang_cc1 -std=c++11 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +v \ -// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s -// RUN: %clang_cc1 -std=c++11 -triple riscv64 -mriscv-abi-vlen=256 -target-feature +zve32x \ -// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN-ZVE32X %s #include @@ -38,25 +34,19 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { } // CHECK-LLVM: define dso_local void @_Z14test_vls_no_ccDv4_i(i128 noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: 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 void @_Z25test_vls_default_abi_vlenDv4_i( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i( 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( 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 void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) [[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} // CHECK-LLVM: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( 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 void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) -// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) [[riscv::vls_cc(1024)]] void test_vls_least_element(__attribute__((vector_size(8))) int arg) {} From 9d1f138f14291d9040d5e41d6a8917ed7fa0b099 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Sun, 5 Jan 2025 22:25:17 -0800 Subject: [PATCH 06/12] fixup! handle struct and minor fixup --- clang/lib/CodeGen/CGCall.cpp | 11 ++ clang/lib/CodeGen/Targets/RISCV.cpp | 160 +++++++++++++++++- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 108 ++++++++++++ .../riscv-vector-callingconv-llvm-ir.cpp | 108 ++++++++++++ 4 files changed, 384 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 9e143c26fb47e..e2364cf3b303c 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3240,6 +3240,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(ConvertType(Ty)) && + (isa(ArgI.getCoerceToType()) || + isa(ArgI.getCoerceToType()))) { + ArgVals.push_back(ParamValue::forDirect(AI)); + break; + } + llvm::StructType *STy = dyn_cast(ArgI.getCoerceToType()); Address Alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg), diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index cff3f3c87214d..80e09ec6c455f 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -35,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) @@ -361,6 +364,149 @@ 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 power of 2. + // 3. Total number of vector registers needed should not exceed 8. + // + // Examples: Assume ABI_VLEN = 128. + // These are legal structs: + // a. Structs with 1, 2, 4 or 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, 2, 4 + // or 8, e.g. + // struct { + // __attribute__((vector_size(16))) int a[2]; + // } + // These are illegal structs: + // a. Structs with 3 fixed-length vectors, e.g. + // struct { + // __attribute__((vector_size(16))) int a; + // __attribute__((vector_size(16))) int b; + // __attribute__((vector_size(16))) int c; + // } + // + // 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(CGT.ConvertType(Ty))) { + int NumElts = STy->getStructNumElements(); + if (NumElts > 8 || !llvm::isPowerOf2_32(NumElts)) + 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(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(FirstEltTy)) { + int NumArrElt = ArrTy->getNumElements(); + if (NumArrElt > 8 || !llvm::isPowerOf2_32(NumArrElt)) + return false; + + auto *ArrEltTy = dyn_cast(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, @@ -410,11 +556,13 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, (EltType->isBFloatTy() && !TI.hasFeature("zvfbfmin")) || (EltType->isFloatTy() && !TI.hasFeature("zve32f")) || (EltType->isDoubleTy() && !TI.hasFeature("zve64d")) || - (EltType->isIntegerTy(64) && !TI.hasFeature("zve64x")) || - EltType->isIntegerTy(128)) { + EltType->isIntegerTy(128)) EltType = llvm::Type::getIntNTy(getVMContext(), EltType->getScalarSizeInBits()); - } + + // 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. @@ -485,6 +633,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" 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 3cb1fa0407d8a..78e1ed3772789 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -67,3 +67,111 @@ void __attribute__((riscv_vls_cc(1024))) test_vls_least_element(__attribute__((v // CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_least_element_c23( 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_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 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 void @test_too_large_256( noundef %arg.coerce) +void __attribute__((riscv_vls_cc(256))) test_too_large_256(int32x64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4( %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4(struct st_i32x4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_256( %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4_256(struct st_i32x4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr1( %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr1_256( %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 void @test_st_i32x4_arr4( %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr4_256( %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 void @test_st_i32x4_arr8( %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr8_256( %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 void @test_st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x2(struct st_i32x4x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4x2_256(target("riscv.vector.tuple", , 2) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x2_256(struct st_i32x4x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x8x2(struct st_i32x8x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x8x2_256(target("riscv.vector.tuple", , 2) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x8x2_256(struct st_i32x8x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc 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 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 void @test_st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +void __attribute__((riscv_vls_cc)) test_st_i32x4x8(struct st_i32x4x8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4x8_256(target("riscv.vector.tuple", , 8) %arg) +void __attribute__((riscv_vls_cc(256))) test_st_i32x4x8_256(struct st_i32x4x8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc 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 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 4265e129c2fdb..6281b640c4df0 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -50,3 +50,111 @@ void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} // CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_vls_least_elementDv2_i( 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_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 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 void @_Z18test_too_large_256Dv64_i( noundef %arg.coerce) +[[riscv::vls_cc(256)]] void test_too_large_256(int32x64_t arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z13test_st_i32x48st_i32x4( %arg) +[[riscv::vls_cc]] void test_st_i32x4(struct st_i32x4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z17test_st_i32x4_2568st_i32x4( %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_256(struct st_i32x4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr113st_i32x4_arr1( %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1( %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr413st_i32x4_arr4( %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4( %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr813st_i32x4_arr8( %arg) +[[riscv::vls_cc]] void test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8( %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +[[riscv::vls_cc]] void test_st_i32x4x2(struct st_i32x4x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x4x2_25610st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x2_256(struct st_i32x4x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z15test_st_i32x8x210st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +[[riscv::vls_cc]] void test_st_i32x8x2(struct st_i32x8x2 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x8x2_25610st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x8x2_256(struct st_i32x8x2 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc 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 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 void @_Z15test_st_i32x4x810st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +[[riscv::vls_cc]] void test_st_i32x4x8(struct st_i32x4x8 arg) {} +// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x4x8_25610st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x8_256(struct st_i32x4x8 arg) {} + +// CHECK-LLVM: define dso_local riscv_vls_cc 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 void @_Z19test_st_i32x4x9_25610st_i32x4x9(ptr noundef %arg) +[[riscv::vls_cc(256)]] void test_st_i32x4x9_256(struct st_i32x4x9 arg) {} From 22a5b0e03e561cfabf3d6be605afe6f04aab3c61 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Tue, 14 Jan 2025 02:31:59 -0800 Subject: [PATCH 07/12] fixup! Add all 32-65536 calling conventions and remove log2ABIVLen --- clang/include/clang-c/Index.h | 13 +- clang/include/clang/AST/Type.h | 44 +++---- clang/include/clang/AST/TypeProperties.td | 7 +- clang/include/clang/Basic/Specifiers.h | 62 +++++---- clang/include/clang/CodeGen/CGFunctionInfo.h | 9 +- clang/lib/AST/ASTContext.cpp | 2 - clang/lib/AST/ItaniumMangle.cpp | 15 ++- clang/lib/AST/Type.cpp | 16 ++- clang/lib/AST/TypePrinter.cpp | 20 ++- clang/lib/Basic/Targets/RISCV.cpp | 13 +- clang/lib/CodeGen/CGCall.cpp | 42 ++++++- clang/lib/CodeGen/CGDebugInfo.cpp | 17 ++- clang/lib/CodeGen/Targets/RISCV.cpp | 43 ++++++- clang/lib/Sema/SemaDeclAttr.cpp | 25 +++- clang/lib/Sema/SemaType.cpp | 38 +++--- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 60 ++++----- .../riscv-vector-callingconv-llvm-ir.cpp | 50 ++++---- .../CodeGen/RISCV/riscv-vector-callingconv.c | 12 +- .../RISCV/riscv-vector-callingconv.cpp | 6 +- clang/tools/libclang/CXType.cpp | 13 +- llvm/include/llvm/IR/CallingConv.h | 13 +- llvm/lib/AsmParser/LLParser.cpp | 30 ++++- llvm/lib/IR/AsmWriter.cpp | 18 ++- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 15 ++- llvm/test/Assembler/riscv_vls_cc.ll | 118 +++++++++++++++++- llvm/test/Bitcode/compatibility.ll | 50 +++++++- 26 files changed, 564 insertions(+), 187 deletions(-) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 21a4863203b6e..dfcd493470075 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3053,7 +3053,18 @@ enum CXCallingConv { CXCallingConv_M68kRTD = 19, CXCallingConv_PreserveNone = 20, CXCallingConv_RISCVVectorCall = 21, - CXCallingConv_RISCVVLSCall = 22, + 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 ccdcbfe14ff24..1568ee4c8f8dc 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 : 18; + unsigned ExtInfo : 14; /// The ref-qualifier associated with a \c FunctionProtoType. /// @@ -4437,40 +4437,36 @@ 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 | - // |RISCV-ABI-VLEN| - // |13 .. 17| + // |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 { CallConvMask = 0x3F }; + enum { NoReturnMask = 0x40 }; + enum { ProducesResultMask = 0x80 }; + enum { NoCallerSavedRegsMask = 0x100 }; enum { - RegParmMask = 0x700, - RegParmOffset = 8 + RegParmMask = 0xe00, + RegParmOffset = 9 }; - enum { NoCfCheckMask = 0x800 }; - enum { CmseNSCallMask = 0x1000 }; - enum { Log2RISCVABIVLenMask = 0x3E000, Log2RISCVABIVLenOffset = 13 }; - uint32_t Bits = CC_C; + enum { NoCfCheckMask = 0x1000 }; + enum { CmseNSCallMask = 0x2000 }; + uint16_t Bits = CC_C; - ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} + ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs, bool NoCfCheck, - bool cmseNSCall, unsigned Log2RISCVABIVLen) { + bool cmseNSCall) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | (producesResult ? ProducesResultMask : 0) | (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | (NoCfCheck ? NoCfCheckMask : 0) | - (cmseNSCall ? CmseNSCallMask : 0) | - (Log2RISCVABIVLen << Log2RISCVABIVLenOffset); + (cmseNSCall ? CmseNSCallMask : 0); } // Constructor with all defaults. Use when for example creating a @@ -4497,10 +4493,6 @@ class FunctionType : public Type { CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } - unsigned getLog2RISCVABIVLen() const { - return (Bits & Log2RISCVABIVLenMask) >> Log2RISCVABIVLenOffset; - } - bool operator==(ExtInfo Other) const { return Bits == Other.Bits; } @@ -4556,11 +4548,6 @@ class FunctionType : public Type { return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } - ExtInfo withLog2RISCVABIVLen(unsigned Log2RISCVABIVLen) const { - return ExtInfo((Bits & ~Log2RISCVABIVLenMask) | - (Log2RISCVABIVLen << Log2RISCVABIVLenOffset)); - } - void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } @@ -4670,9 +4657,6 @@ class FunctionType : public Type { bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } - unsigned getLog2RISCVABIVLen() const { - return getExtInfo().getLog2RISCVABIVLen(); - } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index d5f653013a9b8..6f1a76bd18fb5 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -313,9 +313,6 @@ let Class = FunctionType in { def : Property<"cmseNSCall", Bool> { let Read = [{ node->getExtInfo().getCmseNSCall() }]; } - def : Property<"Log2RISCVABIVLen", UInt32> { - let Read = [{ node->getExtInfo().getLog2RISCVABIVLen() }]; - } } let Class = FunctionNoProtoType in { @@ -323,7 +320,7 @@ let Class = FunctionNoProtoType in { auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, callingConvention, producesResult, noCallerSavedRegs, noCfCheck, - cmseNSCall, Log2RISCVABIVLen); + cmseNSCall); return ctx.getFunctionNoProtoType(returnType, extInfo); }]>; } @@ -366,7 +363,7 @@ let Class = FunctionProtoType in { auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, callingConvention, producesResult, noCallerSavedRegs, noCfCheck, - cmseNSCall, Log2RISCVABIVLen); + cmseNSCall); FunctionProtoType::ExtProtoInfo epi; epi.ExtInfo = extInfo; epi.Variadic = variadic; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index d2df5a24da143..491badcc804e7 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -276,31 +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_RISCVVLSCall, // __attribute__((riscv_vls_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/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 44ae2755a2ab0..9d785d878b61d 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -625,9 +625,6 @@ class CGFunctionInfo final /// Log 2 of the maximum vector width. unsigned MaxVectorWidth : 4; - /// Log2 of ABI_VLEN used in RISCV VLS calling convention. - unsigned Log2RISCVABIVLen : 5; - RequiredArgs Required; /// The struct representing all arguments passed in memory. Only used when @@ -738,13 +735,11 @@ class CGFunctionInfo final bool getHasRegParm() const { return HasRegParm; } unsigned getRegParm() const { return RegParm; } - unsigned getLog2RISCVABIVLen() const { return Log2RISCVABIVLen; } - FunctionType::ExtInfo getExtInfo() const { return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), getASTCallingConvention(), isReturnsRetained(), isNoCallerSavedRegs(), isNoCfCheck(), - isCmseNSCall(), getLog2RISCVABIVLen()); + isCmseNSCall()); } CanQualType getReturnType() const { return getArgsBuffer()[0].type; } @@ -798,7 +793,6 @@ class CGFunctionInfo final ID.AddInteger(RegParm); ID.AddBoolean(NoCfCheck); ID.AddBoolean(CmseNSCall); - ID.AddInteger(Log2RISCVABIVLen); ID.AddInteger(Required.getOpaqueData()); ID.AddBoolean(HasExtParameterInfos); if (HasExtParameterInfos) { @@ -826,7 +820,6 @@ class CGFunctionInfo final ID.AddInteger(info.getRegParm()); ID.AddBoolean(info.getNoCfCheck()); ID.AddBoolean(info.getCmseNSCall()); - ID.AddInteger(info.getLog2RISCVABIVLen()); ID.AddInteger(required.getOpaqueData()); ID.AddBoolean(!paramInfos.empty()); if (!paramInfos.empty()) { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 7d043068fa095..be1dd29d46278 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11108,8 +11108,6 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return {}; if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck()) return {}; - if (lbaseInfo.getLog2RISCVABIVLen() != rbaseInfo.getLog2RISCVABIVLen()) - return {}; // When merging declarations, it's common for supplemental information like // attributes to only be present in one of the declarations, and we generally diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index a63556c647af4..a6ec9925a6fc2 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3489,7 +3489,20 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_M68kRTD: case CC_PreserveNone: case CC_RISCVVectorCall: - case CC_RISCVVLSCall: +#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 3472972f6f106..ff7ea5d97b83b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3561,7 +3561,21 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_PreserveNone: return "preserve_none"; // clang-format off case CC_RISCVVectorCall: return "riscv_vector_cc"; - case CC_RISCVVLSCall: return "riscv_vls_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 } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 65d3b3108175d..ca62112e22c61 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1136,9 +1136,23 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_RISCVVectorCall: OS << "__attribute__((riscv_vector_cc))"; break; - case CC_RISCVVLSCall: - OS << "__attribute__((riscv_vls_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 } } diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index ebced9da22e8c..d7fa44f5cf400 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -516,7 +516,18 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { return CCCR_Warning; case CC_C: case CC_RISCVVectorCall: - case CC_RISCVVLSCall: + 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 e2364cf3b303c..1564b2cdcdf3a 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -76,8 +76,23 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_PreserveNone: return llvm::CallingConv::PreserveNone; // clang-format off case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall; - case CC_RISCVVLSCall: return llvm::CallingConv::RISCV_VLSCall; // 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 } } @@ -267,8 +282,28 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, if (D->hasAttr()) return CC_RISCVVectorCall; - if (D->hasAttr()) - return CC_RISCVVLSCall; + if (RISCVVLSCCAttr *PCS = D->getAttr()) { + 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; } @@ -865,7 +900,6 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, bool instanceMethod, FI->HasExtParameterInfos = !paramInfos.empty(); FI->getArgsBuffer()[0].type = resultType; FI->MaxVectorWidth = 0; - FI->Log2RISCVABIVLen = info.getLog2RISCVABIVLen(); for (unsigned i = 0, e = argTypes.size(); i != e; ++i) FI->getArgsBuffer()[i + 1].type = argTypes[i]; for (unsigned i = 0, e = paramInfos.size(); i != e; ++i) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 9d6fa7f98461b..68bf847f86813 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1593,8 +1593,21 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_PreserveNone; case CC_RISCVVectorCall: return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; - case CC_RISCVVLSCall: - 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 80e09ec6c455f..bbc23738074fc 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -115,7 +115,48 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, } void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { - unsigned ABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen(); + unsigned ABIVLen; + switch (FI.getExtInfo().getCC()) { + default: + ABIVLen = 1; + break; + case CallingConv::CC_RISCVVLSCall_32: + ABIVLen = 32; + break; + case CallingConv::CC_RISCVVLSCall_64: + ABIVLen = 64; + break; + case CallingConv::CC_RISCVVLSCall_128: + ABIVLen = 128; + break; + case CallingConv::CC_RISCVVLSCall_256: + ABIVLen = 256; + break; + case CallingConv::CC_RISCVVLSCall_512: + ABIVLen = 512; + break; + case CallingConv::CC_RISCVVLSCall_1024: + ABIVLen = 1024; + break; + case CallingConv::CC_RISCVVLSCall_2048: + ABIVLen = 2048; + break; + case CallingConv::CC_RISCVVLSCall_4096: + ABIVLen = 4096; + break; + case CallingConv::CC_RISCVVLSCall_8192: + ABIVLen = 8192; + break; + case CallingConv::CC_RISCVVLSCall_16384: + ABIVLen = 16384; + break; + case CallingConv::CC_RISCVVLSCall_32768: + ABIVLen = 32768; + break; + case CallingConv::CC_RISCVVLSCall_65536: + ABIVLen = 65536; + break; + } QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(RetTy, ABIVLen); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4645c47f85b59..e730f25201dcd 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5248,9 +5248,30 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_RISCVVectorCC: CC = CC_RISCVVectorCall; break; - case ParsedAttr::AT_RISCVVLSCC: - CC = CC_RISCVVLSCall; + 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::CC_RISCVVLSCall_32 + + llvm::Log2_64(ABIVLen) - 5); break; + } default: llvm_unreachable("unexpected attribute kind"); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 88e47fd5f8249..04e024764c22c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7618,8 +7618,20 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_RISCVVectorCC: return createSimpleAttr(Ctx, Attr); - case ParsedAttr::AT_RISCVVLSCC: - return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, /*dummy*/ 0); + 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 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!"); } @@ -8106,28 +8118,6 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, CallingConv CCOld = fn->getCallConv(); Attr *CCAttr = getCCTypeAttr(S.Context, attr); - if (attr.getKind() == 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() && - !S.checkUInt32Argument(attr, attr.getArgAsExpr(0), ABIVLen)) - return false; - if (attr.getNumArgs() && (ABIVLen < 32 || ABIVLen > 65536)) { - S.Diag(attr.getLoc(), diag::err_argument_invalid_range) - << ABIVLen << 32 << 65536; - return false; - } - if (!llvm::isPowerOf2_64(ABIVLen)) { - S.Diag(attr.getLoc(), diag::err_argument_not_power_of_2); - return false; - } - - auto EI = unwrapped.get()->getExtInfo().withLog2RISCVABIVLen( - llvm::Log2_64(ABIVLen)); - type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); - } - if (CCOld != CC) { // Error out on when there's already an attribute on the type // and the CCs don't match. 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 78e1ed3772789..61300d62e1eb6 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -38,34 +38,34 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { // 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 void @test_vls_default_abi_vlen( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen( 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 void @test_vls_default_abi_vlen_c23( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23( 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 void @test_vls_default_abi_vlen_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature( 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 void @test_vls_default_abi_vlen_unsupported_feature_zve32x( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature_zve32x( 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 void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( noundef %arg.coerce) [[riscv::vls_cc]] void test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_256_abi_vlen( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_vls_256_abi_vlen( 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 void @test_vls_256_abi_vlen_c23( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_vls_256_abi_vlen_c23( 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 void @test_vls_least_element( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @test_vls_least_element( 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 void @test_vls_least_element_c23( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @test_vls_least_element_c23( noundef %arg.coerce) [[riscv::vls_cc(1024)]] void test_vls_least_element_c23(__attribute__((vector_size(8))) int arg) {} @@ -126,52 +126,52 @@ struct st_i32x4x9{ typedef int __attribute__((vector_size(256))) int32x64_t; -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_too_large(ptr noundef %0) +// 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 void @test_too_large_256( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_too_large_256( noundef %arg.coerce) void __attribute__((riscv_vls_cc(256))) test_too_large_256(int32x64_t arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4( %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4(struct st_i32x4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_256( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_256( %arg) void __attribute__((riscv_vls_cc(256))) test_st_i32x4_256(struct st_i32x4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr1( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr1( %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr1_256( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr1_256( %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 void @test_st_i32x4_arr4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4( %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr4_256( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256( %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 void @test_st_i32x4_arr8( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8( %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4_arr8_256( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256( %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 void @test_st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4x2(struct st_i32x4x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4x2_256(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x2_256(target("riscv.vector.tuple", , 2) %arg) void __attribute__((riscv_vls_cc(256))) test_st_i32x4x2_256(struct st_i32x4x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) void __attribute__((riscv_vls_cc)) test_st_i32x8x2(struct st_i32x8x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x8x2_256(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x8x2_256(target("riscv.vector.tuple", , 2) %arg) void __attribute__((riscv_vls_cc(256))) test_st_i32x8x2_256(struct st_i32x8x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x64x2(ptr noundef %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 void @test_st_i32x64x2_256(ptr noundef %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 void @test_st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) void __attribute__((riscv_vls_cc)) test_st_i32x4x8(struct st_i32x4x8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4x8_256(target("riscv.vector.tuple", , 8) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4x8_256(target("riscv.vector.tuple", , 8) %arg) void __attribute__((riscv_vls_cc(256))) test_st_i32x4x8_256(struct st_i32x4x8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @test_st_i32x4x9(ptr noundef %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 void @test_st_i32x4x9_256(ptr noundef %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 6281b640c4df0..dbf7671d96732 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -36,19 +36,19 @@ vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { // 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 void @_Z25test_vls_default_abi_vlenDv4_i( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z25test_vls_default_abi_vlenDv4_i( 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( 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 void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( noundef %arg.coerce) [[riscv::vls_cc]] void test_vls_default_abi_vlen_unsupported_feature_zve32x(__attribute__((vector_size(16))) float arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z21test_vls_256_abi_vlenDv4_i( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z21test_vls_256_abi_vlenDv4_i( 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 void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(1024) void @_Z22test_vls_least_elementDv2_i( noundef %arg.coerce) [[riscv::vls_cc(1024)]] void test_vls_least_element(__attribute__((vector_size(8))) int arg) {} @@ -109,52 +109,52 @@ struct st_i32x4x9{ typedef int __attribute__((vector_size(256))) int32x64_t; -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z14test_too_largeDv64_i(ptr noundef %0) +// 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 void @_Z18test_too_large_256Dv64_i( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z18test_too_large_256Dv64_i( noundef %arg.coerce) [[riscv::vls_cc(256)]] void test_too_large_256(int32x64_t arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z13test_st_i32x48st_i32x4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z13test_st_i32x48st_i32x4( %arg) [[riscv::vls_cc]] void test_st_i32x4(struct st_i32x4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z17test_st_i32x4_2568st_i32x4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z17test_st_i32x4_2568st_i32x4( %arg) [[riscv::vls_cc(256)]] void test_st_i32x4_256(struct st_i32x4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr113st_i32x4_arr1( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr113st_i32x4_arr1( %arg) [[riscv::vls_cc]] void test_st_i32x4_arr1(struct st_i32x4_arr1 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1( %arg) [[riscv::vls_cc(256)]] void test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr413st_i32x4_arr4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4( %arg) [[riscv::vls_cc]] void test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4( %arg) [[riscv::vls_cc(256)]] void test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z18test_st_i32x4_arr813st_i32x4_arr8( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8( %arg) [[riscv::vls_cc]] void test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8( %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8( %arg) [[riscv::vls_cc(256)]] void test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) [[riscv::vls_cc]] void test_st_i32x4x2(struct st_i32x4x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x4x2_25610st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x2_25610st_i32x4x2(target("riscv.vector.tuple", , 2) %arg) [[riscv::vls_cc(256)]] void test_st_i32x4x2_256(struct st_i32x4x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z15test_st_i32x8x210st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x8x210st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) [[riscv::vls_cc]] void test_st_i32x8x2(struct st_i32x8x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x8x2_25610st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x8x2_25610st_i32x8x2(target("riscv.vector.tuple", , 2) %arg) [[riscv::vls_cc(256)]] void test_st_i32x8x2_256(struct st_i32x8x2 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z16test_st_i32x64x211st_i32x64x2(ptr noundef %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 void @_Z20test_st_i32x64x2_25611st_i32x64x2(ptr noundef %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 void @_Z15test_st_i32x4x810st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x810st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) [[riscv::vls_cc]] void test_st_i32x4x8(struct st_i32x4x8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z19test_st_i32x4x8_25610st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) +// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z19test_st_i32x4x8_25610st_i32x4x8(target("riscv.vector.tuple", , 8) %arg) [[riscv::vls_cc(256)]] void test_st_i32x4x8_256(struct st_i32x4x8 arg) {} -// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z15test_st_i32x4x910st_i32x4x9(ptr noundef %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 void @_Z19test_st_i32x4x9_25610st_i32x4x9(ptr noundef %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 da4819186f4e2..6a71d1a9db81f 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c @@ -19,17 +19,17 @@ void test_no_attribute2(int); // expected-note {{previous declaration is here}} __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]}} expected-warning {{'riscv_vls_cc' only applies to function types; type here is 'void (void)__attribute__((riscv_vls_cc))'}} -__attribute__((riscv_vls_cc(129))) void func_vls_invalid(); // expected-error {{argument should be a power of 2}} expected-warning {{'riscv_vls_cc' only applies to function types; type here is 'void (void)__attribute__((riscv_vls_cc))'}} +__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' here was previously declared without calling convention}} +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]}} expected-warning {{'vls_cc' only applies to function types; type here is 'void (void)'}} -[[riscv::vls_cc(129)]] void func_vls_invalid2(); // expected-error {{argument should be a power of 2}} expected-warning {{'vls_cc' only applies to function types; type here is 'void (void)'}} +[[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' here was previously declared without calling convention}} +[[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 5e27c76d5307f..f041b0d36529c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp @@ -37,11 +37,11 @@ void test_lambda2() { [[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]}} expected-warning {{'vls_cc' only applies to function types; type here is 'void ()'}} -[[riscv::vls_cc(129)]] void func_invalid_vls(); // expected-error {{argument should be a power of 2}} expected-warning {{'vls_cc' only applies to function types; type here is 'void ()'}} +[[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' here was previously declared without calling convention}} +[[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(); diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index 65fa6fa254095..f4227fd030734 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -701,7 +701,18 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(M68kRTD); TCALLINGCONV(PreserveNone); TCALLINGCONV(RISCVVectorCall); - TCALLINGCONV(RISCVVLSCall); + 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/IR/CallingConv.h b/llvm/include/llvm/IR/CallingConv.h index bc3a75f2fe665..7897aabb6c1a9 100644 --- a/llvm/include/llvm/IR/CallingConv.h +++ b/llvm/include/llvm/IR/CallingConv.h @@ -271,7 +271,18 @@ namespace CallingConv { AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1 = 111, /// Calling convention used for RISC-V V-extension fixed vectors. - RISCV_VLSCall = 112, + 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/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index abf98f76b6a61..6d5600212f263 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2285,8 +2285,36 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) { CC = CallingConv::RISCV_VectorCall; break; case lltok::kw_riscv_vls_cc: - CC = CallingConv::RISCV_VLSCall; + // 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 67a8e6260f1e3..f3cbc13a534e1 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -368,9 +368,23 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::RISCV_VectorCall: Out << "riscv_vector_cc"; break; - case CallingConv::RISCV_VLSCall: - Out << "riscv_vls_cc"; +#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 96f51580d6ace..0103b7d428976 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -19901,7 +19901,20 @@ SDValue RISCVTargetLowering::LowerFormalArguments( case CallingConv::SPIR_KERNEL: case CallingConv::GRAAL: case CallingConv::RISCV_VectorCall: - case CallingConv::RISCV_VLSCall: +#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 index cc63e61ed6a1f..bfe1def3fc3be 100644 --- a/llvm/test/Assembler/riscv_vls_cc.ll +++ b/llvm/test/Assembler/riscv_vls_cc.ll @@ -1,12 +1,122 @@ ; RUN: llvm-as < %s | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: define riscv_vls_cc void @no_args() { -define riscv_vls_cc void @no_args() { +; 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 void @byval_arg(ptr byval(i32) %0) { -define riscv_vls_cc void @byval_arg(ptr byval(i32)) { +; 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 485508ca0013a..3e68ca061bd2e 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -517,9 +517,53 @@ declare cc96 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 void @f.cc112() -declare riscv_vls_cc void @riscv_vls_cc() -; CHECK: declare riscv_vls_cc void @riscv_vls_cc() +; 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() From 29b0c56c9ff62a008e3bd892dc89de22471793c6 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Fri, 17 Jan 2025 02:55:21 -0800 Subject: [PATCH 08/12] fixup! fixed comments --- clang/include/clang/Driver/Options.td | 1 + clang/lib/CodeGen/Targets/RISCV.cpp | 26 ++++++++++------- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 29 +++++++++++++------ .../riscv-vector-callingconv-llvm-ir.cpp | 29 +++++++++++++------ 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4a4900a0e3b6e..2721c1b5d8dc5 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4992,6 +4992,7 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group, !eq(GlobalDocumentation.Program, "Flang") : "", true: " The value will be reflected in __riscv_v_fixed_vlen preprocessor define"), " (RISC-V only)")>; + def munaligned_access : Flag<["-"], "munaligned-access">, Group, HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">; def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group, diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index bbc23738074fc..66ab6d9261e1f 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -118,7 +118,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { unsigned ABIVLen; switch (FI.getExtInfo().getCC()) { default: - ABIVLen = 1; + ABIVLen = 0; break; case CallingConv::CC_RISCVVLSCall_32: ABIVLen = 32; @@ -414,28 +414,34 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, // 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 power of 2. + // 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, 2, 4 or 8 "same" fixed-length vectors, e.g. + // 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, 2, 4 - // or 8, e.g. + // b. Structs with "single" fixed-length vector array with lengh 1~8, e.g. // struct { - // __attribute__((vector_size(16))) int a[2]; + // __attribute__((vector_size(16))) int a[3]; // } // These are illegal structs: - // a. Structs with 3 fixed-length vectors, e.g. + // 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. @@ -461,7 +467,7 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, if (llvm::StructType *STy = dyn_cast(CGT.ConvertType(Ty))) { int NumElts = STy->getStructNumElements(); - if (NumElts > 8 || !llvm::isPowerOf2_32(NumElts)) + if (NumElts > 8) return false; auto *FirstEltTy = STy->getElementType(0); @@ -517,7 +523,7 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, // if legal. if (auto *ArrTy = dyn_cast(FirstEltTy)) { int NumArrElt = ArrTy->getNumElements(); - if (NumArrElt > 8 || !llvm::isPowerOf2_32(NumArrElt)) + if (NumArrElt > 8) return false; auto *ArrEltTy = dyn_cast(ArrTy->getElementType()); @@ -728,7 +734,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) return coerceVLSVector(Ty); - if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 1) + if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 0) // Generic vector without riscv_vls_cc should fall through and pass by // reference. return coerceVLSVector(Ty, ABIVLen); 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 61300d62e1eb6..ec4fd44be4193 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -69,39 +69,45 @@ void __attribute__((riscv_vls_cc(1024))) test_vls_least_element(__attribute__((v [[riscv::vls_cc(1024)]] void test_vls_least_element_c23(__attribute__((vector_size(8))) int arg) {} -struct st_i32x4{ +struct st_i32x4 { __attribute__((vector_size(16))) int i32; }; -struct st_i32x4_arr1{ +struct st_i32x4_arr1 { __attribute__((vector_size(16))) int i32[1]; }; -struct st_i32x4_arr4{ +struct st_i32x4_arr4 { __attribute__((vector_size(16))) int i32[4]; }; -struct st_i32x4_arr8{ +struct st_i32x4_arr8 { __attribute__((vector_size(16))) int i32[8]; }; -struct st_i32x4x2{ +struct st_i32x4x2 { __attribute__((vector_size(16))) int i32_1; __attribute__((vector_size(16))) int i32_2; }; -struct st_i32x8x2{ +struct st_i32x8x2 { __attribute__((vector_size(32))) int i32_1; __attribute__((vector_size(32))) int i32_2; }; -struct st_i32x64x2{ +struct st_i32x64x2 { __attribute__((vector_size(256))) int i32_1; __attribute__((vector_size(256))) int i32_2; }; -struct st_i32x4x8{ +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; @@ -112,7 +118,7 @@ struct st_i32x4x8{ __attribute__((vector_size(16))) int i32_8; }; -struct st_i32x4x9{ +struct st_i32x4x9 { __attribute__((vector_size(16))) int i32_1; __attribute__((vector_size(16))) int i32_2; __attribute__((vector_size(16))) int i32_3; @@ -166,6 +172,11 @@ 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", , 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", , 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", , 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", , 8) %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 dbf7671d96732..0eedb13b53033 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -52,39 +52,45 @@ void test_vls_no_cc(__attribute__((vector_size(16))) int arg) {} [[riscv::vls_cc(1024)]] void test_vls_least_element(__attribute__((vector_size(8))) int arg) {} -struct st_i32x4{ +struct st_i32x4 { __attribute__((vector_size(16))) int i32; }; -struct st_i32x4_arr1{ +struct st_i32x4_arr1 { __attribute__((vector_size(16))) int i32[1]; }; -struct st_i32x4_arr4{ +struct st_i32x4_arr4 { __attribute__((vector_size(16))) int i32[4]; }; -struct st_i32x4_arr8{ +struct st_i32x4_arr8 { __attribute__((vector_size(16))) int i32[8]; }; -struct st_i32x4x2{ +struct st_i32x4x2 { __attribute__((vector_size(16))) int i32_1; __attribute__((vector_size(16))) int i32_2; }; -struct st_i32x8x2{ +struct st_i32x8x2 { __attribute__((vector_size(32))) int i32_1; __attribute__((vector_size(32))) int i32_2; }; -struct st_i32x64x2{ +struct st_i32x64x2 { __attribute__((vector_size(256))) int i32_1; __attribute__((vector_size(256))) int i32_2; }; -struct st_i32x4x8{ +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; @@ -95,7 +101,7 @@ struct st_i32x4x8{ __attribute__((vector_size(16))) int i32_8; }; -struct st_i32x4x9{ +struct st_i32x4x9 { __attribute__((vector_size(16))) int i32_1; __attribute__((vector_size(16))) int i32_2; __attribute__((vector_size(16))) int i32_3; @@ -149,6 +155,11 @@ typedef int __attribute__((vector_size(256))) int32x64_t; // 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", , 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", , 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", , 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", , 8) %arg) From 62196b846b901859340fc8759cf9aaa120aa7476 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Fri, 17 Jan 2025 03:05:20 -0800 Subject: [PATCH 09/12] fixup! clang-format --- clang/include/clang/AST/Type.h | 5 +---- clang/lib/CodeGen/Targets/RISCV.cpp | 8 +++----- clang/lib/Sema/SemaDeclAttr.cpp | 6 +++--- llvm/lib/AsmParser/LLParser.cpp | 6 +++--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 1568ee4c8f8dc..5af8541813540 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4444,10 +4444,7 @@ class FunctionType : public Type { enum { NoReturnMask = 0x40 }; enum { ProducesResultMask = 0x80 }; enum { NoCallerSavedRegsMask = 0x100 }; - enum { - RegParmMask = 0xe00, - RegParmOffset = 9 - }; + enum { RegParmMask = 0xe00, RegParmOffset = 9 }; enum { NoCfCheckMask = 0x1000 }; enum { CmseNSCallMask = 0x2000 }; uint16_t Bits = CC_C; diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 66ab6d9261e1f..9d39cb9dfc5c7 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -8,7 +8,6 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" -#include "llvm/TargetParser/RISCVTargetParser.h" using namespace clang; using namespace clang::CodeGen; @@ -41,8 +40,8 @@ class RISCVABIInfo : public DefaultABIInfo { public: RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, bool EABI) - : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), - NumArgGPRs(EABI ? 6 : 8), NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} + : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8), + NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload it. @@ -556,8 +555,7 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, // 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, - unsigned ABIVLen) const { +ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const { assert(Ty->isVectorType() && "expected vector type!"); const auto *VT = Ty->castAs(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e730f25201dcd..8425ea2173730 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5254,17 +5254,17 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, unsigned ABIVLen = 128; if (Attrs.getNumArgs() && !checkUInt32Argument(Attrs, Attrs.getArgAsExpr(0), ABIVLen)) { - Attrs.setInvalid(); + Attrs.setInvalid(); return true; } if (Attrs.getNumArgs() && (ABIVLen < 32 || ABIVLen > 65536)) { - Attrs.setInvalid(); + Attrs.setInvalid(); Diag(Attrs.getLoc(), diag::err_argument_invalid_range) << ABIVLen << 32 << 65536; return true; } if (!llvm::isPowerOf2_64(ABIVLen)) { - Attrs.setInvalid(); + Attrs.setInvalid(); Diag(Attrs.getLoc(), diag::err_argument_not_power_of_2); return true; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 6d5600212f263..dfbf80ab0437e 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2296,9 +2296,9 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) { switch (ABIVlen) { default: return tokError("unknown RISC-V ABI VLEN"); -#define CC_VLS_CASE(ABIVlen) \ - case ABIVlen: \ - CC = CallingConv::RISCV_VLSCall_##ABIVlen; \ +#define CC_VLS_CASE(ABIVlen) \ + case ABIVlen: \ + CC = CallingConv::RISCV_VLSCall_##ABIVlen; \ break; CC_VLS_CASE(32) CC_VLS_CASE(64) From 27fd1b7676dcb940414b4e5a2b3d17b65d991f1b Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Fri, 17 Jan 2025 03:16:47 -0800 Subject: [PATCH 10/12] fixup! missing include RISCVTargetParser.h --- clang/lib/CodeGen/Targets/RISCV.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 9d39cb9dfc5c7..3de35b3a7f4bd 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; From e84ce1660674ddb2417222677dbaef40dee46946 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Tue, 18 Feb 2025 08:13:11 -0800 Subject: [PATCH 11/12] fixup! [RISCV][VLS] Support RISCV VLS calling convention --- clang/lib/CodeGen/Targets/RISCV.cpp | 89 +++++++++---------- .../RISCV/riscv-vector-callingconv-llvm-ir.c | 14 ++- .../riscv-vector-callingconv-llvm-ir.cpp | 7 +- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 3de35b3a7f4bd..f5ea69dcc694e 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -120,42 +120,23 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { default: ABIVLen = 0; break; - case CallingConv::CC_RISCVVLSCall_32: - ABIVLen = 32; - break; - case CallingConv::CC_RISCVVLSCall_64: - ABIVLen = 64; - break; - case CallingConv::CC_RISCVVLSCall_128: - ABIVLen = 128; - break; - case CallingConv::CC_RISCVVLSCall_256: - ABIVLen = 256; - break; - case CallingConv::CC_RISCVVLSCall_512: - ABIVLen = 512; - break; - case CallingConv::CC_RISCVVLSCall_1024: - ABIVLen = 1024; - break; - case CallingConv::CC_RISCVVLSCall_2048: - ABIVLen = 2048; - break; - case CallingConv::CC_RISCVVLSCall_4096: - ABIVLen = 4096; - break; - case CallingConv::CC_RISCVVLSCall_8192: - ABIVLen = 8192; - break; - case CallingConv::CC_RISCVVLSCall_16384: - ABIVLen = 16384; - break; - case CallingConv::CC_RISCVVLSCall_32768: - ABIVLen = 32768; - break; - case CallingConv::CC_RISCVVLSCall_65536: - ABIVLen = 65536; +#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)) @@ -466,7 +447,7 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, // Otherwise, pass the struct indirectly. if (llvm::StructType *STy = dyn_cast(CGT.ConvertType(Ty))) { - int NumElts = STy->getStructNumElements(); + unsigned NumElts = STy->getStructNumElements(); if (NumElts > 8) return false; @@ -522,7 +503,7 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen, // Check array of fixed-length vector and turn it into scalable vector type // if legal. if (auto *ArrTy = dyn_cast(FirstEltTy)) { - int NumArrElt = ArrTy->getNumElements(); + unsigned NumArrElt = ArrTy->getNumElements(); if (NumArrElt > 8) return false; @@ -595,17 +576,6 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const { // * (RVVBitsPerBlock / EltSize) ResType = llvm::ScalableVectorType::get(EltType, NumElts / VScale->first); } else { - // If the corresponding extension is not supported, just make it an i32 - // vector. - 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(128)) - EltType = - llvm::Type::getIntNTy(getVMContext(), EltType->getScalarSizeInBits()); - // Check registers needed <= 8. if ((EltType->getScalarSizeInBits() * NumElts / ABIVLen) > 8) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); @@ -615,6 +585,23 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const { 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); @@ -726,7 +713,11 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, return ABIArgInfo::getDirect(); } - if (const VectorType *VT = Ty->getAs()) { + // TODO: _BitInt is not handled yet in VLS calling convention since _BitInt + // ABI is also not merged yet in RISCV: + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/419 + if (const VectorType *VT = Ty->getAs(); + VT && !VT->getElementType()->isBitIntType()) { if (VT->getVectorKind() == VectorKind::RVVFixedLengthData || VT->getVectorKind() == VectorKind::RVVFixedLengthMask || VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 || 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 ec4fd44be4193..3044d91f1c31c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -44,18 +44,24 @@ void __attribute__((riscv_vls_cc)) test_vls_default_abi_vlen(__attribute__((vect // CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23( 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( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature( 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( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature( 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( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_unsupported_feature_zve32x( 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( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x( 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( 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( 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( noundef %arg.coerce) void __attribute__((riscv_vls_cc(256))) test_vls_256_abi_vlen(__attribute__((vector_size(16))) int 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 0eedb13b53033..594bfe159b28c 100644 --- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -39,12 +39,15 @@ 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( 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_( noundef %arg.coerce) +// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_( 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( noundef %arg.coerce) +// CHECK-LLVM-ZVE32X: define dso_local riscv_vls_cc(128) void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f( 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( 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( noundef %arg.coerce) [[riscv::vls_cc(256)]] void test_vls_256_abi_vlen(__attribute__((vector_size(16))) int arg) {} From 70a96912231315b72d89cec6ff61feda6e477030 Mon Sep 17 00:00:00 2001 From: Brandon Wu Date: Tue, 18 Feb 2025 08:28:22 -0800 Subject: [PATCH 12/12] fixup! [RISCV][VLS] Support RISCV VLS calling convention --- clang/lib/CodeGen/Targets/RISCV.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index f5ea69dcc694e..37e19cc0a5552 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -714,7 +714,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, } // TODO: _BitInt is not handled yet in VLS calling convention since _BitInt - // ABI is also not merged yet in RISCV: + // 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(); VT && !VT->getElementType()->isBitIntType()) {