diff --git a/cranelift-codegen/src/verifier/mod.rs b/cranelift-codegen/src/verifier/mod.rs index f31b4e234..06d440fba 100644 --- a/cranelift-codegen/src/verifier/mod.rs +++ b/cranelift-codegen/src/verifier/mod.rs @@ -64,6 +64,7 @@ use crate::flowgraph::{BasicBlock, ControlFlowGraph}; use crate::ir; use crate::ir::entities::AnyEntity; use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint}; +use crate::ir::types::I8X16; use crate::ir::{ types, ArgumentLoc, Ebb, FuncRef, Function, GlobalValue, Inst, InstructionData, JumpTable, Opcode, SigRef, StackSlot, StackSlotKind, Type, Value, ValueDef, ValueList, ValueLoc, @@ -1189,6 +1190,12 @@ impl<'a> Verifier<'a> { let arg_type = self.func.dfg.value_type(arg); match constraints.value_argument_constraint(i, ctrl_type) { ResolvedConstraint::Bound(expected_type) => { + // Skip checking of the V128 default type (i.e. I8X16): this relaxation of type + // checking allows incoming values of I8X16 (say from a function signature) to + // be used as any vector type of the same width. + if arg_type == I8X16 && expected_type.bits() == arg_type.bits() { + continue; + } if arg_type != expected_type { report!( errors, @@ -1412,6 +1419,15 @@ impl<'a> Verifier<'a> { } for (i, (&arg, &expected_type)) in args.iter().zip(expected_types).enumerate() { let arg_type = self.func.dfg.value_type(arg); + // Skip checking of the V128 default type (i.e. I8X16): this relaxation of type + // checking is the inverse of the one in `typecheck_fixed_args` above. It allows + // values returned from a function to be any vector of the same width as the + // default type. + if expected_type.value_type == I8X16 + && arg_type.bits() == expected_type.value_type.bits() + { + continue; + } if arg_type != expected_type.value_type { report!( errors, diff --git a/filetests/verifier/simd-default-type.clif b/filetests/verifier/simd-default-type.clif new file mode 100644 index 000000000..8a2a0e34e --- /dev/null +++ b/filetests/verifier/simd-default-type.clif @@ -0,0 +1,39 @@ +test verifier +set enable_simd +target x86_64 + +; This file tests using I8X16 as a default type to represent Wasm's V128 type. Values of Wasm's V128 +; type can be used in any instruction of similar width (e.g. `i32x4.add`). Cranelift must build +; signatures for Wasm functions using V128 and, lacking a special type to do so, Cranelift +; uses I8X16 for V128. To avoid excessive bitcasting, however, we relax the verifier to allow +; I8X16 to type-check as the other 128-bit types. This implies that: +; - SIMD instructions must have explicit types (e.g. iadd.i32x4) to avoid type inference deciding +; a wrong type and emitting the wrong instruction +; - The verifier will be unable to catch unintended errors in sequences like: `v1 = iadd.i8x16 v0, +; v0; v2 = isub.i32x4 v1, v0` (presumably we want v0 and v1 to be I8X16 in fact and would want the +; verifier to tell us that we should not add them as I32X4s). + +function %passes_non_default_type(i32x4) { +ebb0(v0: i32x4): + v1 = fneg.f32x4 v0 ; error: arg 0 (v0) has type i32x4, expected f32x4 + return +} + +function %passes_default_type(i8x16) { +ebb0(v0: i8x16): + v1 = fadd.f32x4 v0, v0 + return +} + +function %returns_non_default_type() -> i64x2 { +ebb0: + v1 = vconst.i32x4 [0 1 2 3] + return v1 ; error: arg 0 (v1) has type i32x4, must match function signature of i64x2 +} + +function %returns_default_type() -> i8x16 { +ebb0: + v1 = vconst.i32x4 [0 1 2 3] + return v1 +} +