[llvm] [clang] [RISCV] CodeGen of RVE and ilp32e/lp64e ABIs (PR #76777)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 2 20:24:30 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Wang Pengcheng (wangpc-pp)
<details>
<summary>Changes</summary>
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
---
Patch is 422.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76777.diff
45 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+2)
- (modified) clang/lib/Basic/Targets/RISCV.cpp (+13-1)
- (modified) clang/lib/Basic/Targets/RISCV.h (+12)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+2-1)
- (modified) clang/lib/CodeGen/TargetInfo.h (+2-1)
- (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+25-10)
- (modified) clang/lib/Driver/ToolChains/Arch/RISCV.cpp (+4)
- (modified) clang/test/CodeGen/RISCV/riscv32-abi.c (+3)
- (added) clang/test/CodeGen/RISCV/riscv32-ilp32e-error.c (+4)
- (modified) clang/test/CodeGen/RISCV/riscv32-vararg.c (+421-141)
- (modified) clang/test/CodeGen/RISCV/riscv64-abi.c (+4)
- (modified) clang/test/CodeGen/RISCV/riscv64-vararg.c (+2)
- (modified) clang/test/Preprocessor/riscv-target-features.c (+22)
- (modified) llvm/docs/RISCVUsage.rst (+6)
- (modified) llvm/docs/ReleaseNotes.rst (+2)
- (modified) llvm/include/llvm/Support/RISCVAttributes.h (+1-1)
- (modified) llvm/lib/Support/RISCVISAInfo.cpp (+4-4)
- (modified) llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp (+1-1)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp (+5)
- (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp (+8-5)
- (modified) llvm/lib/Target/RISCV/RISCVCallingConv.td (+14-1)
- (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+7)
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+21-3)
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+1-6)
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+65-28)
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.h (+1-1)
- (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+17-3)
- (modified) llvm/lib/Target/RISCV/RISCVTargetMachine.cpp (+13-3)
- (modified) llvm/test/CodeGen/RISCV/callee-saved-fpr32s.ll (+432-2)
- (modified) llvm/test/CodeGen/RISCV/callee-saved-fpr64s.ll (+216-1)
- (modified) llvm/test/CodeGen/RISCV/callee-saved-gprs.ll (+530)
- (added) llvm/test/CodeGen/RISCV/calling-conv-ilp32e.ll (+2556)
- (added) llvm/test/CodeGen/RISCV/calling-conv-lp64e.ll (+221)
- (added) llvm/test/CodeGen/RISCV/calling-conv-rv32f-ilp32e.ll (+83)
- (modified) llvm/test/CodeGen/RISCV/interrupt-attr.ll (+745)
- (added) llvm/test/CodeGen/RISCV/rv32e.ll (+25)
- (added) llvm/test/CodeGen/RISCV/rv64e.ll (+25)
- (removed) llvm/test/CodeGen/RISCV/rve.ll (-8)
- (modified) llvm/test/CodeGen/RISCV/stack-realignment-with-variable-sized-objects.ll (+60)
- (modified) llvm/test/CodeGen/RISCV/stack-realignment.ll (+652)
- (modified) llvm/test/CodeGen/RISCV/target-abi-valid.ll (+4-5)
- (added) llvm/test/CodeGen/RISCV/vararg-ilp32e.ll (+148)
- (modified) llvm/test/CodeGen/RISCV/vararg.ll (+1261)
- (modified) llvm/test/MC/RISCV/option-invalid.s (-3)
- (modified) llvm/test/MC/RISCV/target-abi-invalid.s (+6-3)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0c8fec691bf3c9..aa8d27f5c17551 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -971,6 +971,8 @@ RISC-V Support
^^^^^^^^^^^^^^
- Unaligned memory accesses can be toggled by ``-m[no-]unaligned-access`` or the
aliases ``-m[no-]strict-align``.
+- CodeGen of RV32E/RV64E are supported experimentally.
+- CodeGen of ilp32e/lp64e are supported experimentally.
- Default ABI with F but without D was changed to ilp32f for RV32 and to lp64f
for RV64.
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 6bc57a83a2d5ae..8db989df04c87b 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -154,7 +154,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
else
Builder.defineMacro("__riscv_float_abi_soft");
- if (ABIName == "ilp32e")
+ if (ABIName == "ilp32e" || ABIName == "lp64e")
Builder.defineMacro("__riscv_abi_rve");
Builder.defineMacro("__riscv_arch_test");
@@ -215,6 +215,13 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_misaligned_fast");
else
Builder.defineMacro("__riscv_misaligned_avoid");
+
+ if (ISAInfo->hasExtension("e")) {
+ if (Is64Bit)
+ Builder.defineMacro("__riscv_64e");
+ else
+ Builder.defineMacro("__riscv_32e");
+ }
}
static constexpr Builtin::Info BuiltinInfo[] = {
@@ -386,6 +393,11 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
if (llvm::is_contained(Features, "+experimental"))
HasExperimental = true;
+ if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
+ Diags.Report(diag::err_invalid_feature_combination)
+ << "ILP32E must not be used with the D ISA extension";
+ return false;
+ }
return true;
}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index f98c88cd45f831..bfbdafb682c851 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -132,6 +132,12 @@ class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
}
bool setABI(const std::string &Name) override {
+ if (Name == "ilp32e") {
+ ABI = Name;
+ resetDataLayout("e-m:e-p:32:32-i64:64-n32-S32");
+ return true;
+ }
+
if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") {
ABI = Name;
return true;
@@ -156,6 +162,12 @@ class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo {
}
bool setABI(const std::string &Name) override {
+ if (Name == "lp64e") {
+ ABI = Name;
+ resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S64");
+ return true;
+ }
+
if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") {
ABI = Name;
return true;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d78f2594a23764..4e999ddf9fe027 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -229,7 +229,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
ABIFLen = 32;
else if (ABIStr.ends_with("d"))
ABIFLen = 64;
- return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen);
+ bool EABI = ABIStr.endswith("e");
+ 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 0c0781a2d5ab9d..7682f197041c74 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -496,7 +496,8 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind,
bool SoftFloatABI);
std::unique_ptr<TargetCodeGenInfo>
-createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen);
+createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen,
+ 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 1e1d249b37ac06..0851d1993d0c0f 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -25,8 +25,9 @@ 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;
- static const int NumArgGPRs = 8;
- static const int NumArgFPRs = 8;
+ const int NumArgGPRs;
+ const int NumArgFPRs;
+ const bool EABI;
bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
llvm::Type *&Field1Ty,
CharUnits &Field1Off,
@@ -34,8 +35,10 @@ class RISCVABIInfo : public DefaultABIInfo {
CharUnits &Field2Off) const;
public:
- RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen)
- : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {}
+ RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
+ bool EABI)
+ : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8),
+ NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {}
// DefaultABIInfo's classifyReturnType and classifyArgumentType are
// non-virtual, but computeInfo is virtual, so we overload it.
@@ -86,7 +89,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
- int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
+ int ArgFPRsLeft = NumArgFPRs;
int NumFixedArgs = FI.getNumRequiredArgs();
int ArgNum = 0;
@@ -396,9 +399,12 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
// Determine the number of GPRs needed to pass the current argument
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
// register pairs, so may consume 3 registers.
+ // TODO: To be compatible with GCC's behaviors, we don't align registers
+ // currently if we are using ILP32E calling convention. This behavior may be
+ // changed when RV32E/ILP32E is ratified.
int NeededArgGPRs = 1;
if (!IsFixed && NeededAlign == 2 * XLen)
- NeededArgGPRs = 2 + (ArgGPRsLeft % 2);
+ NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2));
else if (Size > XLen && Size <= 2 * XLen)
NeededArgGPRs = 2;
@@ -480,6 +486,13 @@ Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
auto TInfo = getContext().getTypeInfoInChars(Ty);
+ // TODO: To be compatible with GCC's behaviors, we force arguments with
+ // 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
+ // `unsigned long long` and `double` to have 4-byte alignment. This
+ // behavior may be changed when RV32E/ILP32E is ratified.
+ if (EABI && XLen == 32)
+ TInfo.Align = std::min(TInfo.Align, CharUnits::fromQuantity(4));
+
// Arguments bigger than 2*Xlen bytes are passed indirectly.
bool IsIndirect = TInfo.Width > 2 * SlotSize;
@@ -499,8 +512,9 @@ namespace {
class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
public:
RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
- unsigned FLen)
- : TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen)) {}
+ unsigned FLen, bool EABI)
+ : TargetCodeGenInfo(
+ std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override {
@@ -526,6 +540,7 @@ class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
std::unique_ptr<TargetCodeGenInfo>
CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen,
- unsigned FLen) {
- return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen);
+ unsigned FLen, bool EABI) {
+ return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen,
+ EABI);
}
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 0717e3b813e1e2..76fedc576b8656 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -210,6 +210,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
// rv32e -> ilp32e
// rv32* -> ilp32
// rv64g | rv64*d -> lp64d
+ // rv64e -> lp64e
// rv64* -> lp64
StringRef Arch = getRISCVArch(Args, Triple);
@@ -285,6 +286,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 3. Choose a default based on `-mabi=`
//
// ilp32e -> rv32e
+ // lp64e -> rv64e
// ilp32 | ilp32f | ilp32d -> rv32imafdc
// lp64 | lp64f | lp64d -> rv64imafdc
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
@@ -292,6 +294,8 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
if (MABI.equals_insensitive("ilp32e"))
return "rv32e";
+ else if (MABI.starts_with_insensitive("lp64e"))
+ return "rv64e";
else if (MABI.starts_with_insensitive("ilp32"))
return "rv32imafdc";
else if (MABI.starts_with_insensitive("lp64")) {
diff --git a/clang/test/CodeGen/RISCV/riscv32-abi.c b/clang/test/CodeGen/RISCV/riscv32-abi.c
index 040ae500fc60e4..3645e15ccefcdc 100644
--- a/clang/test/CodeGen/RISCV/riscv32-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-abi.c
@@ -5,6 +5,8 @@
// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32F-ILP32D,ILP32-ILP32F,ILP32F %s
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32F-ILP32D,ILP32D %s
+// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-abi ilp32e %s -o - \
+// RUN: | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32-ILP32F,ILP32,ILP32E %s
#include <stddef.h>
#include <stdint.h>
@@ -2064,4 +2066,5 @@ union float16_u f_ret_float16_u(void) {
}
//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+// ILP32E: {{.*}}
// ILP32F: {{.*}}
diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32e-error.c b/clang/test/CodeGen/RISCV/riscv32-ilp32e-error.c
new file mode 100644
index 00000000000000..86444112bde297
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv32-ilp32e-error.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -triple riscv32 -target-feature +d -emit-llvm -target-abi ilp32e %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ILP32E-WITH-FD %s
+
+// ILP32E-WITH-FD: error: invalid feature combination: ILP32E must not be used with the D ISA extension
diff --git a/clang/test/CodeGen/RISCV/riscv32-vararg.c b/clang/test/CodeGen/RISCV/riscv32-vararg.c
index 02b1ed38e26556..1c4e41f2f54c8f 100644
--- a/clang/test/CodeGen/RISCV/riscv32-vararg.c
+++ b/clang/test/CodeGen/RISCV/riscv32-vararg.c
@@ -1,9 +1,11 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
-// RUN: | FileCheck %s
+// RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-ILP32F
// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
-// RUN: | FileCheck %s
+// RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-ILP32D
+// RUN: %clang_cc1 -triple riscv32 -target-abi ilp32e -emit-llvm %s -o - \
+// RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-ILP32E
#include <stddef.h>
#include <stdint.h>
@@ -102,24 +104,60 @@ int f_va_1(char *fmt, ...) {
// used to pass varargs with 2x xlen alignment and 2x xlen size. Ensure the
// correct offsets are used.
-// CHECK-LABEL: define dso_local double @f_va_2
-// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VA:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[V:%.*]] = alloca double, align 8
-// CHECK-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
-// CHECK-NEXT: call void @llvm.va_start(ptr [[VA]])
-// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
-// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)
-// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
-// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
-// CHECK-NEXT: store double [[TMP1]], ptr [[V]], align 8
-// CHECK-NEXT: call void @llvm.va_end(ptr [[VA]])
-// CHECK-NEXT: [[TMP2:%.*]] = load double, ptr [[V]], align 8
-// CHECK-NEXT: ret double [[TMP2]]
+// CHECK-ILP32F-LABEL: define dso_local double @f_va_2
+// CHECK-ILP32F-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-ILP32F-NEXT: entry:
+// CHECK-ILP32F-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-ILP32F-NEXT: [[VA:%.*]] = alloca ptr, align 4
+// CHECK-ILP32F-NEXT: [[V:%.*]] = alloca double, align 8
+// CHECK-ILP32F-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-ILP32F-NEXT: call void @llvm.va_start(ptr [[VA]])
+// CHECK-ILP32F-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-ILP32F-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
+// CHECK-ILP32F-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)
+// CHECK-ILP32F-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
+// CHECK-ILP32F-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-ILP32F-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
+// CHECK-ILP32F-NEXT: store double [[TMP1]], ptr [[V]], align 8
+// CHECK-ILP32F-NEXT: call void @llvm.va_end(ptr [[VA]])
+// CHECK-ILP32F-NEXT: [[TMP2:%.*]] = load double, ptr [[V]], align 8
+// CHECK-ILP32F-NEXT: ret double [[TMP2]]
+//
+// CHECK-ILP32D-LABEL: define dso_local double @f_va_2
+// CHECK-ILP32D-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-ILP32D-NEXT: entry:
+// CHECK-ILP32D-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-ILP32D-NEXT: [[VA:%.*]] = alloca ptr, align 4
+// CHECK-ILP32D-NEXT: [[V:%.*]] = alloca double, align 8
+// CHECK-ILP32D-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-ILP32D-NEXT: call void @llvm.va_start(ptr [[VA]])
+// CHECK-ILP32D-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-ILP32D-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
+// CHECK-ILP32D-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)
+// CHECK-ILP32D-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
+// CHECK-ILP32D-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-ILP32D-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
+// CHECK-ILP32D-NEXT: store double [[TMP1]], ptr [[V]], align 8
+// CHECK-ILP32D-NEXT: call void @llvm.va_end(ptr [[VA]])
+// CHECK-ILP32D-NEXT: [[TMP2:%.*]] = load double, ptr [[V]], align 8
+// CHECK-ILP32D-NEXT: ret double [[TMP2]]
+//
+// CHECK-ILP32E-LABEL: define dso_local double @f_va_2
+// CHECK-ILP32E-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-ILP32E-NEXT: entry:
+// CHECK-ILP32E-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-ILP32E-NEXT: [[VA:%.*]] = alloca ptr, align 4
+// CHECK-ILP32E-NEXT: [[V:%.*]] = alloca double, align 8
+// CHECK-ILP32E-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-ILP32E-NEXT: call void @llvm.va_start(ptr [[VA]])
+// CHECK-ILP32E-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-ILP32E-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 8
+// CHECK-ILP32E-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-ILP32E-NEXT: [[TMP0:%.*]] = load double, ptr [[ARGP_CUR]], align 4
+// CHECK-ILP32E-NEXT: store double [[TMP0]], ptr [[V]], align 8
+// CHECK-ILP32E-NEXT: call void @llvm.va_end(ptr [[VA]])
+// CHECK-ILP32E-NEXT: [[TMP1:%.*]] = load double, ptr [[V]], align 8
+// CHECK-ILP32E-NEXT: ret double [[TMP1]]
//
double f_va_2(char *fmt, ...) {
__builtin_va_list va;
@@ -133,40 +171,106 @@ double f_va_2(char *fmt, ...) {
// Two "aligned" register pairs.
-// CHECK-LABEL: define dso_local double @f_va_3
-// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VA:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[V:%.*]] = alloca double, align 8
-// CHECK-NEXT: [[W:%.*]] = alloca i32, align 4
-// CHECK-NEXT: [[X:%.*]] = alloca double, align 8
-// CHECK-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
-// CHECK-NEXT: call void @llvm.va_start(ptr [[VA]])
-// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
-// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)
-// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
-// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
-// CHECK-NEXT: store double [[TMP1]], ptr [[V]], align 8
-// CHECK-NEXT: [[ARGP_CUR1:%.*]] = load ptr, ptr [[VA]], align 4
-// CHECK-NEXT: [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4
-// CHECK-NEXT: store ptr [[ARGP_NEXT2]], ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARGP_CUR1]], align 4
-// CHECK-NEXT: store i32 [[TMP2]], ptr [[W]], align 4
-// CHECK-NEXT: [[ARGP_CUR3:%.*]] = load ptr, ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i32 7
-// CHECK-NEXT: [[ARGP_CUR3_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP3]], i32 -8)
-// CHECK-NEXT: [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3_ALIGNED]], i32 8
-// CHECK-NEXT: store ptr [[ARGP_NEXT4]], ptr [[VA]], align 4
-// CHECK-NEXT: [[TMP4:%.*]] = load double, ptr [[ARGP_CUR3_ALIGNED]], align 8
-// CHECK-NEXT: store double [[TMP4]], ptr [[X]], align 8
-// CHECK-NEXT: call void @llvm.va_end(ptr [[VA]])
-// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[V]], align 8
-// CHECK-NEXT: [[TMP6:%.*]] = load double, ptr [[X]], align 8
-// CHECK-NEXT: [[ADD:%.*]] = fadd double [[TMP5]], [[TMP6]]
-// CHECK-NEXT: ret double [[ADD]]
+// CHECK-ILP32F-LABEL: define dso_local double @f_va_3
+// CHECK-ILP32F-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-ILP32F-NEXT: entry:
+// CHECK-ILP32F-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-ILP32F-NEXT: [[VA:%.*]] = alloca ptr, align 4
+// CHECK-ILP32F-NEXT: [[V:%.*]] = alloca double, align 8
+// CHECK-ILP32F-NEXT: [[W:%.*]] = alloca i32, align 4
+// CHECK-ILP32F-NEXT: [[X:%.*]] = alloca double, align 8
+// CHECK-ILP32F-NEXT: store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-ILP32F-NEXT: call void @llvm.va_start(ptr [[VA]])
+// CHECK-ILP32F-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-ILP32F-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
+// CHECK-ILP32F-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)
+// CHECK-ILP32F-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
+// CHECK-ILP32F-NEXT: store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-ILP32F-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
+// CHECK-ILP32F-NEXT: store double [[...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/76777
More information about the cfe-commits
mailing list