Skip to content

Commit 5c31b24

Browse files
authored
Unrolled build for rust-lang#131323
Rollup merge of rust-lang#131323 - jfrimmel:avr-inline-asm-clobber-abi, r=Amanieu Support `clobber_abi` in AVR inline assembly This PR implements the `clobber_abi` part necessary to eventually stabilize the inline assembly for AVR. This is tracked in rust-lang#93335. This is heavily inspired by the sibling-PR rust-lang#131310 for the MSP430. I've explained my reasoning in the first commit message in detail, which is reproduced below for easier reviewing: This follows the [ABI documentation] of AVR-GCC: > The [...] call-clobbered general purpose registers (GPRs) are registers that might be destroyed (clobbered) by a function call. > > - **R18–R27, R30, R31** > > These GPRs are call clobbered. An ordinary function may use them without restoring the contents. [...] > > - **R0, T-Flag** > > The temporary register and the T-flag in SREG are also call-clobbered, but this knowledge is not exposed explicitly to the compiler (R0 is a fixed register). Therefore this commit lists the aforementioned registers `r18–r27`, `r30` and `r31` as clobbered registers. Since the `r0` register (listed above as well) is not available in inline assembly at all (potentially because the AVR-GCC considers it a fixed register causing the register to never be used in register allocation and LLVM adopting this), there is no need to list it in the clobber list (the `r0`-variant is not even available). A comment was added to ensure, that the `r0` gets added to the clobber-list once the register gets usable in inline ASM. Since the SREG is normally considered clobbered anyways (unless the user supplies the `preserve_flags`-option), there is no need to explicitly list a bit in this register (which is not possible to list anyways). Note, that this commit completely ignores the case of interrupts (that are described in the ABI-specification), since every register touched in an ISR need to be saved anyways. [ABI documentation]: https://gcc.gnu.org/wiki/avr-gcc#Call-Used_Registers r? ``@Amanieu`` ``@rustbot`` label +O-AVR
2 parents 0c4f3a4 + 67d2f3f commit 5c31b24

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

Diff for: compiler/rustc_target/src/asm/avr.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ def_regs! {
105105
#error = ["SP", "SPL", "SPH"] =>
106106
"the stack pointer cannot be used as an operand for inline asm",
107107
#error = ["r0", "r1", "r1r0"] =>
108-
"r0 and r1 are not available due to an issue in LLVM",
108+
"LLVM reserves r0 (scratch register) and r1 (zero register)",
109+
// If this changes within LLVM, the compiler might use the registers
110+
// in the future. This must be reflected in the set of clobbered
111+
// registers, else the clobber ABI implementation is *unsound*, as
112+
// this generates invalid code (register is not marked as clobbered
113+
// but may change the register content).
109114
}
110115
}
111116

Diff for: compiler/rustc_target/src/asm/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ pub enum InlineAsmClobberAbi {
928928
AArch64,
929929
AArch64NoX18,
930930
Arm64EC,
931+
Avr,
931932
RiscV,
932933
RiscVE,
933934
LoongArch,
@@ -986,6 +987,10 @@ impl InlineAsmClobberAbi {
986987
}),
987988
_ => Err(&["C", "system", "efiapi"]),
988989
},
990+
InlineAsmArch::Avr => match name {
991+
"C" | "system" => Ok(InlineAsmClobberAbi::Avr),
992+
_ => Err(&["C", "system"]),
993+
},
989994
InlineAsmArch::LoongArch64 => match name {
990995
"C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
991996
_ => Err(&["C", "system"]),
@@ -1133,6 +1138,23 @@ impl InlineAsmClobberAbi {
11331138
d24, d25, d26, d27, d28, d29, d30, d31,
11341139
}
11351140
},
1141+
InlineAsmClobberAbi::Avr => clobbered_regs! {
1142+
Avr AvrInlineAsmReg {
1143+
// The list of "Call-Used Registers" according to
1144+
// https://gcc.gnu.org/wiki/avr-gcc#Call-Used_Registers
1145+
1146+
// Clobbered registers available in inline assembly
1147+
r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r30, r31,
1148+
// As per the AVR-GCC-ABI documentation linked above, the R0
1149+
// register is a clobbered register as well. Since we don't
1150+
// allow the usage of R0 in inline assembly, nothing has to
1151+
// be done here.
1152+
// Likewise, the T-flag in the SREG should be clobbered, but
1153+
// this is not necessary to be listed here, since the SREG
1154+
// is considered clobbered anyways unless `preserve_flags`
1155+
// is used.
1156+
}
1157+
},
11361158
InlineAsmClobberAbi::RiscV => clobbered_regs! {
11371159
RiscV RiscVInlineAsmReg {
11381160
// ra

Diff for: tests/codegen/asm/avr-clobbers.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ assembly-output: emit-asm
2+
//@ compile-flags: --target avr-unknown-gnu-atmega328
3+
//@ needs-llvm-components: avr
4+
5+
#![crate_type = "rlib"]
6+
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
7+
#![no_core]
8+
9+
#[lang = "sized"]
10+
trait Sized {}
11+
12+
#[rustc_builtin_macro]
13+
macro_rules! asm {
14+
() => {};
15+
}
16+
17+
// CHECK-LABEL: @sreg_is_clobbered
18+
// CHECK: void asm sideeffect "", "~{sreg}"()
19+
#[no_mangle]
20+
pub unsafe fn sreg_is_clobbered() {
21+
asm!("", options(nostack, nomem));
22+
}
23+
24+
// CHECK-LABEL: @sreg_is_not_clobbered_if_preserve_flags_is_used
25+
// CHECK: void asm sideeffect "", ""()
26+
#[no_mangle]
27+
pub unsafe fn sreg_is_not_clobbered_if_preserve_flags_is_used() {
28+
asm!("", options(nostack, nomem, preserves_flags));
29+
}
30+
31+
// CHECK-LABEL: @clobber_abi
32+
// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31},~{sreg}"()
33+
#[no_mangle]
34+
pub unsafe fn clobber_abi() {
35+
asm!("", clobber_abi("C"), options(nostack, nomem));
36+
}
37+
38+
// CHECK-LABEL: @clobber_abi_with_preserved_flags
39+
// CHECK: asm sideeffect "", "={r18},={r19},={r20},={r21},={r22},={r23},={r24},={r25},={r26},={r27},={r30},={r31}"()
40+
#[no_mangle]
41+
pub unsafe fn clobber_abi_with_preserved_flags() {
42+
asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
43+
}

0 commit comments

Comments
 (0)