diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02e2c48f..d67021b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 with: repository: WebAssembly/wabt - ref: 7c88424c98f157d375458fe6b2cd392959d7d217 + ref: 8e42376ccd5f05dc1036f91b4262e67b0fc66c2d path: wabt - name: Build wabt run: | diff --git a/Cargo.toml b/Cargo.toml index 664e945b..02d46fec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ leb128 = "0.2.4" log = "0.4.8" rayon = { version = "1.1.0", optional = true } walrus-macro = { path = './crates/macro', version = '=0.18.0' } -wasmparser = "0.62.0" +wasmparser = "0.65.0" [features] parallel = ['rayon', 'id-arena/rayon'] diff --git a/crates/tests/tests/round_trip/simd.wat b/crates/tests/tests/round_trip/simd.wat index 263b29b4..c0c4d0b8 100644 --- a/crates/tests/tests/round_trip/simd.wat +++ b/crates/tests/tests/round_trip/simd.wat @@ -289,26 +289,26 @@ local.get 0 local.get 1 i8x16.add) - (func $i8x16.add_saturate_u (export "i8x16.add_saturate_u") (param v128 v128) (result v128) + (func $i8x16.add_sat_u (export "i8x16.add_sat_u") (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.add_saturate_u) - (func $i8x16.add_saturate_s (export "i8x16.add_saturate_s") (param v128 v128) (result v128) + i8x16.add_sat_u) + (func $i8x16.add_sat_s (export "i8x16.add_sat_s") (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.add_saturate_s) + i8x16.add_sat_s) (func $i8x16.sub (export "i8x16.sub") (param v128 v128) (result v128) local.get 0 local.get 1 i8x16.sub) - (func $i8x16.sub_saturate_u (export "i8x16.sub_saturate_u") (param v128 v128) (result v128) + (func $i8x16.sub_sat_u (export "i8x16.sub_sat_u") (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.sub_saturate_u) - (func $i8x16.sub_saturate_s (export "i8x16.sub_saturate_s") (param v128 v128) (result v128) + i8x16.sub_sat_u) + (func $i8x16.sub_sat_s (export "i8x16.sub_sat_s") (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.sub_saturate_s) + i8x16.sub_sat_s) (func $i16x8.neg (export "i16x8.neg") (param v128) (result v128) local.get 0 @@ -335,26 +335,26 @@ local.get 0 local.get 1 i16x8.add) - (func $i16x8.add_saturate_u (export "i16x8.add_saturate_u") (param v128 v128) (result v128) + (func $i16x8.add_sat_u (export "i16x8.add_sat_u") (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.add_saturate_u) - (func $i16x8.add_saturate_s (export "i16x8.add_saturate_s") (param v128 v128) (result v128) + i16x8.add_sat_u) + (func $i16x8.add_sat_s (export "i16x8.add_sat_s") (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.add_saturate_s) + i16x8.add_sat_s) (func $i16x8.sub (export "i16x8.sub") (param v128 v128) (result v128) local.get 0 local.get 1 i16x8.sub) - (func $i16x8.sub_saturate_u (export "i16x8.sub_saturate_u") (param v128 v128) (result v128) + (func $i16x8.sub_sat_u (export "i16x8.sub_sat_u") (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.sub_saturate_u) - (func $i16x8.sub_saturate_s (export "i16x8.sub_saturate_s") (param v128 v128) (result v128) + i16x8.sub_sat_u) + (func $i16x8.sub_sat_s (export "i16x8.sub_sat_s") (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.sub_saturate_s) + i16x8.sub_sat_s) (func $i16x8.mul (export "i16x8.mul") (param v128 v128) (result v128) local.get 0 local.get 1 @@ -729,26 +729,26 @@ local.get 0 local.get 1 i8x16.add) - (func $i8x16.add_saturate_u (type 15) (param v128 v128) (result v128) + (func $i8x16.add_sat_u (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.add_saturate_u) - (func $i8x16.add_saturate_s (type 15) (param v128 v128) (result v128) + i8x16.add_sat_u) + (func $i8x16.add_sat_s (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.add_saturate_s) + i8x16.add_sat_s) (func $i8x16.sub (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 i8x16.sub) - (func $i8x16.sub_saturate_u (type 15) (param v128 v128) (result v128) + (func $i8x16.sub_sat_u (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.sub_saturate_u) - (func $i8x16.sub_saturate_s (type 15) (param v128 v128) (result v128) + i8x16.sub_sat_u) + (func $i8x16.sub_sat_s (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i8x16.sub_saturate_s) + i8x16.sub_sat_s) (func $i16x8.shl (type 11) (param v128 i32) (result v128) local.get 0 local.get 1 @@ -765,26 +765,26 @@ local.get 0 local.get 1 i16x8.add) - (func $i16x8.add_saturate_u (type 15) (param v128 v128) (result v128) + (func $i16x8.add_sat_u (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.add_saturate_u) - (func $i16x8.add_saturate_s (type 15) (param v128 v128) (result v128) + i16x8.add_sat_u) + (func $i16x8.add_sat_s (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.add_saturate_s) + i16x8.add_sat_s) (func $i16x8.sub (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 i16x8.sub) - (func $i16x8.sub_saturate_u (type 15) (param v128 v128) (result v128) + (func $i16x8.sub_sat_u (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.sub_saturate_u) - (func $i16x8.sub_saturate_s (type 15) (param v128 v128) (result v128) + i16x8.sub_sat_u) + (func $i16x8.sub_sat_s (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 - i16x8.sub_saturate_s) + i16x8.sub_sat_s) (func $i16x8.mul (type 15) (param v128 v128) (result v128) local.get 0 local.get 1 @@ -1064,11 +1064,11 @@ (export "i8x16.shr_s" (func $i8x16.shr_s)) (export "i8x16.shr_u" (func $i8x16.shr_u)) (export "i8x16.add" (func $i8x16.add)) - (export "i8x16.add_saturate_u" (func $i8x16.add_saturate_u)) - (export "i8x16.add_saturate_s" (func $i8x16.add_saturate_s)) + (export "i8x16.add_sat_u" (func $i8x16.add_sat_u)) + (export "i8x16.add_sat_s" (func $i8x16.add_sat_s)) (export "i8x16.sub" (func $i8x16.sub)) - (export "i8x16.sub_saturate_u" (func $i8x16.sub_saturate_u)) - (export "i8x16.sub_saturate_s" (func $i8x16.sub_saturate_s)) + (export "i8x16.sub_sat_u" (func $i8x16.sub_sat_u)) + (export "i8x16.sub_sat_s" (func $i8x16.sub_sat_s)) (export "i16x8.neg" (func $i16x8.neg)) (export "i16x8.any_true" (func $i16x8.any_true)) (export "i16x8.all_true" (func $i16x8.all_true)) @@ -1076,11 +1076,11 @@ (export "i16x8.shr_s" (func $i16x8.shr_s)) (export "i16x8.shr_u" (func $i16x8.shr_u)) (export "i16x8.add" (func $i16x8.add)) - (export "i16x8.add_saturate_u" (func $i16x8.add_saturate_u)) - (export "i16x8.add_saturate_s" (func $i16x8.add_saturate_s)) + (export "i16x8.add_sat_u" (func $i16x8.add_sat_u)) + (export "i16x8.add_sat_s" (func $i16x8.add_sat_s)) (export "i16x8.sub" (func $i16x8.sub)) - (export "i16x8.sub_saturate_u" (func $i16x8.sub_saturate_u)) - (export "i16x8.sub_saturate_s" (func $i16x8.sub_saturate_s)) + (export "i16x8.sub_sat_u" (func $i16x8.sub_sat_u)) + (export "i16x8.sub_sat_s" (func $i16x8.sub_sat_s)) (export "i16x8.mul" (func $i16x8.mul)) (export "i32x4.neg" (func $i32x4.neg)) (export "i32x4.any_true" (func $i32x4.any_true)) diff --git a/crates/tests/tests/spec-tests b/crates/tests/tests/spec-tests index d2163dac..18f83401 160000 --- a/crates/tests/tests/spec-tests +++ b/crates/tests/tests/spec-tests @@ -1 +1 @@ -Subproject commit d2163dace09d647bccf34b9b82a6f05a3b23cf29 +Subproject commit 18f83401a47a0e43772cf7d9f216e994bf7c7fa6 diff --git a/crates/tests/tests/spec-tests.rs b/crates/tests/tests/spec-tests.rs index a27afeeb..d352bc05 100644 --- a/crates/tests/tests/spec-tests.rs +++ b/crates/tests/tests/spec-tests.rs @@ -33,10 +33,7 @@ fn run(wast: &Path) -> Result<(), anyhow::Error> { Some("simd") => &["--enable-simd"], Some("bulk-memory-operations") => &["--enable-bulk-memory"], - // Some("reference-types") => &["--enable-reference-types", "--enable-bulk-memory"], - // TODO: waiting for wabt to update its implementation of reference - // types. - Some("reference-types") => return Ok(()), + Some("reference-types") => &["--enable-reference-types", "--enable-bulk-memory"], // TODO: should get threads working Some("threads") => return Ok(()), @@ -49,6 +46,7 @@ fn run(wast: &Path) -> Result<(), anyhow::Error> { // not implemented in walrus yet Some("function-references") => return Ok(()), Some("exception-handling") => return Ok(()), + Some("memory64") => return Ok(()), // Some("threads") => &["--enable-threads"], Some(other) => panic!("unknown wasm proposal: {}", other), diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 6fde9a76..abd225c2 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -539,11 +539,11 @@ pub enum Instr { /// `v128.bitselect` V128Bitselect {}, - /// `v128.swizzle` - V128Swizzle {}, + /// `i8x16.swizzle` + I8x16Swizzle {}, - /// `v128.shuffle` - V128Shuffle { + /// `i8x16.shuffle` + I8x16Shuffle { /// The indices that are used to create the final vector of this /// instruction #[walrus(skip_visit)] @@ -795,20 +795,20 @@ pub enum BinaryOp { I8x16ShrS, I8x16ShrU, I8x16Add, - I8x16AddSaturateS, - I8x16AddSaturateU, + I8x16AddSatS, + I8x16AddSatU, I8x16Sub, - I8x16SubSaturateS, - I8x16SubSaturateU, + I8x16SubSatS, + I8x16SubSatU, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, - I16x8AddSaturateS, - I16x8AddSaturateU, + I16x8AddSatS, + I16x8AddSatU, I16x8Sub, - I16x8SubSaturateS, - I16x8SubSaturateU, + I16x8SubSatS, + I16x8SubSatU, I16x8Mul, I32x4Shl, I32x4ShrS, @@ -829,12 +829,16 @@ pub enum BinaryOp { F32x4Div, F32x4Min, F32x4Max, + F32x4PMin, + F32x4PMax, F64x2Add, F64x2Sub, F64x2Mul, F64x2Div, F64x2Min, F64x2Max, + F64x2PMin, + F64x2PMax, I8x16NarrowI16x8S, I8x16NarrowI16x8U, @@ -855,6 +859,8 @@ pub enum BinaryOp { I32x4MinU, I32x4MaxS, I32x4MaxU, + + I32x4DotI16x8S, } /// Possible unary operations in wasm @@ -958,9 +964,17 @@ pub enum UnaryOp { F32x4Abs, F32x4Neg, F32x4Sqrt, + F32x4Ceil, + F32x4Floor, + F32x4Trunc, + F32x4Nearest, F64x2Abs, F64x2Neg, F64x2Sqrt, + F64x2Ceil, + F64x2Floor, + F64x2Trunc, + F64x2Nearest, I32x4TruncSatF32x4S, I32x4TruncSatF32x4U, @@ -1014,12 +1028,15 @@ pub enum LoadSimdKind { Splat16, Splat32, Splat64, - I16x8Load8x8S, - I16x8Load8x8U, - I32x4Load16x4S, - I32x4Load16x4U, - I64x2Load32x2S, - I64x2Load32x2U, + + V128Load8x8S, + V128Load8x8U, + V128Load16x4S, + V128Load16x4U, + V128Load32x2S, + V128Load32x2U, + V128Load32Zero, + V128Load64Zero, } /// The kinds of extended loads which can happen @@ -1212,8 +1229,8 @@ impl Instr { | Instr::RefIsNull(..) | Instr::RefFunc(..) | Instr::V128Bitselect(..) - | Instr::V128Swizzle(..) - | Instr::V128Shuffle(..) + | Instr::I8x16Swizzle(..) + | Instr::I8x16Shuffle(..) | Instr::LoadSimd(..) | Instr::AtomicFence(..) | Instr::TableInit(..) diff --git a/src/module/functions/local_function/emit.rs b/src/module/functions/local_function/emit.rs index acde6863..663173a7 100644 --- a/src/module/functions/local_function/emit.rs +++ b/src/module/functions/local_function/emit.rs @@ -326,11 +326,11 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { I8x16ShrS => self.simd(0x6c), I8x16ShrU => self.simd(0x6d), I8x16Add => self.simd(0x6e), - I8x16AddSaturateS => self.simd(0x6f), - I8x16AddSaturateU => self.simd(0x70), + I8x16AddSatS => self.simd(0x6f), + I8x16AddSatU => self.simd(0x70), I8x16Sub => self.simd(0x71), - I8x16SubSaturateS => self.simd(0x72), - I8x16SubSaturateU => self.simd(0x73), + I8x16SubSatS => self.simd(0x72), + I8x16SubSatU => self.simd(0x73), I8x16MinS => self.simd(0x76), I8x16MinU => self.simd(0x77), I8x16MaxS => self.simd(0x78), @@ -343,11 +343,11 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { I16x8ShrS => self.simd(0x8c), I16x8ShrU => self.simd(0x8d), I16x8Add => self.simd(0x8e), - I16x8AddSaturateS => self.simd(0x8f), - I16x8AddSaturateU => self.simd(0x90), + I16x8AddSatS => self.simd(0x8f), + I16x8AddSatU => self.simd(0x90), I16x8Sub => self.simd(0x91), - I16x8SubSaturateS => self.simd(0x92), - I16x8SubSaturateU => self.simd(0x93), + I16x8SubSatS => self.simd(0x92), + I16x8SubSatU => self.simd(0x93), I16x8Mul => self.simd(0x95), I16x8MinS => self.simd(0x96), I16x8MinU => self.simd(0x97), @@ -379,6 +379,8 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { F32x4Div => self.simd(0xe7), F32x4Min => self.simd(0xe8), F32x4Max => self.simd(0xe9), + F32x4PMin => self.simd(0xea), + F32x4PMax => self.simd(0xeb), F64x2Add => self.simd(0xf0), F64x2Sub => self.simd(0xf1), @@ -386,6 +388,10 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { F64x2Div => self.simd(0xf3), F64x2Min => self.simd(0xf4), F64x2Max => self.simd(0xf5), + F64x2PMin => self.simd(0xf6), + F64x2PMax => self.simd(0xf7), + + I32x4DotI16x8S => self.simd(0xba), } } @@ -525,10 +531,18 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { F32x4Abs => self.simd(0xe0), F32x4Neg => self.simd(0xe1), F32x4Sqrt => self.simd(0xe3), + F32x4Ceil => self.simd(0xd8), + F32x4Floor => self.simd(0xd9), + F32x4Trunc => self.simd(0xda), + F32x4Nearest => self.simd(0xdb), F64x2Abs => self.simd(0xec), F64x2Neg => self.simd(0xed), F64x2Sqrt => self.simd(0xef), + F64x2Ceil => self.simd(0xdc), + F64x2Floor => self.simd(0xdd), + F64x2Trunc => self.simd(0xde), + F64x2Nearest => self.simd(0xdf), I32x4TruncSatF32x4S => self.simd(0xf8), I32x4TruncSatF32x4U => self.simd(0xf9), @@ -817,25 +831,27 @@ impl<'instr> Visitor<'instr> for Emit<'_, '_> { V128Bitselect(_) => { self.simd(0x52); } - V128Shuffle(e) => { + I8x16Shuffle(e) => { self.simd(0x0d); self.encoder.raw(&e.indices); } - V128Swizzle(_) => { + I8x16Swizzle(_) => { self.simd(0x0e); } LoadSimd(e) => { match e.kind { - LoadSimdKind::I16x8Load8x8S => self.simd(0x01), - LoadSimdKind::I16x8Load8x8U => self.simd(0x02), - LoadSimdKind::I32x4Load16x4S => self.simd(0x03), - LoadSimdKind::I32x4Load16x4U => self.simd(0x04), - LoadSimdKind::I64x2Load32x2S => self.simd(0x05), - LoadSimdKind::I64x2Load32x2U => self.simd(0x06), + LoadSimdKind::V128Load8x8S => self.simd(0x01), + LoadSimdKind::V128Load8x8U => self.simd(0x02), + LoadSimdKind::V128Load16x4S => self.simd(0x03), + LoadSimdKind::V128Load16x4U => self.simd(0x04), + LoadSimdKind::V128Load32x2S => self.simd(0x05), + LoadSimdKind::V128Load32x2U => self.simd(0x06), LoadSimdKind::Splat8 => self.simd(0x07), LoadSimdKind::Splat16 => self.simd(0x08), LoadSimdKind::Splat32 => self.simd(0x09), LoadSimdKind::Splat64 => self.simd(0x0a), + LoadSimdKind::V128Load32Zero => self.simd(0xfc), + LoadSimdKind::V128Load64Zero => self.simd(0xfd), } self.memarg(e.memory, &e.arg); } diff --git a/src/module/functions/local_function/mod.rs b/src/module/functions/local_function/mod.rs index 65622c07..3937a260 100644 --- a/src/module/functions/local_function/mod.rs +++ b/src/module/functions/local_function/mod.rs @@ -984,12 +984,12 @@ fn append_instruction<'context>( ctx.alloc_instr(RefFunc { func }, loc); } - Operator::V8x16Swizzle => { - ctx.alloc_instr(V128Swizzle {}, loc); + Operator::I8x16Swizzle => { + ctx.alloc_instr(I8x16Swizzle {}, loc); } - Operator::V8x16Shuffle { lanes } => { - ctx.alloc_instr(V128Shuffle { indices: lanes }, loc); + Operator::I8x16Shuffle { lanes } => { + ctx.alloc_instr(I8x16Shuffle { indices: lanes }, loc); } Operator::I8x16Splat => unop(ctx, UnaryOp::I8x16Splat), @@ -1072,11 +1072,11 @@ fn append_instruction<'context>( Operator::I8x16ShrS => binop(ctx, BinaryOp::I8x16ShrS), Operator::I8x16ShrU => binop(ctx, BinaryOp::I8x16ShrU), Operator::I8x16Add => binop(ctx, BinaryOp::I8x16Add), - Operator::I8x16AddSaturateS => binop(ctx, BinaryOp::I8x16AddSaturateS), - Operator::I8x16AddSaturateU => binop(ctx, BinaryOp::I8x16AddSaturateU), + Operator::I8x16AddSatS => binop(ctx, BinaryOp::I8x16AddSatS), + Operator::I8x16AddSatU => binop(ctx, BinaryOp::I8x16AddSatU), Operator::I8x16Sub => binop(ctx, BinaryOp::I8x16Sub), - Operator::I8x16SubSaturateS => binop(ctx, BinaryOp::I8x16SubSaturateS), - Operator::I8x16SubSaturateU => binop(ctx, BinaryOp::I8x16SubSaturateU), + Operator::I8x16SubSatS => binop(ctx, BinaryOp::I8x16SubSatS), + Operator::I8x16SubSatU => binop(ctx, BinaryOp::I8x16SubSatU), Operator::I16x8Abs => unop(ctx, UnaryOp::I16x8Abs), Operator::I16x8Neg => unop(ctx, UnaryOp::I16x8Neg), @@ -1086,11 +1086,11 @@ fn append_instruction<'context>( Operator::I16x8ShrS => binop(ctx, BinaryOp::I16x8ShrS), Operator::I16x8ShrU => binop(ctx, BinaryOp::I16x8ShrU), Operator::I16x8Add => binop(ctx, BinaryOp::I16x8Add), - Operator::I16x8AddSaturateS => binop(ctx, BinaryOp::I16x8AddSaturateS), - Operator::I16x8AddSaturateU => binop(ctx, BinaryOp::I16x8AddSaturateU), + Operator::I16x8AddSatS => binop(ctx, BinaryOp::I16x8AddSatS), + Operator::I16x8AddSatU => binop(ctx, BinaryOp::I16x8AddSatU), Operator::I16x8Sub => binop(ctx, BinaryOp::I16x8Sub), - Operator::I16x8SubSaturateS => binop(ctx, BinaryOp::I16x8SubSaturateS), - Operator::I16x8SubSaturateU => binop(ctx, BinaryOp::I16x8SubSaturateU), + Operator::I16x8SubSatS => binop(ctx, BinaryOp::I16x8SubSatS), + Operator::I16x8SubSatU => binop(ctx, BinaryOp::I16x8SubSatU), Operator::I16x8Mul => binop(ctx, BinaryOp::I16x8Mul), Operator::I32x4Abs => unop(ctx, UnaryOp::I32x4Abs), @@ -1121,6 +1121,12 @@ fn append_instruction<'context>( Operator::F32x4Div => binop(ctx, BinaryOp::F32x4Div), Operator::F32x4Min => binop(ctx, BinaryOp::F32x4Min), Operator::F32x4Max => binop(ctx, BinaryOp::F32x4Max), + Operator::F32x4Ceil => unop(ctx, UnaryOp::F32x4Ceil), + Operator::F32x4Floor => unop(ctx, UnaryOp::F32x4Floor), + Operator::F32x4Trunc => unop(ctx, UnaryOp::F32x4Trunc), + Operator::F32x4Nearest => unop(ctx, UnaryOp::F32x4Nearest), + Operator::F32x4PMin => binop(ctx, BinaryOp::F32x4PMin), + Operator::F32x4PMax => binop(ctx, BinaryOp::F32x4PMax), Operator::F64x2Abs => unop(ctx, UnaryOp::F64x2Abs), Operator::F64x2Neg => unop(ctx, UnaryOp::F64x2Neg), @@ -1131,6 +1137,12 @@ fn append_instruction<'context>( Operator::F64x2Div => binop(ctx, BinaryOp::F64x2Div), Operator::F64x2Min => binop(ctx, BinaryOp::F64x2Min), Operator::F64x2Max => binop(ctx, BinaryOp::F64x2Max), + Operator::F64x2Ceil => unop(ctx, UnaryOp::F64x2Ceil), + Operator::F64x2Floor => unop(ctx, UnaryOp::F64x2Floor), + Operator::F64x2Trunc => unop(ctx, UnaryOp::F64x2Trunc), + Operator::F64x2Nearest => unop(ctx, UnaryOp::F64x2Nearest), + Operator::F64x2PMin => binop(ctx, BinaryOp::F64x2PMin), + Operator::F64x2PMax => binop(ctx, BinaryOp::F64x2PMax), Operator::I32x4TruncSatF32x4S => unop(ctx, UnaryOp::I32x4TruncSatF32x4S), Operator::I32x4TruncSatF32x4U => unop(ctx, UnaryOp::I32x4TruncSatF32x4U), @@ -1146,10 +1158,12 @@ fn append_instruction<'context>( Operator::I64TruncSatF64S => unop(ctx, UnaryOp::I64TruncSSatF64), Operator::I64TruncSatF64U => unop(ctx, UnaryOp::I64TruncUSatF64), - Operator::V8x16LoadSplat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat8), - Operator::V16x8LoadSplat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat16), - Operator::V32x4LoadSplat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat32), - Operator::V64x2LoadSplat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat64), + Operator::V128Load8Splat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat8), + Operator::V128Load16Splat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat16), + Operator::V128Load32Splat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat32), + Operator::V128Load64Splat { memarg } => load_simd(ctx, memarg, LoadSimdKind::Splat64), + Operator::V128Load32Zero { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load32Zero), + Operator::V128Load64Zero { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load64Zero), Operator::I8x16NarrowI16x8S => binop(ctx, BinaryOp::I8x16NarrowI16x8S), Operator::I8x16NarrowI16x8U => binop(ctx, BinaryOp::I8x16NarrowI16x8U), @@ -1163,12 +1177,12 @@ fn append_instruction<'context>( Operator::I32x4WidenLowI16x8U => unop(ctx, UnaryOp::I32x4WidenLowI16x8U), Operator::I32x4WidenHighI16x8S => unop(ctx, UnaryOp::I32x4WidenHighI16x8S), Operator::I32x4WidenHighI16x8U => unop(ctx, UnaryOp::I32x4WidenHighI16x8U), - Operator::I16x8Load8x8S { memarg } => load_simd(ctx, memarg, LoadSimdKind::I16x8Load8x8S), - Operator::I16x8Load8x8U { memarg } => load_simd(ctx, memarg, LoadSimdKind::I16x8Load8x8U), - Operator::I32x4Load16x4S { memarg } => load_simd(ctx, memarg, LoadSimdKind::I32x4Load16x4S), - Operator::I32x4Load16x4U { memarg } => load_simd(ctx, memarg, LoadSimdKind::I32x4Load16x4U), - Operator::I64x2Load32x2S { memarg } => load_simd(ctx, memarg, LoadSimdKind::I64x2Load32x2S), - Operator::I64x2Load32x2U { memarg } => load_simd(ctx, memarg, LoadSimdKind::I64x2Load32x2U), + Operator::V128Load8x8S { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load8x8S), + Operator::V128Load8x8U { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load8x8U), + Operator::V128Load16x4S { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load16x4S), + Operator::V128Load16x4U { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load16x4U), + Operator::V128Load32x2S { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load32x2S), + Operator::V128Load32x2U { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load32x2U), Operator::I8x16RoundingAverageU => binop(ctx, BinaryOp::I8x16RoundingAverageU), Operator::I16x8RoundingAverageU => binop(ctx, BinaryOp::I16x8RoundingAverageU), @@ -1189,6 +1203,8 @@ fn append_instruction<'context>( Operator::I16x8Bitmask => unop(ctx, UnaryOp::I16x8Bitmask), Operator::I32x4Bitmask => unop(ctx, UnaryOp::I32x4Bitmask), + Operator::I32x4DotI16x8S => binop(ctx, BinaryOp::I32x4DotI16x8S), + Operator::TableCopy { src_table, dst_table, diff --git a/src/module/mod.rs b/src/module/mod.rs index 5eb0ea1b..ad57f96f 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -265,11 +265,6 @@ impl Module { ret.producers .add_processed_by("walrus", env!("CARGO_PKG_VERSION")); - // TODO: probably run this in a different location - if !ret.config.skip_strict_validate { - crate::passes::validate::run(&ret)?; - } - if let Some(on_parse) = &config.on_parse { on_parse(&mut ret, &indices)?; } diff --git a/src/passes/mod.rs b/src/passes/mod.rs index 43f5c1aa..a99ecc17 100644 --- a/src/passes/mod.rs +++ b/src/passes/mod.rs @@ -2,5 +2,4 @@ pub mod gc; mod used; -pub mod validate; pub use self::used::Roots; diff --git a/src/passes/validate.rs b/src/passes/validate.rs deleted file mode 100644 index 4ebe9811..00000000 --- a/src/passes/validate.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! Validation of a wasm module -//! -//! Currently only does some basic sanity checks, but it's intended that -//! eventually this is a full typechecking pass! - -use crate::ir::*; -use crate::ValType; -use crate::{ElementKind, Function, FunctionId, FunctionKind, InitExpr, Result}; -use crate::{Global, GlobalKind, Memory, MemoryId, Module, Table}; -use anyhow::{anyhow, bail, Context}; -use std::collections::HashSet; - -#[cfg(feature = "parallel")] -use rayon::prelude::*; - -/// Validate a wasm module, returning an error if it fails to validate. -pub fn run(module: &Module) -> Result<()> { - log::debug!("validating module"); - - if module.config.only_stable_features { - if module.tables.iter().count() > 1 { - bail!("multiple tables not allowed in the wasm spec yet"); - } - if module.memories.iter().count() > 1 { - bail!("multiple memories not allowed in the wasm spec yet"); - } - } - - for memory in module.memories.iter() { - validate_memory(memory)?; - } - for table in module.tables.iter() { - validate_table(table)?; - } - let mut defined_funcs = HashSet::new(); - for element in module.elements.iter() { - if let ElementKind::Declared = element.kind { - defined_funcs.extend(element.members.iter().cloned().filter_map(|x| x)); - } - } - for global in module.globals.iter() { - validate_global(module, global, &defined_funcs)?; - } - validate_exports(module)?; - - // Validate the start function, if present, has the correct signature - if let Some(start) = module.start { - let ty = module.funcs.get(start).ty(); - let ty = module.types.get(ty); - if ty.results().len() > 0 || ty.params().len() > 0 { - bail!("start function must take no arguments and return nothing"); - } - } - - // Validate each function in the module, collecting errors and returning - // them all at once if there are any. - let funcs = &module.funcs; - let errs = maybe_parallel!(funcs.(iter | par_iter)) - .map(|function| { - let mut errs = Vec::new(); - let local = match &function.kind { - FunctionKind::Local(local) => local, - _ => return Vec::new(), - }; - let mut cx = Validate { - errs: &mut errs, - function, - module, - defined_funcs: &defined_funcs, - }; - dfs_in_order(&mut cx, local, local.entry_block()); - errs - }) - .collect::>(); - if errs.iter().all(|e| e.is_empty()) { - return Ok(()); - } - - let mut msg = format!("errors validating module:\n"); - for error in errs.into_iter().flat_map(|v| v) { - msg.push_str(&format!(" * {}\n", error)); - for cause in error.chain() { - msg.push_str(&format!(" * {}\n", cause)); - } - } - bail!("{}", msg) -} - -fn validate_memory(m: &Memory) -> Result<()> { - if m.shared && m.maximum.is_none() { - bail!("shared memories must have a maximum size"); - } - validate_limits(m.initial, m.maximum, u32::from(u16::max_value()) + 1) - .context("when validating a memory")?; - Ok(()) -} - -fn validate_table(t: &Table) -> Result<()> { - validate_limits(t.initial, t.maximum, u32::max_value()).context("when validating a table")?; - Ok(()) -} - -fn validate_limits(initial: u32, maximum: Option, k: u32) -> Result<()> { - match (initial, maximum) { - (min, Some(max)) if max < min || max > k => { - bail!("invalid limits: min = {}, max = {}; k = {}", min, max, k) - } - (min, _) => { - if min <= k { - Ok(()) - } else { - bail!("invalid limits: min = {}, k = {}", min, k) - } - } - } -} - -fn validate_exports(module: &Module) -> Result<()> { - // All exported names must be unique, so if there's any duplicate-named - // exports then we generate an error - let mut exports = HashSet::new(); - for export in module.exports.iter() { - if !exports.insert(&export.name) { - bail!("duplicate export of `{}`", export.name) - } - } - Ok(()) -} - -fn validate_global( - module: &Module, - global: &Global, - defined_funcs: &HashSet, -) -> Result<()> { - match global.kind { - GlobalKind::Import(_) => return Ok(()), - GlobalKind::Local(InitExpr::Value(value)) => { - validate_value(value, global.ty).context("invalid type on global")?; - } - GlobalKind::Local(InitExpr::Global(other)) => { - let other = module.globals.get(other); - match other.kind { - GlobalKind::Import(_) => {} - GlobalKind::Local(_) => { - bail!("initializer for local global must be imported global"); - } - } - if other.ty != global.ty { - bail!("locally defined global does not match type of import"); - } - } - GlobalKind::Local(InitExpr::RefNull(ty)) => { - if global.ty != ty { - bail!("invalid type on global"); - } - } - GlobalKind::Local(InitExpr::RefFunc(idx)) => { - if ValType::Funcref != global.ty { - bail!("invalid type on global"); - } - if !defined_funcs.contains(&idx) { - bail!("referenced function in global not declared in element segment"); - } - } - } - Ok(()) -} - -fn validate_value(value: Value, ty: ValType) -> Result<()> { - match (value, ty) { - (Value::I32(_), ValType::I32) => {} - (Value::I64(_), ValType::I64) => {} - (Value::F32(_), ValType::F32) => {} - (Value::F64(_), ValType::F64) => {} - (Value::V128(_), ValType::V128) => {} - _ => bail!("mismatched types in value"), - } - Ok(()) -} - -struct Validate<'a> { - errs: &'a mut Vec, - function: &'a Function, - module: &'a Module, - defined_funcs: &'a HashSet, -} - -impl Validate<'_> { - fn memarg(&mut self, arg: &MemArg, width: u32) { - // The alignment of a memory operation must be less than or equal to the - // width of the memory operation, currently wasm doesn't allow - // over-aligned memory ops. - if arg.align > width { - self.err("memory operation with alignment greater than natural size"); - } - } - - fn require_shared(&mut self, m: MemoryId) { - let mem = self.module.memories.get(m); - if !mem.shared { - self.err("atomic operations require a shared memory"); - } - } - - fn require_atomic(&mut self, m: MemoryId, arg: &MemArg, width: u32) { - self.require_shared(m); - if arg.align != width { - self.err("alignment for atomics must be same as natural width"); - } - } - - fn err(&mut self, msg: &str) { - let mut err = anyhow!("{}", msg); - if let Some(name) = &self.function.name { - err = err.context(format!("in function {}", name)).into(); - } - self.errs.push(err); - } -} - -impl<'a> Visitor<'a> for Validate<'a> { - fn visit_load(&mut self, e: &Load) { - if e.kind.atomic() { - self.require_atomic(e.memory, &e.arg, e.kind.width()); - } else { - self.memarg(&e.arg, e.kind.width()); - } - } - - fn visit_store(&mut self, e: &Store) { - if e.kind.atomic() { - self.require_atomic(e.memory, &e.arg, e.kind.width()); - } else { - self.memarg(&e.arg, e.kind.width()); - } - } - - fn visit_atomic_rmw(&mut self, e: &AtomicRmw) { - self.require_atomic(e.memory, &e.arg, e.width.bytes()); - } - - fn visit_cmpxchg(&mut self, e: &Cmpxchg) { - self.require_atomic(e.memory, &e.arg, e.width.bytes()); - } - - fn visit_atomic_notify(&mut self, e: &AtomicNotify) { - self.require_shared(e.memory); - // TODO: should alignment or things be validated? - } - - fn visit_atomic_wait(&mut self, e: &AtomicWait) { - let width = if e.sixty_four { 8 } else { 4 }; - self.require_atomic(e.memory, &e.arg, width); - } - - fn visit_global_set(&mut self, e: &GlobalSet) { - if !self.module.globals.get(e.global).mutable { - self.err("cannot mutate immutable global"); - } - } - - fn visit_ref_func(&mut self, e: &RefFunc) { - if !self.defined_funcs.contains(&e.func) { - self.err("referenced function not declared in element segment"); - } - } -}