[clang] [lld] [llvm] [RISC-V][LTO] Add baseline tests for LTO inline assembly and mapping symbols (PR #225129)
Alexander Richardson via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 08:57:15 PDT 2026
https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/225129
>From efbb6403d1741dc2f8273db237d4b3c69f86df94 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Mon, 21 Sep 2026 08:58:45 -0700
Subject: [PATCH 1/5] [RISC-V][LTO] Add baseline tests for LTO inline assembly
and mapping symbols
No functional change intended here, just adding test coverage for RISC-V LTO
inline assembly ABI handling (following up on
https://github.com/llvm/llvm-project/pull/223606) and for the `$x<arch>` ELF
mapping symbols emitted for module and function target features.
The `TODO`s for `.lto_discard` dropping module inline asm target features and
for the missing/duplicate `$x<arch>` mapping symbols will be addressed in the
following commits.
This commit was created with the help of AI tools
---
clang/test/CodeGen/RISCV/lto-module-asm-abi.c | 36 +++++++
cross-project-tests/riscv/lit.local.cfg | 6 ++
.../riscv/lto-inline-asm-abi.c | 79 +++++++++++++++
lld/test/ELF/lto/riscv-target-abi.ll | 98 ++++++++++++++++---
.../test/CodeGen/RISCV/module-asm-features.ll | 22 ++++-
.../RISCV/riscv-func-target-feature.ll | 60 +++++++++---
llvm/test/LTO/RISCV/module-asm.ll | 15 ++-
llvm/test/MC/RISCV/mapping-across-sections.s | 27 +++--
8 files changed, 302 insertions(+), 41 deletions(-)
create mode 100644 clang/test/CodeGen/RISCV/lto-module-asm-abi.c
create mode 100644 cross-project-tests/riscv/lit.local.cfg
create mode 100644 cross-project-tests/riscv/lto-inline-asm-abi.c
diff --git a/clang/test/CodeGen/RISCV/lto-module-asm-abi.c b/clang/test/CodeGen/RISCV/lto-module-asm-abi.c
new file mode 100644
index 0000000000000..cceafaac3ba0e
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/lto-module-asm-abi.c
@@ -0,0 +1,36 @@
+// REQUIRES: riscv-registered-target
+
+/// Regression test for https://github.com/llvm/llvm-project/pull/213410:
+/// Check that -march=rv64gcv -flto records +d in module asm and function
+/// target-features even though the driver only passes mcpu=generic-rv64 to lld.
+
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -flto %s -S -emit-llvm -o - \
+// RUN: | FileCheck %s --check-prefix=IR
+
+// IR: module asm(target_features: "{{.*}}+d{{.*}}", target_cpu: "generic-rv64")
+// IR-NEXT: "nop"
+// IR: define dso_local void @_start() #[[#ATTR:]] {{.*}} {
+// IR-NEXT: entry:
+// IR-NEXT: call void asm sideeffect "nop", ""()
+// IR-NEXT: ret void
+// IR-NEXT: }
+// IR-EMPTY:
+// IR-NEXT: attributes #[[#ATTR]] = { {{.*}}"target-cpu"="generic-rv64" "target-features"="{{.*}}+d{{.*}}"
+// IR: ![[#]] = !{i32 1, !"target-abi", !"lp64d"}
+// IR-NEXT: ![[#]] = !{i32 6, !"riscv-isa", ![[#ISA:]]}
+// IR-NEXT: ![[#ISA]] = !{!"{{.*}}_d2p2_{{.*}}"}
+
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -flto -shared -nostdlib -fuse-ld=lld %s -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=DRIVER
+
+// DRIVER: "-cc1"{{.*}}"-target-cpu" "generic-rv64"{{.*}}"-target-feature" "+d"{{.*}}"-target-abi" "lp64d"
+// DRIVER: "{{[^"]*}}ld.lld{{(\.exe)?}}"
+// DRIVER-NOT: mattr
+// DRIVER-SAME: "-plugin-opt=mcpu=generic-rv64"
+// DRIVER-NOT: mattr
+
+__asm__("nop");
+
+void _start(void) {
+ __asm__ volatile("nop");
+}
diff --git a/cross-project-tests/riscv/lit.local.cfg b/cross-project-tests/riscv/lit.local.cfg
new file mode 100644
index 0000000000000..e966a6d4ed56e
--- /dev/null
+++ b/cross-project-tests/riscv/lit.local.cfg
@@ -0,0 +1,6 @@
+if (
+ "clang" not in config.available_features
+ or "ld.lld" not in config.available_features
+ or "RISCV" not in config.targets_to_build
+):
+ config.unsupported = True
diff --git a/cross-project-tests/riscv/lto-inline-asm-abi.c b/cross-project-tests/riscv/lto-inline-asm-abi.c
new file mode 100644
index 0000000000000..3092708562686
--- /dev/null
+++ b/cross-project-tests/riscv/lto-inline-asm-abi.c
@@ -0,0 +1,79 @@
+// REQUIRES: ld.lld
+/// Regression test for https://github.com/llvm/llvm-project/pull/213410:
+/// Check that module-level inline assembly (including .symver imported by
+/// ThinLTO) and function-level inline assembly link cleanly under RegularLTO
+/// and ThinLTO when targeting riscv64 with lp64d ABI and -march=rv64gcv.
+// RUN: rm -rf %t && split-file %s %t
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -c %t/a.c -o %t1.o
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -c %t/b.c -o %t2.o
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -shared -nostdlib -fuse-ld=lld -Wl,--version-script=%t/ver.ver %t1.o %t2.o -o %t.so 2>&1 \
+// RUN: | FileCheck %s --allow-empty --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+// RUN: llvm-readobj --file-headers %t.so | FileCheck %s --check-prefix=FLAGS
+// RUN: llvm-objdump -d --show-all-symbols --no-show-raw-insn %t.so | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -t %t.so | FileCheck %s --check-prefix=SYMS --implicit-check-not='\$x'
+//
+/// TODO: ThinLTO fails because IRMover drops TargetTriple when importing the
+/// module-level .symver inline asm into b.c's empty ThinLTO module, causing
+/// RISC-V module inline asm in a.c and b.c to use the default lp64 ABI instead
+/// of lp64d.
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -c %t/a.c -o %t1.thin.o
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -c %t/b.c -o %t2.thin.o
+// RUN: not %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -shared -nostdlib -fuse-ld=lld -Wl,--version-script=%t/ver.ver %t1.thin.o %t2.thin.o -o %t.thin.so 2>&1 \
+// RUN: | FileCheck %s --check-prefix=THIN-ERR
+//
+// THIN-ERR: ld.lld: error: {{.*}}.lto.a.o: cannot link object files with different floating-point ABI
+//
+// FLAGS: Flags [ (0x5)
+// FLAGS-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
+// FLAGS-NEXT: EF_RISCV_RVC (0x1)
+// FLAGS-NEXT: ]
+//
+/// TODO: RISCVTargetELFStreamer::emitTextAttribute does not update the
+/// streamer's ArchString when emitting the module's RISCVAttrs::ARCH attribute
+/// ("rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_...").
+// DISASM-LABEL: Disassembly of section .text:
+// DISASM-EMPTY:
+// DISASM-NEXT: [[#%x,]] <$xrv64i2p1>:
+// DISASM-NEXT: [[#%x,]]: nop
+// DISASM-EMPTY:
+// DISASM-NEXT: [[#%x,]] <$xrv64i2p1>:
+// DISASM-NEXT: [[#%x,]] <symver_fn>:
+// DISASM-NEXT: [[#%x,]]: ret
+// DISASM-EMPTY:
+// DISASM-NEXT: [[#%x,]] <$xrv64i2p1>:
+// DISASM-NEXT: [[#%x,]] <fn>:
+// DISASM-NEXT: [[#%x,]]: nop
+// DISASM-NEXT: [[#%x,]]: ret
+// DISASM-EMPTY:
+// DISASM-NEXT: [[#%x,]] <$xrv64i2p1>:
+// DISASM-NEXT: [[#%x,]] <caller>:
+// DISASM-NEXT: [[#%x,]]: nop
+// DISASM-NEXT: [[#%x,]]: ret
+// DISASM-NOT: {{.}}
+//
+// SYMS: [[#%x,]] l .text 0000000000000000 $xrv64i2p1{{$}}
+// SYMS: [[#%x,]] l .text 0000000000000000 $xrv64i2p1{{$}}
+// SYMS: [[#%x,]] l .text 0000000000000000 $xrv64i2p1{{$}}
+// SYMS: [[#%x,]] l .text 0000000000000000 $xrv64i2p1{{$}}
+// SYMS: [[#%x,]] g F .text 0000000000000004 fn{{$}}
+// SYMS: [[#%x,]] g F .text 0000000000000002 symver_fn{{$}}
+// SYMS: [[#%x,]] g F .text 0000000000000004 caller{{$}}
+
+//--- ver.ver
+VER_1.0 {};
+
+//--- a.c
+__asm__("nop");
+__asm__(".symver symver_fn, symver_fn at VER_1.0");
+
+void symver_fn(void) {}
+
+void fn(void) {
+ __asm__ volatile("nop");
+}
+
+//--- b.c
+extern void fn(void);
+void caller(void) {
+ fn();
+}
diff --git a/lld/test/ELF/lto/riscv-target-abi.ll b/lld/test/ELF/lto/riscv-target-abi.ll
index 23f722e91a6fb..b4e805e3c2187 100644
--- a/lld/test/ELF/lto/riscv-target-abi.ll
+++ b/lld/test/ELF/lto/riscv-target-abi.ll
@@ -1,27 +1,30 @@
; REQUIRES: riscv
+; RUN: rm -rf %t && split-file %s %t
-;; The module flag asks for lp64d, but without -mcpu we default to no D extension,
-;; so we print a warning and ignore the module flag.
-; RUN: llvm-as %s -o %t.bc
-; RUN: ld.lld -shared %t.bc -o %t.so 2>&1 | FileCheck %s --check-prefix=WARN \
+;--- no-ext.ll
+;; The module flag asks for lp64d, and _start() has no target-features attribute.
+;; Without -mcpu we default to no D extension, so RISCVSubtarget prints a note
+;; and ignores the module flag.
+; RUN: llvm-as %t/no-ext.ll -o %t/no-ext.bc
+; RUN: ld.lld -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=WARN \
; RUN: --implicit-check-not="ignoring target-abi" --implicit-check-not="error:" --implicit-check-not="warning:"
; WARN: note: hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi)
;; TODO: This is inconsistent: RISCVAsmPrinter::emitStartOfAsmFile sets e_flags
;; based on the raw module flag not the ABI actually used for codegen.
;; This means we are setting EF_RISCV_FLOAT_ABI_DOUBLE on a file built for soft float ABI
-; RUN: llvm-readobj --file-headers %t.so | FileCheck %s --check-prefix=FLAGS-ABI-IGNORED
+; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-ABI-IGNORED
; FLAGS-ABI-IGNORED: Flags [ (0x4)
; FLAGS-ABI-IGNORED-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
; FLAGS-ABI-IGNORED-NEXT: ]
-;; Passing -mcpu that has D makes the ABI valid again, so no warning.
-; RUN: ld.lld -mllvm -mcpu=sifive-u74 -shared %t.bc -o %t.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
-; RUN: --implicit-check-not="error:" --implicit-check-not="warning:"
-; RUN: llvm-readobj --file-headers %t.so | FileCheck %s --check-prefix=FLAGS-MCPU
-; RUN: ld.lld -plugin-opt=mcpu=sifive-u74 -shared %t.bc -o %t.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
-; RUN: --implicit-check-not="error:" --implicit-check-not="warning:"
-; RUN: llvm-readobj --file-headers %t.so | FileCheck %s --check-prefix=FLAGS-MCPU
+;; Passing -mcpu that has D makes the ABI valid again, so no warning/note.
+; RUN: ld.lld -mllvm -mcpu=sifive-u74 -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
+; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-MCPU
+; RUN: ld.lld -plugin-opt=mcpu=sifive-u74 -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
+; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-MCPU
; NOWARN-NOT: ignoring target-abi
; FLAGS-MCPU: Flags [ (0x5)
; FLAGS-MCPU-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
@@ -32,9 +35,7 @@ target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
target triple = "riscv64"
module asm "nop"
-;; Module asm with target features not including 'd' (would fail before fix)
module asm(target_features: "+c") "c.nop"
-;; Module asm with target features enabling 'd'
module asm(target_features: "+d") "fld f0, 0(sp)"
define void @_start() {
@@ -44,3 +45,72 @@ define void @_start() {
!llvm.module.flags = !{!0}
!0 = !{i32 1, !"target-abi", !"lp64d"}
+
+;--- fn-inline-asm-no-ext.ll
+;; Function-level inline asm without +d on the function emits the missing D
+;; note once from RISCVSubtarget, without re-validating target-abi in RISCVAsmParser.
+; RUN: llvm-as %t/fn-inline-asm-no-ext.ll -o %t/fn-inline-asm-no-ext.bc
+; RUN: ld.lld -shared %t/fn-inline-asm-no-ext.bc -o %t/fn-inline-asm-no-ext.so 2>&1 | FileCheck %s --check-prefix=WARN \
+; RUN: --implicit-check-not="ignoring target-abi" --implicit-check-not="error:" --implicit-check-not="warning:"
+
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target triple = "riscv64"
+
+define void @_start() {
+ call void asm sideeffect "nop", ""()
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"lp64d"}
+
+;--- module-asm-no-ext.ll
+;; Module-level inline asm without target_features (e.g. Rust global_asm!) should
+;; not warn when functions in the module have +f,+d.
+; RUN: llvm-as %t/module-asm-no-ext.ll -o %t/module-asm-no-ext.bc
+; RUN: ld.lld -plugin-opt=mcpu=generic-rv64 -shared %t/module-asm-no-ext.bc -o %t/module-asm-no-ext.so 2>&1 \
+; RUN: | FileCheck %s --check-prefix=NOWARN --allow-empty \
+; RUN: --implicit-check-not="ignoring target-abi" --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+; RUN: ld.lld -plugin-opt=mcpu=sifive-u74 -shared %t/module-asm-no-ext.bc -o %t/module-asm-no-ext.so 2>&1 \
+; RUN: | FileCheck %s --check-prefix=NOWARN --allow-empty \
+; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target triple = "riscv64"
+
+module asm "nop"
+
+define void @_start() #0 {
+ ret void
+}
+attributes #0 = { "target-features"="+f,+d" }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"lp64d"}
+
+;--- module-asm-abi.ll
+;; Regression test for https://github.com/llvm/llvm-project/pull/213410:
+;; Module asm and function target-features specifying +c,+d should link cleanly
+;; even when the LTO backend is invoked with -plugin-opt=mcpu=generic-rv64.
+; RUN: llvm-as %t/module-asm-abi.ll -o %t/module-asm-abi.bc
+; RUN: ld.lld -plugin-opt=mcpu=generic-rv64 -shared %t/module-asm-abi.bc -o %t/module-asm-abi.so 2>&1 \
+; RUN: | FileCheck %s --check-prefix=NOWARN --allow-empty \
+; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+; RUN: llvm-readobj --file-headers %t/module-asm-abi.so | FileCheck %s --check-prefix=FLAGS-MCPU
+
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target triple = "riscv64"
+
+module asm(target_features: "+c,+d")
+ "nop"
+
+define void @_start() #0 {
+ call void asm sideeffect "nop", ""()
+ ret void
+}
+attributes #0 = { "target-features"="+c,+d" }
+
+!llvm.module.flags = !{!0, !1}
+!0 = !{i32 1, !"target-abi", !"lp64d"}
+!1 = !{i32 6, !"riscv-isa", !2}
+!2 = !{!"rv64i2p1_c2p0_d2p2"}
diff --git a/llvm/test/CodeGen/RISCV/module-asm-features.ll b/llvm/test/CodeGen/RISCV/module-asm-features.ll
index ab16acab48688..63fbce7a4ea65 100644
--- a/llvm/test/CodeGen/RISCV/module-asm-features.ll
+++ b/llvm/test/CodeGen/RISCV/module-asm-features.ll
@@ -1,14 +1,28 @@
; RUN: llc -mtriple=riscv64-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,EXTRA-FEATURES
; RUN: llc -mtriple=riscv64-unknown-linux-gnu -mattr=+d < %s | FileCheck %s --check-prefixes=CHECK,SAME-FEATURES
+; RUN: llc -mtriple=riscv64-unknown-linux-gnu -filetype=obj < %s | llvm-objdump -d --show-all-symbols --no-show-raw-insn - | FileCheck %s --check-prefix=OBJ
; This should work fine, because the module asm specifies the necessary
; target features
; SAME-FEATURES-NOT: .option arch
-; EXTRA-FEATURES: .option push
-; EXTRA-FEATURES: .option arch, +d
-; CHECK: fld ft0, 0(sp)
-; EXTRA-FEATURES: .option pop
+; EXTRA-FEATURES: .option push
+; EXTRA-FEATURES-NEXT: .option arch, +d, +f, +zicsr{{$}}
+; CHECK: .globl func
+; CHECK-NEXT: func:
+; CHECK-NEXT: fld ft0, 0(sp)
+; CHECK-NEXT: ret
+; EXTRA-FEATURES-NEXT: .option pop
+
+;; TODO: emitTargetFeaturePush does not call setArchString(), so the mapping
+;; symbol does not record +d/+f/+zicsr when assembling directly to an object file.
+; OBJ-LABEL: Disassembly of section .text:
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000000 <$xrv64i2p1>:
+; OBJ-NEXT: 0000000000000000 <func>:
+; OBJ-NEXT: 0: fld ft0, 0x0(sp)
+; OBJ-NEXT: 4: ret
+; OBJ-NOT: {{.}}
module asm(target_features: "+d")
".globl func"
diff --git a/llvm/test/CodeGen/RISCV/riscv-func-target-feature.ll b/llvm/test/CodeGen/RISCV/riscv-func-target-feature.ll
index d627ae9c90394..de3de8c27df1d 100644
--- a/llvm/test/CodeGen/RISCV/riscv-func-target-feature.ll
+++ b/llvm/test/CodeGen/RISCV/riscv-func-target-feature.ll
@@ -1,44 +1,72 @@
; RUN: llc -mtriple=riscv64 -mcpu=sifive-u74 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mcpu=sifive-u74 -filetype=obj < %s \
+; RUN: | llvm-objdump -d --show-all-symbols --no-show-raw-insn - | FileCheck %s --check-prefix=OBJ
-; CHECK: .option push
-; CHECK-NEXT: .option arch, +v, +zve32f, +zve32x, +zve64d, +zve64f, +zve64x, +zvl128b, +zvl32b, +zvl64b
+;; TODO: emitTargetFeaturePush does not call setArchString(), so per-function
+;; target-features are not reflected in the $x<arch> mapping symbols.
+; OBJ-LABEL: Disassembly of section .text:
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000000 <$xrv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0>:
+; OBJ-NEXT: 0000000000000000 <test1>:
+; OBJ-NEXT: 0: ret
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000002 <test2>:
+; OBJ-NEXT: 2: ret
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000004 <test3>:
+; OBJ-NEXT: 4: ret
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000006 <test4>:
+; OBJ-NEXT: 6: ret
+; OBJ-EMPTY:
+; OBJ-NEXT: 0000000000000008 <test5>:
+; OBJ-NEXT: 8: ret
+; OBJ-NOT: {{.}}
+
+; CHECK: .option push
+; CHECK-NEXT: .option arch, +v, +zve32f, +zve32x, +zve64d, +zve64f, +zve64x, +zvl128b, +zvl32b, +zvl64b{{$}}
define void @test1() "target-features"="+a,+d,+f,+m,+c,+v,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" {
-; CHECK-LABEL: test1
-; CHECK: .option pop
+; CHECK-LABEL: test1:
+; CHECK: ret
+; CHECK: .option pop
entry:
ret void
}
-; CHECK: .option push
-; CHECK-NEXT: .option arch, +zihintntl
+; CHECK-NEXT: .option push
+; CHECK-NEXT: .option arch, +zihintntl{{$}}
define void @test2() "target-features"="+a,+d,+f,+m,+zihintntl,+zifencei" {
-; CHECK-LABEL: test2
-; CHECK: .option pop
+; CHECK-LABEL: test2:
+; CHECK: ret
+; CHECK: .option pop
entry:
ret void
}
-; CHECK: .option push
-; CHECK-NEXT: .option arch, -a, -d, -f, -m
+; CHECK-NEXT: .option push
+; CHECK-NEXT: .option arch, -a, -d, -f, -m, -zcd{{$}}
define void @test3() "target-features"="-a,-d,-f,-m" {
-; CHECK-LABEL: test3
-; CHECK: .option pop
+; CHECK-LABEL: test3:
+; CHECK: ret
+; CHECK: .option pop
entry:
ret void
}
; CHECK-NOT: .option push
define void @test4() {
-; CHECK-LABEL: test4
-; CHECK-NOT: .option pop
+; CHECK-LABEL: test4:
+; CHECK: ret
+; CHECK-NOT: .option pop
entry:
ret void
}
; CHECK-NOT: .option push
define void @test5() "target-features"="+unaligned-scalar-mem" {
-; CHECK-LABEL: test5
-; CHECK-NOT: .option pop
+; CHECK-LABEL: test5:
+; CHECK: ret
+; CHECK-NOT: .option pop
entry:
ret void
}
diff --git a/llvm/test/LTO/RISCV/module-asm.ll b/llvm/test/LTO/RISCV/module-asm.ll
index 73320185e778a..e213ec14a2a58 100644
--- a/llvm/test/LTO/RISCV/module-asm.ll
+++ b/llvm/test/LTO/RISCV/module-asm.ll
@@ -2,11 +2,24 @@
; RUN: llvm-lto2 run -save-temps -filetype=asm -o %t.s %t.o -r=%t.o,func,p
; RUN: llvm-nm %t.o | FileCheck %s --check-prefix NM
; RUN: llvm-nm %t.s.0.5.precodegen.bc | FileCheck %s --check-prefix NM
+; RUN: llvm-dis %t.s.0.5.precodegen.bc -o - | FileCheck %s --check-prefix=IR
; RUN: FileCheck %s --input-file %t.s.0
; NM: T func
-; CHECK: fld ft0, 0(sp)
+;; TODO: LTO::addRegularLTO prepends ".lto_discard" without preserving the
+;; existing module inline asm's TargetCPU and TargetFeatures.
+; IR: module asm
+; IR-NEXT: ".lto_discard"
+; IR-NEXT: module asm(target_features: "+d")
+; IR-NEXT: ".globl func"
+; IR-NEXT: "func:"
+; IR-NEXT: "fld f0, 0(sp)"
+; IR-NEXT: "ret"
+
+; CHECK-LABEL: func:
+; CHECK-NEXT: fld ft0, 0(sp)
+; CHECK-NEXT: ret
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"
diff --git a/llvm/test/MC/RISCV/mapping-across-sections.s b/llvm/test/MC/RISCV/mapping-across-sections.s
index ecb8292dd6664..9a741e792a244 100644
--- a/llvm/test/MC/RISCV/mapping-across-sections.s
+++ b/llvm/test/MC/RISCV/mapping-across-sections.s
@@ -18,6 +18,13 @@
.text
nop
+# Pushing a data section and popping back to .text should also preserve .text's
+# mapping symbol state and not emit a redundant $x.
+ .pushsection .starts_data
+ .word 42
+ .popsection
+ nop
+
# With all those constraints, we want:
# + .text to have $x<ISA> at 0 and no others
# + .wibble to have $x<ISA> at 0 (each code section records the active ISA
@@ -28,9 +35,17 @@
# CHECK: [[#WIBBLE:]]] .wibble
# CHECK: [[#STARTS_DATA:]]] .starts_data
-# CHECK: Value Size Type Bind Vis Ndx Name
-# CHECK-RV32: 00000000 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv32i2p1{{$}}
-# CHECK-RV64: 00000000 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv64i2p1{{$}}
-# CHECK-RV32: 00000000 0 NOTYPE LOCAL DEFAULT [[#WIBBLE]] $xrv32i2p1{{$}}
-# CHECK-RV64: 00000000 0 NOTYPE LOCAL DEFAULT [[#WIBBLE]] $xrv64i2p1{{$}}
-# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT [[#STARTS_DATA]] $d{{$}}
+## TODO: RISCVELFStreamer::changeSection saves mapping symbol state to
+## getPreviousSection() instead of getCurrentSection() on popSection(), causing
+## a duplicate $x mapping symbol at offset 8 in .text.
+# CHECK: Symbol table '.symtab' contains 5 entries:
+# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 0: {{0+}} 0 NOTYPE LOCAL DEFAULT UND {{$}}
+# CHECK-RV32-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv32i2p1{{$}}
+# CHECK-RV64-NEXT: 1: {{0+}} 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv64i2p1{{$}}
+# CHECK-RV32-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT [[#WIBBLE]] $xrv32i2p1{{$}}
+# CHECK-RV64-NEXT: 2: {{0+}} 0 NOTYPE LOCAL DEFAULT [[#WIBBLE]] $xrv64i2p1{{$}}
+# CHECK-NEXT: 3: {{0+}} 0 NOTYPE LOCAL DEFAULT [[#STARTS_DATA]] $d{{$}}
+# CHECK-RV32-NEXT: 4: 00000008 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv32i2p1{{$}}
+# CHECK-RV64-NEXT: 4: {{0+}}8 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $xrv64i2p1{{$}}
+# CHECK-NOT: {{.}}
>From 3fbe62a2a64261598bd53f1e5131bccac8aa74d8 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Mon, 21 Sep 2026 10:02:58 -0700
Subject: [PATCH 2/5] clang-format
---
cross-project-tests/.clang-format | 2 ++
cross-project-tests/riscv/lto-inline-asm-abi.c | 8 ++------
2 files changed, 4 insertions(+), 6 deletions(-)
create mode 100644 cross-project-tests/.clang-format
diff --git a/cross-project-tests/.clang-format b/cross-project-tests/.clang-format
new file mode 100644
index 0000000000000..f5e3ec5b16d1f
--- /dev/null
+++ b/cross-project-tests/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+ReflowComments: false
diff --git a/cross-project-tests/riscv/lto-inline-asm-abi.c b/cross-project-tests/riscv/lto-inline-asm-abi.c
index 3092708562686..8caf1bda734c9 100644
--- a/cross-project-tests/riscv/lto-inline-asm-abi.c
+++ b/cross-project-tests/riscv/lto-inline-asm-abi.c
@@ -68,12 +68,8 @@ __asm__(".symver symver_fn, symver_fn at VER_1.0");
void symver_fn(void) {}
-void fn(void) {
- __asm__ volatile("nop");
-}
+void fn(void) { __asm__ volatile("nop"); }
//--- b.c
extern void fn(void);
-void caller(void) {
- fn();
-}
+void caller(void) { fn(); }
>From 537826ad0e78eafddd03f8168f3a93903bab39b2 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Mon, 21 Sep 2026 23:42:18 -0700
Subject: [PATCH 3/5] reformat and fix tests after rebase
---
.../riscv/lto-inline-asm-abi.c | 32 +++++++++++++------
.../test/CodeGen/RISCV/module-asm-features.ll | 5 +--
2 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/cross-project-tests/riscv/lto-inline-asm-abi.c b/cross-project-tests/riscv/lto-inline-asm-abi.c
index 8caf1bda734c9..e89e1e4f0687d 100644
--- a/cross-project-tests/riscv/lto-inline-asm-abi.c
+++ b/cross-project-tests/riscv/lto-inline-asm-abi.c
@@ -6,22 +6,32 @@
// RUN: rm -rf %t && split-file %s %t
// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -c %t/a.c -o %t1.o
// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -c %t/b.c -o %t2.o
-// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -shared -nostdlib -fuse-ld=lld -Wl,--version-script=%t/ver.ver %t1.o %t2.o -o %t.so 2>&1 \
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto -shared -nostdlib -fuse-ld=lld -Wl,-save-temps -Wl,--version-script=%t/ver.ver %t1.o %t2.o -o %t.so 2>&1 \
// RUN: | FileCheck %s --allow-empty --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+// RUN: llvm-dis %t.so.0.5.precodegen.bc -o - | FileCheck %s --check-prefix=REGULAR-IR
// RUN: llvm-readobj --file-headers %t.so | FileCheck %s --check-prefix=FLAGS
// RUN: llvm-objdump -d --show-all-symbols --no-show-raw-insn %t.so | FileCheck %s --check-prefix=DISASM
// RUN: llvm-objdump -t %t.so | FileCheck %s --check-prefix=SYMS --implicit-check-not='\$x'
//
-/// TODO: ThinLTO fails because IRMover drops TargetTriple when importing the
-/// module-level .symver inline asm into b.c's empty ThinLTO module, causing
-/// RISC-V module inline asm in a.c and b.c to use the default lp64 ABI instead
-/// of lp64d.
// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -c %t/a.c -o %t1.thin.o
// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -c %t/b.c -o %t2.thin.o
-// RUN: not %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -shared -nostdlib -fuse-ld=lld -Wl,--version-script=%t/ver.ver %t1.thin.o %t2.thin.o -o %t.thin.so 2>&1 \
-// RUN: | FileCheck %s --check-prefix=THIN-ERR
+// RUN: %clang --target=riscv64-linux-android -march=rv64gcv -O2 -flto=thin -shared -nostdlib -fuse-ld=lld -Wl,-save-temps -Wl,--version-script=%t/ver.ver %t1.thin.o %t2.thin.o -o %t.thin.so 2>&1 \
+// RUN: | FileCheck %s --allow-empty --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
+// RUN: llvm-dis %t2.thin.o.5.precodegen.bc -o - | FileCheck %s --check-prefix=THIN-IR
+// RUN: llvm-readobj --file-headers %t.thin.so | FileCheck %s --check-prefix=FLAGS
+// RUN: llvm-objdump -d --show-all-symbols --no-show-raw-insn %t.thin.so | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -t %t.thin.so | FileCheck %s --check-prefix=SYMS --implicit-check-not='\$x'
+//
+/// TODO: LTO::addRegularLTO and IRLinker::run drop target_features and
+/// target_cpu when synthesizing .lto_discard and imported .symver directives.
+// REGULAR-IR: module asm{{$}}
+// REGULAR-IR-NEXT: ".lto_discard "
+// REGULAR-IR-NEXT: module asm(target_features: "+64bit,{{.*}}", target_cpu: "generic-rv64")
+// REGULAR-IR-NEXT: "nop"
+// REGULAR-IR-NEXT: ".symver symver_fn, symver_fn at VER_1.0"
//
-// THIN-ERR: ld.lld: error: {{.*}}.lto.a.o: cannot link object files with different floating-point ABI
+// THIN-IR: module asm{{$}}
+// THIN-IR-NEXT: ".symver symver_fn, symver_fn at VER_1.0"
//
// FLAGS: Flags [ (0x5)
// FLAGS-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
@@ -72,4 +82,8 @@ void fn(void) { __asm__ volatile("nop"); }
//--- b.c
extern void fn(void);
-void caller(void) { fn(); }
+extern void symver_fn(void);
+void caller(void) {
+ fn();
+ symver_fn();
+}
diff --git a/llvm/test/CodeGen/RISCV/module-asm-features.ll b/llvm/test/CodeGen/RISCV/module-asm-features.ll
index 63fbce7a4ea65..7fee7188e0ed8 100644
--- a/llvm/test/CodeGen/RISCV/module-asm-features.ll
+++ b/llvm/test/CodeGen/RISCV/module-asm-features.ll
@@ -15,12 +15,13 @@
; EXTRA-FEATURES-NEXT: .option pop
;; TODO: emitTargetFeaturePush does not call setArchString(), so the mapping
-;; symbol does not record +d/+f/+zicsr when assembling directly to an object file.
+;; symbol does not record +d/+f/+zicsr when assembling directly to an object
+;; file, causing llvm-objdump to fail to disassemble `fld`.
; OBJ-LABEL: Disassembly of section .text:
; OBJ-EMPTY:
; OBJ-NEXT: 0000000000000000 <$xrv64i2p1>:
; OBJ-NEXT: 0000000000000000 <func>:
-; OBJ-NEXT: 0: fld ft0, 0x0(sp)
+; OBJ-NEXT: 0: <unknown>
; OBJ-NEXT: 4: ret
; OBJ-NOT: {{.}}
>From 7062463e732a14f071399bdfbbbe2f7a2e862500 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Tue, 22 Sep 2026 22:52:23 -0700
Subject: [PATCH 4/5] address feedback
---
lld/test/ELF/lto/riscv-target-abi.ll | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/lld/test/ELF/lto/riscv-target-abi.ll b/lld/test/ELF/lto/riscv-target-abi.ll
index b4e805e3c2187..c33b39a9a5508 100644
--- a/lld/test/ELF/lto/riscv-target-abi.ll
+++ b/lld/test/ELF/lto/riscv-target-abi.ll
@@ -1,6 +1,18 @@
; REQUIRES: riscv
; RUN: rm -rf %t && split-file %s %t
+; WARN: note: hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi)
+; NOWARN-NOT: ignoring target-abi
+
+; FLAGS-ABI-IGNORED: Flags [ (0x4)
+; FLAGS-ABI-IGNORED-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
+; FLAGS-ABI-IGNORED-NEXT: ]
+
+; FLAGS-MCPU: Flags [ (0x5)
+; FLAGS-MCPU-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
+; FLAGS-MCPU-NEXT: EF_RISCV_RVC (0x1)
+; FLAGS-MCPU-NEXT: ]
+
;--- no-ext.ll
;; The module flag asks for lp64d, and _start() has no target-features attribute.
;; Without -mcpu we default to no D extension, so RISCVSubtarget prints a note
@@ -8,15 +20,11 @@
; RUN: llvm-as %t/no-ext.ll -o %t/no-ext.bc
; RUN: ld.lld -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=WARN \
; RUN: --implicit-check-not="ignoring target-abi" --implicit-check-not="error:" --implicit-check-not="warning:"
-; WARN: note: hard-float 'd' ABI can't be used for a target that doesn't support the D instruction set extension (ignoring target-abi)
;; TODO: This is inconsistent: RISCVAsmPrinter::emitStartOfAsmFile sets e_flags
;; based on the raw module flag not the ABI actually used for codegen.
;; This means we are setting EF_RISCV_FLOAT_ABI_DOUBLE on a file built for soft float ABI
; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-ABI-IGNORED
-; FLAGS-ABI-IGNORED: Flags [ (0x4)
-; FLAGS-ABI-IGNORED-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
-; FLAGS-ABI-IGNORED-NEXT: ]
;; Passing -mcpu that has D makes the ABI valid again, so no warning/note.
; RUN: ld.lld -mllvm -mcpu=sifive-u74 -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
@@ -25,11 +33,6 @@
; RUN: ld.lld -plugin-opt=mcpu=sifive-u74 -shared %t/no-ext.bc -o %t/no-ext.so 2>&1 | FileCheck %s --check-prefix=NOWARN --allow-empty \
; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-MCPU
-; NOWARN-NOT: ignoring target-abi
-; FLAGS-MCPU: Flags [ (0x5)
-; FLAGS-MCPU-NEXT: EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
-; FLAGS-MCPU-NEXT: EF_RISCV_RVC (0x1)
-; FLAGS-MCPU-NEXT: ]
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
target triple = "riscv64"
@@ -65,8 +68,8 @@ define void @_start() {
!0 = !{i32 1, !"target-abi", !"lp64d"}
;--- module-asm-no-ext.ll
-;; Module-level inline asm without target_features (e.g. Rust global_asm!) should
-;; not warn when functions in the module have +f,+d.
+;; Module-level inline asm without target_features does not re-validate
+;; target-abi in RISCVAsmParser when functions in the module have +f,+d.
; RUN: llvm-as %t/module-asm-no-ext.ll -o %t/module-asm-no-ext.bc
; RUN: ld.lld -plugin-opt=mcpu=generic-rv64 -shared %t/module-asm-no-ext.bc -o %t/module-asm-no-ext.so 2>&1 \
; RUN: | FileCheck %s --check-prefix=NOWARN --allow-empty \
>From 02d1e5daec2e9a424c941d9c5161cdcb36f5958e Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 25 Sep 2026 08:52:49 -0700
Subject: [PATCH 5/5] fix datalayout
---
lld/test/ELF/lto/riscv-target-abi.ll | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lld/test/ELF/lto/riscv-target-abi.ll b/lld/test/ELF/lto/riscv-target-abi.ll
index c33b39a9a5508..3859377445a8d 100644
--- a/lld/test/ELF/lto/riscv-target-abi.ll
+++ b/lld/test/ELF/lto/riscv-target-abi.ll
@@ -34,7 +34,7 @@
; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
; RUN: llvm-readobj --file-headers %t/no-ext.so | FileCheck %s --check-prefix=FLAGS-MCPU
-target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64"
module asm "nop"
@@ -56,7 +56,7 @@ define void @_start() {
; RUN: ld.lld -shared %t/fn-inline-asm-no-ext.bc -o %t/fn-inline-asm-no-ext.so 2>&1 | FileCheck %s --check-prefix=WARN \
; RUN: --implicit-check-not="ignoring target-abi" --implicit-check-not="error:" --implicit-check-not="warning:"
-target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64"
define void @_start() {
@@ -78,7 +78,7 @@ define void @_start() {
; RUN: | FileCheck %s --check-prefix=NOWARN --allow-empty \
; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
-target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64"
module asm "nop"
@@ -101,7 +101,7 @@ attributes #0 = { "target-features"="+f,+d" }
; RUN: --implicit-check-not="error:" --implicit-check-not="warning:" --implicit-check-not="note:"
; RUN: llvm-readobj --file-headers %t/module-asm-abi.so | FileCheck %s --check-prefix=FLAGS-MCPU
-target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64"
module asm(target_features: "+c,+d")
More information about the llvm-commits
mailing list