[llvm] [Mips] Derive module ABI flags from a function definition (PR #220672)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 24 03:13:57 PDT 2026
https://github.com/ItsNoHax updated https://github.com/llvm/llvm-project/pull/220672
>From 34b09c333e04aa48e4ff8d3b2439e6e8c9ffa381 Mon Sep 17 00:00:00 2001
From: ItsNoHax <itsnohax at gmail.com>
Date: Wed, 2 Sep 2026 19:24:34 +0200
Subject: [PATCH] [Mips] Don't guess the module ABI flags from a function that
has none
emitStartOfAsmFile() falls back to the "target-features" and
"use-soft-float" attributes of *M.begin() when the target machine has no
feature string of its own. Two kinds of module get the default
subtarget's ABI flags -- hard float, double precision -- whatever they
were actually built for:
- a module that starts with a declaration, since declarations carry no
target attributes;
- a module with no functions at all, where there is nothing to read.
Compiling a single translation unit is mostly unaffected, because the
target machine carries the feature string and the fallback never runs.
It shows up under LTO, where the code generator is configured by the
linker, so one link can end up with objects tagged both ways, which lld
rejects.
Read the attributes from the first function definition rather than the
first function, keeping the first function as a fallback so that
declaration-only modules are unchanged. For a module with no functions,
leave the FP ABI unset rather than asserting the default: an object with
no code makes no floating point ABI demands, and 'any' is the value that
says so.
---
llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 30 +++++++++++-
.../CodeGen/Mips/abiflags-module-fallback.ll | 47 +++++++++++++++++++
2 files changed, 75 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/Mips/abiflags-module-fallback.ll
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index adda6154e15a5..433665ebef251 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -730,9 +730,28 @@ void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
// around it by re-initializing the PIC state here.
TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());
- // Try to get target-features from the first function.
+ // Try to get target-features from the first function definition. A module
+ // can start with declarations, which carry no target attributes, so
+ // reading them off M.begin() unconditionally selects the default subtarget
+ // for such a module. That is most visible under LTO, where the target
+ // machine has no feature string of its own and the layout of the merged
+ // module decides which ABI flags are emitted. Fall back to the first
+ // function if the module has no definitions at all.
+ const Function *F = M.empty() ? nullptr : &*M.begin();
+ for (const Function &Fn : M) {
+ if (!Fn.isDeclaration()) {
+ F = &Fn;
+ break;
+ }
+ }
+
+ // A module with no functions at all tells us nothing about the ABI it was
+ // built for. Emitting the default subtarget's FP ABI would be a guess, and
+ // a linker has to reject it when the rest of the link disagrees, so leave
+ // the FP ABI unset for those. LTO produces such modules routinely.
+ const bool HaveFpABI = !M.empty() || !TM.getTargetFeatureString().empty();
+
StringRef FS = TM.getTargetFeatureString();
- Module::iterator F = M.begin();
if (FS.empty() && M.size() && F->hasFnAttribute("target-features"))
FS = F->getFnAttribute("target-features").getValueAsString();
@@ -775,6 +794,13 @@ void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
TS.updateABIInfo(STI);
+ // updateABIInfo() derives the FP ABI from STI via setFpAbiFromPredicates(),
+ // which for a module with no functions is the default subtarget's. Reset
+ // it to 'any' in that case, as explained above.
+ if (!HaveFpABI)
+ TS.getABIFlagsSection().setFpABI(MipsABIFlagsSection::FpABIKind::ANY,
+ ABI.IsO32());
+
// We should always emit a '.module fp=...' but binutils 2.24 does not
// accept it. We therefore emit it when it contradicts the ABI defaults
// (-mfpxx or -mfp64) and omit it otherwise.
diff --git a/llvm/test/CodeGen/Mips/abiflags-module-fallback.ll b/llvm/test/CodeGen/Mips/abiflags-module-fallback.ll
new file mode 100644
index 0000000000000..8add6fb00e4a0
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/abiflags-module-fallback.ll
@@ -0,0 +1,47 @@
+; When the target machine has no feature string of its own, the module's ABI
+; flags are derived from a function's target attributes. Check the two cases
+; where the function they used to be read from carries no attributes: a module
+; starting with a declaration, and a module with no functions at all.
+
+; RUN: split-file %s %t
+; RUN: llc -filetype=obj -mtriple mipsel-unknown-linux -mcpu=mips32 \
+; RUN: %t/single-float.ll -o %t/single-float.o
+; RUN: llvm-readobj -A %t/single-float.o | FileCheck %s -check-prefix=SINGLE
+; RUN: llc -filetype=obj -mtriple mipsel-unknown-linux -mcpu=mips32 \
+; RUN: %t/soft-float.ll -o %t/soft-float.o
+; RUN: llvm-readobj -A %t/soft-float.o | FileCheck %s -check-prefix=SOFT
+; RUN: llc -filetype=asm -mtriple mipsel-unknown-linux -mcpu=mips32 \
+; RUN: %t/soft-float.ll -o - | FileCheck %s -check-prefix=SOFT-ASM
+; RUN: llc -filetype=obj -mtriple mipsel-unknown-linux -mcpu=mips32 \
+; RUN: %t/no-functions.ll -o %t/no-functions.o
+; RUN: llvm-readobj -A %t/no-functions.o | FileCheck %s -check-prefix=NONE
+
+;--- single-float.ll
+; SINGLE: FP ABI: Hard float (single precision)
+
+declare void @a_declaration()
+
+define dso_local void @a_definition() #0 {
+ call void @a_declaration()
+ ret void
+}
+
+attributes #0 = { "target-features"="+single-float" }
+
+;--- soft-float.ll
+; SOFT: FP ABI: Soft float
+; SOFT-ASM: .module softfloat
+
+declare void @another_declaration()
+
+define dso_local void @another_definition() "use-soft-float"="true" {
+ call void @another_declaration()
+ ret void
+}
+
+;--- no-functions.ll
+; A module with no functions says nothing about the FP ABI it was built for,
+; so it must not claim one. LTO produces such modules.
+; NONE: FP ABI: Hard or soft float
+
+ at a_global = global i32 0
More information about the llvm-commits
mailing list