diff options
author | Ben Smith <binjimin@gmail.com> | 2018-12-18 09:27:18 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-18 09:27:18 -0800 |
commit | 3ac02b6d3cc5bc3ff6cfe57df312b2677ca83d75 (patch) | |
tree | 6a470c926a25457fadab32cffc8373b255b73cbd /src | |
parent | 32ee1f63cf9489d47896dfc2e7d294fdfee13d3d (diff) | |
download | wabt-3ac02b6d3cc5bc3ff6cfe57df312b2677ca83d75.tar.gz wabt-3ac02b6d3cc5bc3ff6cfe57df312b2677ca83d75.tar.bz2 wabt-3ac02b6d3cc5bc3ff6cfe57df312b2677ca83d75.zip |
Fold multi-value results properly (#984)
Expressions need to be treated specially when folding an expression
with a result count > 1. Since the expression cannot be split, we can
only include it as a child of another expression if all of its values
are used, for example:
```
(func $dup (result i32 i32) ...)
(call $dup) ;; produces two values
(i32.add) ;; consumes two values
```
Diffstat (limited to 'src')
-rw-r--r-- | src/wat-writer.cc | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 9f646e50..58e30249 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -79,18 +79,12 @@ enum class NextChar { }; struct ExprTree { - explicit ExprTree(const Expr* expr = nullptr) : expr(expr) {} - // For debugging. - std::string describe() const { - std::string result("ExprTree("); - if (expr) { - result.append(GetExprTypeName(*expr)); - } - return result + ")"; - } + explicit ExprTree(const Expr* expr, Index result_count) + : expr(expr), result_count(result_count) {} const Expr* expr; std::vector<ExprTree> children; + Index result_count; }; struct Label { @@ -1196,18 +1190,43 @@ void WatWriter::PushExpr(const Expr* expr, Index result_count) { WABT_TRACE_ARGS(PushExpr, "%s, %" PRIindex ", %" PRIindex "", GetExprTypeName(*expr), operand_count, result_count); - if (operand_count <= expr_tree_stack_.size()) { + + // Try to pop operand off the expr stack to use as this expr's children. One + // expr can have multiple return values (with the multi-value extension), so + // we have to iterate over each in reverse. + + auto first_operand = expr_tree_stack_.end(); + + Index current_count = 0; + if (operand_count > 0) { + for (auto iter = expr_tree_stack_.rbegin(); iter != expr_tree_stack_.rend(); + ++iter) { + assert(iter->result_count > 0); + current_count += iter->result_count; + + if (current_count == operand_count) { + first_operand = iter.base() - 1; + break; + } else if (current_count > operand_count) { + // We went over the number of operands this instruction wants; this can + // only happen when there are expressions on the stack with a + // result_count > 1. When this happens we can't fold, since any result + // we produce will not make sense. + break; + } + } + } + + ExprTree tree(expr, result_count); + + if (current_count == operand_count && operand_count > 0) { auto last_operand = expr_tree_stack_.end(); - auto first_operand = last_operand - operand_count; - ExprTree tree(expr); std::move(first_operand, last_operand, std::back_inserter(tree.children)); expr_tree_stack_.erase(first_operand, last_operand); - expr_tree_stack_.emplace_back(tree); - if (result_count == 0) { - FlushExprTreeStack(); - } - } else { - expr_tree_stack_.emplace_back(expr); + } + + expr_tree_stack_.emplace_back(std::move(tree)); + if (current_count > operand_count || result_count == 0) { FlushExprTreeStack(); } } |