[clang] [llvm] [RISCV][VLS] Support RISCV VLS calling convention (PR #100346)
Brandon Wu via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 25 02:29:11 PDT 2024
https://github.com/4vtomat updated https://github.com/llvm/llvm-project/pull/100346
>From 15161b0b7637d52b6285624a4bf9f52a6664082c 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/4] [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.
An option `-mriscv-abi-vlen=N` is also added to specify the `ABI_VLEN`
globally, it's used for every functions are being compiled, however if
both function attribute and option are specified, the function attribute
has higher priority than the option which means the function attribute
overwrites the `ABI_VLEN` specified by the option.
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/Specifiers.h | 1 +
clang/include/clang/CodeGen/CGFunctionInfo.h | 9 ++-
clang/include/clang/Driver/Options.td | 2 +
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/Targets/RISCV.cpp | 73 ++++++++++++-------
clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 4 +
clang/lib/Sema/SemaDeclAttr.cpp | 30 +++++++-
clang/lib/Sema/SemaType.cpp | 17 ++++-
.../RISCV/riscv-vector-callingconv-llvm-ir.c | 24 ++++++
.../riscv-vector-callingconv-llvm-ir.cpp | 14 ++++
.../CodeGen/RISCV/riscv-vector-callingconv.c | 16 ++++
.../RISCV/riscv-vector-callingconv.cpp | 17 +++++
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/RISCVFeatures.td | 9 +++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 1 +
llvm/lib/Target/RISCV/RISCVSubtarget.h | 1 +
33 files changed, 265 insertions(+), 39 deletions(-)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 115f5ab090f96..159f21846fc3b 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3005,6 +3005,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 72723c7c56e07..bb3956b1d2094 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1942,7 +1942,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 : 17;
/// The ref-qualifier associated with a \c FunctionProtoType.
///
@@ -4395,6 +4395,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 };
@@ -4407,23 +4409,25 @@ class FunctionType : public Type {
};
enum { NoCfCheckMask = 0x800 };
enum { CmseNSCallMask = 0x1000 };
- uint16_t Bits = CC_C;
+ enum { Log2RISCVABIVLenMask = 0x1E000, 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
@@ -4450,6 +4454,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;
}
@@ -4505,6 +4513,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);
}
@@ -4609,6 +4622,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 7d4353c2773a3..66bff0f879b56 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 4825979a974d2..ec2c1bedaef50 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3139,6 +3139,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 99738812c8157..1eba3b2945f7b 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5554,6 +5554,17 @@ them if they use them.
}];
}
+def RISCVVLSCCDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Heading = "riscv::vls_cc, riscv_vls_cc, clang::riscv_vls_cc";
+ let Content = [{
+The ``riscv_vls_cc`` attribute can be applied to a function. Functions
+declared with this attribute will utilize the standard fixed-length vector
+calling convention variant instead of the default calling convention defined by
+the ABI. This variant aims to pass fixed-length vectors via vector registers,
+if possible, rather than through general-purpose registers.}];
+}
+
def PreferredNameDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index fb11e8212f8b6..81b0b856c33d0 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -297,6 +297,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 811f33407368c..aae13d77d9050 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -608,6 +608,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 : 4;
+
RequiredArgs Required;
/// The struct representing all arguments passed in memory. Only used when
@@ -718,11 +721,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; }
@@ -776,6 +781,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) {
@@ -803,6 +809,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 28a5cb71d2219..6882b0d684fc3 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4865,6 +4865,8 @@ 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>,
+ HelpText<"Specify the VLEN for VLS calling convention.">;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/MIPSr6 only)">;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a465cdfcf3c89..cccf3d6f848bb 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10826,6 +10826,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 d46d621d4c7d4..ba8f2a4c6776b 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3452,6 +3452,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 fdaab8e434593..7e2ffb09e340a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3510,6 +3510,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
// clang-format off
case CC_RISCVVectorCall: return "riscv_vector_cc";
// clang-format on
+ case CC_RISCVVLSCall: return "riscv_vls_cc";
}
llvm_unreachable("Invalid calling convention.");
@@ -4162,6 +4163,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 ffec3ef9d2269..1a66843f7600d 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1114,6 +1114,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;
}
}
@@ -2014,6 +2017,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 41d836330b38c..7b649f05f0aa9 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -476,6 +476,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 2f3dd5d01fa6c..952e8c85e4eaa 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -77,6 +77,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
// clang-format off
case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall;
// clang-format on
+ case CC_RISCVVLSCall: return llvm::CallingConv::RISCV_VLSCall;
}
}
@@ -266,6 +267,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 3d8a715b692de..d437688fb577c 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1554,6 +1554,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/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index f2add9351c03c..4d16eaad781dc 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;
@@ -45,8 +46,8 @@ class RISCVABIInfo : public DefaultABIInfo {
void computeInfo(CGFunctionInfo &FI) const override;
ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft,
- int &ArgFPRsLeft) const;
- ABIArgInfo classifyReturnType(QualType RetTy) const;
+ int &ArgFPRsLeft, unsigned ABIVLen) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, unsigned ABIVLen) const;
RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
AggValueSlot Slot) const override;
@@ -62,14 +63,23 @@ class RISCVABIInfo : public DefaultABIInfo {
llvm::Type *Field2Ty,
CharUnits Field2Off) const;
- ABIArgInfo coerceVLSVector(QualType Ty) const;
+ ABIArgInfo coerceVLSVector(QualType Ty, unsigned ABIVLen = 0) const;
};
} // end anonymous namespace
void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ unsigned ABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen();
+ if (ABIVLen == 1)
+ // No riscv_vls_cc in the function, check if there's one passed from
+ // compiler options.
+ for (unsigned i = 5; i <= 16; ++i)
+ if (getContext().getTargetInfo().getTargetOpts().FeatureMap.contains(
+ "abi-vlen-" + llvm::utostr(1 << i) + "b"))
+ ABIVLen = 1 << i;
+
QualType RetTy = FI.getReturnType();
if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(RetTy);
+ FI.getReturnInfo() = classifyReturnType(RetTy, ABIVLen);
// IsRetIndirect is true if classifyArgumentType indicated the value should
// be passed indirect, or if the type size is a scalar greater than 2*XLen
@@ -96,7 +106,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
for (auto &ArgInfo : FI.arguments()) {
bool IsFixed = ArgNum < NumFixedArgs;
ArgInfo.info =
- classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft);
+ classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft, ABIVLen);
ArgNum++;
}
}
@@ -317,38 +327,44 @@ 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 ABIVLen) const {
assert(Ty->isVectorType() && "expected vector type!");
const auto *VT = Ty->castAs<VectorType>();
assert(VT->getElementType()->isBuiltinType() && "expected builtin type!");
- auto VScale =
- getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());
-
unsigned NumElts = VT->getNumElements();
- llvm::Type *EltType;
- if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) {
- NumElts *= 8;
- EltType = llvm::Type::getInt1Ty(getVMContext());
+ llvm::ScalableVectorType *ResType;
+ llvm::Type *EltType = CGT.ConvertType(VT->getElementType());;
+
+ if (ABIVLen == 0) {
+ // RVV fixed-length vector
+ auto VScale =
+ getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());
+
+ if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) {
+ NumElts *= 8;
+ EltType = llvm::Type::getInt1Ty(getVMContext());
+ }
+
+ // The MinNumElts is simplified from equation:
+ // NumElts / VScale =
+ // (EltSize * NumElts / (VScale * RVVBitsPerBlock))
+ // * (RVVBitsPerBlock / EltSize)
+ ResType = llvm::ScalableVectorType::get(EltType, NumElts / VScale->first);
} else {
- assert(VT->getVectorKind() == VectorKind::RVVFixedLengthData &&
- "Unexpected vector kind");
- EltType = CGT.ConvertType(VT->getElementType());
+ // Generic vector
+ ResType = llvm::ScalableVectorType::get(
+ EltType, NumElts * llvm::RISCV::RVVBitsPerBlock / ABIVLen);
}
- // The MinNumElts is simplified from equation:
- // NumElts / VScale =
- // (EltSize * NumElts / (VScale * RVVBitsPerBlock))
- // * (RVVBitsPerBlock / EltSize)
- llvm::ScalableVectorType *ResType =
- llvm::ScalableVectorType::get(EltType, NumElts / VScale->first);
return ABIArgInfo::getDirect(ResType);
}
ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
int &ArgGPRsLeft,
- int &ArgFPRsLeft) const {
+ int &ArgFPRsLeft,
+ unsigned ABIVLen) const {
assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
Ty = useFirstFieldIfTransparentUnion(Ty);
@@ -451,10 +467,15 @@ 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)
return coerceVLSVector(Ty);
+ if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 1)
+ // Generic vector without riscv_vls_cc should fall through and pass by
+ // reference.
+ return coerceVLSVector(Ty, ABIVLen);
+ }
// Aggregates which are <= 2*XLen will be passed in registers if possible,
// so coerce to integers.
@@ -477,7 +498,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
}
-ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
+ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, unsigned ABIVLen) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -487,7 +508,7 @@ 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);
+ ArgFPRsLeft, ABIVLen);
}
RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 149a31f58e75d..b64682f546a8b 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
if (Args.hasArg(options::OPT_ffixed_x1))
Features.push_back("+reserve-x1");
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 39675422e3f9f..fea75747acb8f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4768,6 +4768,15 @@ 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;
+ D->addAttr(::new (S.Context) RISCVVLSCCAttr(S.Context, AL, VectorLength));
+ return;
+ }
default:
llvm_unreachable("unexpected attribute kind");
}
@@ -4887,10 +4896,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.
@@ -4975,6 +4993,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");
}
@@ -6808,6 +6829,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 6fa39cdccef2b..895569e896eba 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -144,7 +144,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 \
@@ -7480,6 +7481,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!");
}
@@ -7920,6 +7923,18 @@ 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;
+
+ auto EI = unwrapped.get()->getExtInfo().withLog2RISCVABIVLen(
+ llvm::Log2_64(ABIVLen));
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ }
+
if (CCOld != CC) {
// Error out on when there's already an attribute on the type
// and the CCs don't match.
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
index 072d8a863d457..0a299e9dc5cfb 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 -target-feature +v -target-feature +abi-vlen-256b \
+// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s
+// RUN: %clang_cc1 -std=c23 -triple riscv64 -target-feature +v -target-feature +abi-vlen-256b \
+// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s
#include <riscv_vector.h>
@@ -32,3 +36,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 @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_64_abi_vlen(<vscale x 4 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_64_abi_vlen(<vscale x 4 x i32> noundef %arg.coerce)
+void __attribute__((riscv_vls_cc(64))) test_vls_64_abi_vlen(__attribute__((vector_size(16))) int arg) {}
+
+// CHECK-LLVM: define dso_local riscv_vls_cc void @test_vls_64_abi_vlen_c23(<vscale x 4 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @test_vls_64_abi_vlen_c23(<vscale x 4 x i32> noundef %arg.coerce)
+[[riscv::vls_cc(64)]] void test_vls_64_abi_vlen_c23(__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 c01aeb21f6757..5e4e4858f8c9b 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
@@ -1,6 +1,8 @@
// REQUIRES: riscv-registered-target
// RUN: %clang_cc1 -std=c++11 -triple riscv64 -target-feature +v \
// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s
+// RUN: %clang_cc1 -std=c++11 -triple riscv64 -target-feature +v -target-feature +abi-vlen-256b \
+// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM-ABI-VLEN %s
#include <riscv_vector.h>
@@ -30,3 +32,15 @@ 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 @_Z20test_vls_64_abi_vlenDv4_i(<vscale x 4 x i32> noundef %arg.coerce)
+// CHECK-LLVM-ABI-VLEN: define dso_local riscv_vls_cc void @_Z20test_vls_64_abi_vlenDv4_i(<vscale x 4 x i32> noundef %arg.coerce)
+[[riscv::vls_cc(64)]] void test_vls_64_abi_vlen(__attribute__((vector_size(16))) int arg) {}
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c
index 5c35901799b42..c17a83c721c9b 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c
@@ -15,3 +15,19 @@ 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();
+
+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();
+
+void test_vls_no_attribute2(int); // expected-note {{previous declaration is here}}
+[[riscv::vls_cc]] void test_vls_no_attribute2(int x) { } // expected-error {{function declared 'riscv_vls_cc' here was previously declared without calling convention}}
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp
index 264bb7d9ad7c0..1c01145116e9c 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp
@@ -33,3 +33,20 @@ 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();
+
+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 991767dc4c49c..e9e167c02c5f7 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -681,6 +681,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 db6780b70ca5a..59c87b45063f9 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -184,6 +184,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 d55947fc5103a..5fa35d8625f31 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 55e32028e3ed0..bc3a75f2fe665 100644
--- a/llvm/include/llvm/IR/CallingConv.h
+++ b/llvm/include/llvm/IR/CallingConv.h
@@ -270,6 +270,9 @@ namespace CallingConv {
/// Preserve X1-X15, X19-X29, SP, Z0-Z31, P0-P15.
AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1 = 111,
+ /// Calling convention used for RISC-V V-extension fixed vectors.
+ RISCV_VLSCall = 112,
+
/// The highest possible ID. Must be some 2^k - 1.
MaxID = 1023
};
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 7d7fe19568e8a..f176f3d7bfb30 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -643,6 +643,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 a886f6e3a4b93..e816742169d44 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 6599730590de6..a9686067925ca 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -369,6 +369,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/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 3c868dbbf8b3a..ca6a13f15b917 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1333,6 +1333,15 @@ def Experimental
: SubtargetFeature<"experimental", "HasExperimental",
"true", "Experimental intrinsics">;
+def FeatureABIVLen32B
+ : SubtargetFeature<"abi-vlen-32b", "ABIVLen", "32", "ABI_VLEN desc">;
+
+foreach i = { 6-16 } in {
+ defvar I = !shl(1, i);
+ def FeatureABIVLen # I # B
+ : SubtargetFeature<"abi-vlen-"#I#"b", "ABIVLen", !cast<string>(I), "ABI_VLEN desc">;
+}
+
// Some vector hardware implementations do not process all VLEN bits in parallel
// and instead split over multiple cycles. DLEN refers to the datapath width
// that can be done in parallel.
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d40d4997d7614..f07dd81b5d793 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19515,6 +19515,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/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 377d080ad4bfc..cfee21c76931e 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -75,6 +75,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
#include "RISCVGenSubtargetInfo.inc"
unsigned ZvlLen = 0;
+ unsigned ABIVLen = 0;
unsigned RVVVectorBitsMin;
unsigned RVVVectorBitsMax;
uint8_t MaxInterleaveFactor = 2;
>From 8ba2c492bf841f3b212ea7770dfbe2e6d393205d Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Wed, 24 Jul 2024 04:53:38 -0700
Subject: [PATCH 2/4] fixup! Add IR assembler and bitcode compatibility tests
---
llvm/test/Assembler/riscv_vls_cc.ll | 12 ++++++++++++
llvm/test/Bitcode/compatibility.ll | 4 ++++
2 files changed, 16 insertions(+)
create mode 100644 llvm/test/Assembler/riscv_vls_cc.ll
diff --git a/llvm/test/Assembler/riscv_vls_cc.ll b/llvm/test/Assembler/riscv_vls_cc.ll
new file mode 100644
index 0000000000000..cc63e61ed6a1f
--- /dev/null
+++ b/llvm/test/Assembler/riscv_vls_cc.ll
@@ -0,0 +1,12 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; RUN: verify-uselistorder %s
+
+; CHECK: define riscv_vls_cc void @no_args() {
+define riscv_vls_cc void @no_args() {
+ ret void
+}
+
+; CHECK: define riscv_vls_cc void @byval_arg(ptr byval(i32) %0) {
+define riscv_vls_cc void @byval_arg(ptr byval(i32)) {
+ ret void
+}
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index e437c37d8d1c8..077e9a045abb4 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 9689ac039df014d95f938fec30af44aa98b26da2 Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Wed, 24 Jul 2024 04:59:10 -0700
Subject: [PATCH 3/4] fixup! clang-format
---
clang/lib/AST/Type.cpp | 2 +-
clang/lib/CodeGen/CGCall.cpp | 2 +-
clang/lib/CodeGen/Targets/RISCV.cpp | 13 +++++++------
clang/lib/Sema/SemaType.cpp | 2 +-
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 7e2ffb09e340a..8f950332c8c58 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3509,8 +3509,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_PreserveNone: return "preserve_none";
// clang-format off
case CC_RISCVVectorCall: return "riscv_vector_cc";
- // clang-format on
case CC_RISCVVLSCall: return "riscv_vls_cc";
+ // clang-format on
}
llvm_unreachable("Invalid calling convention.");
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 952e8c85e4eaa..a1aaf129e3daa 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -76,8 +76,8 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_PreserveNone: return llvm::CallingConv::PreserveNone;
// clang-format off
case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall;
- // clang-format on
case CC_RISCVVLSCall: return llvm::CallingConv::RISCV_VLSCall;
+ // clang-format on
}
}
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index 4d16eaad781dc..da3320d9129d2 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -105,8 +105,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, ABIVLen);
+ ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft,
+ ArgFPRsLeft, ABIVLen);
ArgNum++;
}
}
@@ -335,7 +335,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const {
unsigned NumElts = VT->getNumElements();
llvm::ScalableVectorType *ResType;
- llvm::Type *EltType = CGT.ConvertType(VT->getElementType());;
+ llvm::Type *EltType = CGT.ConvertType(VT->getElementType());
if (ABIVLen == 0) {
// RVV fixed-length vector
@@ -498,7 +498,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
}
-ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, unsigned ABIVLen) const {
+ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy,
+ unsigned ABIVLen) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -507,8 +508,8 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy, unsigned ABIVLen) co
// The rules for return and argument types are the same, so defer to
// classifyArgumentType.
- return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft,
- ArgFPRsLeft, ABIVLen);
+ return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, ArgFPRsLeft,
+ ABIVLen);
}
RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 895569e896eba..01660eb37f336 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7482,7 +7482,7 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
case ParsedAttr::AT_RISCVVectorCC:
return createSimpleAttr<RISCVVectorCCAttr>(Ctx, Attr);
case ParsedAttr::AT_RISCVVLSCC:
- return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, /*dummy*/0);
+ return ::new (Ctx) RISCVVLSCCAttr(Ctx, Attr, /*dummy*/ 0);
}
llvm_unreachable("unexpected attribute kind!");
}
>From 0acf8c5824ffa6e3a61231b0db3fe8919b5c9054 Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Thu, 25 Jul 2024 02:23:04 -0700
Subject: [PATCH 4/4] fixup! [RISCV][VLS] Support RISCV VLS calling convention
---
clang/include/clang/AST/Type.h | 4 +-
clang/include/clang/Basic/CodeGenOptions.def | 3 ++
clang/include/clang/CodeGen/CGFunctionInfo.h | 2 +-
clang/include/clang/Driver/Options.td | 5 +-
clang/lib/CodeGen/CodeGenModule.cpp | 3 +-
clang/lib/CodeGen/TargetInfo.h | 2 +-
clang/lib/CodeGen/Targets/RISCV.cpp | 54 +++++++++----------
clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 4 --
clang/lib/Driver/ToolChains/Clang.cpp | 4 ++
.../RISCV/riscv-vector-callingconv-llvm-ir.c | 4 +-
.../riscv-vector-callingconv-llvm-ir.cpp | 2 +-
llvm/lib/Target/RISCV/RISCVFeatures.td | 9 ----
llvm/lib/Target/RISCV/RISCVSubtarget.h | 1 -
13 files changed, 45 insertions(+), 52 deletions(-)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index bb3956b1d2094..16c533c2d13d5 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1942,7 +1942,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 : 17;
+ unsigned ExtInfo : 18;
/// The ref-qualifier associated with a \c FunctionProtoType.
///
@@ -4409,7 +4409,7 @@ class FunctionType : public Type {
};
enum { NoCfCheckMask = 0x800 };
enum { CmseNSCallMask = 0x1000 };
- enum { Log2RISCVABIVLenMask = 0x1E000, Log2RISCVABIVLenOffset = 13 };
+ enum { Log2RISCVABIVLenMask = 0x3E000, Log2RISCVABIVLenOffset = 13 };
uint32_t Bits = CC_C;
ExtInfo(unsigned Bits) : Bits(static_cast<uint32_t>(Bits)) {}
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 5728ab8d86702..edc8258e30664 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -457,6 +457,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/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index aae13d77d9050..4bcb2b5d38e13 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -609,7 +609,7 @@ class CGFunctionInfo final
unsigned MaxVectorWidth : 4;
/// Log2 of ABI_VLEN used in RISCV VLS calling convention.
- unsigned Log2RISCVABIVLen : 4;
+ unsigned Log2RISCVABIVLen : 5;
RequiredArgs Required;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6882b0d684fc3..4e0ea97adfdfc 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4866,8 +4866,9 @@ def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_Group>,
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>,
- HelpText<"Specify the VLEN for VLS calling convention.">;
-
+ 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 63ed5b4dd0c31..983cea25f7cb4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -238,7 +238,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 2f2138582ba1e..2f2eb5b5c332f 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -519,7 +519,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 da3320d9129d2..3bb14d7dda085 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -26,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;
@@ -37,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, unsigned ABIVLen) const;
- ABIArgInfo classifyReturnType(QualType RetTy, unsigned ABIVLen) 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;
@@ -63,23 +64,18 @@ class RISCVABIInfo : public DefaultABIInfo {
llvm::Type *Field2Ty,
CharUnits Field2Off) const;
- ABIArgInfo coerceVLSVector(QualType Ty, unsigned ABIVLen = 0) const;
+ ABIArgInfo coerceVLSVector(QualType Ty, unsigned ArgABIVLen = 0) const;
};
} // end anonymous namespace
void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
- unsigned ABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen();
- if (ABIVLen == 1)
- // No riscv_vls_cc in the function, check if there's one passed from
- // compiler options.
- for (unsigned i = 5; i <= 16; ++i)
- if (getContext().getTargetInfo().getTargetOpts().FeatureMap.contains(
- "abi-vlen-" + llvm::utostr(1 << i) + "b"))
- ABIVLen = 1 << i;
+ unsigned ArgABIVLen = 1 << FI.getExtInfo().getLog2RISCVABIVLen();
+ if (ArgABIVLen == 1)
+ ArgABIVLen = ABIVLen;
QualType RetTy = FI.getReturnType();
if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(RetTy, ABIVLen);
+ 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
@@ -106,7 +102,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
for (auto &ArgInfo : FI.arguments()) {
bool IsFixed = ArgNum < NumFixedArgs;
ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft,
- ArgFPRsLeft, ABIVLen);
+ ArgFPRsLeft, ArgABIVLen);
ArgNum++;
}
}
@@ -327,7 +323,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, unsigned ABIVLen) const {
+ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty,
+ unsigned ArgABIVLen) const {
assert(Ty->isVectorType() && "expected vector type!");
const auto *VT = Ty->castAs<VectorType>();
@@ -337,7 +334,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const {
llvm::ScalableVectorType *ResType;
llvm::Type *EltType = CGT.ConvertType(VT->getElementType());
- if (ABIVLen == 0) {
+ if (ArgABIVLen == 0) {
// RVV fixed-length vector
auto VScale =
getContext().getTargetInfo().getVScaleRange(getContext().getLangOpts());
@@ -355,7 +352,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const {
} else {
// Generic vector
ResType = llvm::ScalableVectorType::get(
- EltType, NumElts * llvm::RISCV::RVVBitsPerBlock / ABIVLen);
+ EltType, NumElts * llvm::RISCV::RVVBitsPerBlock / ArgABIVLen);
}
return ABIArgInfo::getDirect(ResType);
@@ -364,7 +361,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, unsigned ABIVLen) const {
ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
int &ArgGPRsLeft,
int &ArgFPRsLeft,
- unsigned ABIVLen) const {
+ unsigned ArgABIVLen) const {
assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
Ty = useFirstFieldIfTransparentUnion(Ty);
@@ -471,10 +468,10 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
VT->getVectorKind() == VectorKind::RVVFixedLengthMask)
return coerceVLSVector(Ty);
- if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 1)
+ if (VT->getVectorKind() == VectorKind::Generic && ArgABIVLen != 0)
// Generic vector without riscv_vls_cc should fall through and pass by
// reference.
- return coerceVLSVector(Ty, ABIVLen);
+ return coerceVLSVector(Ty, ArgABIVLen);
}
// Aggregates which are <= 2*XLen will be passed in registers if possible,
@@ -499,7 +496,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
}
ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy,
- unsigned ABIVLen) const {
+ unsigned ArgABIVLen) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -509,7 +506,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,
- ABIVLen);
+ ArgABIVLen);
}
RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -548,9 +545,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);
}
@@ -579,7 +576,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 b64682f546a8b..149a31f58e75d 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
if (Args.hasArg(options::OPT_ffixed_x1))
Features.push_back("+reserve-x1");
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4a94df7d5f42e..335ac9f1a7a4d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2206,6 +2206,10 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args,
<< A->getSpelling() << Val;
}
}
+
+ if (Arg *A = Args.getLastArg(options::OPT_mriscv_abi_vlen_EQ))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-mriscv-abi-vlen=") + A->getValue()));
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
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 0a299e9dc5cfb..8f155467c7f03 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
@@ -3,9 +3,9 @@
// 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 -target-feature +v -target-feature +abi-vlen-256b \
+// 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 -target-feature +v -target-feature +abi-vlen-256b \
+// 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>
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 5e4e4858f8c9b..be1f6e14cd7aa 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
@@ -1,7 +1,7 @@
// 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 +v -target-feature +abi-vlen-256b \
+// 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>
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index ca6a13f15b917..3c868dbbf8b3a 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1333,15 +1333,6 @@ def Experimental
: SubtargetFeature<"experimental", "HasExperimental",
"true", "Experimental intrinsics">;
-def FeatureABIVLen32B
- : SubtargetFeature<"abi-vlen-32b", "ABIVLen", "32", "ABI_VLEN desc">;
-
-foreach i = { 6-16 } in {
- defvar I = !shl(1, i);
- def FeatureABIVLen # I # B
- : SubtargetFeature<"abi-vlen-"#I#"b", "ABIVLen", !cast<string>(I), "ABI_VLEN desc">;
-}
-
// Some vector hardware implementations do not process all VLEN bits in parallel
// and instead split over multiple cycles. DLEN refers to the datapath width
// that can be done in parallel.
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index cfee21c76931e..377d080ad4bfc 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -75,7 +75,6 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
#include "RISCVGenSubtargetInfo.inc"
unsigned ZvlLen = 0;
- unsigned ABIVLen = 0;
unsigned RVVVectorBitsMin;
unsigned RVVVectorBitsMax;
uint8_t MaxInterleaveFactor = 2;
More information about the llvm-commits
mailing list