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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
