diff options
author | Thomas Lively <tlively@google.com> | 2022-10-25 09:09:26 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-25 07:09:26 -0700 |
commit | 79e032ac1124f82729bb21684f370044612c7124 (patch) | |
tree | 2d369f5afb693dc5b8cc9e8f10cce9e33a528892 /src | |
parent | 5245b8cdf64dad2e2b7c19b08fe22d2e6039ffa7 (diff) | |
download | binaryen-79e032ac1124f82729bb21684f370044612c7124.tar.gz binaryen-79e032ac1124f82729bb21684f370044612c7124.tar.bz2 binaryen-79e032ac1124f82729bb21684f370044612c7124.zip |
[Parser] Parse `return` (#5181)
Unlike in the legacy parser, we cannot depend on the folded text format to
determine how many values to return, so we determine that solely based on the
current function context.
To handle multivalue return correctly, fix a bug in which we could synthesize
new `unreachable`s and place them before existing unreachable instructions (like
returns) at the end of instruction sequences.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wat-parser.cpp | 38 |
1 files changed, 36 insertions, 2 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> |