diff options
-rw-r--r-- | src/wasm/wat-parser.cpp | 38 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 97 |
2 files changed, 113 insertions, 22 deletions
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 82f8368af..abcff8c43 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -725,6 +725,7 @@ struct NullInstrParserCtx { InstrT makeMemoryCopy(Index, MemoryT*, MemoryT*) { return Ok{}; } InstrT makeMemoryFill(Index, MemoryT*) { return Ok{}; } + InstrT makeReturn(Index) { return Ok{}; } template<typename HeapTypeT> InstrT makeRefNull(Index, HeapTypeT) { return {}; } @@ -1253,12 +1254,23 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { // instructions and reset the context for the next sequence. if (type.isTuple()) { std::vector<Expression*> elems(type.size()); + bool hadUnreachableElem = false; for (size_t i = 0; i < elems.size(); ++i) { auto elem = pop(self().in.getPos()); CHECK_ERR(elem); elems[elems.size() - 1 - i] = *elem; + if ((*elem)->type == Type::unreachable) { + // We don't want to pop back past an unreachable here. Push the + // unreachable back and throw away any post-unreachable values we have + // popped. + exprStack.push_back(*elem); + hadUnreachableElem = true; + break; + } + } + if (!hadUnreachableElem) { + exprStack.push_back(builder.makeTupleMake(std::move(elems))); } - exprStack.push_back(builder.makeTupleMake(std::move(elems))); } else if (type != Type::none) { // Ensure the last expression produces the value. auto expr = pop(self().in.getPos()); @@ -1727,6 +1739,28 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return push(pos, builder.makeMemoryFill(*dest, *val, *size, *m)); } + Result<> makeReturn(Index pos) { + if (!func) { + return in.err("cannot return outside of a function"); + } + size_t n = func->getResults().size(); + if (n == 0) { + return push(pos, builder.makeReturn()); + } + if (n == 1) { + auto val = pop(pos); + CHECK_ERR(val); + return push(pos, builder.makeReturn(*val)); + } + std::vector<Expression*> vals(n); + for (size_t i = 0; i < n; ++i) { + auto val = pop(pos); + CHECK_ERR(val); + vals[n - i - 1] = *val; + } + return push(pos, builder.makeReturn(builder.makeTupleMake(vals))); + } + Result<> makeRefNull(Index pos, HeapType type) { return push(pos, builder.makeRefNull(type)); } @@ -2709,7 +2743,7 @@ Result<typename Ctx::InstrT> makeBreakTable(Ctx& ctx, Index pos) { template<typename Ctx> Result<typename Ctx::InstrT> makeReturn(Ctx& ctx, Index pos) { - return ctx.in.err("unimplemented instruction"); + return ctx.makeReturn(pos); } template<typename Ctx> diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index e621961a7..4c643f6a1 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -39,6 +39,16 @@ ;; CHECK: (type $i32_i32_i64_i64_=>_none (func_subtype (param i32 i32 i64 i64) func)) + ;; CHECK: (type $i32_=>_i32 (func_subtype (param i32) (result i32) func)) + + ;; CHECK: (type $i32_i64_=>_i32_i64 (func_subtype (param i32 i64) (result i32 i64) func)) + + ;; CHECK: (type $i64_=>_i32_i64 (func_subtype (param i64) (result i32 i64) func)) + + ;; CHECK: (type $i32_=>_i32_i64 (func_subtype (param i32) (result i32 i64) func)) + + ;; CHECK: (type $none_=>_i32_i64 (func_subtype (result i32 i64) func)) + ;; CHECK: (rec ;; CHECK-NEXT: (type $s0 (struct_subtype data)) (type $s0 (sub (struct))) @@ -466,15 +476,9 @@ ) ;; CHECK: (func $add-twice-unreachable (type $ret2) (result i32 i32) - ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: (i32.const 4) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $add-twice-unreachable (type $ret2) @@ -493,13 +497,7 @@ ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: (i32.const 4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $add-twice-unreachable-2 (type $ret2) i32.const 1 @@ -524,10 +522,7 @@ ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $add-twice-unreachable-3 (type $ret2) i32.const 1 @@ -1123,6 +1118,68 @@ memory.fill $mem-i64 ) + ;; CHECK: (func $return-none (type $void) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + (func $return-none + return + ) + + ;; CHECK: (func $return-one (type $i32_=>_i32) (param $0 i32) (result i32) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $return-one (param i32) (result i32) + local.get 0 + return + ) + + ;; CHECK: (func $return-two (type $i32_i64_=>_i32_i64) (param $0 i32) (param $1 i64) (result i32 i64) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $return-two (param i32 i64) (result i32 i64) + local.get 0 + local.get 1 + return + ) + + ;; CHECK: (func $return-two-first-unreachable (type $i64_=>_i32_i64) (param $0 i64) (result i32 i64) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $return-two-first-unreachable (param i64) (result i32 i64) + unreachable + local.get 0 + return + ) + + ;; CHECK: (func $return-two-second-unreachable (type $i32_=>_i32_i64) (param $0 i32) (result i32 i64) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (tuple.make + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $return-two-second-unreachable (param i32) (result i32 i64) + local.get 0 + unreachable + return + ) + ;; CHECK: (func $use-types (type $ref|$s0|_ref|$s1|_ref|$s2|_ref|$s3|_ref|$s4|_ref|$s5|_ref|$s6|_ref|$s7|_ref|$s8|_ref|$a0|_ref|$a1|_ref|$a2|_ref|$a3|_ref|$subvoid|_ref|$submany|_=>_none) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) |