Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support clobber_abi in AVR inline assembly #131323

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jfrimmel
Copy link
Contributor

@jfrimmel jfrimmel commented Oct 6, 2024

This PR implements the clobber_abi part necessary to eventually stabilize the inline assembly for AVR. This is tracked in #93335.
This is heavily inspired by the sibling-PR #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.

r? @Amanieu

@rustbot label +O-AVR

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. O-AVR Target: AVR processors (ATtiny, ATmega, etc.) labels Oct 6, 2024
@@ -106,6 +106,7 @@ 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 issue is resolved, then R0 has to be added to clobbered registers
Copy link
Member

Choose a reason for hiding this comment

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

We need to carefully keep track of LLVM here: if LLVM ceases to treat these registers as reserved then we must immediately add them to the set of clobbered registers, otherwise incorrect code will be generated. This comment should be updated to reflect this.

Also, while reviewing the GCC docs, it seems that R1 always holds a value of 0. If this is a guarantee that asm can use then it should be documented, similar to how on x86 we guarantee the direction flag is always clear when entering or exiting inline asm.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the feedback!

Do you have an idea on how to track LLVM here? I'd expect the ABI to be stable, but I don't know on how to test this, except for producing register-heavy code and hoping, that the "no more fixed register" would be used causing the test to fail. This seems rather fragile, though.
Or do you "just" want to phrase the comment different, so that the required immediate action is more clear?

For the second issue, I'll go ahead and document, that the R1 register needs to be restored if altered.

Copy link
Member

Choose a reason for hiding this comment

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

It's enough to just reword the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've reworded the comment, please have a look if this works for you.

Regarding the R1 register content: the unstable-book already documents, that the value needs to be restored if altered:

| AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. |

This commit adds the relevant registers to the list of clobbered regis-
ters (part of rust-lang#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
@jfrimmel
Copy link
Contributor Author

@rustbot labels: +A-inline-assembly
@rustbot ready

@rustbot rustbot added the A-inline-assembly Area: Inline assembly (`asm!(…)`) label Oct 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inline-assembly Area: Inline assembly (`asm!(…)`) O-AVR Target: AVR processors (ATtiny, ATmega, etc.) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants