2014-02-19 18:56:33 -08:00
|
|
|
use std::fmt;
|
2013-03-13 22:25:28 -04:00
|
|
|
|
2019-11-09 22:27:52 +01:00
|
|
|
use rustc_macros::HashStable_Generic;
|
2022-09-08 15:37:15 +02:00
|
|
|
use rustc_span::symbol::sym;
|
|
|
|
use rustc_span::{Span, Symbol};
|
2019-11-09 22:27:52 +01:00
|
|
|
|
2019-08-01 03:20:03 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
|
|
|
|
#[derive(HashStable_Generic, Encodable, Decodable)]
|
2013-03-13 22:25:28 -04:00
|
|
|
pub enum Abi {
|
2021-06-11 14:22:13 +03:00
|
|
|
// Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
|
|
|
|
// hashing tests. These are used in many places, so giving them stable values reduces test
|
|
|
|
// churn. The specific values are meaningless.
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
Rust,
|
|
|
|
C { unwind: bool },
|
2022-02-01 18:53:45 +01:00
|
|
|
Cdecl { unwind: bool },
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
Stdcall { unwind: bool },
|
2022-02-01 18:53:45 +01:00
|
|
|
Fastcall { unwind: bool },
|
|
|
|
Vectorcall { unwind: bool },
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
Thiscall { unwind: bool },
|
2022-02-01 18:53:45 +01:00
|
|
|
Aapcs { unwind: bool },
|
|
|
|
Win64 { unwind: bool },
|
|
|
|
SysV64 { unwind: bool },
|
2016-12-22 16:24:29 -05:00
|
|
|
PtxKernel,
|
2016-12-18 23:45:20 -05:00
|
|
|
Msp430Interrupt,
|
2017-02-14 21:39:42 +01:00
|
|
|
X86Interrupt,
|
2018-07-01 22:42:00 -05:00
|
|
|
AmdGpuKernel,
|
2019-10-24 15:29:29 +00:00
|
|
|
EfiApi,
|
2016-05-06 09:32:10 -04:00
|
|
|
AvrInterrupt,
|
|
|
|
AvrNonBlockingInterrupt,
|
2021-01-24 17:15:05 +00:00
|
|
|
CCmseNonSecureCall,
|
rustc: Add a new `wasm` ABI
This commit implements the idea of a new ABI for the WebAssembly target,
one called `"wasm"`. This ABI is entirely of my own invention
and has no current precedent, but I think that the addition of this ABI
might help solve a number of issues with the WebAssembly targets.
When `wasm32-unknown-unknown` was first added to Rust I naively
"implemented an abi" for the target. I then went to write `wasm-bindgen`
which accidentally relied on details of this ABI. Turns out the ABI
definition didn't match C, which is causing issues for C/Rust interop.
Currently the compiler has a "wasm32 bindgen compat" ABI which is the
original implementation I added, and it's purely there for, well,
`wasm-bindgen`.
Another issue with the WebAssembly target is that it's not clear to me
when and if the default C ABI will change to account for WebAssembly's
multi-value feature (a feature that allows functions to return multiple
values). Even if this does happen, though, it seems like the C ABI will
be guided based on the performance of WebAssembly code and will likely
not match even what the current wasm-bindgen-compat ABI is today. This
leaves a hole in Rust's expressivity in binding WebAssembly where given
a particular import type, Rust may not be able to import that signature
with an updated C ABI for multi-value.
To fix these issues I had the idea of a new ABI for WebAssembly, one
called `wasm`. The definition of this ABI is "what you write
maps straight to wasm". The goal here is that whatever you write down in
the parameter list or in the return values goes straight into the
function's signature in the WebAssembly file. This special ABI is for
intentionally matching the ABI of an imported function from the
environment or exporting a function with the right signature.
With the addition of a new ABI, this enables rustc to:
* Eventually remove the "wasm-bindgen compat hack". Once this
ABI is stable wasm-bindgen can switch to using it everywhere.
Afterwards the wasm32-unknown-unknown target can have its default ABI
updated to match C.
* Expose the ability to precisely match an ABI signature for a
WebAssembly function, regardless of what the C ABI that clang chooses
turns out to be.
* Continue to evolve the definition of the default C ABI to match what
clang does on all targets, since the purpose of that ABI will be
explicitly matching C rather than generating particular function
imports/exports.
Naturally this is implemented as an unstable feature initially, but it
would be nice for this to get stabilized (if it works) in the near-ish
future to remove the wasm32-unknown-unknown incompatibility with the C
ABI. Doing this, however, requires the feature to be on stable because
wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
|
|
|
Wasm,
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
System { unwind: bool },
|
2013-03-13 22:25:28 -04:00
|
|
|
RustIntrinsic,
|
2014-05-28 22:26:56 -07:00
|
|
|
RustCall,
|
2015-08-06 11:11:26 -07:00
|
|
|
PlatformIntrinsic,
|
2016-12-23 10:05:41 +02:00
|
|
|
Unadjusted,
|
2022-05-29 00:25:14 -07:00
|
|
|
RustCold,
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
RiscvInterruptM,
|
|
|
|
RiscvInterruptS,
|
2013-03-13 22:25:28 -04:00
|
|
|
}
|
|
|
|
|
2022-08-08 15:31:32 +02:00
|
|
|
impl Abi {
|
|
|
|
pub fn supports_varargs(self) -> bool {
|
|
|
|
// * C and Cdecl obviously support varargs.
|
|
|
|
// * C can be based on SysV64 or Win64, so they must support varargs.
|
|
|
|
// * EfiApi is based on Win64 or C, so it also supports it.
|
|
|
|
//
|
|
|
|
// * Stdcall does not, because it would be impossible for the callee to clean
|
|
|
|
// up the arguments. (callee doesn't know how many arguments are there)
|
|
|
|
// * Same for Fastcall, Vectorcall and Thiscall.
|
|
|
|
// * System can become Stdcall, so is also a no-no.
|
|
|
|
// * Other calling conventions are related to hardware or the compiler itself.
|
|
|
|
match self {
|
|
|
|
Self::C { .. }
|
|
|
|
| Self::Cdecl { .. }
|
|
|
|
| Self::Win64 { .. }
|
|
|
|
| Self::SysV64 { .. }
|
|
|
|
| Self::EfiApi => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:59 -04:00
|
|
|
#[derive(Copy, Clone)]
|
2014-02-27 18:48:21 +11:00
|
|
|
pub struct AbiData {
|
2013-03-13 22:25:28 -04:00
|
|
|
abi: Abi,
|
|
|
|
|
2016-10-24 11:04:04 +02:00
|
|
|
/// Name of this ABI as we like it called.
|
2013-03-13 22:25:28 -04:00
|
|
|
name: &'static str,
|
|
|
|
}
|
|
|
|
|
2014-10-27 15:37:07 -07:00
|
|
|
#[allow(non_upper_case_globals)]
|
2018-08-09 15:42:43 +02:00
|
|
|
const AbiDatas: &[AbiData] = &[
|
2021-06-11 14:22:13 +03:00
|
|
|
AbiData { abi: Abi::Rust, name: "Rust" },
|
|
|
|
AbiData { abi: Abi::C { unwind: false }, name: "C" },
|
|
|
|
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
|
2022-02-01 18:53:45 +01:00
|
|
|
AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
|
|
|
|
AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
|
2021-06-11 14:22:13 +03:00
|
|
|
AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
|
|
|
|
AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
|
2022-02-01 18:53:45 +01:00
|
|
|
AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
|
|
|
|
AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
|
|
|
|
AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
|
|
|
|
AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
|
2021-06-11 14:22:13 +03:00
|
|
|
AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
|
|
|
|
AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
|
2022-02-01 18:53:45 +01:00
|
|
|
AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
|
|
|
|
AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
|
|
|
|
AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
|
|
|
|
AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
|
|
|
|
AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
|
|
|
|
AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
|
2021-06-11 14:22:13 +03:00
|
|
|
AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
|
|
|
|
AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
|
|
|
|
AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
|
|
|
|
AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel" },
|
|
|
|
AbiData { abi: Abi::EfiApi, name: "efiapi" },
|
|
|
|
AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
|
|
|
|
AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
|
|
|
|
AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
|
|
|
|
AbiData { abi: Abi::Wasm, name: "wasm" },
|
|
|
|
AbiData { abi: Abi::System { unwind: false }, name: "system" },
|
|
|
|
AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
|
|
|
|
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
|
|
|
|
AbiData { abi: Abi::RustCall, name: "rust-call" },
|
|
|
|
AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
|
|
|
|
AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
|
2022-05-29 00:25:14 -07:00
|
|
|
AbiData { abi: Abi::RustCold, name: "rust-cold" },
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" },
|
|
|
|
AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" },
|
2013-03-13 22:25:28 -04:00
|
|
|
];
|
|
|
|
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub enum AbiUnsupported {
|
|
|
|
Unrecognized,
|
|
|
|
Reason { explain: &'static str },
|
|
|
|
}
|
|
|
|
|
2014-06-09 13:12:30 -07:00
|
|
|
/// Returns the ABI with the given name (if any).
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
|
|
|
|
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi).ok_or_else(|| match name {
|
|
|
|
"riscv-interrupt" => AbiUnsupported::Reason {
|
|
|
|
explain: "please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively",
|
|
|
|
},
|
|
|
|
"riscv-interrupt-u" => AbiUnsupported::Reason {
|
|
|
|
explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314",
|
|
|
|
},
|
|
|
|
|
|
|
|
_ => AbiUnsupported::Unrecognized,
|
|
|
|
|
|
|
|
})
|
2013-03-13 22:25:28 -04:00
|
|
|
}
|
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
pub fn all_names() -> Vec<&'static str> {
|
2014-02-28 12:54:01 -08:00
|
|
|
AbiDatas.iter().map(|d| d.name).collect()
|
2013-03-13 22:25:28 -04:00
|
|
|
}
|
|
|
|
|
2022-09-08 15:37:15 +02:00
|
|
|
pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
|
|
|
|
AbiDatas
|
|
|
|
.iter()
|
|
|
|
.map(|d| d.name)
|
|
|
|
.filter(|name| is_enabled(features, span, name).is_ok())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum AbiDisabled {
|
|
|
|
Unstable { feature: Symbol, explain: &'static str },
|
|
|
|
Unrecognized,
|
|
|
|
}
|
|
|
|
|
2022-10-19 12:41:11 +02:00
|
|
|
pub fn is_enabled(
|
2022-09-08 15:37:15 +02:00
|
|
|
features: &rustc_feature::Features,
|
|
|
|
span: Span,
|
2022-10-19 12:41:11 +02:00
|
|
|
name: &str,
|
2022-09-08 15:37:15 +02:00
|
|
|
) -> Result<(), AbiDisabled> {
|
2022-10-19 12:41:11 +02:00
|
|
|
let s = is_stable(name);
|
|
|
|
if let Err(AbiDisabled::Unstable { feature, .. }) = s {
|
|
|
|
if features.enabled(feature) || span.allows_unstable(feature) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
2022-09-08 15:37:15 +02:00
|
|
|
}
|
2022-10-19 12:41:11 +02:00
|
|
|
s
|
2022-09-08 15:37:15 +02:00
|
|
|
}
|
|
|
|
|
2022-10-19 12:41:11 +02:00
|
|
|
pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
|
2022-09-08 15:37:15 +02:00
|
|
|
match name {
|
|
|
|
// Stable
|
2023-04-03 08:17:48 +01:00
|
|
|
"Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind"
|
|
|
|
| "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind"
|
2023-08-06 23:20:53 +02:00
|
|
|
| "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall"
|
|
|
|
| "thiscall-unwind" => Ok(()),
|
2022-10-19 12:41:11 +02:00
|
|
|
"rust-intrinsic" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::intrinsics,
|
|
|
|
explain: "intrinsics are subject to change",
|
|
|
|
}),
|
|
|
|
"platform-intrinsic" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::platform_intrinsics,
|
|
|
|
explain: "platform intrinsics are experimental and possibly buggy",
|
|
|
|
}),
|
|
|
|
"vectorcall" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_vectorcall,
|
|
|
|
explain: "vectorcall is experimental and subject to change",
|
|
|
|
}),
|
2023-04-03 08:17:48 +01:00
|
|
|
"vectorcall-unwind" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_vectorcall,
|
|
|
|
explain: "vectorcall-unwind ABI is experimental and subject to change",
|
|
|
|
}),
|
2022-10-19 12:41:11 +02:00
|
|
|
"rust-call" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::unboxed_closures,
|
|
|
|
explain: "rust-call ABI is subject to change",
|
|
|
|
}),
|
|
|
|
"rust-cold" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::rust_cold_cc,
|
|
|
|
explain: "rust-cold is experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"ptx-kernel" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_ptx,
|
|
|
|
explain: "PTX ABIs are experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"unadjusted" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_unadjusted,
|
|
|
|
explain: "unadjusted ABI is an implementation detail and perma-unstable",
|
|
|
|
}),
|
|
|
|
"msp430-interrupt" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_msp430_interrupt,
|
|
|
|
explain: "msp430-interrupt ABI is experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"x86-interrupt" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_x86_interrupt,
|
|
|
|
explain: "x86-interrupt ABI is experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"amdgpu-kernel" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_amdgpu_kernel,
|
|
|
|
explain: "amdgpu-kernel ABI is experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_avr_interrupt,
|
|
|
|
explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
|
|
|
|
}),
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
"riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_riscv_interrupt,
|
|
|
|
explain: "riscv-interrupt ABIs are experimental and subject to change",
|
|
|
|
}),
|
2022-10-19 12:41:11 +02:00
|
|
|
"C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::abi_c_cmse_nonsecure_call,
|
|
|
|
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
|
|
|
|
}),
|
|
|
|
"wasm" => Err(AbiDisabled::Unstable {
|
|
|
|
feature: sym::wasm_abi,
|
|
|
|
explain: "wasm ABI is experimental and subject to change",
|
|
|
|
}),
|
2022-09-08 15:37:15 +02:00
|
|
|
_ => Err(AbiDisabled::Unrecognized),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl Abi {
|
2021-07-08 21:58:05 +02:00
|
|
|
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
|
|
|
|
pub const FALLBACK: Abi = Abi::C { unwind: false };
|
|
|
|
|
2013-03-13 22:25:28 -04:00
|
|
|
#[inline]
|
2018-08-09 15:42:43 +02:00
|
|
|
pub fn index(self) -> usize {
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
// N.B., this ordering MUST match the AbiDatas array above.
|
|
|
|
// (This is ensured by the test indices_are_correct().)
|
|
|
|
use Abi::*;
|
2020-10-23 18:49:34 -04:00
|
|
|
let i = match self {
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
// Cross-platform ABIs
|
|
|
|
Rust => 0,
|
|
|
|
C { unwind: false } => 1,
|
|
|
|
C { unwind: true } => 2,
|
|
|
|
// Platform-specific ABIs
|
2022-02-01 18:53:45 +01:00
|
|
|
Cdecl { unwind: false } => 3,
|
|
|
|
Cdecl { unwind: true } => 4,
|
|
|
|
Stdcall { unwind: false } => 5,
|
|
|
|
Stdcall { unwind: true } => 6,
|
|
|
|
Fastcall { unwind: false } => 7,
|
|
|
|
Fastcall { unwind: true } => 8,
|
|
|
|
Vectorcall { unwind: false } => 9,
|
|
|
|
Vectorcall { unwind: true } => 10,
|
|
|
|
Thiscall { unwind: false } => 11,
|
|
|
|
Thiscall { unwind: true } => 12,
|
|
|
|
Aapcs { unwind: false } => 13,
|
|
|
|
Aapcs { unwind: true } => 14,
|
|
|
|
Win64 { unwind: false } => 15,
|
|
|
|
Win64 { unwind: true } => 16,
|
|
|
|
SysV64 { unwind: false } => 17,
|
|
|
|
SysV64 { unwind: true } => 18,
|
|
|
|
PtxKernel => 19,
|
|
|
|
Msp430Interrupt => 20,
|
|
|
|
X86Interrupt => 21,
|
|
|
|
AmdGpuKernel => 22,
|
|
|
|
EfiApi => 23,
|
|
|
|
AvrInterrupt => 24,
|
|
|
|
AvrNonBlockingInterrupt => 25,
|
|
|
|
CCmseNonSecureCall => 26,
|
|
|
|
Wasm => 27,
|
rustc_target: add "unwind" payloads to `Abi`
### Overview
This commit begins the implementation work for RFC 2945. For more
information, see the rendered RFC [1] and tracking issue [2].
A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`,
and `Thiscall` variants, marking whether unwinding across FFI
boundaries is acceptable. The cases where each of these variants'
`unwind` member is true correspond with the `C-unwind`,
`system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings
introduced in RFC 2945 [3].
### Feature Gate and Unstable Book
This commit adds a `c_unwind` feature gate for the new ABI strings.
Tests for this feature gate are included in `src/test/ui/c-unwind/`,
which ensure that this feature gate works correctly for each of the
new ABIs.
A new language features entry in the unstable book is added as well.
### Further Work To Be Done
This commit does not proceed to implement the new unwinding ABIs,
and is intentionally scoped specifically to *defining* the ABIs and
their feature flag.
### One Note on Test Churn
This will lead to some test churn, in re-blessing hash tests, as the
deleted comment in `src/librustc_target/spec/abi.rs` mentioned,
because we can no longer guarantee the ordering of the `Abi`
variants.
While this is a downside, this decision was made bearing in mind
that RFC 2945 states the following, in the "Other `unwind` Strings"
section [3]:
> More unwind variants of existing ABI strings may be introduced,
> with the same semantics, without an additional RFC.
Adding a new variant for each of these cases, rather than specifying
a payload for a given ABI, would quickly become untenable, and make
working with the `Abi` enum prone to mistakes.
This approach encodes the unwinding information *into* a given ABI,
to account for the future possibility of other `-unwind` ABI
strings.
### Ignore Directives
`ignore-*` directives are used in two of our `*-unwind` ABI test
cases.
Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases
ignore architectures that do not support `stdcall` and
`thiscall`, respectively.
These directives are cribbed from
`src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and
`src/test/ui/extern/extern-thiscall.rs` for `thiscall`.
This would otherwise fail on some targets, see:
https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60
### Footnotes
[1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
[2]: https://github.com/rust-lang/rust/issues/74990
[3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
2020-08-27 11:49:18 -04:00
|
|
|
// Cross-platform ABIs
|
2022-02-01 18:53:45 +01:00
|
|
|
System { unwind: false } => 28,
|
|
|
|
System { unwind: true } => 29,
|
|
|
|
RustIntrinsic => 30,
|
|
|
|
RustCall => 31,
|
|
|
|
PlatformIntrinsic => 32,
|
|
|
|
Unadjusted => 33,
|
2022-05-29 00:25:14 -07:00
|
|
|
RustCold => 34,
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
|
|
|
RiscvInterruptM => 35,
|
|
|
|
RiscvInterruptS => 36,
|
2020-10-23 18:49:34 -04:00
|
|
|
};
|
|
|
|
debug_assert!(
|
|
|
|
AbiDatas
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.find(|(_, AbiData { abi, .. })| *abi == self)
|
|
|
|
.map(|(index, _)| index)
|
|
|
|
.expect("abi variant has associated data")
|
|
|
|
== i,
|
|
|
|
"Abi index did not match `AbiDatas` ordering"
|
|
|
|
);
|
|
|
|
i
|
2013-03-13 22:25:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-08-09 15:42:43 +02:00
|
|
|
pub fn data(self) -> &'static AbiData {
|
2013-03-13 22:25:28 -04:00
|
|
|
&AbiDatas[self.index()]
|
|
|
|
}
|
|
|
|
|
2018-08-09 15:42:43 +02:00
|
|
|
pub fn name(self) -> &'static str {
|
2013-03-13 22:25:28 -04:00
|
|
|
self.data().name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 15:45:07 -08:00
|
|
|
impl fmt::Display for Abi {
|
2019-02-08 21:00:07 +09:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2023-04-09 23:08:39 +02:00
|
|
|
write!(f, "\"{}\"", self.name())
|
2013-03-13 22:25:28 -04:00
|
|
|
}
|
|
|
|
}
|