https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/225129
>From e6963e9577a0a5e2b86c6da302a953d691c2ae6d Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Mon, 21 Sep 2026 08:58:45 -0700 Subject: [PATCH 1/4] [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@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 dd8e0a6c3586572456c6548a2265f26895e58e12 Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Mon, 21 Sep 2026 10:02:58 -0700 Subject: [PATCH 2/4] 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@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 f2433b40cb1abdc28c9832ca1d49e262b9c39310 Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Mon, 21 Sep 2026 23:42:18 -0700 Subject: [PATCH 3/4] 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@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@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 4d5b06abab3af7752baa4492701aaca2ad9763d3 Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Tue, 22 Sep 2026 22:52:23 -0700 Subject: [PATCH 4/4] 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 \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
