summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wat-parser.cpp38
-rw-r--r--test/lit/wat-kitchen-sink.wast97
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: )