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