about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJulian Frimmel <julian@fri-me.de>2024-10-06 12:33:25 +0200
committerJulian Frimmel <julian@fri-me.de>2024-11-28 16:12:02 +0100
commitba7316655645c020263e207ee9c036131b511d45 (patch)
tree779e4c6007505f71c01102664006aedb301e0d4c
parent9b4d7c6a40b328d212095c28670c629facf1557d (diff)
downloadrust-ba7316655645c020263e207ee9c036131b511d45.tar.gz
rust-ba7316655645c020263e207ee9c036131b511d45.zip
Support `clobber_abi` for AVR inline assembly
This commit adds the relevant registers to the list of clobbered regis-
ters (part of #93335). 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
-rw-r--r--compiler/rustc_target/src/asm/avr.rs5
-rw-r--r--compiler/rustc_target/src/asm/mod.rs22
2 files changed, 27 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 276f376b297..9adcbecdf3c 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -106,6 +106,11 @@ def_regs! {
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r0", "r1", "r1r0"] =>
             "r0 and r1 are not available due to an issue in LLVM",
+            // If this changes within LLVM, the compiler might use the registers
+            // in the future. This must be reflected in the set of clobbered
+            // registers, else the clobber ABI implementation is *unsound*, as
+            // this generates invalid code (register is not marked as clobbered
+            // but may change the register content).
     }
 }
 
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 9fe733e063c..204d5d53361 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -928,6 +928,7 @@ pub enum InlineAsmClobberAbi {
     AArch64,
     AArch64NoX18,
     Arm64EC,
+    Avr,
     RiscV,
     RiscVE,
     LoongArch,
@@ -986,6 +987,10 @@ impl InlineAsmClobberAbi {
                 }),
                 _ => Err(&["C", "system", "efiapi"]),
             },
+            InlineAsmArch::Avr => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::Avr),
+                _ => Err(&["C", "system"]),
+            },
             InlineAsmArch::LoongArch64 => match name {
                 "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
                 _ => Err(&["C", "system"]),
@@ -1133,6 +1138,23 @@ impl InlineAsmClobberAbi {
                     d24, d25, d26, d27, d28, d29, d30, d31,
                 }
             },
+            InlineAsmClobberAbi::Avr => clobbered_regs! {
+                Avr AvrInlineAsmReg {
+                    // The list of "Call-Used Registers" according to
+                    // https://gcc.gnu.org/wiki/avr-gcc#Call-Used_Registers
+
+                    // Clobbered registers available in inline assembly
+                    r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r30, r31,
+                    // As per the AVR-GCC-ABI documentation linked above, the R0
+                    // register is a clobbered register as well. Since we don't
+                    // allow the usage of R0 in inline assembly, nothing has to
+                    // be done here.
+                    // Likewise, the T-flag in the SREG should be clobbered, but
+                    // this is not necessary to be listed here, since the SREG
+                    // is considered clobbered anyways unless `preserve_flags`
+                    // is used.
+                }
+            },
             InlineAsmClobberAbi::RiscV => clobbered_regs! {
                 RiscV RiscVInlineAsmReg {
                     // ra