Skip to content

Commit 3ac9fe6

Browse files
authored
[RISCV] CodeGen of RVE and ilp32e/lp64e ABIs (#76777)
This commit includes the necessary changes to clang and LLVM to support codegen of `RVE` and the `ilp32e`/`lp64e` ABIs. The differences between `RVE` and `RVI` are: * `RVE` reduces the integer register count to 16(x0-x16). * The ABI should be `ilp32e` for 32 bits and `lp64e` for 64 bits. `RVE` can be combined with all current standard extensions. The central changes in ilp32e/lp64e ABI, compared to ilp32/lp64 are: * Only 6 integer argument registers (rather than 8). * Only 2 callee-saved registers (rather than 12). * A Stack Alignment of 32bits (rather than 128bits). * ilp32e isn't compatible with D ISA extension. If `ilp32e` or `lp64` is used with an ISA that has any of the registers x16-x31 and f0-f31, then these registers are considered temporaries. To be compatible with the implementation of ilp32e in GCC, we don't use aligned registers to pass variadic arguments and set stack alignment\ to 4-bytes for types with length of 2*XLEN. FastCC is also supported on RVE, while GHC isn't since there is only one avaiable register. Differential Revision: https://reviews.llvm.org/D70401
1 parent e2bb47c commit 3ac9fe6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+7889
-234
lines changed

clang/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,8 @@ RISC-V Support
10601060
^^^^^^^^^^^^^^
10611061
- Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the
10621062
aliases ``-m[no-]strict-align``.
1063+
- CodeGen of RV32E/RV64E was supported experimentally.
1064+
- CodeGen of ilp32e/lp64e was supported experimentally.
10631065

10641066
- Default ABI with F but without D was changed to ilp32f for RV32 and to lp64f
10651067
for RV64.

clang/lib/Basic/Targets/RISCV.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
154154
else
155155
Builder.defineMacro("__riscv_float_abi_soft");
156156

157-
if (ABIName == "ilp32e")
157+
if (ABIName == "ilp32e" || ABIName == "lp64e")
158158
Builder.defineMacro("__riscv_abi_rve");
159159

160160
Builder.defineMacro("__riscv_arch_test");
@@ -214,6 +214,13 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
214214
Builder.defineMacro("__riscv_misaligned_fast");
215215
else
216216
Builder.defineMacro("__riscv_misaligned_avoid");
217+
218+
if (ISAInfo->hasExtension("e")) {
219+
if (Is64Bit)
220+
Builder.defineMacro("__riscv_64e");
221+
else
222+
Builder.defineMacro("__riscv_32e");
223+
}
217224
}
218225

219226
static constexpr Builtin::Info BuiltinInfo[] = {
@@ -378,6 +385,11 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
378385
if (llvm::is_contained(Features, "+experimental"))
379386
HasExperimental = true;
380387

388+
if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
389+
Diags.Report(diag::err_invalid_feature_combination)
390+
<< "ILP32E cannot be used with the D ISA extension";
391+
return false;
392+
}
381393
return true;
382394
}
383395

clang/lib/Basic/Targets/RISCV.h

+12
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
132132
}
133133

134134
bool setABI(const std::string &Name) override {
135+
if (Name == "ilp32e") {
136+
ABI = Name;
137+
resetDataLayout("e-m:e-p:32:32-i64:64-n32-S32");
138+
return true;
139+
}
140+
135141
if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") {
136142
ABI = Name;
137143
return true;
@@ -156,6 +162,12 @@ class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo {
156162
}
157163

158164
bool setABI(const std::string &Name) override {
165+
if (Name == "lp64e") {
166+
ABI = Name;
167+
resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S64");
168+
return true;
169+
}
170+
159171
if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") {
160172
ABI = Name;
161173
return true;

clang/lib/CodeGen/CodeGenModule.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
229229
ABIFLen = 32;
230230
else if (ABIStr.ends_with("d"))
231231
ABIFLen = 64;
232-
return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen);
232+
bool EABI = ABIStr.ends_with("e");
233+
return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, EABI);
233234
}
234235

235236
case llvm::Triple::systemz: {

clang/lib/CodeGen/TargetInfo.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind,
496496
bool SoftFloatABI);
497497

498498
std::unique_ptr<TargetCodeGenInfo>
499-
createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen);
499+
createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen,
500+
bool EABI);
500501

501502
std::unique_ptr<TargetCodeGenInfo>
502503
createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM);

clang/lib/CodeGen/Targets/RISCV.cpp

+25-10
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@ class RISCVABIInfo : public DefaultABIInfo {
2525
// ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target
2626
// with soft float ABI has FLen==0).
2727
unsigned FLen;
28-
static const int NumArgGPRs = 8;
29-
static const int NumArgFPRs = 8;
28+
const int NumArgGPRs;
29+
const int NumArgFPRs;
30+
const bool EABI;
3031
bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
3132
llvm::Type *&Field1Ty,
3233
CharUnits &Field1Off,
3334
llvm::Type *&Field2Ty,
3435
CharUnits &Field2Off) const;
3536

