rustc assumes that regular `extern "Rust"` functions unwind only if the
`unwind` panic runtime is linked. `throw` was annotated as such, but
unwound unconditionally. This could cause UB when a crate built with `-C
panic=abort` called `throw` from `core` built with `-C panic=unwind`,
since no terminator was added to handle the panic arising from calling an
allegedly non-unwinding `extern "Rust"` function.
rustc was taught to recognize this condition since
https://github.com/rust-lang/rust/pull/144225 and prevented such
linkage, but this caused regressions in
https://github.com/rust-lang/rust/issues/148246, since this meant that
Emscripten projects could not be built with `-C panic=abort` without
recompiling std.
The most straightforward solution would be to move `throw` into the
`panic_unwind` crate, so that it's only compiled if the panic runtime is
guaranteed to be `unwind`, but this is messy due to our architecture.
Instead, move it into `unwind::wasm`, which is only compiled for
bare-metal targets that default to `panic = "abort"`, rendering the
issue moot.
Mark float intrinsics with no preconditions as safe
Note: for ease of reviewing, the list of safe intrinsics is sorted in the first commit, and then safe intrinsics are added in the second commit.
All *recently added* float intrinsics have been correctly marked as safe to call due to the fact that they have no preconditions. This adds the remaining float intrinsics which are safe to call to the safe intrinsic list, and removes the unsafe blocks around their calls.
---
Side note: this may want a try run before being added to the queue, since I'm not sure if there's any tier-2 code that uses these intrinsics that might not be tested on the usual PR flow. We've already uncovered a few places in subtrees that do this, and it's worth double-checking before clogging up the queue.
This commit performs various improvements (better register allocation,
less register clobbering on the worst case and better readability) of
RISC-V inline assembly use cases.
Note that it does not change the `p` module (which defines the "P"
extension draft instructions but very likely to change).
1. Use `lateout` as possible.
Unlike `out(reg)` and `in(reg)` pair, `lateout(reg)` and `in(reg)`
can share the same register because they state that the late-output
register is written after all the reads are performed.
It can improve register allocation.
2. Add `preserves_flags` option as possible.
While RISC-V doesn't have _regular_ condition codes, RISC-V inline
assembly in the Rust language assumes that some registers
(mainly vector state registers) may be overwritten by default.
By adding `preserves_flags` to the intrinsics corresponding
instructions without overwriting them, it can minimize register
clobbering on the worst case.
3. Use trailing semicolon.
As `asm!` declares an action and it doesn't return a value by
itself, it would be better to have trailing semicolon to denote that
an `asm!` call is effectively a statement.
4. Make most of `asm!` calls multi-lined.
`rustfmt` makes some simple (yet long) `asm!` calls multi-lined but
it does not perform formatting of complex `asm!` calls with inputs
and/or outputs. To keep consistency, it makes most of the `asm!`
calls multi-lined.
This instruction is incorrectly categorized as the same one as
`aes64ks1i` and `aes64ks2` (that should require `zkne || zknd` but
currently require `zkne && zknd`) but `aes64im` only requires
the Zknd extension.
This commit fixes the category of this intrinsic (lowering the
requirements from the Rust perspective but it does not actually lower
it from the RISC-V perspective).
They don't need full "Zbc" extension but only its subset: the "Zbkc"
extension. Since the compiler implies `zbkc` from `zbc`, it's safe to
use `#[target_feature(enable = "zbkc")]`.