the wasm ABI behavior is a bug
This commit is contained in:
parent
243ef313a5
commit
28d152935e
3 changed files with 15 additions and 11 deletions
|
@ -351,15 +351,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||||
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
|
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
|
||||||
// aggregates...
|
// aggregates...
|
||||||
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
|
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
|
||||||
// This is the most critical case for ABI compatibility, since
|
// This really shouldn't happen, since `immediate_llvm_type` will use
|
||||||
// `immediate_llvm_type` will use `layout.fields` to turn this Rust type
|
// `layout.fields` to turn this Rust type into an LLVM type. This means all
|
||||||
// into an LLVM type. ABI-compatible Rust types can have different `fields`,
|
// sorts of Rust type details leak into the ABI. However wasm sadly *does*
|
||||||
// so we need to be very sure that LLVM wil treat those different types in
|
// currently use this mode so we have to allow it -- but we absolutely
|
||||||
// an ABI-compatible way. Mostly we do this by disallowing
|
// shouldn't let any more targets do that.
|
||||||
// `PassMode::Direct` for aggregates, but we actually do use that mode on
|
// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
|
||||||
// wasm. wasm doesn't have aggregate types so we are fairly sure that LLVM
|
|
||||||
// will treat `{ i32, i32, i32 }` and `{ { i32, i32, i32 } }` the same way
|
|
||||||
// for ABI purposes.
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"),
|
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"),
|
||||||
"`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}",
|
"`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}",
|
||||||
|
|
|
@ -36,7 +36,10 @@ pub enum PassMode {
|
||||||
Ignore,
|
Ignore,
|
||||||
/// Pass the argument directly.
|
/// Pass the argument directly.
|
||||||
///
|
///
|
||||||
/// The argument has a layout abi of `Scalar`, `Vector` or in rare cases (e.g. on wasm) `Aggregate`.
|
/// The argument has a layout abi of `Scalar` or `Vector`.
|
||||||
|
/// Unfortunately due to past mistakes, in rare cases on wasm, it can also be `Aggregate`.
|
||||||
|
/// This is bad since it leaks LLVM implementation details into the ABI.
|
||||||
|
/// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
|
||||||
Direct(ArgAttributes),
|
Direct(ArgAttributes),
|
||||||
/// Pass a pair's elements directly in two arguments.
|
/// Pass a pair's elements directly in two arguments.
|
||||||
///
|
///
|
||||||
|
@ -527,7 +530,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
|
||||||
scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)),
|
scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)),
|
||||||
),
|
),
|
||||||
Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
|
Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
|
||||||
// The `Aggregate` ABI is almost always adjusted later.
|
// The `Aggregate` ABI should always be adjusted later.
|
||||||
Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
|
Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
|
||||||
};
|
};
|
||||||
ArgAbi { layout, mode }
|
ArgAbi { layout, mode }
|
||||||
|
|
|
@ -61,6 +61,10 @@ where
|
||||||
/// The purpose of this ABI is for matching the WebAssembly standard. This
|
/// The purpose of this ABI is for matching the WebAssembly standard. This
|
||||||
/// intentionally diverges from the C ABI and is specifically crafted to take
|
/// intentionally diverges from the C ABI and is specifically crafted to take
|
||||||
/// advantage of LLVM's support of multiple returns in WebAssembly.
|
/// advantage of LLVM's support of multiple returns in WebAssembly.
|
||||||
|
///
|
||||||
|
/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM
|
||||||
|
/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change.
|
||||||
|
/// Also see <https://github.com/rust-lang/rust/issues/115666>.
|
||||||
pub fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
pub fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||||
if !fn_abi.ret.is_ignore() {
|
if !fn_abi.ret.is_ignore() {
|
||||||
classify_ret(&mut fn_abi.ret);
|
classify_ret(&mut fn_abi.ret);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue