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

wasm->CLIF translation: consistently bitcast V128 values that are blo… #2303

Merged

Conversation

julian-seward1
Copy link
Collaborator

…ck formal parameters.

In the current translation of wasm (128-bit) SIMD into CLIF, we work around differences in the
type system models of wasm vs CLIF by inserting bitcast (no-op casts) CLIF instructions before
more or less every use of a SIMD value. Unfortunately this was not being done consistently and
even small examples with a single if-then-else diamond that produces a SIMD value, could cause a
verification failure downstream. In this case, the jump out of the "else" block needed a
bitcast, but didn't have one.

This patch wraps creation of CLIF jumps and conditional branches up into a pair of functions,
canonicalise_then_jump and canonicalise_then_br_z_or_nz, and uses them consistently. They
first cast the relevant block formal parameters, then generate the relevant kind of branch/jump.
Hence, provided they are also used consistently in future to generate branches/jumps in this
file, we are protected against such failures.

The patch also adds a large(ish) comment at the top explaining this in more detail.

@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator cranelift:wasm labels Oct 20, 2020
@yurydelendik
Copy link
Collaborator

yurydelendik commented Oct 20, 2020

I wonder if we can wrap SmallVec canonicalised initialization logic into function and do it only when needed. Also, I think it is possible to avoid canonicalise_then_XXXX functions.

fn canonicalise<'a>(
    builder: &mut FunctionBuilder,
    values: &'a [ir::Value],
) -> impl AsRef<[ir::Value]> + 'a {
    enum Result<'a> {
        Ref(&'a [ir::Value]),
        Vec(SmallVec<[ir::Value; 16]>),
    }
    impl<'a> AsRef<[u8]> for Result<'a> {
        fn as_ref(&self) -> &[u8] {
            match self {
                Result::Ref(r) => r,
                Result::Vec(v) => v.as_slice(),
            }
        }    
    }
    
    // do_checks_and_stuff

    if ... {
        Result::Vec(canonicalised)
    } else {
        Result::Ref(values)
    }
}

// do e.g.
let params = canonicalise(builder, destination_args);
builder
  .ins()
  .jump(real_dest_block, params.as_ref());

It is nice to see fast path for canonicalise when SIMD is not in use too.

cranelift/wasm/src/code_translator.rs Outdated Show resolved Hide resolved
cranelift/wasm/src/code_translator.rs Outdated Show resolved Hide resolved
cranelift/wasm/src/code_translator.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@abrown abrown left a comment

Choose a reason for hiding this comment

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

Could you create tests for this in tests/wasm or cranelift/wasmtests? I think the reason that jumps/branches weren't covered when I had to add the original bitcasts is that I believed the spec testsuite covered these cases... but apparently not.

…ck formal parameters.

In the current translation of wasm (128-bit) SIMD into CLIF, we work around differences in the
type system models of wasm vs CLIF by inserting `bitcast` (a no-op cast) CLIF instructions before
more or less every use of a SIMD value.  Unfortunately this was not being done consistently and
even small examples with a single if-then-else diamond that produces a SIMD value, could cause a
verification failure downstream.  In this case, the jump out of the "else" block needed a
bitcast, but didn't have one.

This patch wraps creation of CLIF jumps and conditional branches up into three functions,
`canonicalise_then_jump` and `canonicalise_then_br{z,nz}`, and uses them consistently.  They
first cast the relevant block formal parameters, then generate the relevant kind of branch/jump.
Hence, provided they are also used consistently in future to generate branches/jumps in this
file, we are protected against such failures.

The patch also adds a large(ish) comment at the top explaining this in more detail.
@julian-seward1
Copy link
Collaborator Author

Thanks all for the various comments/suggestions. I pushed a revised patch that addresses all of them.

@julian-seward1 julian-seward1 merged commit ab65d8f into bytecodealliance:main Oct 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:wasm cranelift Issues related to the Cranelift code generator
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants