Skip to content

Commit

Permalink
Implement the br_on_cast[_fail] Wasm GC instructions (#9438)
Browse files Browse the repository at this point in the history
Just gluing our existing `ref.test` and conditional branching support together.
  • Loading branch information
fitzgen authored Oct 10, 2024
1 parent d5652f5 commit a94c775
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 6 deletions.
71 changes: 67 additions & 4 deletions crates/cranelift/src/translate/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2783,6 +2783,73 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
state.push1(r);
}
Operator::BrOnCast {
relative_depth,
to_ref_type,
// TODO: we should take advantage of our knowledge of the type we
// are casting from when generating the test.
from_ref_type: _,
} => {
let r = state.peek1();

let to_ref_type = environ.convert_ref_type(*to_ref_type);
let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r)?;

let (cast_succeeds_block, inputs) = translate_br_if_args(*relative_depth, state);
let cast_fails_block = builder.create_block();
canonicalise_brif(
builder,
cast_is_okay,
cast_succeeds_block,
inputs,
cast_fails_block,
&[
// NB: the `cast_fails_block` is dominated by the current
// block, and therefore doesn't need any block params.
],
);

// The only predecessor is the current block.
builder.seal_block(cast_fails_block);

// The next Wasm instruction is executed when the cast failed and we
// did not branch away.
builder.switch_to_block(cast_fails_block);
}
Operator::BrOnCastFail {
relative_depth,
to_ref_type,
// TODO: we should take advantage of our knowledge of the type we
// are casting from when generating the test.
from_ref_type: _,
} => {
let r = state.peek1();

let to_ref_type = environ.convert_ref_type(*to_ref_type);
let cast_is_okay = environ.translate_ref_test(builder, to_ref_type, r)?;

let (cast_fails_block, inputs) = translate_br_if_args(*relative_depth, state);
let cast_succeeds_block = builder.create_block();
canonicalise_brif(
builder,
cast_is_okay,
cast_succeeds_block,
&[
// NB: the `cast_succeeds_block` is dominated by the current
// block, and therefore doesn't need any block params.
],
cast_fails_block,
inputs,
);

// The only predecessor is the current block.
builder.seal_block(cast_succeeds_block);

// The next Wasm instruction is executed when the cast succeeded and
// we did not branch away.
builder.switch_to_block(cast_succeeds_block);
}

Operator::AnyConvertExtern => {
// Pop an `externref`, push an `anyref`. But they have the same
// representation, so we don't actually need to do anything.
Expand All @@ -2792,10 +2859,6 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// representation, so we don't actually need to do anything.
}

Operator::BrOnCast { .. } | Operator::BrOnCastFail { .. } => {
return Err(wasm_unsupported!("GC operator not yet implemented: {op:?}"));
}

Operator::GlobalAtomicGet { .. }
| Operator::GlobalAtomicSet { .. }
| Operator::GlobalAtomicRmwAdd { .. }
Expand Down
2 changes: 0 additions & 2 deletions tests/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,6 @@ fn should_fail(test: &Path, strategy: Strategy) -> bool {
}
let unsupported_gc_tests = [
"binary_gc.wast",
"br_on_cast_fail.wast",
"br_on_cast.wast",
"table_sub.wast",
"type_canon.wast",
"type_equivalence.wast",
Expand Down

0 comments on commit a94c775

Please sign in to comment.