From bd95bf59a50c4a8e3340cae7518afb97b91547ff Mon Sep 17 00:00:00 2001 From: Nerry <108566+neri@users.noreply.github.com> Date: Wed, 7 Feb 2024 01:07:55 +0900 Subject: [PATCH] Update --- Cargo.toml | 8 +- src/cg/intcode.rs | 2 - src/cg/intr.rs | 10 -- src/cg/mod.rs | 4 +- src/tests.rs | 106 ++++++++++++++- src/wasm.rs | 5 +- test/tester.wasm | Bin 4511 -> 5211 bytes test/tester.wat | 329 +++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 435 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 08e75b7..a52ed08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,12 +12,12 @@ default = [] # float = [] [dependencies] -bitflags = { version = "2.4.2", default-features = false } -num-traits = { version = "0.2.17", default-features = false } -smallvec = { version = "1.10.0", default-features = false } +bitflags = {version = "2.4.2", default-features = false} libm = {} +num-traits = {version = "0.2.17", default-features = false} +smallvec = {version = "1.10.0", default-features = false} [workspace] members = [ - "cli", + "cli", ] diff --git a/src/cg/intcode.rs b/src/cg/intcode.rs index 5de7c49..a3e5bd3 100644 --- a/src/cg/intcode.rs +++ b/src/cg/intcode.rs @@ -231,7 +231,6 @@ pub enum WasmImInstruction { FusedI64SetConst(LocalVarIndex, i64), FusedI32AddI(i32), - FusedI32SubI(i32), FusedI32AndI(u32), FusedI32OrI(u32), FusedI32XorI(u32), @@ -240,7 +239,6 @@ pub enum WasmImInstruction { FusedI32ShrUI(u32), FusedI64AddI(i64), - FusedI64SubI(i64), FusedI64AndI(u64), FusedI64OrI(u64), FusedI64XorI(u64), diff --git a/src/cg/intr.rs b/src/cg/intr.rs index c8c33e5..ecd9cf0 100644 --- a/src/cg/intr.rs +++ b/src/cg/intr.rs @@ -1211,11 +1211,6 @@ impl WasmInterpreter<'_> { lhs.map_i32(|lhs| lhs.wrapping_add(val)); }); } - WasmImInstruction::FusedI32SubI(val) => { - Self::unary_op(code, &mut value_stack, |lhs| unsafe { - lhs.map_i32(|lhs| lhs.wrapping_sub(val)); - }); - } WasmImInstruction::FusedI32AndI(val) => { Self::unary_op(code, &mut value_stack, |lhs| unsafe { lhs.map_u32(|lhs| lhs & val); @@ -1252,11 +1247,6 @@ impl WasmInterpreter<'_> { lhs.map_i64(|lhs| lhs.wrapping_add(val)); }); } - WasmImInstruction::FusedI64SubI(val) => { - Self::unary_op(code, &mut value_stack, |lhs| unsafe { - lhs.map_i64(|lhs| lhs.wrapping_sub(val)); - }); - } WasmImInstruction::FusedI64AndI(val) => { Self::unary_op(code, &mut value_stack, |lhs| unsafe { lhs.map_u64(|lhs| lhs & val); diff --git a/src/cg/mod.rs b/src/cg/mod.rs index c5b4dce..6afea4e 100644 --- a/src/cg/mod.rs +++ b/src/cg/mod.rs @@ -1421,7 +1421,7 @@ impl WasmCodeBlock { fused2!(int_codes, i, FusedI32AddI(*val)); } (I32Const(val), I32Sub) => { - fused2!(int_codes, i, FusedI32SubI(*val)); + fused2!(int_codes, i, FusedI32AddI(0i32.wrapping_sub(*val))); } (I32Const(val), I32And) => { fused2!(int_codes, i, FusedI32AndI(*val as u32)); @@ -1449,7 +1449,7 @@ impl WasmCodeBlock { fused2!(int_codes, i, FusedI64AddI(*val)); } (I64Const(val), I64Sub) => { - fused2!(int_codes, i, FusedI64SubI(*val)); + fused2!(int_codes, i, FusedI64AddI(0i64.wrapping_sub(*val))); } (I64Const(val), I64And) => { fused2!(int_codes, i, FusedI64AndI(*val as u64)); diff --git a/src/tests.rs b/src/tests.rs index 8bf0d44..9cf94dd 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -964,6 +964,54 @@ fn opr_test_i32() { assert_eq!(memory.read_u32(0x74), 0xCCCCCCCC); assert_eq!(memory.read_u64(0x78), 0xCCCC_CCCC_CCCC_CCCC); } + + for val in [ + 0i32, + 1, + -1, + 0x1234_5678, + 0x5555_5555, + 0xAAAA_AAAAu32 as i32, + 0x0000_FFFF, + 0xFFFF_0000u32 as i32, + ] { + memory.fill(0xCC); + let result = instance + .function("test_fused_i32") + .unwrap() + .invoke(&[val.into()]) + .unwrap() + .unwrap() + .get_i32() + .unwrap(); + assert_eq!(result, 0x4C); + + assert_eq!(memory.read_u64(0), 0xCCCC_CCCC_CCCC_CCCC); + assert_eq!(memory.read_u64(8), 0xCCCC_CCCC_CCCC_CCCC); + + let valu = val as u32; + assert_eq!(memory.read_i32(0x10), 0x12345678); + assert_eq!(memory.read_i32(0x14), val.wrapping_add(1234)); + assert_eq!(memory.read_i32(0x18), val.wrapping_sub(1234)); + assert_eq!(memory.read_i32(0x1C), val.wrapping_add(5678)); + + assert_eq!(memory.read_u32(0x20), valu & 0x5555_5555); + assert_eq!(memory.read_u32(0x24), valu & 0xaaaa_aaaa); + assert_eq!(memory.read_u32(0x28), valu | 0x5555_5555); + assert_eq!(memory.read_u32(0x2C), valu | 0xaaaa_aaaa); + assert_eq!(memory.read_u32(0x30), valu ^ 0x5555_5555); + assert_eq!(memory.read_u32(0x34), valu ^ 0xaaaa_aaaa); + + assert_eq!(memory.read_u32(0x38), valu.wrapping_shl(7)); + assert_eq!(memory.read_u32(0x3C), valu.wrapping_shl(19)); + assert_eq!(memory.read_i32(0x40), val.wrapping_shr(5)); + assert_eq!(memory.read_i32(0x44), val.wrapping_shr(17)); + assert_eq!(memory.read_u32(0x48), valu.wrapping_shr(3)); + assert_eq!(memory.read_u32(0x4C), valu.wrapping_shr(13)); + + assert_eq!(memory.read_u64(0x50), 0xCCCC_CCCC_CCCC_CCCC); + assert_eq!(memory.read_u64(0x58), 0xCCCC_CCCC_CCCC_CCCC); + } } #[test] @@ -1072,6 +1120,54 @@ fn opr_test_i64() { assert_eq!(memory.read_u64(0xB0), 0xCCCC_CCCC_CCCC_CCCC); } + + for val in [ + 0i64, + 1, + -1, + 0x1234_5678_ABCD_DEF0, + 0x5555_5555_5555_5555, + 0xAAAA_AAAA_AAAA_AAAAu64 as i64, + 0x0000_0000_FFFF_FFFF, + 0xFFFF_FFFF_0000_0000u64 as i64, + ] { + memory.fill(0xCC); + let result = instance + .function("test_fused_i64") + .unwrap() + .invoke(&[val.into()]) + .unwrap() + .unwrap() + .get_i32() + .unwrap(); + assert_eq!(result, 0x88); + + assert_eq!(memory.read_u64(0), 0xCCCC_CCCC_CCCC_CCCC); + assert_eq!(memory.read_u64(8), 0xCCCC_CCCC_CCCC_CCCC); + + let valu = val as u64; + assert_eq!(memory.read_i64(0x10), 0x12345678); + assert_eq!(memory.read_i64(0x18), val.wrapping_add(12345678)); + assert_eq!(memory.read_i64(0x20), val.wrapping_sub(12345678)); + assert_eq!(memory.read_i64(0x28), val.wrapping_add(987654321)); + + assert_eq!(memory.read_u64(0x30), valu & 0x5555_5555_5555_5555); + assert_eq!(memory.read_u64(0x38), valu & 0xaaaa_aaaa_aaaa_aaaa); + assert_eq!(memory.read_u64(0x40), valu | 0x5555_5555_5555_5555); + assert_eq!(memory.read_u64(0x48), valu | 0xaaaa_aaaa_aaaa_aaaa); + assert_eq!(memory.read_u64(0x50), valu ^ 0x5555_5555_5555_5555); + assert_eq!(memory.read_u64(0x58), valu ^ 0xaaaa_aaaa_aaaa_aaaa); + + assert_eq!(memory.read_u64(0x60), valu.wrapping_shl(7)); + assert_eq!(memory.read_u64(0x68), valu.wrapping_shl(19)); + assert_eq!(memory.read_i64(0x70), val.wrapping_shr(5)); + assert_eq!(memory.read_i64(0x78), val.wrapping_shr(17)); + assert_eq!(memory.read_u64(0x80), valu.wrapping_shr(3)); + assert_eq!(memory.read_u64(0x88), valu.wrapping_shr(13)); + + assert_eq!(memory.read_u64(0x90), 0xCCCC_CCCC_CCCC_CCCC); + assert_eq!(memory.read_u64(0x98), 0xCCCC_CCCC_CCCC_CCCC); + } } #[test] @@ -1183,16 +1279,16 @@ fn call_indirect_test() { // let memory = instance.memory(0).unwrap().try_borrow().unwrap(); - for a1 in [0u32, 0x12345678, 0x55555555, 0xAAAAAAAA] { + for a1 in [0i32, 0x12345678, 0x55555555, 0xAAAAAAAAu32 as i32] { for i in 1..=3 { - let base = [0, 123, 456, 789][i as usize]; + let base = [0i32, 123, -456, 789][i as usize]; let result = instance .function("call_indirect_test") .unwrap() - .invoke(&[i.into(), a1.into()]) + .invoke(&[(i as i32).into(), a1.into()]) .unwrap() .unwrap() - .get_u32() + .get_i32() .unwrap(); assert_eq!(result, a1.wrapping_add(base)); } @@ -1200,7 +1296,7 @@ fn call_indirect_test() { let e = instance .function("call_indirect_test") .unwrap() - .invoke(&[0.into(), a1.into()]) + .invoke(&[4.into(), a1.into()]) .unwrap_err(); assert_matches!(e.kind(), WasmRuntimeErrorKind::TypeMismatch); diff --git a/src/wasm.rs b/src/wasm.rs index 4b2e1aa..c193d24 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -631,7 +631,6 @@ impl WasmInstance { } #[inline] - #[allow(dead_code)] pub fn function(&self, name: &str) -> Result { for export in &self.module.exports { if let WasmExportDesc::Function(index) = export.desc { @@ -640,7 +639,7 @@ impl WasmInstance { .module .functions .get(index) - .map(|v| WasmRunnable::from_function(v, self)) + .map(|v| WasmRunnable::new(v, self)) .ok_or(WasmRuntimeErrorKind::NoMethod); } } @@ -2360,7 +2359,7 @@ pub struct WasmRunnable<'a> { impl<'a> WasmRunnable<'a> { #[inline] - const fn from_function(function: &'a WasmFunction, instance: &'a WasmInstance) -> Self { + const fn new(function: &'a WasmFunction, instance: &'a WasmInstance) -> Self { Self { function, instance } } } diff --git a/test/tester.wasm b/test/tester.wasm index 4b8d169d237bda498de72ddce1d27a8781885377..36f72388fe24423f8a3f4e6de5670579ece38bff 100644 GIT binary patch delta 844 zcmbQQd|P8e8ENWfWyb>+@X)GH5ekbC?Xp#{=8PtjH(Lc zH85moMo|kBUR94Oj!@r%Lp`cELVYV(eLc*<2n!$*Fmd)a6mx}9xvcFdvVy2w<_;8D zUI>?);VUOgUSe)4;~N&e&98a9nN&~{tFe(TTHP zjNHtcTH0K*gtazjGk0>zIG$iuV94U;U~rtu24XPm i32 (func $local_test (export "local_test") (result i32) @@ -1535,9 +1535,9 @@ ) (func $elem2 (param $a0 i32) (result i32) - i32.const 456 local.get $a0 - i32.add + i32.const 456 + i32.sub ) (func $elem3 (param $a0 i32) (result i32) @@ -1545,4 +1545,327 @@ local.get $a0 i32.add ) + + ;; fn test_fused_i32(a0: i32) -> i32 + (func $test_fused_i32 (export "test_fused_i32") (param $a0 i32) (result i32) + (local $p i32) + (local $i i32) + + ;; i32.const N; local.set -> FusedI32SetConst + i32.const 0x10 + local.tee $p + i32.const 0x12345678 + local.set $i + i64.const 0xcccccccc + drop + local.get $i + i32.store + + ;; i32.const N; i32.add -> FusedI32AddI + ;; i32.const N; i32.sub -> FusedI32AddI (sign reversed) + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 1234 + i32.add + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 1234 + i32.sub + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 5678 + i32.add + i32.store + + ;; i32.const N; i32.and -> FusedI32AndI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0x55555555 + i32.and + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0xaaaaaaaa + i32.and + i32.store + + ;; i32.const N; i32.or -> FusedI32OrI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0x55555555 + i32.or + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0xaaaaaaaa + i32.or + i32.store + + ;; i32.const N; i32.xor -> FusedI32XorI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0x55555555 + i32.xor + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 0xaaaaaaaa + i32.xor + i32.store + + ;; i32.const N; i32.shl -> FusedI32ShlI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 7 + i32.shl + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 19 + i32.shl + i32.store + + ;; i32.const N; i32.shr_s -> FusedI32ShrSI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 5 + i32.shr_s + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 17 + i32.shr_s + i32.store + + ;; i32.const N; i32.shr_s -> FusedI32ShrUI + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 3 + i32.shr_u + i32.store + + local.get $p + i32.const 4 + i32.add + local.tee $p + local.get $a0 + i32.const 13 + i32.shr_u + i32.store + + local.get $p + ) + + ;; fn test_fused_i64(a0: i64) -> i32 + (func $test_fused_i64 (export "test_fused_i64") (param $a0 i64) (result i32) + (local $p i32) + (local $l i64) + + ;; i64.const N; local.set -> FusedI64SetConst + i32.const 0x10 + local.tee $p + i64.const 0x12345678 + local.set $l + i64.const 0xcccccccc + drop + local.get $l + i64.store + + ;; i64.const N; i64.add -> FusedI64AddI + ;; i64.const N; i64.sub -> FusedI64AddI (sign reversed) + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 12345678 + i64.add + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 12345678 + i64.sub + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 987654321 + i64.add + i64.store + + ;; i64.const N; i64.and -> FusedI64AndI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0x5555555555555555 + i64.and + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0xaaaaaaaaaaaaaaaa + i64.and + i64.store + + ;; i64.const N; i64.or -> FusedI64OrI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0x5555555555555555 + i64.or + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0xaaaaaaaaaaaaaaaa + i64.or + i64.store + + ;; i64.const N; i64.xor -> FusedI64XorI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0x5555555555555555 + i64.xor + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 0xaaaaaaaaaaaaaaaa + i64.xor + i64.store + + ;; i64.const N; i64.shl -> FusedI64ShlI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 7 + i64.shl + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 19 + i64.shl + i64.store + + ;; i64.const N; i64.shr_s -> FusedI64ShrSI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 5 + i64.shr_s + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 17 + i64.shr_s + i64.store + + ;; i64.const N; i64.shr_s -> FusedI64ShrUI + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 3 + i64.shr_u + i64.store + + local.get $p + i32.const 8 + i32.add + local.tee $p + local.get $a0 + i64.const 13 + i64.shr_u + i64.store + + local.get $p + ) + )