[clang] [llvm] [RISCV][VLS] Support RISCV VLS calling convention (PR #100346)
Brandon Wu via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 5 23:16:34 PST 2025
https://github.com/4vtomat updated https://github.com/llvm/llvm-project/pull/100346
>From 8a4257e75fb37a31c77c33bed35b8a7023065e3e Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Sun, 21 Jul 2024 09:49:11 -0700
Subject: [PATCH 1/6] [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(<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.
---
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 0c5ac80772e2b9..696f9ca59546c6 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3013,6 +3013,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 1bcc7ee0b70dee..5b30a31d1787db 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1953,7 +1953,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.
///
@@ -4440,6 +4440,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 };
@@ -4452,23 +4454,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<uint16_t>(Bits)) {}
+ ExtInfo(unsigned Bits) : Bits(static_cast<uint32_t>(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
@@ -4495,6 +4499,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;
}
@@ -4550,6 +4558,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);
}
@@ -4654,6 +4667,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 42f62695963a2d..22eba9c0ca8c79 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 156fbd1c4442eb..47c03a7eca20ab 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3204,6 +3204,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 b497cce37625c9..c2ab6cc115d6cd 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5645,6 +5645,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 e45370bde74a5d..894aaff054b631 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -464,6 +464,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 9c089908fdc130..d2df5a24da143e 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 9d785d878b61dc..44ae2755a2ab04 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 805b79491e6ea4..eeac988ba5ead9 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4950,7 +4950,10 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_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<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Specify the VLEN for VLS calling convention.">,
+ MarshallingInfoInt<CodeGenOpts<"RISCVABIVLen">>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">;
def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_Group>,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 11e79d296cbec3..0b3ed5d9b663e3 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -11046,6 +11046,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 14bc260d0245fb..730c2fda1aae4c 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3490,6 +3490,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 6bf2908e667c07..6664f7d5ae9507 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3529,6 +3529,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
}
@@ -4196,6 +4197,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 6d8db5cf4ffd22..1e1794fc3ad882 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1135,6 +1135,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;
}
}
@@ -2053,6 +2056,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 eaaba7642bd7b2..c9c32330d34af9 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -483,6 +483,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 8f4f5d3ed81601..816c5ebc18623c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -77,6 +77,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
}
}
@@ -267,6 +268,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D,
if (D->hasAttr<RISCVVectorCCAttr>())
return CC_RISCVVectorCall;
+ if (D->hasAttr<RISCVVLSCCAttr>())
+ return CC_RISCVVLSCall;
+
return CC_C;
}
@@ -862,6 +866,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 ad64abe7cd40a3..38149305eb2442 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1595,6 +1595,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 ba376f9ecfacde..dcb43b3da26af8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -234,7 +234,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 373f8b8a80fdb1..e94d04f1159404 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -533,7 +533,7 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind,
std::unique_ptr<TargetCodeGenInfo>
createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen,
- bool EABI);
+ unsigned ABIVLen, bool EABI);
std::unique_ptr<TargetCodeGenInfo>
createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM);
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index b04e436c665f52..35763b824a7168 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<VectorType>();
@@ -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);
@@ -504,13 +536,18 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
return Info;
}
- if (const VectorType *VT = Ty->getAs<VectorType>())
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
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.
@@ -533,7 +570,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();
@@ -542,8 +580,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,
@@ -582,9 +620,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<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {
+ std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, ABIVLen, EABI)) {
SwiftInfo =
std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
}
@@ -616,7 +654,8 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
std::unique_ptr<TargetCodeGenInfo>
CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
- unsigned FLen, bool EABI) {
+ unsigned FLen, unsigned ABIVLen,
+ bool EABI) {
return std::make_unique<RISCVTargetCodeGenInfo>(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 6935904a24edbf..18da247b3eab48 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 dca8d3fd7b3eaf..89749b64a3dfd9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2203,6 +2203,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 601c6f2eef1d9c..2d1885bec36280 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4855,6 +4855,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");
}
@@ -4974,10 +4993,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.
@@ -5062,6 +5090,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");
}
@@ -6894,6 +6925,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 e526a11973975d..0b1f7f51bc05c6 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -148,7 +148,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 \
@@ -7591,6 +7592,8 @@ 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:
+ return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, /*dummy*/ 0);
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -8031,6 +8034,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 072d8a863d4570..8c205459db9993 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 <riscv_vector.h>
@@ -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(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_default_abi_vlen_c23(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 2 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_256_abi_vlen_c23(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_least_element(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_least_element_c23(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
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 c01aeb21f67571..9447e6fae0cea2 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 <riscv_vector.h>
@@ -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(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @_Z22test_vls_least_elementDv2_i(<vscale x 1 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c
index 5c35901799b427..da4819186f4e21 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 264bb7d9ad7c00..5e27c76d5307fc 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 b4df12405cf356..070c4203ab5e84 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -686,6 +686,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 178c911120b4ce..55d5f903ca0d32 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 0cbbbe823c06b5..8dd4220b72d345 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -1116,6 +1116,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 55e32028e3ed08..bc3a75f2fe6656 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 56abd03d623541..28fe7c55266838 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -656,6 +656,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 8ddb2efb0e26c2..52e351130dd940 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -2205,6 +2205,7 @@ void LLParser::parseOptionalDLLStorageClass(unsigned &Res) {
/// ::= 'm68k_rtdcc'
/// ::= 'graalcc'
/// ::= 'riscv_vector_cc'
+/// ::= 'riscv_vls_cc'
/// ::= 'cc' UINT
///
bool LLParser::parseOptionalCallingConv(unsigned &CC) {
@@ -2281,6 +2282,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 4bc7d9e68280d5..ebeae8d387f953 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 3b6dd0c11bbf90..4055f30d72165c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19460,6 +19460,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 00000000000000..cc63e61ed6a1f7
--- /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 a849789da536ac..f814408dbddc3f 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 14a75f09362dd05f941d7a1a60858e15174537cd Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Sat, 9 Nov 2024 18:58:14 -0800
Subject: [PATCH 2/6] 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 35763b824a7168..b1601a76e4b703 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 2d1885bec36280..18ff259449d6e0 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4994,7 +4994,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 65361ab9c6f9a97138bb482f110cdbba701af074 Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Tue, 3 Dec 2024 23:28:32 -0800
Subject: [PATCH 3/6] 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 b1601a76e4b703..093ef52c7595ea 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
@@ -543,7 +548,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 0b1f7f51bc05c6..f12eba7c312005 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8035,12 +8035,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 8c205459db9993..0b06bede29dc76 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(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen(<vscale x 1 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 void @test_vls_default_abi_vlen_c23(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23(<vscale x 1 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 void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 4 x i16> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i16> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 4 x i16> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 2 x i16> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature_zve32x(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(<vscale x 1 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
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 9447e6fae0cea2..0b91f8b3877eb2 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 <riscv_vector.h>
@@ -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(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i(<vscale x 1 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 4 x i16> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i16> 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(<vscale x 2 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f(<vscale x 1 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
>From b10ff510e98672503fe434f6310828d1d5c705df Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Mon, 9 Dec 2024 10:04:07 -0800
Subject: [PATCH 4/6] 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 f12eba7c312005..cd70a8f0230d90 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8041,7 +8041,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 6b76dbc1c06c1516f234a6cffbd271ee2dd46cd7 Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Sun, 22 Dec 2024 23:10:58 -0800
Subject: [PATCH 5/6] 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 894aaff054b631..e45370bde74a5d 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -464,9 +464,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 eeac988ba5ead9..7da0d3902e2166 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4950,10 +4950,6 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_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<m_Group>,
- Visibility<[ClangOption, CC1Option]>,
- HelpText<"Specify the VLEN for VLS calling convention.">,
- MarshallingInfoInt<CodeGenOpts<"RISCVABIVLen">>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">;
def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_Group>,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dcb43b3da26af8..ba376f9ecfacde 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -234,8 +234,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 e94d04f1159404..373f8b8a80fdb1 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -533,7 +533,7 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind,
std::unique_ptr<TargetCodeGenInfo>
createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen,
- unsigned ABIVLen, bool EABI);
+ bool EABI);
std::unique_ptr<TargetCodeGenInfo>
createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM);
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index 093ef52c7595ea..fd75a7b2666f9d 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<VectorType>();
@@ -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);
@@ -548,10 +539,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,
@@ -576,7 +567,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();
@@ -586,7 +577,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,
@@ -625,9 +616,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<RISCVABIInfo>(CGT, XLen, FLen, ABIVLen, EABI)) {
+ std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {
SwiftInfo =
std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
}
@@ -659,8 +650,7 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
std::unique_ptr<TargetCodeGenInfo>
CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
- unsigned FLen, unsigned ABIVLen,
- bool EABI) {
+ unsigned FLen, bool EABI) {
return std::make_unique<RISCVTargetCodeGenInfo>(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 18da247b3eab48..6935904a24edbf 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 89749b64a3dfd9..dca8d3fd7b3eaf 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2203,21 +2203,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 cd70a8f0230d90..827024477cf12b 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8035,9 +8035,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 0b06bede29dc76..3cb1fa0407d8a8 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 <riscv_vector.h>
@@ -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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen(<vscale x 1 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 void @test_vls_default_abi_vlen_c23(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23(<vscale x 1 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 void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 4 x i16> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature(<vscale x 2 x i16> 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(<vscale x 4 x i16> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature(<vscale x 2 x i16> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_unsupported_feature_zve32x(<vscale x 1 x i32> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @test_vls_default_abi_vlen_c23_unsupported_feature_zve32x(<vscale x 1 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_256_abi_vlen_c23(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_least_element(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @test_vls_least_element_c23(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
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 0b91f8b3877eb2..4265e129c2fdb8 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 <riscv_vector.h>
@@ -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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z25test_vls_default_abi_vlenDv4_i(<vscale x 1 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 void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 4 x i16> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z45test_vls_default_abi_vlen_unsupported_featureDv8_DF16_(<vscale x 2 x i16> 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(<vscale x 2 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN-ZVE32X: define dso_local riscv_vls_cc void @_Z52test_vls_default_abi_vlen_unsupported_feature_zve32xDv4_f(<vscale x 1 x i32> 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(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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 void @_Z22test_vls_least_elementDv2_i(<vscale x 1 x i32> noundef %arg.coerce)
-// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc 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) {}
>From 68d23382c970fdf4520fc7eab8089cad854b87ee Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Sun, 5 Jan 2025 22:25:17 -0800
Subject: [PATCH 6/6] fixup! handle struct and minor fixup
---
clang/lib/CodeGen/CGCall.cpp | 27 ++-
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(+), 19 deletions(-)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 816c5ebc18623c..e6f927358b0105 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3239,24 +3239,19 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
}
}
- llvm::StructType *STy =
- dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
- if (ArgI.isDirect() && !ArgI.getCanBeFlattened() && STy &&
- STy->getNumElements() > 1) {
- [[maybe_unused]] llvm::TypeSize StructSize =
- CGM.getDataLayout().getTypeAllocSize(STy);
- [[maybe_unused]] llvm::TypeSize PtrElementSize =
- CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(Ty));
- if (STy->containsHomogeneousScalableVectorTypes()) {
- assert(StructSize == PtrElementSize &&
- "Only allow non-fractional movement of structure with"
- "homogeneous scalable vector type");
-
- ArgVals.push_back(ParamValue::forDirect(AI));
- break;
- }
+ // 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),
Arg->getName());
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index fd75a7b2666f9d..28b5540b6cbb5d 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<llvm::StructType>(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<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)) {
+ int NumArrElt = ArrTy->getNumElements();
+ if (NumArrElt > 8 || !llvm::isPowerOf2_32(NumArrElt))
+ 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,
@@ -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 3cb1fa0407d8a8..78e1ed37727894 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(<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_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(<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 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 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 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 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 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 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 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 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 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 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 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 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 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", <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 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 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 4265e129c2fdb8..6281b640c4df06 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(<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_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(<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 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 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 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 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 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 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 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 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 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 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 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 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 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", <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 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 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) {}
More information about the llvm-commits
mailing list