3637
public:
37-
RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen)
38-
: DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {}
38+
RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
39+
bool EABI)
40+
: DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8),
41+
NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {}
3942

4043
// DefaultABIInfo's classifyReturnType and classifyArgumentType are
4144
// non-virtual, but computeInfo is virtual, so we overload it.
@@ -86,7 +89,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
8689
}
8790

8891
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
89-
int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
92+
int ArgFPRsLeft = NumArgFPRs;
9093
int NumFixedArgs = FI.getNumRequiredArgs();
9194

9295
int ArgNum = 0;
@@ -396,9 +399,12 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
396399
// Determine the number of GPRs needed to pass the current argument
397400
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
398401
// register pairs, so may consume 3 registers.
402+
// TODO: To be compatible with GCC's behaviors, we don't align registers
403+
// currently if we are using ILP32E calling convention. This behavior may be
404+
// changed when RV32E/ILP32E is ratified.
399405
int NeededArgGPRs = 1;
400406
if (!IsFixed && NeededAlign == 2 * XLen)
401-
NeededArgGPRs = 2 + (ArgGPRsLeft % 2);
407+
NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2));
402408
else if (Size > XLen && Size <= 2 * XLen)
403409
NeededArgGPRs = 2;
404410

@@ -480,6 +486,13 @@ Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
480486

481487
auto TInfo = getContext().getTypeInfoInChars(Ty);
482488

489+
// TODO: To be compatible with GCC's behaviors, we force arguments with
490+
// 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
491+
// `unsigned long long` and `double` to have 4-byte alignment. This
492+
// behavior may be changed when RV32E/ILP32E is ratified.
493+
if (EABI && XLen == 32)
494+
TInfo.Align = std::min(TInfo.Align, CharUnits::fromQuantity(4));
495+
483496
// Arguments bigger than 2*Xlen bytes are passed indirectly.
484497
bool IsIndirect = TInfo.Width > 2 * SlotSize;
485498

@@ -499,8 +512,9 @@ namespace {
499512
class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
500513
public:
501514
RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
502-
unsigned FLen)
503-
: TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen)) {}
515+
unsigned FLen, bool EABI)
516+
: TargetCodeGenInfo(
517+
std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {}
504518

505519
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
506520
CodeGen::CodeGenModule &CGM) const override {
@@ -526,6 +540,7 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
526540

527541
std::unique_ptr<TargetCodeGenInfo>
528542
CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
529-
unsigned FLen) {
530-
return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen);
543+
unsigned FLen, bool EABI) {
544+
return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen,
545+
EABI);
531546
}

clang/lib/Driver/ToolChains/Arch/RISCV.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
210210
// rv32e -> ilp32e
211211
// rv32* -> ilp32
212212
// rv64g | rv64*d -> lp64d
213+
// rv64e -> lp64e
213214
// rv64* -> lp64
214215
StringRef Arch = getRISCVArch(Args, Triple);
215216

@@ -285,13 +286,16 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
285286
// 3. Choose a default based on `-mabi=`
286287
//
287288
// ilp32e -> rv32e
289+
// lp64e -> rv64e
288290
// ilp32 | ilp32f | ilp32d -> rv32imafdc
289291
// lp64 | lp64f | lp64d -> rv64imafdc
290292
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
291293
StringRef MABI = A->getValue();
292294

293295
if (MABI.equals_insensitive("ilp32e"))
294296
return "rv32e";
297+
else if (MABI.equals_insensitive("lp64e"))
298+
return "rv64e";
295299
else if (MABI.starts_with_insensitive("ilp32"))
296300
return "rv32imafdc";
297301
else if (MABI.starts_with_insensitive("lp64")) {

clang/test/CodeGen/RISCV/riscv32-abi.c

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32F-ILP32D,ILP32-ILP32F,ILP32F %s
66
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
77
// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32F-ILP32D,ILP32D %s
8+
// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-abi ilp32e %s -o - \
9+
// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32-ILP32F,ILP32,ILP32E %s
810

911
#include <stddef.h>
1012
#include <stdint.h>
@@ -2064,4 +2066,5 @@ union float16_u f_ret_float16_u(void) {
20642066
}
20652067

20662068
//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
2069+
// ILP32E: {{.*}}
20672070
// ILP32F: {{.*}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// RUN: not %clang_cc1 -triple riscv32 -target-feature +d -emit-llvm -target-abi ilp32e %s 2>&1 \
2+
// RUN: | FileCheck -check-prefix=ILP32E-WITH-FD %s
3+
4+
// ILP32E-WITH-FD: error: invalid feature combination: ILP32E cannot be used with the D ISA extension

0 commit comments

Comments
 (0)