Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 61 additions & 11 deletions compiler/rustc_target/src/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_macros::{Decodable, Encodable, StableHash};
use rustc_span::Symbol;

use crate::spec::{Arch, RelocModel, Target};
use crate::spec::{Arch, LlvmAbi, RelocModel, Target};

pub struct ModifierInfo {
pub modifier: char,
Expand Down Expand Up @@ -1018,6 +1018,7 @@ pub enum InlineAsmClobberAbi {
Arm64EC,
Avr,
RiscV,
RiscVD,
RiscVE,
LoongArch,
PowerPC,
Expand Down Expand Up @@ -1071,11 +1072,15 @@ impl InlineAsmClobberAbi {
_ => Err(&["C", "system"]),
},
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
"C" | "system" | "efiapi" => Ok(if riscv::is_e(target_features) {
InlineAsmClobberAbi::RiscVE
} else {
InlineAsmClobberAbi::RiscV
}),
"C" | "system" | "efiapi" => {
Ok(match target.llvm_abiname {
LlvmAbi::Ilp32e | LlvmAbi::Lp64e => InlineAsmClobberAbi::RiscVE,
// FIXME: Once LLVM adds support for the `q` extension, `d` will no longer
// be the largest supported FLEN, so change this to Lp64q => RiscVQ.
LlvmAbi::Ilp32d | LlvmAbi::Lp64d => InlineAsmClobberAbi::RiscVD,
_ => InlineAsmClobberAbi::RiscV,
})
}
_ => Err(&["C", "system", "efiapi"]),
},
InlineAsmArch::Avr => match name {
Expand Down Expand Up @@ -1268,13 +1273,54 @@ impl InlineAsmClobberAbi {
x10, x11, x12, x13, x14, x15, x16, x17,
// t3-t6
x28, x29, x30, x31,

// Only ABI_FLEN bits of the callee-saved floating point registers are
// preserved. As LLVM doesn't have partial clobbers, this means we have to
// clobber the callee-saved floating point registers as well as the temporary
// registers.

@Amanieu Amanieu Oct 5, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we instead have 3 variants of the clobber ABI:

  • RiscVE where upper X registers and all FP registers are clobbered
  • RiscV where all FP regsiters are clobbered.
  • RiscVD where only caller-saved FP registers are clobbered.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, although it will need updating once support for the q extension is added to LLVM.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add that ABI to the enum to bug! if it gets hit and we forget to update?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the lp64q ABI that would cause the issue: LLVM understanding how to use the 128-bit FLEN from the q target feature and the q feature being enabled (either via -Ctarget-feature/-Zllvm-target-feature or in C code that has the feature enabled and is LTOed to the Rust code) would make the ABI_FLEN==FLEN assumption invalid. LLVM currently only has assembler support for q, so this is not yet an issue.

// ft0-ft7
f0, f1, f2, f3, f4, f5, f6, f7,
// fs0-fs1 (callee-saved)
f8, f9,
// fa0-fa7
f10, f11, f12, f13, f14, f15, f16, f17,
// fs2-fs11 (callee-saved)
f18, f19, f20, f21, f22, f23, f24, f25,
f26, f27,
// ft8-ft11
f28, f29, f30, f31,

// v0-v31
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14, v15,
v16, v17, v18, v19, v20, v21, v22, v23,
v24, v25, v26, v27, v28, v29, v30, v31,
}
},
InlineAsmClobberAbi::RiscVD => clobbered_regs! {
RiscV RiscVInlineAsmReg {
// ra
x1,
// t0-t2
x5, x6, x7,
// a0-a7
x10, x11, x12, x13, x14, x15, x16, x17,
// t3-t6
x28, x29, x30, x31,

// Only ABI_FLEN bits of the callee-saved floating point registers are
// preserved. As `d` (FLEN == 64) is the largest floating point register LLVM
// currently supports (`q` is currently assembly only), and ABI_FLEN == 64,
// ABI_FLEN must equal FLEN and therefore there is no need to clobber the
// callee-saved registers.
// ft0-ft7
f0, f1, f2, f3, f4, f5, f6, f7,
// fa0-fa7
f10, f11, f12, f13, f14, f15, f16, f17,
// ft8-ft11
f28, f29, f30, f31,

// v0-v31
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14, v15,
v16, v17, v18, v19, v20, v21, v22, v23,
Expand All @@ -1293,13 +1339,17 @@ impl InlineAsmClobberAbi {
x5, x6, x7,
// a0-a5
x10, x11, x12, x13, x14, x15,
// ft0-ft7
// x16-x31
x16, x17, x18, x19, x20, x21, x22, x23,
x24, x25, x26, x27, x28, x29, x30, x31,

// f0-f31
f0, f1, f2, f3, f4, f5, f6, f7,
// fa0-fa7
f10, f11, f12, f13, f14, f15, f16, f17,
// ft8-ft11
f28, f29, f30, f31,
f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23,
f24, f25, f26, f27, f28, f29, f30, f31,

// v0-v31
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14, v15,
v16, v17, v18, v19, v20, v21, v22, v23,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_target/src/asm/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl RiscVInlineAsmRegClass {
}
}

pub(crate) fn is_e(target_features: &FxIndexSet<Symbol>) -> bool {
fn is_e(target_features: &FxIndexSet<Symbol>) -> bool {
target_features.contains(&sym::character('e'))
}

Expand All @@ -63,9 +63,9 @@ fn not_e(
_reloc_model: RelocModel,
target_features: &FxIndexSet<Symbol>,
_target: &Target,
_is_clobber: bool,
is_clobber: bool,
) -> Result<(), &'static str> {
if is_e(target_features) {
if is_e(target_features) && !is_clobber {
Err("register can't be used with the `e` target feature")
} else {
Ok(())
Expand Down
26 changes: 16 additions & 10 deletions tests/codegen-llvm/asm/riscv-clobbers.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//@ add-minicore
//@ assembly-output: emit-asm
//@ revisions: rv32i rv64i rv32e
//@[rv32i] compile-flags: --target riscv32i-unknown-none-elf
//@[rv32i] needs-llvm-components: riscv
//@[rv64i] compile-flags: --target riscv64imac-unknown-none-elf
//@[rv64i] needs-llvm-components: riscv
//@[rv32e] compile-flags: --target riscv32e-unknown-none-elf
//@[rv32e] needs-llvm-components: riscv
//@ revisions: ilp32 ilp32f ilp32d ilp32e ilp32e_extra lp64 lp64d
//@[ilp32] compile-flags: --target riscv32i-unknown-none-elf
//@[ilp32f] compile-flags: --target riscv32imfc-unknown-none-elf
//@[ilp32d] compile-flags: --target riscv32gc-unknown-linux-gnu
//@[ilp32e] compile-flags: --target riscv32e-unknown-none-elf
//@[ilp32e_extra] compile-flags:--target riscv32e-unknown-none-elf -Ctarget-feature=-e,+f
//@[lp64] compile-flags: --target riscv64im-unknown-none-elf
//@[lp64d] compile-flags: --target riscv64gc-unknown-none-elf
//@ needs-llvm-components: riscv
// ignore-tidy-linelength

#![crate_type = "rlib"]
Expand All @@ -31,9 +33,13 @@ pub unsafe fn no_clobber() {
}

// CHECK-LABEL: @clobber_abi
// rv32i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// rv64i: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// rv32e: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// ilp32: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// ilp32f: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={f14},={f15},={f16},={f17},={f18},={f19},={f20},={f21},={f22},={f23},={f24},={f25},={f26},={f27},={f28},={f29},={f30},={f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// ilp32d: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f10},={f11},={f12},={f13},={f14},={f15},={f16},={f17},={f28},={f29},={f30},={f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// ilp32e: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x18},={x19},={x20},={x21},={x22},={x23},={x24},={x25},={x26},={x27},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// ilp32e_extra: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x18},={x19},={x20},={x21},={x22},={x23},={x24},={x25},={x26},={x27},={x28},={x29},={x30},={x31},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={f14},={f15},={f16},={f17},={f18},={f19},={f20},={f21},={f22},={f23},={f24},={f25},={f26},={f27},={f28},={f29},={f30},={f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// lp64: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f11},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
// lp64d: asm sideeffect "", "={x1},={x5},={x6},={x7},={x10},={x11},={x12},={x13},={x14},={x15},={x16},={x17},={x28},={x29},={x30},={x31},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f10},={f11},={f12},={f13},={f14},={f15},={f16},={f17},={f28},={f29},={f30},={f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"()
#[no_mangle]
pub unsafe fn clobber_abi() {
asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
Expand Down
Loading
Loading