diff options
36 files changed, 105 insertions, 162 deletions
@@ -298,7 +298,7 @@ def run_spec_tests(): if len(requested) == 0: # FIXME we support old and new memory formats, for now, until 0xc, and so can't pass this old-style test. - BLACKLIST = ['memory.wast', 'binary.wast'] + BLACKLIST = ['binary.wast'] # FIXME to update the spec to 0xd, we need to implement (register "name") for import.wast spec_tests = [os.path.join('spec', t) for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'spec'))) if t not in BLACKLIST] else: diff --git a/src/ir/memory-utils.h b/src/ir/memory-utils.h index 5980a3218..c8f39a2ec 100644 --- a/src/ir/memory-utils.h +++ b/src/ir/memory-utils.h @@ -48,6 +48,14 @@ namespace MemoryUtils { memory.segments[0].data.swap(data); return true; } + + // Ensures that the memory exists (of minimal size). + inline void ensureExists(Memory& memory) { + if (!memory.exists) { + memory.exists = true; + memory.initial = memory.max = 1; + } + } }; } // namespace wasm diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index 4575dd2f8..ae69ec19d 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -27,6 +27,7 @@ #include "emscripten-optimizer/istring.h" #include "support/name.h" #include "wasm-builder.h" +#include "ir/memory-utils.h" #include "ir/module-utils.h" #include "ir/names.h" #include "asmjs/shared-constants.h" @@ -608,6 +609,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ); setOutParam(result, std::move(highBits)); replaceCurrent(result); + ensureMinimalMemory(); } void lowerReinterpretInt64(Unary* curr) { @@ -620,6 +622,13 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { builder->makeLoad(8, true, 0, 8, builder->makeConst(Literal(int32_t(0))), f64) ); replaceCurrent(result); + ensureMinimalMemory(); + } + + // Ensure memory exists with a minimal size, enough for round-tripping operations on + // address 0, which we need for reinterpret operations. + void ensureMinimalMemory() { + MemoryUtils::ensureExists(getModule()->memory); } void lowerTruncFloatToInt(Unary *curr) { diff --git a/src/passes/RemoveNonJSOps.cpp b/src/passes/RemoveNonJSOps.cpp index cc9a40a1f..342f59eba 100644 --- a/src/passes/RemoveNonJSOps.cpp +++ b/src/passes/RemoveNonJSOps.cpp @@ -33,6 +33,7 @@ #include "asmjs/shared-constants.h" #include "wasm-builder.h" #include "wasm-s-parser.h" +#include "ir/memory-utils.h" #include "ir/module-utils.h" #include "ir/find_all.h" #include "passes/intrinsics-module.h" @@ -97,6 +98,9 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> { } neededFunctions.clear(); } + + // Intrinsics may use memory, so ensure the module has one. + MemoryUtils::ensureExists(module->memory); } void addNeededFunctions(Module &m, Name name, std::set<Name> &needed) { diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 6aa0764f1..b17be8afe 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -29,6 +29,7 @@ high chance for set at start of loop #include <ir/find_all.h> #include <ir/literal-utils.h> #include <ir/manipulation.h> +#include "ir/memory-utils.h" #include <ir/utils.h> namespace wasm { @@ -254,9 +255,7 @@ private: } void setupMemory() { - wasm.memory.exists = true; - // use one page - wasm.memory.initial = wasm.memory.max = 1; + MemoryUtils::ensureExists(wasm.memory); // init some data wasm.memory.segments.emplace_back(builder.makeConst(Literal(int32_t(0)))); auto num = upTo(USABLE_MEMORY * 2); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 6d4490982..79c1d4f9b 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -512,6 +512,7 @@ void FunctionValidator::visitSetGlobal(SetGlobal* curr) { } void FunctionValidator::visitLoad(Load* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); if (curr->isAtomic) { shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeTrue(curr->type == i32 || curr->type == i64 || curr->type == unreachable, curr, "Atomic load should be i32 or i64"); @@ -528,6 +529,7 @@ void FunctionValidator::visitLoad(Load* curr) { } void FunctionValidator::visitStore(Store* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); if (curr->isAtomic) { shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeTrue(curr->valueType == i32 || curr->valueType == i64 || curr->valueType == unreachable, curr, "Atomic store should be i32 or i64"); @@ -545,6 +547,7 @@ void FunctionValidator::visitStore(Store* curr) { } void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); @@ -554,6 +557,7 @@ void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { } void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); @@ -567,6 +571,7 @@ void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { } void FunctionValidator::visitAtomicWait(AtomicWait* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicWait must have type i32"); @@ -577,6 +582,7 @@ void FunctionValidator::visitAtomicWait(AtomicWait* curr) { } void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicNotify must have type i32"); @@ -647,6 +653,7 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) { } void FunctionValidator::visitMemoryInit(MemoryInit* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.init must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.init dest must be an i32"); @@ -656,12 +663,14 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) { } void FunctionValidator::visitDataDrop(DataDrop* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "data.drop must have type none"); shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "data.drop segment index out of bounds"); } void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.copy must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.copy dest must be an i32"); @@ -670,6 +679,7 @@ void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { } void FunctionValidator::visitMemoryFill(MemoryFill* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.fill must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.fill dest must be an i32"); @@ -1289,6 +1299,7 @@ static void validateGlobals(Module& module, ValidationInfo& info) { static void validateMemory(Module& module, ValidationInfo& info) { auto& curr = module.memory; info.shouldBeFalse(curr.initial > curr.max, "memory", "memory max >= initial"); + info.shouldBeTrue(curr.initial <= Memory::kMaxSize, "memory", "initial memory must be <= 4GB"); info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize, "memory", "max memory must be <= 4GB, or unlimited"); info.shouldBeTrue(!curr.shared || curr.hasMax(), "memory", "shared memory must have max size"); if (curr.shared) info.shouldBeTrue(info.features.hasAtomics(), "memory", "memory is shared, but atomics are disabled"); diff --git a/test/passes/code-pushing_ignore-implicit-traps.txt b/test/passes/code-pushing_ignore-implicit-traps.txt index 95b6edb52..f21915829 100644 --- a/test/passes/code-pushing_ignore-implicit-traps.txt +++ b/test/passes/code-pushing_ignore-implicit-traps.txt @@ -1,6 +1,7 @@ (module (type $0 (func)) (type $1 (func (result i32))) + (memory $0 1) (func $push1 (; 0 ;) (type $0) (local $x i32) (block $out diff --git a/test/passes/code-pushing_ignore-implicit-traps.wast b/test/passes/code-pushing_ignore-implicit-traps.wast index a091608c1..3f70c24a6 100644 --- a/test/passes/code-pushing_ignore-implicit-traps.wast +++ b/test/passes/code-pushing_ignore-implicit-traps.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func $push1 (local $x i32) (block $out diff --git a/test/passes/flatten_rereloop.txt b/test/passes/flatten_rereloop.txt index c60bbf006..162336420 100644 --- a/test/passes/flatten_rereloop.txt +++ b/test/passes/flatten_rereloop.txt @@ -5,6 +5,7 @@ (type $3 (func (param i32))) (type $4 (func (param i32) (result f32))) (type $5 (func (result f32))) + (memory $0 1) (global $global (mut i32) (i32.const 0)) (func $0 (; 0 ;) (type $0) (result f64) (local $0 f64) diff --git a/test/passes/flatten_rereloop.wast b/test/passes/flatten_rereloop.wast index e8259885e..5ff0e9960 100644 --- a/test/passes/flatten_rereloop.wast +++ b/test/passes/flatten_rereloop.wast @@ -1,4 +1,5 @@ (module + (memory 1) (global $global (mut i32) (i32.const 0)) (func $0 (result f64) (if diff --git a/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast b/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast index b301608ca..0de6200c7 100644 --- a/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast +++ b/test/passes/flatten_simplify-locals-nonesting_dfo_O3.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func "if-select" (local $var$0 i32) (nop) diff --git a/test/passes/licm.txt b/test/passes/licm.txt index 032b88462..2db8aac32 100644 --- a/test/passes/licm.txt +++ b/test/passes/licm.txt @@ -4,6 +4,7 @@ (type $2 (func (result i64))) (type $3 (func (param i32))) (type $4 (func (param i32) (result i32))) + (memory $0 1) (global $glob (mut i32) (i32.const 1)) (func $loop1 (; 0 ;) (type $0) (drop diff --git a/test/passes/licm.wast b/test/passes/licm.wast index ad88c3e92..14d97afd9 100644 --- a/test/passes/licm.wast +++ b/test/passes/licm.wast @@ -1,4 +1,5 @@ (module + (memory 1) (global $glob (mut i32) (i32.const 1)) (func $loop1 (loop $loop diff --git a/test/passes/optimize-added-constants-propagate_low-memory-unused.txt b/test/passes/optimize-added-constants-propagate_low-memory-unused.txt index 3e2ec5b9d..3d6a644e9 100644 --- a/test/passes/optimize-added-constants-propagate_low-memory-unused.txt +++ b/test/passes/optimize-added-constants-propagate_low-memory-unused.txt @@ -2,6 +2,7 @@ (type $0 (func)) (type $1 (func (param i32))) (type $2 (func (param i32) (result i32))) + (memory $0 1 1) (func $consts (; 0 ;) (type $0) (drop (i32.load diff --git a/test/passes/optimize-added-constants-propagate_low-memory-unused.wast b/test/passes/optimize-added-constants-propagate_low-memory-unused.wast index 0582294c8..d62d487d2 100644 --- a/test/passes/optimize-added-constants-propagate_low-memory-unused.wast +++ b/test/passes/optimize-added-constants-propagate_low-memory-unused.wast @@ -1,4 +1,5 @@ (module + (memory 1 1) (func $consts (drop (i32.load (i32.const 0)) diff --git a/test/passes/optimize-added-constants_low-memory-unused.txt b/test/passes/optimize-added-constants_low-memory-unused.txt index 81f2ba216..174897946 100644 --- a/test/passes/optimize-added-constants_low-memory-unused.txt +++ b/test/passes/optimize-added-constants_low-memory-unused.txt @@ -2,6 +2,7 @@ (type $0 (func)) (type $1 (func (param i32))) (type $2 (func (param i32) (result i32))) + (memory $0 1 1) (func $consts (; 0 ;) (type $0) (drop (i32.load diff --git a/test/passes/optimize-added-constants_low-memory-unused.wast b/test/passes/optimize-added-constants_low-memory-unused.wast index b31f80a25..ac7d77fc4 100644 --- a/test/passes/optimize-added-constants_low-memory-unused.wast +++ b/test/passes/optimize-added-constants_low-memory-unused.wast @@ -1,4 +1,5 @@ (module + (memory 1 1) (func $consts (drop (i32.load (i32.const 0)) diff --git a/test/passes/pick-load-signs.txt b/test/passes/pick-load-signs.txt index d719f11a9..126343b79 100644 --- a/test/passes/pick-load-signs.txt +++ b/test/passes/pick-load-signs.txt @@ -1,6 +1,7 @@ (module (type $0 (func)) (type $1 (func (result i32))) + (memory $0 1) (func $a (; 0 ;) (type $0) (local $y i32) (local.set $y diff --git a/test/passes/pick-load-signs.wast b/test/passes/pick-load-signs.wast index 975d1ac75..3b12c02bf 100644 --- a/test/passes/pick-load-signs.wast +++ b/test/passes/pick-load-signs.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func $a ;; load 8s, but use is 8u, so load should be signed (local $y i32) (local.set $y diff --git a/test/passes/remove-non-js-ops.txt b/test/passes/remove-non-js-ops.txt index cedb062cf..59977b859 100644 --- a/test/passes/remove-non-js-ops.txt +++ b/test/passes/remove-non-js-ops.txt @@ -6,6 +6,7 @@ (type $4 (func (param f64) (result f64))) (type $5 (func (param f32) (result f32))) (type $6 (func (param i32) (result i32))) + (memory $0 1) (func $copysign64 (; 0 ;) (type $0) (param $0 f64) (param $1 f64) (result f64) (f64.reinterpret_i64 (i64.or diff --git a/test/passes/remove-non-js-ops.wast b/test/passes/remove-non-js-ops.wast index de74fe1f4..ef3229e5a 100644 --- a/test/passes/remove-non-js-ops.wast +++ b/test/passes/remove-non-js-ops.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func $copysign64 (param $0 f64) (param $1 f64) (result f64) (f64.copysign (local.get $0) (local.get $1))) (func $copysign32 (param $0 f32) (param $1 f32) (result f32) diff --git a/test/passes/safe-heap_disable-simd.txt b/test/passes/safe-heap_disable-simd.txt index ab7338ea6..d2a109c0d 100644 --- a/test/passes/safe-heap_disable-simd.txt +++ b/test/passes/safe-heap_disable-simd.txt @@ -3,6 +3,7 @@ (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32)) (import "env" "segfault" (func $segfault)) (import "env" "alignfault" (func $alignfault)) + (memory $0 1 1) (func $SAFE_HEAP_LOAD_i32_1_1 (; 2 ;) (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local.set $2 diff --git a/test/passes/safe-heap_disable-simd.wast b/test/passes/safe-heap_disable-simd.wast index 3af8f2545..13f77a0bc 100644 --- a/test/passes/safe-heap_disable-simd.wast +++ b/test/passes/safe-heap_disable-simd.wast @@ -1 +1,3 @@ -(module) +(module + (memory 1 1) +) diff --git a/test/passes/simplify-locals-nostructure.txt b/test/passes/simplify-locals-nostructure.txt index 42ee14a0f..10f1544e1 100644 --- a/test/passes/simplify-locals-nostructure.txt +++ b/test/passes/simplify-locals-nostructure.txt @@ -2,6 +2,7 @@ (type $0 (func)) (type $1 (func (param i32 i32) (result f64))) (type $2 (func (param i32) (result i32))) + (memory $0 1) (func $contrast (; 0 ;) (type $0) (local $x i32) (local $y i32) diff --git a/test/passes/simplify-locals-nostructure.wast b/test/passes/simplify-locals-nostructure.wast index 9c04b753a..4dc6cfb82 100644 --- a/test/passes/simplify-locals-nostructure.wast +++ b/test/passes/simplify-locals-nostructure.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func $contrast ;; check for tee and structure sinking (local $x i32) (local $y i32) diff --git a/test/passes/vacuum.txt b/test/passes/vacuum.txt index 9f106cd89..638aa3bed 100644 --- a/test/passes/vacuum.txt +++ b/test/passes/vacuum.txt @@ -329,6 +329,7 @@ (module (type $0 (func (param i32) (result i32))) (type $1 (func (param i32 i32 i32))) + (memory $0 1 1) (global $global$1 (mut i32) (i32.const 0)) (export "compress" (func $3)) (func $_deflate (; 0 ;) (type $0) (param $0 i32) (result i32) diff --git a/test/passes/vacuum.wast b/test/passes/vacuum.wast index 0e15c76ad..0408277d7 100644 --- a/test/passes/vacuum.wast +++ b/test/passes/vacuum.wast @@ -686,6 +686,7 @@ ) ) (module ;; vacuum away a drop on an if where both arms can be vacuumed + (memory 1 1) (global $global$1 (mut i32) (i32.const 0)) (func $_deflate (param i32) (result i32) (call $_deflate (local.get $0)) diff --git a/test/passes/vacuum_ignore-implicit-traps.txt b/test/passes/vacuum_ignore-implicit-traps.txt index 46db916c8..5df38be47 100644 --- a/test/passes/vacuum_ignore-implicit-traps.txt +++ b/test/passes/vacuum_ignore-implicit-traps.txt @@ -1,6 +1,7 @@ (module (type $0 (func (result i32))) (type $1 (func)) + (memory $0 1) (func $load-would-normally-have-side-effects (; 0 ;) (type $0) (result i32) (i64.ge_s (i64.const 2912825531628789796) diff --git a/test/passes/vacuum_ignore-implicit-traps.wast b/test/passes/vacuum_ignore-implicit-traps.wast index 83ec69c9e..ab958cec7 100644 --- a/test/passes/vacuum_ignore-implicit-traps.wast +++ b/test/passes/vacuum_ignore-implicit-traps.wast @@ -1,4 +1,5 @@ (module + (memory 1) (func $load-would-normally-have-side-effects (result i32) (i64.ge_s (block (result i64) diff --git a/test/simd.wast b/test/simd.wast index 11f0c19a6..572efa0f5 100644 --- a/test/simd.wast +++ b/test/simd.wast @@ -1,4 +1,5 @@ (module + (memory 1 1) (func $v128.load (param $0 i32) (result v128) (v128.load offset=0 align=16 (local.get $0) diff --git a/test/simd.wast.from-wast b/test/simd.wast.from-wast index fe1fd241d..55e97a6f1 100644 --- a/test/simd.wast.from-wast +++ b/test/simd.wast.from-wast @@ -15,6 +15,7 @@ (type $13 (func (param v128 f64) (result v128))) (type $14 (func (param v128) (result v128))) (type $15 (func (param v128 v128 v128) (result v128))) + (memory $0 1 1) (func $v128.load (; 0 ;) (type $0) (param $0 i32) (result v128) (v128.load (local.get $0) diff --git a/test/simd.wast.fromBinary b/test/simd.wast.fromBinary index f3ea3ca91..9d06742dd 100644 --- a/test/simd.wast.fromBinary +++ b/test/simd.wast.fromBinary @@ -15,6 +15,7 @@ (type $13 (func (param v128 f64) (result v128))) (type $14 (func (param v128) (result v128))) (type $15 (func (param v128 v128 v128) (result v128))) + (memory $0 1 1) (func $v128.load (; 0 ;) (type $0) (param $0 i32) (result v128) (v128.load (local.get $0) diff --git a/test/simd.wast.fromBinary.noDebugInfo b/test/simd.wast.fromBinary.noDebugInfo index 75ff49595..9b8cbeef0 100644 --- a/test/simd.wast.fromBinary.noDebugInfo +++ b/test/simd.wast.fromBinary.noDebugInfo @@ -15,6 +15,7 @@ (type $13 (func (param v128 f64) (result v128))) (type $14 (func (param v128) (result v128))) (type $15 (func (param v128 v128 v128) (result v128))) + (memory $0 1 1) (func $0 (; 0 ;) (type $0) (param $0 i32) (result v128) (v128.load (local.get $0) diff --git a/test/spec/memory.wast b/test/spec/memory.wast index bb0226ed2..5f926339b 100644 --- a/test/spec/memory.wast +++ b/test/spec/memory.wast @@ -1,66 +1,39 @@ ;; Test memory section structure + (module (memory 0 0)) (module (memory 0 1)) (module (memory 1 256)) (module (memory 0 65536)) -(module (memory 0 0) (data (i32.const 0))) -(module (memory 0 0) (data (i32.const 0) "")) -(module (memory 1 1) (data (i32.const 0) "a")) -(module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 65535) "b")) -(module (memory 1 2) - (data (i32.const 0) "a") (data (i32.const 1) "b") (data (i32.const 2) "c") -) - -(module (memory (data)) (func (export "memsize") (result i32) (current_memory))) -(assert_return (invoke "memsize") (i32.const 0)) -(module (memory (data "")) (func (export "memsize") (result i32) (current_memory))) -(assert_return (invoke "memsize") (i32.const 0)) -(module (memory (data "x")) (func (export "memsize") (result i32) (current_memory))) -(assert_return (invoke "memsize") (i32.const 1)) (assert_invalid (module (data (i32.const 0))) "unknown memory") (assert_invalid (module (data (i32.const 0) "")) "unknown memory") (assert_invalid (module (data (i32.const 0) "x")) "unknown memory") (assert_invalid - (module (memory 1) (data (i64.const 0))) - "type mismatch" -) -(assert_invalid - (module (memory 1) (data (i32.ctz (i32.const 0)))) - "constant expression required" + (module (func (drop (f32.load (i32.const 0))))) + "unknown memory" ) (assert_invalid - (module (memory 1) (data (nop))) - "constant expression required" + (module (func (f32.store (f32.const 0) (i32.const 0)))) + "unknown memory" ) - (assert_invalid - (module (memory 1 0)) - "memory size minimum must not be greater than maximum" + (module (func (drop (i32.load8_s (i32.const 0))))) + "unknown memory" ) (assert_invalid - (module (memory 0 0) (data (i32.const 0) "a")) - "data segment does not fit" + (module (func (i32.store8 (i32.const 0) (i32.const 0)))) + "unknown memory" ) (assert_invalid - (module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b")) - "data segment does not fit" -) -(assert_invalid - (module (memory 1 2) (data (i32.const 0) "abc") (data (i32.const 0) "def")) - "data segment not disjoint and ordered" -) -(assert_invalid - (module (memory 1 2) (data (i32.const 3) "ab") (data (i32.const 0) "de")) - "data segment not disjoint and ordered" + (module (func (drop (memory.grow (i32.const 0))))) + "unknown memory" ) + + (assert_invalid - (module - (memory 1 2) - (data (i32.const 0) "a") (data (i32.const 2) "b") (data (i32.const 1) "c") - ) - "data segment not disjoint and ordered" + (module (memory 1 0)) + "size minimum must not be greater than maximum" ) (assert_invalid (module (memory 65537)) @@ -87,70 +60,6 @@ "memory size must be at most 65536 pages (4GiB)" ) -;; Test alignment annotation rules -(module (memory 0) (func (drop (i32.load8_u align=1 (i32.const 0))))) -(module (memory 0) (func (drop (i32.load16_u align=2 (i32.const 0))))) -(module (memory 0) (func (drop (i32.load align=4 (i32.const 0))))) -(module (memory 0) (func (drop (f32.load align=4 (i32.const 0))))) - -(assert_invalid - (module (memory 0) (func (drop (i64.load align=0 (i32.const 0))))) - "alignment must be a power of two" -) -(assert_invalid - (module (memory 0) (func (drop (i64.load align=3 (i32.const 0))))) - "alignment must be a power of two" -) -(assert_invalid - (module (memory 0) (func (drop (i64.load align=5 (i32.const 0))))) - "alignment must be a power of two" -) -(assert_invalid - (module (memory 0) (func (drop (i64.load align=6 (i32.const 0))))) - "alignment must be a power of two" -) -(assert_invalid - (module (memory 0) (func (drop (i64.load align=7 (i32.const 0))))) - "alignment must be a power of two" -) - -(assert_invalid - (module (memory 0) (func (drop (i64.load align=16 (i32.const 0))))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (drop (i64.load align=32 (i32.const 0))))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (drop (i32.load align=8 (i32.const 0))))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (drop (i32.load16_u align=4 (i32.const 0))))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (drop (i32.load8_u align=2 (i32.const 0))))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (i32.store8 align=2 (i32.const 0) (i32.const 0)))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (i32.load16_u align=4 (i32.const 0)))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (i32.load8_u align=2 (i32.const 0)))) - "alignment must not be larger than natural" -) -(assert_invalid - (module (memory 0) (func (i32.store8 align=2 (i32.const 0) (i32.const 0)))) - "alignment must not be larger than natural" -) - (module (memory 1) (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM") @@ -181,54 +90,6 @@ ) ) - ;; Aligned read/write - (func (export "aligned") (result i32) - (local i32 i32 i32) - (local.set 0 (i32.const 10)) - (block - (loop - (if - (i32.eq (local.get 0) (i32.const 0)) - (br 2) - ) - (local.set 2 (i32.mul (local.get 0) (i32.const 4))) - (i32.store (local.get 2) (local.get 0)) - (local.set 1 (i32.load (local.get 2))) - (if - (i32.ne (local.get 0) (local.get 1)) - (return (i32.const 0)) - ) - (local.set 0 (i32.sub (local.get 0) (i32.const 1))) - (br 0) - ) - ) - (i32.const 1) - ) - - ;; Unaligned read/write - (func (export "unaligned") (result i32) - (local i32 f64 f64) - (local.set 0 (i32.const 10)) - (block - (loop - (if - (i32.eq (local.get 0) (i32.const 0)) - (br 2) - ) - (local.set 2 (f64.convert_i32_s (local.get 0))) - (f64.store align=1 (local.get 0) (local.get 2)) - (local.set 1 (f64.load align=1 (local.get 0))) - (if - (f64.ne (local.get 2) (local.get 1)) - (return (i32.const 0)) - ) - (local.set 0 (i32.sub (local.get 0) (i32.const 1))) - (br 0) - ) - ) - (i32.const 1) - ) - ;; Memory cast (func (export "cast") (result f64) (i64.store (i32.const 8) (i64.const -12345)) @@ -237,7 +98,7 @@ (f64.load (i32.const 8)) (f64.reinterpret_i64 (i64.const -12345)) ) - (return (f64.const 0)) + (then (return (f64.const 0))) ) (i64.store align=1 (i32.const 9) (i64.const 0)) (i32.store16 align=1 (i32.const 15) (i32.const 16453)) @@ -288,8 +149,6 @@ ) (assert_return (invoke "data") (i32.const 1)) -(assert_return (invoke "aligned") (i32.const 1)) -(assert_return (invoke "unaligned") (i32.const 1)) (assert_return (invoke "cast") (f64.const 42.0)) (assert_return (invoke "i32_load8_s" (i32.const -1)) (i32.const -1)) @@ -302,6 +161,15 @@ (assert_return (invoke "i32_load16_s" (i32.const 20000)) (i32.const 20000)) (assert_return (invoke "i32_load16_u" (i32.const 40000)) (i32.const 40000)) +(assert_return (invoke "i32_load8_s" (i32.const 0xfedc6543)) (i32.const 0x43)) +(assert_return (invoke "i32_load8_s" (i32.const 0x3456cdef)) (i32.const 0xffffffef)) +(assert_return (invoke "i32_load8_u" (i32.const 0xfedc6543)) (i32.const 0x43)) +(assert_return (invoke "i32_load8_u" (i32.const 0x3456cdef)) (i32.const 0xef)) +(assert_return (invoke "i32_load16_s" (i32.const 0xfedc6543)) (i32.const 0x6543)) +(assert_return (invoke "i32_load16_s" (i32.const 0x3456cdef)) (i32.const 0xffffcdef)) +(assert_return (invoke "i32_load16_u" (i32.const 0xfedc6543)) (i32.const 0x6543)) +(assert_return (invoke "i32_load16_u" (i32.const 0x3456cdef)) (i32.const 0xcdef)) + (assert_return (invoke "i64_load8_s" (i64.const -1)) (i64.const -1)) (assert_return (invoke "i64_load8_u" (i64.const -1)) (i64.const 255)) (assert_return (invoke "i64_load16_s" (i64.const -1)) (i64.const -1)) @@ -315,3 +183,16 @@ (assert_return (invoke "i64_load16_u" (i64.const 40000)) (i64.const 40000)) (assert_return (invoke "i64_load32_s" (i64.const 20000)) (i64.const 20000)) (assert_return (invoke "i64_load32_u" (i64.const 40000)) (i64.const 40000)) + +(assert_return (invoke "i64_load8_s" (i64.const 0xfedcba9856346543)) (i64.const 0x43)) +(assert_return (invoke "i64_load8_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffffef)) +(assert_return (invoke "i64_load8_u" (i64.const 0xfedcba9856346543)) (i64.const 0x43)) +(assert_return (invoke "i64_load8_u" (i64.const 0x3456436598bacdef)) (i64.const 0xef)) +(assert_return (invoke "i64_load16_s" (i64.const 0xfedcba9856346543)) (i64.const 0x6543)) +(assert_return (invoke "i64_load16_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffffffffcdef)) +(assert_return (invoke "i64_load16_u" (i64.const 0xfedcba9856346543)) (i64.const 0x6543)) +(assert_return (invoke "i64_load16_u" (i64.const 0x3456436598bacdef)) (i64.const 0xcdef)) +(assert_return (invoke "i64_load32_s" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543)) +(assert_return (invoke "i64_load32_s" (i64.const 0x3456436598bacdef)) (i64.const 0xffffffff98bacdef)) +(assert_return (invoke "i64_load32_u" (i64.const 0xfedcba9856346543)) (i64.const 0x56346543)) +(assert_return (invoke "i64_load32_u" (i64.const 0x3456436598bacdef)) (i64.const 0x98bacdef)) diff --git a/test/unit/test_features.py b/test/unit/test_features.py index 9f9f618b0..f939025e0 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -60,6 +60,7 @@ class FeatureValidationTest(unittest.TestCase): def test_simd_load(self): module = """ (module + (memory 1 1) (func $foo (drop (v128.load (i32.const 0))) ) diff --git a/test/wasm2js/unaligned.wast b/test/wasm2js/unaligned.wast index 600d22459..c55870603 100644 --- a/test/wasm2js/unaligned.wast +++ b/test/wasm2js/unaligned.wast @@ -1,4 +1,6 @@ (module + (memory 1 1) + (func (export "i32.load") (result i32) (i32.load align=1 (i32.const 0))) (func (export "i64.load") (result i64) |