PowerPC: Rename "float-abi" module flag to "long-double-type" (#210817)

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>
This commit is contained in:
Matt Arsenault 2026-07-28 20:10:25 +02:00 committed by GitHub
parent 6d59a24272
commit 9d4eb0a855
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 241 additions and 29 deletions

View file

@ -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));
}
}

View file

@ -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"

View file

@ -9407,6 +9407,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

View file

@ -6626,6 +6626,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

View file

@ -2000,6 +2000,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

View file

@ -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);

View file

@ -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"}

View file

@ -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"}

View file

@ -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
; IEEE: .gnu_attribute 4, 13
; IBM: .gnu_attribute 4, 5
; DBL: .gnu_attribute 4, 9
; NONE-NOT: .gnu_attribute 4,
; 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, !"float-abi", !"FLTABI"}
!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
;--- 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}
; NONE-NOT: .gnu_attribute 4,

View file

@ -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"}

View file

@ -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