[clang] [llvm] PPC: Read the ELF ABI from the "target-abi" module flag (PR #221669)
Matt Arsenault via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 8 10:51:16 PDT 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/221669
>From 4d2e8febf9d1b1d1265446e5d97f9c2ac693ebf4 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 6 Sep 2026 13:48:59 +0200
Subject: [PATCH] PPC: Read the ELF ABI from the "target-abi" module flag
Resolve the ELFv2 ABI from the effective ABI name module flag,
rather than strictly relying on the -target-abi flag.
Also start emitting "target-abi" for PPC from clang.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
clang/lib/CodeGen/CodeGenModule.cpp | 3 +-
clang/test/CodeGen/stack-protector-guard.c | 2 +-
llvm/lib/Target/PowerPC/PPC.h | 4 ++
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 3 +-
llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp | 2 +-
llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 8 ++--
llvm/lib/Target/PowerPC/PPCSubtarget.h | 5 ++-
llvm/lib/Target/PowerPC/PPCTargetMachine.cpp | 35 +++++++++---------
llvm/lib/Target/PowerPC/PPCTargetMachine.h | 7 ++--
.../Target/PowerPC/PPCTargetTransformInfo.cpp | 3 +-
.../CodeGen/PowerPC/target-abi-module-flag.ll | 37 +++++++++++++++++++
11 files changed, 79 insertions(+), 30 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/target-abi-module-flag.ll
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 8890d2a4b1b7e..cbf64364b3a38 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1490,7 +1490,8 @@ void CodeGenModule::Release() {
// Other targets have no apparent need for the ABI name, but set a non-empty
// value.
if (StringRef ABIStr = Target.getABI();
- !ABIStr.empty() && (T.isARM() || T.isThumb() || T.isRISCV())) {
+ !ABIStr.empty() &&
+ (T.isARM() || T.isThumb() || T.isRISCV() || T.isPPC())) {
getModule().addModuleFlag(llvm::Module::Error, "target-abi",
llvm::MDString::get(VMContext, ABIStr));
}
diff --git a/clang/test/CodeGen/stack-protector-guard.c b/clang/test/CodeGen/stack-protector-guard.c
index 5438671483aff..e90b2070f630f 100644
--- a/clang/test/CodeGen/stack-protector-guard.c
+++ b/clang/test/CodeGen/stack-protector-guard.c
@@ -67,7 +67,7 @@ void bar(int x) {
// RISCV: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"tp"}
// RISCV: [[ATTR3]] = !{i32 1, !"stack-protector-guard-offset", i32 44}
-// POWERPC64: !llvm.module.flags = !{[[ATTR1:![0-9]+]], [[ATTR2:![0-9]+]], [[ATTR3:![0-9]+]]}
+// POWERPC64: !llvm.module.flags = !{{{.*}}[[ATTR1:![0-9]+]], [[ATTR2:![0-9]+]], [[ATTR3:![0-9]+]]}
// POWERPC64: [[ATTR1]] = !{i32 1, !"stack-protector-guard", !"tls"}
// POWERPC64: [[ATTR2]] = !{i32 1, !"stack-protector-guard-reg", !"r13"}
// POWERPC64: [[ATTR3]] = !{i32 1, !"stack-protector-guard-offset", i32 52}
diff --git a/llvm/lib/Target/PowerPC/PPC.h b/llvm/lib/Target/PowerPC/PPC.h
index cf60a23aa5b4a..7fe80d5ba52f3 100644
--- a/llvm/lib/Target/PowerPC/PPC.h
+++ b/llvm/lib/Target/PowerPC/PPC.h
@@ -97,6 +97,10 @@ class ModulePass;
InstructionSelector *
createPPCInstructionSelector(const PPCTargetMachine &, const PPCSubtarget &,
const PPCRegisterBankInfo &);
+
+ /// The PowerPC ABI variant.
+ enum PPCABI { PPC_ABI_UNKNOWN, PPC_ABI_ELFv1, PPC_ABI_ELFv2 };
+
namespace PPCII {
/// Target Operand Flag enum.
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index f4b7a7d701e65..e78eb5239871f 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -1941,7 +1941,8 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) {
}
void PPCLinuxAsmPrinter::emitStartOfAsmFile(Module &M) {
- if (static_cast<const PPCTargetMachine &>(TM).isELFv2ABI()) {
+ if (PPCTargetMachine::computeABI(M.getTargetTriple(),
+ TM.getTargetABIName(M)) == PPC_ABI_ELFv2) {
PPCTargetStreamer *TS =
static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
TS->emitAbiVersion(2);
diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
index 1f6c9e4c4a7a8..ea96394f97ff3 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -687,7 +687,7 @@ PPCRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
// For Power9 we allow the user to enable GPR to vector spills.
// FIXME: Currently limited to spilling GP8RC. A follow on patch will add
// support to spill GPRC.
- if (TM.isELFv2ABI() || Subtarget.isAIXABI()) {
+ if (Subtarget.isELFv2ABI() || Subtarget.isAIXABI()) {
if (Subtarget.hasP9Vector() && EnableGPRToVecSpills &&
RC == &PPC::G8RCRegClass) {
InflateGP8RC++;
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index 1641e335159a7..2dfb67ff4c33d 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -52,8 +52,10 @@ PPCSubtarget &PPCSubtarget::initializeSubtargetDependencies(StringRef CPU,
}
PPCSubtarget::PPCSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU,
- StringRef FS, const PPCTargetMachine &TM)
- : PPCGenSubtargetInfo(TT, CPU, TuneCPU, FS), TM(TM),
+ StringRef FS, StringRef ABIName,
+ const PPCTargetMachine &TM)
+ : PPCGenSubtargetInfo(TT, CPU, TuneCPU, FS),
+ TargetABI(PPCTargetMachine::computeABI(TT, ABIName)), TM(TM),
FrameLowering(initializeSubtargetDependencies(CPU, TuneCPU, FS)),
InstrInfo(*this), TLInfo(TM, *this) {
TSInfo = std::make_unique<PPCSelectionDAGInfo>();
@@ -247,7 +249,7 @@ CodeModel::Model PPCSubtarget::getCodeModel(const TargetMachine &TM,
return ModuleModel;
}
-bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); }
+bool PPCSubtarget::isELFv2ABI() const { return TargetABI == PPC_ABI_ELFv2; }
bool PPCSubtarget::isUsingPCRelativeCalls() const {
return isPPC64() && hasPCRelativeMemops() && isELFv2ABI() &&
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.h b/llvm/lib/Target/PowerPC/PPCSubtarget.h
index eec0e141debd4..f303a3e7ee217 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.h
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.h
@@ -94,6 +94,9 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
bool IsLittleEndian;
+ /// The selected ABI variant.
+ PPCABI TargetABI = PPC_ABI_UNKNOWN;
+
POPCNTDKind HasPOPCNTD;
const PPCTargetMachine &TM;
@@ -115,7 +118,7 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
/// of the specified triple.
///
PPCSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS,
- const PPCTargetMachine &TM);
+ StringRef ABIName, const PPCTargetMachine &TM);
~PPCSubtarget() override;
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
index 07638bcf507e3..ef86320bd5c87 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -192,26 +192,23 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
return std::make_unique<PPC64LinuxTargetObjectFile>();
}
-static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT,
- const TargetOptions &Options) {
- if (Options.MCOptions.getABIName().starts_with("elfv1"))
- return PPCTargetMachine::PPC_ABI_ELFv1;
- else if (Options.MCOptions.getABIName().starts_with("elfv2"))
- return PPCTargetMachine::PPC_ABI_ELFv2;
+// An explicit ABI name takes precedence; otherwise use the triple default.
+PPCABI PPCTargetMachine::computeABI(const Triple &TT, StringRef ABIName) {
+ if (ABIName.starts_with("elfv1"))
+ return PPC_ABI_ELFv1;
+ if (ABIName.starts_with("elfv2"))
+ return PPC_ABI_ELFv2;
- assert(Options.MCOptions.getABIName().empty() &&
- "Unknown target-abi option!");
+ if (TT.isOSAIX())
+ return PPC_ABI_UNKNOWN;
switch (TT.getArch()) {
case Triple::ppc64le:
- return PPCTargetMachine::PPC_ABI_ELFv2;
+ return PPC_ABI_ELFv2;
case Triple::ppc64:
- if (TT.isPPC64ELFv2ABI())
- return PPCTargetMachine::PPC_ABI_ELFv2;
- else
- return PPCTargetMachine::PPC_ABI_ELFv1;
+ return TT.isPPC64ELFv2ABI() ? PPC_ABI_ELFv2 : PPC_ABI_ELFv1;
default:
- return PPCTargetMachine::PPC_ABI_UNKNOWN;
+ return PPC_ABI_UNKNOWN;
}
}
@@ -306,7 +303,6 @@ PPCTargetMachine::PPCTargetMachine(const Target &T, const Triple &TT,
getEffectiveRelocModel(TT, RM),
getEffectivePPCCodeModel(TT, CM, JIT), OL),
TLOF(createTLOF(getTargetTriple())),
- TargetABI(computeTargetABI(TT, Options)),
Endianness(TT.isLittleEndian() ? Endian::LITTLE : Endian::BIG) {
initAsmInfo();
}
@@ -337,7 +333,11 @@ PPCTargetMachine::getSubtargetImpl(const Function &F) const {
if (SoftFloat)
FS += FS.empty() ? "-hard-float" : ",-hard-float";
- auto &I = SubtargetMap[CPU + TuneCPU + FS];
+ // Prefer the "target-abi" module flag, falling back to the -target-abi
+ // option.
+ StringRef ABIName = getTargetABIName(*F.getParent());
+
+ auto &I = SubtargetMap[CPU + TuneCPU + FS + ABIName.str()];
if (!I) {
I = std::make_unique<PPCSubtarget>(
TargetTriple, CPU, TuneCPU,
@@ -347,7 +347,8 @@ PPCTargetMachine::getSubtargetImpl(const Function &F) const {
// shouldn't require adding them. Fixing this means pulling Feature64Bit
// out of most of the target cpus in the .td file and making it set only
// as part of initialization via the TargetTriple.
- computeFSAdditions(FS, getOptLevel(), getTargetTriple()), *this);
+ computeFSAdditions(FS, getOptLevel(), getTargetTriple()), ABIName,
+ *this);
}
return I.get();
}
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.h b/llvm/lib/Target/PowerPC/PPCTargetMachine.h
index cb02b446fadb3..660f47b355648 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.h
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.h
@@ -25,12 +25,10 @@ namespace llvm {
///
class PPCTargetMachine final : public CodeGenTargetMachineImpl {
public:
- enum PPCABI { PPC_ABI_UNKNOWN, PPC_ABI_ELFv1, PPC_ABI_ELFv2 };
enum Endian { NOT_DETECTED, LITTLE, BIG };
private:
std::unique_ptr<TargetLoweringObjectFile> TLOF;
- PPCABI TargetABI;
Endian Endianness = Endian::NOT_DETECTED;
mutable bool HasGlibcHWCAPAccess = false;
@@ -68,7 +66,10 @@ class PPCTargetMachine final : public CodeGenTargetMachineImpl {
ScheduleDAGInstrs *
createPostMachineScheduler(MachineSchedContext *C) const override;
- bool isELFv2ABI() const { return TargetABI == PPC_ABI_ELFv2; }
+ /// Compute the ABI variant for \p TT and \p ABIName (the "target-abi" module
+ /// flag), falling back to the triple default.
+ static PPCABI computeABI(const Triple &TT, StringRef ABIName);
+
bool hasGlibcHWCAPAccess() const { return HasGlibcHWCAPAccess; }
void setGlibcHWCAPAccess(bool Val = true) const { HasGlibcHWCAPAccess = Val; }
bool isPPC64() const {
diff --git a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
index 32a7f3701f9f2..3b2c5b06e0cfa 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
@@ -983,9 +983,8 @@ bool PPCTTIImpl::isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
bool PPCTTIImpl::isNumRegsMajorCostOfLSR() const { return false; }
bool PPCTTIImpl::shouldBuildRelLookupTables() const {
- const PPCTargetMachine &TM = ST->getTargetMachine();
// XCOFF hasn't implemented lowerRelativeReference, disable non-ELF for now.
- if (!TM.isELFv2ABI())
+ if (!ST->isELFv2ABI())
return false;
return BaseT::shouldBuildRelLookupTables();
}
diff --git a/llvm/test/CodeGen/PowerPC/target-abi-module-flag.ll b/llvm/test/CodeGen/PowerPC/target-abi-module-flag.ll
new file mode 100644
index 0000000000000..b2b778f0e25e4
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/target-abi-module-flag.ll
@@ -0,0 +1,37 @@
+; Check that the "target-abi" module flag selects the PPC ELF ABI, so the ABI
+; is taken from the IR when no -target-abi option is given. The flag overrides
+; the triple default in both directions (.abiversion 2 is emitted for ELFv2).
+
+; RUN: split-file %s %t
+
+; powerpc64 big-endian defaults to ELFv1; an elfv2 module flag overrides that.
+; RUN: llc -mtriple=powerpc64-unknown-linux < %t/elfv2.ll | FileCheck %s --check-prefix=ELFv2
+
+; powerpc64le defaults to ELFv2; an elfv1 module flag overrides that.
+; RUN: llc -mtriple=powerpc64le-unknown-linux < %t/elfv1.ll | FileCheck %s --check-prefix=ELFv1
+
+; A matching -target-abi option is accepted.
+; RUN: llc -mtriple=powerpc64-unknown-linux -target-abi elfv2 < %t/elfv2.ll | FileCheck %s --check-prefix=ELFv2
+
+; A conflicting -target-abi option is rejected.
+; RUN: not llc -mtriple=powerpc64-unknown-linux -target-abi elfv1 < %t/elfv2.ll 2>&1 | FileCheck %s --check-prefix=CONFLICT
+
+; ELFv2: .abiversion 2
+; ELFv1-NOT: .abiversion 2
+; CONFLICT: -target-abi option != target-abi module flag
+
+;--- elfv1.ll
+define void @f() {
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"elfv1"}
+
+;--- elfv2.ll
+define void @g() {
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"elfv2"}
More information about the cfe-commits
mailing list