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
This commit is contained in:
Julian Frimmel 2024-10-06 12:33:25 +02:00
parent 9b4d7c6a40
commit ba73166556
No known key found for this signature in database
2 changed files with 27 additions and 0 deletions

View File

@ -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).
}
}

View File

@ -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