-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[PowerPC] Take ABI into account for data layout #149725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Prior to this change, the data layout calculation would not account for explicitly set -mabi=elfv2 on powerpc64-unknown-linux-gnu, a target that defaults to elfv1. Signed-off-by: Jens Reidel <[email protected]>
@llvm/pr-subscribers-clang Author: Jens Reidel (Gelbpunkt) ChangesPrior to this change, the data layout calculation would not account for explicitly set This is loosely inspired by the equivalent ARM / RISC-V code.
Full diff: https://github.com/llvm/llvm-project/pull/149725.diff 2 Files Affected:
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 9f3a4cd2da716..4cceebf6c2826 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -445,27 +445,17 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
Int64Type = SignedLong;
- std::string DataLayout;
if (Triple.isOSAIX()) {
// TODO: Set appropriate ABI for AIX platform.
- DataLayout = "E-m:a-Fi64-i64:64-i128:128-n32:64";
LongDoubleWidth = 64;
LongDoubleAlign = DoubleAlign = 32;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- } else if ((Triple.getArch() == llvm::Triple::ppc64le)) {
- DataLayout = "e-m:e-Fn32-i64:64-i128:128-n32:64";
+ } else if ((Triple.getArch() == llvm::Triple::ppc64le) ||
+ Triple.isPPC64ELFv2ABI()) {
ABI = "elfv2";
} else {
- DataLayout = "E-m:e";
- if (Triple.isPPC64ELFv2ABI()) {
- ABI = "elfv2";
- DataLayout += "-Fn32";
- } else {
- ABI = "elfv1";
- DataLayout += "-Fi64";
- }
- DataLayout += "-i64:64-i128:128-n32:64";
+ ABI = "elfv1";
}
if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) {
@@ -473,14 +463,12 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
}
- if (Triple.isOSAIX() || Triple.isOSLinux())
- DataLayout += "-S128-v256:256:256-v512:512:512";
- resetDataLayout(DataLayout);
-
// Newer PPC64 instruction sets support atomics up to 16 bytes.
MaxAtomicPromoteWidth = 128;
// Baseline PPC64 supports inlining atomics up to 8 bytes.
MaxAtomicInlineWidth = 64;
+
+ calculateDataLayout();
}
void setMaxAtomicWidth() override {
@@ -495,10 +483,33 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
return TargetInfo::CharPtrBuiltinVaList;
}
+ void calculateDataLayout() {
+ std::string DataLayout;
+
+ if (getTriple().isOSAIX()) {
+ DataLayout = "E-m:a-Fi64-i64:64-i128:128-n32:64";
+ } else if ((getTriple().getArch() == llvm::Triple::ppc64le)) {
+ DataLayout = "e-m:e-Fn32-i64:64-i128:128-n32:64";
+ } else {
+ DataLayout = "E-m:e";
+ if (ABI == "elfv2") {
+ DataLayout += "-Fn32";
+ } else {
+ DataLayout += "-Fi64";
+ }
+ DataLayout += "-i64:64-i128:128-n32:64";
+ }
+
+ if (getTriple().isOSAIX() || getTriple().isOSLinux())
+ DataLayout += "-S128-v256:256:256-v512:512:512";
+ resetDataLayout(DataLayout);
+ }
+
// PPC64 Linux-specific ABI options.
bool setABI(const std::string &Name) override {
if (Name == "elfv1" || Name == "elfv2") {
ABI = Name;
+ calculateDataLayout();
return true;
}
return false;
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
index b5c6ac111dff0..10d7f12884728 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -154,8 +154,10 @@ static bool isLittleEndianTriple(const Triple &T) {
}
/// Return the datalayout string of a subtarget.
-static std::string getDataLayoutString(const Triple &T) {
+static std::string computeDataLayout(const Triple &T,
+ const TargetOptions &Options) {
bool is64Bit = T.getArch() == Triple::ppc64 || T.getArch() == Triple::ppc64le;
+ StringRef ABIName = Options.MCOptions.getABIName();
std::string Ret;
// Most PPC* platforms are big endian, PPC(64)LE is little endian.
@@ -174,7 +176,8 @@ static std::string getDataLayoutString(const Triple &T) {
// If the target ABI uses function descriptors, then the alignment of function
// pointers depends on the alignment used to emit the descriptor. Otherwise,
// function pointers are aligned to 32 bits because the instructions must be.
- if ((T.getArch() == Triple::ppc64 && !T.isPPC64ELFv2ABI())) {
+ if ((T.getArch() == Triple::ppc64 &&
+ (!T.isPPC64ELFv2ABI() && ABIName != "elfv2"))) {
Ret += "-Fi64";
} else if (T.isOSAIX()) {
Ret += is64Bit ? "-Fi64" : "-Fi32";
@@ -348,7 +351,7 @@ PPCTargetMachine::PPCTargetMachine(const Target &T, const Triple &TT,
std::optional<Reloc::Model> RM,
std::optional<CodeModel::Model> CM,
CodeGenOptLevel OL, bool JIT)
- : CodeGenTargetMachineImpl(T, getDataLayoutString(TT), TT, CPU,
+ : CodeGenTargetMachineImpl(T, computeDataLayout(TT, Options), TT, CPU,
computeFSAdditions(FS, OL, TT), Options,
getEffectiveRelocModel(TT, RM),
getEffectivePPCCodeModel(TT, CM, JIT), OL),
|
@llvm/pr-subscribers-backend-powerpc Author: Jens Reidel (Gelbpunkt) ChangesPrior to this change, the data layout calculation would not account for explicitly set This is loosely inspired by the equivalent ARM / RISC-V code.
Full diff: https://github.com/llvm/llvm-project/pull/149725.diff 2 Files Affected:
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 9f3a4cd2da716..4cceebf6c2826 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -445,27 +445,17 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
Int64Type = SignedLong;
- std::string DataLayout;
if (Triple.isOSAIX()) {
// TODO: Set appropriate ABI for AIX platform.
- DataLayout = "E-m:a-Fi64-i64:64-i128:128-n32:64";
LongDoubleWidth = 64;
LongDoubleAlign = DoubleAlign = 32;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- } else if ((Triple.getArch() == llvm::Triple::ppc64le)) {
- DataLayout = "e-m:e-Fn32-i64:64-i128:128-n32:64";
+ } else if ((Triple.getArch() == llvm::Triple::ppc64le) ||
+ Triple.isPPC64ELFv2ABI()) {
ABI = "elfv2";
} else {
- DataLayout = "E-m:e";
- if (Triple.isPPC64ELFv2ABI()) {
- ABI = "elfv2";
- DataLayout += "-Fn32";
- } else {
- ABI = "elfv1";
- DataLayout += "-Fi64";
- }
- DataLayout += "-i64:64-i128:128-n32:64";
+ ABI = "elfv1";
}
if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) {
@@ -473,14 +463,12 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
}
- if (Triple.isOSAIX() || Triple.isOSLinux())
- DataLayout += "-S128-v256:256:256-v512:512:512";
- resetDataLayout(DataLayout);
-
// Newer PPC64 instruction sets support atomics up to 16 bytes.
MaxAtomicPromoteWidth = 128;
// Baseline PPC64 supports inlining atomics up to 8 bytes.
MaxAtomicInlineWidth = 64;
+
+ calculateDataLayout();
}
void setMaxAtomicWidth() override {
@@ -495,10 +483,33 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
return TargetInfo::CharPtrBuiltinVaList;
}
+ void calculateDataLayout() {
+ std::string DataLayout;
+
+ if (getTriple().isOSAIX()) {
+ DataLayout = "E-m:a-Fi64-i64:64-i128:128-n32:64";
+ } else if ((getTriple().getArch() == llvm::Triple::ppc64le)) {
+ DataLayout = "e-m:e-Fn32-i64:64-i128:128-n32:64";
+ } else {
+ DataLayout = "E-m:e";
+ if (ABI == "elfv2") {
+ DataLayout += "-Fn32";
+ } else {
+ DataLayout += "-Fi64";
+ }
+ DataLayout += "-i64:64-i128:128-n32:64";
+ }
+
+ if (getTriple().isOSAIX() || getTriple().isOSLinux())
+ DataLayout += "-S128-v256:256:256-v512:512:512";
+ resetDataLayout(DataLayout);
+ }
+
// PPC64 Linux-specific ABI options.
bool setABI(const std::string &Name) override {
if (Name == "elfv1" || Name == "elfv2") {
ABI = Name;
+ calculateDataLayout();
return true;
}
return false;
diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
index b5c6ac111dff0..10d7f12884728 100644
--- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -154,8 +154,10 @@ static bool isLittleEndianTriple(const Triple &T) {
}
/// Return the datalayout string of a subtarget.
-static std::string getDataLayoutString(const Triple &T) {
+static std::string computeDataLayout(const Triple &T,
+ const TargetOptions &Options) {
bool is64Bit = T.getArch() == Triple::ppc64 || T.getArch() == Triple::ppc64le;
+ StringRef ABIName = Options.MCOptions.getABIName();
std::string Ret;
// Most PPC* platforms are big endian, PPC(64)LE is little endian.
@@ -174,7 +176,8 @@ static std::string getDataLayoutString(const Triple &T) {
// If the target ABI uses function descriptors, then the alignment of function
// pointers depends on the alignment used to emit the descriptor. Otherwise,
// function pointers are aligned to 32 bits because the instructions must be.
- if ((T.getArch() == Triple::ppc64 && !T.isPPC64ELFv2ABI())) {
+ if ((T.getArch() == Triple::ppc64 &&
+ (!T.isPPC64ELFv2ABI() && ABIName != "elfv2"))) {
Ret += "-Fi64";
} else if (T.isOSAIX()) {
Ret += is64Bit ? "-Fi64" : "-Fi32";
@@ -348,7 +351,7 @@ PPCTargetMachine::PPCTargetMachine(const Target &T, const Triple &TT,
std::optional<Reloc::Model> RM,
std::optional<CodeModel::Model> CM,
CodeGenOptLevel OL, bool JIT)
- : CodeGenTargetMachineImpl(T, getDataLayoutString(TT), TT, CPU,
+ : CodeGenTargetMachineImpl(T, computeDataLayout(TT, Options), TT, CPU,
computeFSAdditions(FS, OL, TT), Options,
getEffectiveRelocModel(TT, RM),
getEffectivePPCCodeModel(TT, CM, JIT), OL),
|
From https://sourceware.org/glibc/wiki/ABIList#powerpc (emphasis mine):
Is this no longer the case? |
The only Linux distro I can find that actually claims support for
... but that's not really ELFv2 then, is it? If that ABI variant is what this PR is actually about, then it seems to me that a new name should be created for this to avoid confusion. ( |
The page is probably correct in so far that glibc doesn't explicitly support it. However, out of the 64-bit big endian Linux distributions using glibc that I'm aware of (Arch Linux POWER, Void Linux for PowerPC, Gentoo), the first two use ELFv2 and Gentoo at least lists it as a theoretical option. Also, this isn't exactly a fix limited to glibc target triples. It fixes the data layout on any target triple that defaults to ELFv1 when |
This one claims to support old processors too, so seems like also a case of "loosened" ELFv2?
Sure, I'm not objecting to the fix. From a quick glance, it seems ok to me. I'm just concerned about what downstream projects seem to be doing with the term |
Correct, it isn't strictly ELFv2.
Fair point, ideally I'd like both the "proper" ELFv2 with BE to have its target triple and the "loosened" ELFv2 to have one. Currently, LLVM will enable the VSX and POWER8-specific parts of the ABI based on the endianess or CPU, not the ABI. That should probably be changed then? I could do that in a follow-up PR. |
Potentially, but we should probably get some input from the PPC backend maintainers (I'm not one) before making changes on that front. |
Prior to this change, the data layout calculation would not account for explicitly set
-mabi=elfv2
onpowerpc64-unknown-linux-gnu
, a target that defaults toelfv1
.This is loosely inspired by the equivalent ARM / RISC-V code.
make check-llvm
passes fine for me, though AFAICT all the tests specify the data layout manually so there isn't really a test for this and I am not really sure what the best way to go about adding one would be.