Author: Mintsuki
Date: 2026-09-16T10:04:20+02:00
New Revision: 4beeff3c2bf125de9dda8b374ffc9ec052d02810

URL: 
https://github.com/llvm/llvm-project/commit/4beeff3c2bf125de9dda8b374ffc9ec052d02810
DIFF: 
https://github.com/llvm/llvm-project/commit/4beeff3c2bf125de9dda8b374ffc9ec052d02810.diff

LOG: [clang][LoongArch] Emit "target-abi" module flag (#223647)

The LoongArch backend reads the ABI from the "target-abi" module flag,
but clang only emits that flag for ARM, PowerPC and RISC-V. Since LTO code
generation doesn't see the -target-abi option passed to clang, it falls
back to the default ABI of the target, which is lp64d for
loongarch64-unknown-elf, regardless of the ABI the code was compiled for.

When an FPU is enabled, this silently miscompiles code built for another
ABI. For example, with -mabi=lp64s, functions get the lp64d calling
convention after LTO, passing and returning floating-point values in FP 
registers 
instead of general-purpose ones, and the output is marked as double-float. 
Nothing
reports this if every object goes through LTO. For instance, a shared library
built this way links without error, and so does lp64s code built without LTO 
that
uses it. Without an FPU, the generated code keeps the soft-float calling
convention, but the output is still marked as double-float.

The mismatch only shows up as an error when LTO output is linked
together with relocatable objects built without LTO, which LLD rejects with 
"cannot
link object files with different ABI".

This patch adds LoongArch to the targets for which clang emits the flag,
so LTO uses the ABI the code was compiled for. It follows the per-target
approach taken for ARM (#217601) and PowerPC (#221669), and leaves the existing 
TODO about emitting the flag for every target with a non-empty ABI name as is.

With the flag present, LTO-linking bitcode built for different LoongArch
ABIs now fails with "linking module flags 'target-abi': IDs have conflicting
values" instead of silently picking a single ABI. A -target-abi given to the LTO
backend that disagrees with the flag is now also an error. Both match the
existing RISC-V behavior.

Assisted-by: Claude Code (Claude Opus 5)

Signed-off-by: Mintsuki <[email protected]>

Added: 
    clang/test/CodeGen/LoongArch/target-abi-module-flag.c

Modified: 
    clang/lib/CodeGen/CodeGenModule.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 287d1b7b617f8..ed69ef3e71135 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1508,12 +1508,11 @@ void CodeGenModule::Release() {
   llvm::Triple T = Context.getTargetInfo().getTriple();
 
   // TODO: This should probably be just generally emitted for non-empty ABI
-  // names. LoongArch actively consumes the flag, but it is excluded here.
-  // Other targets have no apparent need for the ABI name, but set a non-empty
-  // value.
+  // names. Other targets have no apparent need for the ABI name, but set a
+  // non-empty value.
   if (StringRef ABIStr = Target.getABI();
-      !ABIStr.empty() &&
-      (T.isARM() || T.isThumb() || T.isRISCV() || T.isPPC())) {
+      !ABIStr.empty() && (T.isARM() || T.isThumb() || T.isRISCV() ||
+                          T.isPPC() || T.isLoongArch())) {
     getModule().addModuleFlag(llvm::Module::Error, "target-abi",
                               llvm::MDString::get(VMContext, ABIStr));
   }

diff  --git a/clang/test/CodeGen/LoongArch/target-abi-module-flag.c 
b/clang/test/CodeGen/LoongArch/target-abi-module-flag.c
new file mode 100644
index 0000000000000..5a4826aff180b
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/target-abi-module-flag.c
@@ -0,0 +1,21 @@
+// Check that clang emits the "target-abi" module flag for LoongArch using the
+// target ABI string.
+
+// Default ABIs (no -target-abi override).
+// RUN: %clang_cc1 -triple loongarch32 -emit-llvm -o - %s | FileCheck 
--check-prefix=ILP32D %s
+// RUN: %clang_cc1 -triple loongarch64 -emit-llvm -o - %s | FileCheck 
--check-prefix=LP64D %s
+
+// Explicit -target-abi overrides 
diff ering from the triple default.
+// RUN: %clang_cc1 -triple loongarch32 -target-abi ilp32f -emit-llvm -o - %s | 
FileCheck --check-prefix=ILP32F %s
+// RUN: %clang_cc1 -triple loongarch32 -target-abi ilp32s -emit-llvm -o - %s | 
FileCheck --check-prefix=ILP32S %s
+// RUN: %clang_cc1 -triple loongarch64 -target-abi lp64f -emit-llvm -o - %s | 
FileCheck --check-prefix=LP64F %s
+// RUN: %clang_cc1 -triple loongarch64 -target-abi lp64s -emit-llvm -o - %s | 
FileCheck --check-prefix=LP64S %s
+
+// ILP32D: !{i32 1, !"target-abi", !"ilp32d"}
+// ILP32F: !{i32 1, !"target-abi", !"ilp32f"}
+// ILP32S: !{i32 1, !"target-abi", !"ilp32s"}
+// LP64D: !{i32 1, !"target-abi", !"lp64d"}
+// LP64F: !{i32 1, !"target-abi", !"lp64f"}
+// LP64S: !{i32 1, !"target-abi", !"lp64s"}
+
+int x;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to