summaryrefslogtreecommitdiff
path: root/src/wasm/wat-parser.cpp
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2022-10-25 09:09:26 -0500
committerGitHub <noreply@github.com>2022-10-25 07:09:26 -0700
commit79e032ac1124f82729bb21684f370044612c7124 (patch)
tree2d369f5afb693dc5b8cc9e8f10cce9e33a528892 /src/wasm/wat-parser.cpp
parent5245b8cdf64dad2e2b7c19b08fe22d2e6039ffa7 (diff)
downloadbinaryen-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/wasm/wat-parser.cpp')
-rw-r--r--src/wasm/wat-parser.cpp38
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>