[clang] [llvm] PowerPC: Rename "float-abi" module flag to "long-double-type" (PR #210817)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 20 14:47:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-powerpc
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
PPC was emitting a "float-abi" module flag for indicating the type of long
double. The "float ABI" naming is already widely taken by soft vs. hard
float controls (e.g., the clang flag is called -mfloat-abi), so this shouldn't
have taken it. This should also not be PPC specific; x86 has the same problem.
Rename the flag to the more specific long-double-type, and add appropriate
verification and documentation (which was also missing). Also changes the value
names to match the IR type names.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/210817.diff
11 Files Affected:
- (modified) clang/lib/CodeGen/Targets/PPC.cpp (+8-6)
- (renamed) clang/test/CodeGen/ppc64-long-double-type-attr.c (+4-4)
- (modified) llvm/docs/LangRef.md (+30)
- (modified) llvm/lib/IR/AutoUpgrade.cpp (+20)
- (modified) llvm/lib/IR/Verifier.cpp (+11)
- (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+8-8)
- (added) llvm/test/Assembler/module-flags-long-double-type.ll (+19)
- (added) llvm/test/Bitcode/upgrade-ppc-float-abi.ll (+45)
- (modified) llvm/test/CodeGen/PowerPC/gnu-attribute.ll (+24-7)
- (added) llvm/test/Linker/module-flags-long-double-type.ll (+31)
- (added) llvm/test/Verifier/module-flags-long-double-type.ll (+37)
``````````diff
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index ab069bfbd1b51..92d14261ae81f 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -1046,15 +1046,17 @@ void PPC64_SVR4_TargetCodeGenInfo::emitTargetMetadata(
if (CGM.getTypes().isLongDoubleReferenced()) {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
const auto *flt = &CGM.getTarget().getLongDoubleFormat();
+ StringRef Type;
if (flt == &llvm::APFloat::PPCDoubleDouble())
- CGM.getModule().addModuleFlag(llvm::Module::Error, "float-abi",
- llvm::MDString::get(Ctx, "doubledouble"));
+ Type = "ppc_fp128";
else if (flt == &llvm::APFloat::IEEEquad())
- CGM.getModule().addModuleFlag(llvm::Module::Error, "float-abi",
- llvm::MDString::get(Ctx, "ieeequad"));
+ Type = "fp128";
else if (flt == &llvm::APFloat::IEEEdouble())
- CGM.getModule().addModuleFlag(llvm::Module::Error, "float-abi",
- llvm::MDString::get(Ctx, "ieeedouble"));
+ Type = "double";
+
+ if (!Type.empty())
+ CGM.getModule().addModuleFlag(llvm::Module::Error, "long-double-type",
+ llvm::MDString::get(Ctx, Type));
}
}
diff --git a/clang/test/CodeGen/ppc64-float-abi-attr.c b/clang/test/CodeGen/ppc64-long-double-type-attr.c
similarity index 71%
rename from clang/test/CodeGen/ppc64-float-abi-attr.c
rename to clang/test/CodeGen/ppc64-long-double-type-attr.c
index 8e0eca17b9b6c..b6f3baab28f7d 100644
--- a/clang/test/CodeGen/ppc64-float-abi-attr.c
+++ b/clang/test/CodeGen/ppc64-long-double-type-attr.c
@@ -11,7 +11,7 @@ long double foo(long double a, long double b) {
int bar() { return 1; }
-// CHECK: ![[#]] = !{i32 1, !"float-abi", !"doubledouble"}
-// IEEE: ![[#]] = !{i32 1, !"float-abi", !"ieeequad"}
-// LDBL64: ![[#]] = !{i32 1, !"float-abi", !"ieeedouble"}
-// NOLDBL-NOT: ![[#]] = !{i32 1, !"float-abi"
+// CHECK: ![[#]] = !{i32 1, !"long-double-type", !"ppc_fp128"}
+// IEEE: ![[#]] = !{i32 1, !"long-double-type", !"fp128"}
+// LDBL64: ![[#]] = !{i32 1, !"long-double-type", !"double"}
+// NOLDBL-NOT: ![[#]] = !{i32 1, !"long-double-type"
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 192597944101b..19ace3ff529fd 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -9343,6 +9343,36 @@ enum is the smallest type which can represent all of its values:
!1 = !{i32 1, !"short_enum", i32 0}
```
+### Long Double Type Module Flags Metadata
+
+Describe the floating-point format used by libm for `long double`. The
+value is an `MDString` naming the corresponding IR floating-point
+type, and must be one of:
+
+```{list-table}
+:header-rows: 1
+:widths: 30 70
+* - Value
+ - Meaning
+
+* - `"double"`
+ - IEEE 754 double precision (64-bit).
+
+* - `"fp128"`
+ - IEEE 754 quadruple precision (128-bit).
+
+* - `"ppc_fp128"`
+ - IBM `double-double` (a pair of IEEE doubles).
+
+```
+
+The flag must use the `error` merge behavior, so that linking modules with
+conflicting long double types is rejected. For example:
+```
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"fp128"}
+```
+
### Stack Alignment Metadata
Changes the default stack alignment from the target ABI's implicit default
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 880350a1b159b..3c56b3308e68d 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -6606,6 +6606,26 @@ bool llvm::UpgradeModuleFlags(Module &M) {
ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops));
Changed = true;
}
+
+ // clang/PowerPC used to use "float-abi" to describe the long double format;
+ // it has been renamed to "long-double-type", with its values changed to the
+ // corresponding IR floating-point type names. Map any unrecognized value
+ // (which was never valid) to the PowerPC default ppc_fp128 rather than
+ // erasing the flag.
+ if (M.getTargetTriple().isPPC() && ID->getString() == "float-abi") {
+ StringRef Format;
+ if (auto *S = dyn_cast_or_null<MDString>(Op->getOperand(2)))
+ Format = S->getString();
+ StringRef NewType = StringSwitch<StringRef>(Format)
+ .Case("ieeequad", "fp128")
+ .Case("ieeedouble", "double")
+ .Default("ppc_fp128");
+ Metadata *Ops[3] = {Op->getOperand(0),
+ MDString::get(M.getContext(), "long-double-type"),
+ MDString::get(M.getContext(), NewType)};
+ ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops));
+ Changed = true;
+ }
}
// "Objective-C Class Properties" is recently added for Objective-C. We
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 28459a39fedae..91ddcb0723b75 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1992,6 +1992,17 @@ Verifier::visitModuleFlag(const MDNode *Op,
Check(Value, "wchar_size metadata requires constant integer argument");
}
+ if (ID->getString() == "long-double-type") {
+ Check(MFB == Module::Error,
+ "long-double-type module flag must use 'error' merge behavior", Op);
+ const MDString *Value = dyn_cast_or_null<MDString>(Op->getOperand(2));
+ Check(Value, "long-double-type metadata requires a string argument");
+ if (Value)
+ Check(Value->getString() == "ppc_fp128" ||
+ Value->getString() == "fp128" || Value->getString() == "double",
+ "invalid long-double-type metadata value", Op);
+ }
+
if (ID->getString() == "Linker Options") {
// If the llvm.linker.options named metadata exists, we assume that the
// bitcode reader has upgraded the module flag. Otherwise the flag might
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 51f2ff4a68be7..4ccb578bbe263 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -1768,22 +1768,22 @@ PPCAsmPrinter::getAdjustedFasterLocalExpr(const MachineOperand &MO,
}
void PPCLinuxAsmPrinter::emitGNUAttributes(Module &M) {
- // Emit float ABI into GNU attribute
- Metadata *MD = M.getModuleFlag("float-abi");
- MDString *FloatABI = dyn_cast_or_null<MDString>(MD);
- if (!FloatABI)
+ // Emit long double format into GNU attribute
+ Metadata *MD = M.getModuleFlag("long-double-type");
+ MDString *LongDoubleType = dyn_cast_or_null<MDString>(MD);
+ if (!LongDoubleType)
return;
- StringRef flt = FloatABI->getString();
+ StringRef flt = LongDoubleType->getString();
// TODO: Support emitting soft-fp and hard double/single attributes.
- if (flt == "doubledouble")
+ if (flt == "ppc_fp128")
OutStreamer->emitGNUAttribute(Tag_GNU_Power_ABI_FP,
Val_GNU_Power_ABI_HardFloat_DP |
Val_GNU_Power_ABI_LDBL_IBM128);
- else if (flt == "ieeequad")
+ else if (flt == "fp128")
OutStreamer->emitGNUAttribute(Tag_GNU_Power_ABI_FP,
Val_GNU_Power_ABI_HardFloat_DP |
Val_GNU_Power_ABI_LDBL_IEEE128);
- else if (flt == "ieeedouble")
+ else if (flt == "double")
OutStreamer->emitGNUAttribute(Tag_GNU_Power_ABI_FP,
Val_GNU_Power_ABI_HardFloat_DP |
Val_GNU_Power_ABI_LDBL_64);
diff --git a/llvm/test/Assembler/module-flags-long-double-type.ll b/llvm/test/Assembler/module-flags-long-double-type.ll
new file mode 100644
index 0000000000000..636758d810695
--- /dev/null
+++ b/llvm/test/Assembler/module-flags-long-double-type.ll
@@ -0,0 +1,19 @@
+; RUN: split-file %s %t
+; RUN: llvm-as < %t/ppc_fp128.ll | llvm-dis | FileCheck %s --check-prefix=PPCFP128
+; RUN: llvm-as < %t/fp128.ll | llvm-dis | FileCheck %s --check-prefix=FP128
+; RUN: llvm-as < %t/double.ll | llvm-dis | FileCheck %s --check-prefix=DOUBLE
+
+;--- ppc_fp128.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"ppc_fp128"}
+; PPCFP128: !0 = !{i32 1, !"long-double-type", !"ppc_fp128"}
+
+;--- fp128.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"fp128"}
+; FP128: !0 = !{i32 1, !"long-double-type", !"fp128"}
+
+;--- double.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"double"}
+; DOUBLE: !0 = !{i32 1, !"long-double-type", !"double"}
diff --git a/llvm/test/Bitcode/upgrade-ppc-float-abi.ll b/llvm/test/Bitcode/upgrade-ppc-float-abi.ll
new file mode 100644
index 0000000000000..31df56d973723
--- /dev/null
+++ b/llvm/test/Bitcode/upgrade-ppc-float-abi.ll
@@ -0,0 +1,45 @@
+;; The PowerPC "float-abi" module flag (describing the long double
+;; format) was renamed to "long-double-type", with its values changed
+;; to the corresponding IR floating-point type names.
+
+; RUN: split-file %s %t
+; RUN: llvm-as < %t/doubledouble.ll | llvm-dis | FileCheck %s --check-prefix=DOUBLEDOUBLE
+; RUN: llvm-as < %t/ieeequad.ll | llvm-dis | FileCheck %s --check-prefix=IEEEQUAD
+; RUN: llvm-as < %t/ieeedouble.ll | llvm-dis | FileCheck %s --check-prefix=IEEEDOUBLE
+; RUN: llvm-as < %t/unrecognized.ll | llvm-dis | FileCheck %s --check-prefix=UNRECOGNIZED
+; RUN: llvm-as < %t/arm.ll | llvm-dis | FileCheck %s --check-prefix=ARM
+
+;; All the old PowerPC long double format spellings are upgraded to the new key
+;; and IR type-name values.
+;--- doubledouble.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"float-abi", !"doubledouble"}
+; DOUBLEDOUBLE: !0 = !{i32 1, !"long-double-type", !"ppc_fp128"}
+
+;--- ieeequad.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"float-abi", !"ieeequad"}
+; IEEEQUAD: !0 = !{i32 1, !"long-double-type", !"fp128"}
+
+;--- ieeedouble.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"float-abi", !"ieeedouble"}
+; IEEEDOUBLE: !0 = !{i32 1, !"long-double-type", !"double"}
+
+;--- unrecognized.ll
+;; An unrecognized value was never valid; upgrade it to the PowerPC default
+;; ppc_fp128 rather than leaving a stale "float-abi" flag.
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"float-abi", !"bogus"}
+; UNRECOGNIZED: !0 = !{i32 1, !"long-double-type", !"ppc_fp128"}
+
+;--- arm.ll
+;; A non-PowerPC module is never touched.
+target triple = "armv7-unknown-linux-gnueabihf"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"float-abi", !"hard"}
+; ARM: !0 = !{i32 1, !"float-abi", !"hard"}
diff --git a/llvm/test/CodeGen/PowerPC/gnu-attribute.ll b/llvm/test/CodeGen/PowerPC/gnu-attribute.ll
index 31747146d2345..f33cb8cc7b398 100644
--- a/llvm/test/CodeGen/PowerPC/gnu-attribute.ll
+++ b/llvm/test/CodeGen/PowerPC/gnu-attribute.ll
@@ -1,15 +1,32 @@
-; RUN: sed -e 's/FLTABI/ieeequad/' %s | llc -mtriple=powerpc64le | FileCheck %s --check-prefix=IEEE
-; RUN: sed -e 's/FLTABI/doubledouble/' %s | llc -mtriple=powerpc64le | FileCheck %s --check-prefix=IBM
-; RUN: sed -e 's/FLTABI/ieeedouble/' %s | llc -mtriple=powerpc64le | FileCheck %s --check-prefix=DBL
-; RUN: sed -e 's/FLTABI//' %s | llc -mtriple=powerpc64le | FileCheck %s --check-prefix=NONE
+; RUN: split-file %s %t
+; RUN: llc -mtriple=powerpc64le < %t/fp128.ll | FileCheck %s --check-prefix=IEEE
+; RUN: llc -mtriple=powerpc64le < %t/ppc_fp128.ll | FileCheck %s --check-prefix=IBM
+; RUN: llc -mtriple=powerpc64le < %t/double.ll | FileCheck %s --check-prefix=DBL
+; RUN: llc -mtriple=powerpc64le < %t/none.ll | FileCheck %s --check-prefix=NONE
+;--- fp128.ll
+!llvm.module.flags = !{!0, !1, !2}
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"uwtable", i32 1}
+!2 = !{i32 1, !"long-double-type", !"fp128"}
; IEEE: .gnu_attribute 4, 13
+
+;--- ppc_fp128.ll
+!llvm.module.flags = !{!0, !1, !2}
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"uwtable", i32 1}
+!2 = !{i32 1, !"long-double-type", !"ppc_fp128"}
; IBM: .gnu_attribute 4, 5
-; DBL: .gnu_attribute 4, 9
-; NONE-NOT: .gnu_attribute 4,
+;--- double.ll
!llvm.module.flags = !{!0, !1, !2}
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"uwtable", i32 1}
+!2 = !{i32 1, !"long-double-type", !"double"}
+; DBL: .gnu_attribute 4, 9
+;--- none.ll
+!llvm.module.flags = !{!0, !1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
-!2 = !{i32 1, !"float-abi", !"FLTABI"}
+; NONE-NOT: .gnu_attribute 4,
diff --git a/llvm/test/Linker/module-flags-long-double-type.ll b/llvm/test/Linker/module-flags-long-double-type.ll
new file mode 100644
index 0000000000000..30a85a24273c0
--- /dev/null
+++ b/llvm/test/Linker/module-flags-long-double-type.ll
@@ -0,0 +1,31 @@
+; RUN: split-file %s %t
+
+;; A module with an explicit "long-double-type" flag links cleanly with a module
+;; that has no flag, and the explicit value is preserved (both link orders).
+; RUN: llvm-link %t/fp128.ll %t/none.ll -S -o - | FileCheck %s --check-prefix=FP128
+; RUN: llvm-link %t/none.ll %t/fp128.ll -S -o - | FileCheck %s --check-prefix=FP128
+
+;; Two modules that agree link cleanly.
+; RUN: llvm-link %t/fp128.ll %t/fp128.ll -S -o - | FileCheck %s --check-prefix=FP128
+
+;; Two modules that disagree are rejected by the 'error' merge behavior.
+; RUN: not llvm-link %t/fp128.ll %t/ppc_fp128.ll -S -o /dev/null 2>&1 | FileCheck %s --check-prefix=CONFLICT
+
+; FP128: !{i32 1, !"long-double-type", !"fp128"}
+; CONFLICT: linking module flags 'long-double-type': IDs have conflicting values
+
+;--- none.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+define void @g() {
+ ret void
+}
+
+;--- fp128.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"fp128"}
+
+;--- ppc_fp128.ll
+target triple = "powerpc64le-unknown-linux-gnu"
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"ppc_fp128"}
diff --git a/llvm/test/Verifier/module-flags-long-double-type.ll b/llvm/test/Verifier/module-flags-long-double-type.ll
new file mode 100644
index 0000000000000..5aabbd0768508
--- /dev/null
+++ b/llvm/test/Verifier/module-flags-long-double-type.ll
@@ -0,0 +1,37 @@
+; RUN: split-file %s %t
+; RUN: not llvm-as < %t/not-string.ll -disable-output 2>&1 | FileCheck %s --check-prefix=NOTSTRING
+; RUN: not llvm-as < %t/bad-value.ll -disable-output 2>&1 | FileCheck %s --check-prefix=BADVALUE
+; RUN: not llvm-as < %t/empty-value.ll -disable-output 2>&1 | FileCheck %s --check-prefix=EMPTY
+; RUN: not llvm-as < %t/too-few.ll -disable-output 2>&1 | FileCheck %s --check-prefix=TOOFEW
+; RUN: not llvm-as < %t/too-many.ll -disable-output 2>&1 | FileCheck %s --check-prefix=TOOMANY
+; RUN: not llvm-as < %t/bad-behavior.ll -disable-output 2>&1 | FileCheck %s --check-prefix=BEHAVIOR
+
+;--- not-string.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", i32 1}
+; NOTSTRING: long-double-type metadata requires a string argument
+
+;--- bad-value.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"bogus"}
+; BADVALUE: invalid long-double-type metadata value
+
+;--- empty-value.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !""}
+; EMPTY: invalid long-double-type metadata value
+
+;--- too-few.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type"}
+; TOOFEW: incorrect number of operands in module flag
+
+;--- too-many.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"long-double-type", !"fp128", !"extra"}
+; TOOMANY: incorrect number of operands in module flag
+
+;--- bad-behavior.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"long-double-type", !"fp128"}
+; BEHAVIOR: long-double-type module flag must use 'error' merge behavior
``````````
</details>
https://github.com/llvm/llvm-project/pull/210817
More information about the cfe-commits
mailing list