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

Merged
merged 4 commits into from
Nov 29, 2024

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
@jfrimmel jfrimmel force-pushed the avr-inline-asm-clobber-abi branch from e6e6b84 to 5d58879 Compare October 6, 2024 12:45
@@ -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. |

@jfrimmel jfrimmel force-pushed the avr-inline-asm-clobber-abi branch from 5d58879 to 461c388 Compare October 14, 2024 16:45
@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
Comment on lines 107 to 108
#error = ["r0", "r1", "r1r0"] =>
"r0 and r1 are not available due to an issue in LLVM",
Copy link
Member

Choose a reason for hiding this comment

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

(IIUC since r1 is a zero register, r1 and r1r0 cannot be used as an operand for inline asm, regardless of an LLVM issue.)

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 think, the fact that r1 is the zero-reg is the cause for the registers not being available for inline asm (although I'm not sure). For now, I think this is fine (please correct me if you think otherwise!).

Copy link
Member

Choose a reason for hiding this comment

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

For now, I think this is fine (please correct me if you think otherwise!).

Agreed. We may need to figure it out in some way before stabilization, but at least it should not be a blocker of clobber_abi implementation.

Copy link
Member

Choose a reason for hiding this comment

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

It would actually be nice to make the error message here clearer than "due to an issue in LLVM". The reason is that r0 is reserved as a scratch register and r1 is reserved as a constant zero register by LLVM.

tests/codegen/asm-clobber_abi-avr.rs Outdated Show resolved Hide resolved
@taiki-e
Copy link
Member

taiki-e commented Nov 2, 2024

Btw, AVRTiny1 appears to have a different convention (r0-r15 are unavailable, r16-r17 are similar to r0-r1 in AVR, r18-r19 are call-saved).

Footnotes

  1. avrtiny, attiny4, attiny5, attiny9, attiny10, attiny20, attiny40, attiny102, and attiny104 are marked as FamilyTiny in LLVM

@jfrimmel jfrimmel force-pushed the avr-inline-asm-clobber-abi branch from ccc421a to 558b1ae Compare November 2, 2024 23:37
@jfrimmel
Copy link
Contributor Author

jfrimmel commented Nov 2, 2024

Hm, I think in order to properly address the reduced tiny cores, one would need to wait for #131651 and parse the -Ctarget-cpu-flag to detect such a core. I suppose, this change would also be necessary for the general inline assembly and thus is somewhat out of scope of this PR. I see two options:

  1. merge this as-is and perform the necessary changes in a follow-up PR
  2. close this and wait for Create a generic AVR target: avr-unknown-unknown #131651 to be merged, then fix the reduced tiny cores and then the clobber ABI.

@taiki-e
Copy link
Member

taiki-e commented Nov 3, 2024

I suppose, this change would also be necessary for the general inline assembly and thus is somewhat out of scope of this PR.

I think it is indeed true that inline assembly support for AVRTiny is already broken (registers that should be reserved are not reserved) and therefore does not need to be fixed in this PR.
(EDIT: It should need to be fixed before stabilization, so I added it to #93335 (comment) 's list.)

parse the -Ctarget-cpu-flag to detect such a core.

I think it is better to refer to the tinyencoding target feature as LLVM does, instead of parsing the target-cpu.
(I think this could be implemented in a similar way to #132472 (comment).)

@Amanieu
Copy link
Member

Amanieu commented Nov 15, 2024

Could you please fix the wording as suggested in #131323 (comment), then this can be merged.

@Amanieu
Copy link
Member

Amanieu commented Nov 28, 2024

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 28, 2024
jfrimmel added a commit to jfrimmel/rust that referenced this pull request Nov 28, 2024
Those are reserved as per the GCC (and thus LLVM) ABI, which is distinct from an
issue. The rewording was requested in this [review].

[review]: rust-lang#131323 (comment)
@jfrimmel
Copy link
Contributor Author

Sorry, I've missed your review feedback. I've reworded the line in question.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 28, 2024
@Amanieu
Copy link
Member

Amanieu commented Nov 28, 2024

@bors r+

@bors
Copy link
Contributor

bors commented Nov 28, 2024

📌 Commit 297f2a5 has been approved by Amanieu

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 28, 2024
@bors
Copy link
Contributor

bors commented Nov 28, 2024

☔ The latest upstream changes (presumably #133568) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 28, 2024
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
Those are reserved as per the GCC (and thus LLVM) ABI, which is distinct from an
issue. The rewording was requested in this [review].

[review]: rust-lang#131323 (comment)
@jfrimmel jfrimmel force-pushed the avr-inline-asm-clobber-abi branch from 297f2a5 to 67d2f3f Compare November 28, 2024 15:12
@jfrimmel
Copy link
Contributor Author

rebased

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 28, 2024
@Amanieu
Copy link
Member

Amanieu commented Nov 28, 2024

@bors r+

@bors
Copy link
Contributor

bors commented Nov 28, 2024

📌 Commit 67d2f3f has been approved by Amanieu

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 28, 2024
Zalathar added a commit to Zalathar/rust that referenced this pull request Nov 29, 2024
…i, 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
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 29, 2024
Rollup of 7 pull requests

Successful merges:

 - rust-lang#131323 (Support `clobber_abi` in AVR inline assembly)
 - rust-lang#133092 (Always set the deployment target when building std)
 - rust-lang#133134 (Don't use a SyntheticProvider for literally every type)
 - rust-lang#133538 (Better diagnostic for fn items in variadic functions)
 - rust-lang#133590 (Rename `-Zparse-only`)
 - rust-lang#133592 (Misc: better instructions for envrc, ignore `/build` instead of `build/`)
 - rust-lang#133608 (Revert rust-lang#133418 (Store coverage source regions as `Span`) due to regression rust-lang#133606)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 29, 2024
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#131323 (Support `clobber_abi` in AVR inline assembly)
 - rust-lang#131718 ([rustdoc] Change impl items indent)
 - rust-lang#133565 (chore: fix 404 status URL)
 - rust-lang#133575 (Fix typo in RELEASES.md)
 - rust-lang#133577 (Document s390x machine access via community cloud)
 - rust-lang#133584 (Update more 2024 tests to remove -Zunstable-options)
 - rust-lang#133592 (Misc: better instructions for envrc, ignore `/build` instead of `build/`)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 6c9e922 into rust-lang:master Nov 29, 2024
6 checks passed
@rustbot rustbot added this to the 1.85.0 milestone Nov 29, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Nov 29, 2024
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
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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

6 participants