summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Smith <binjimin@gmail.com>2018-12-18 09:27:18 -0800
committerGitHub <noreply@github.com>2018-12-18 09:27:18 -0800
commit3ac02b6d3cc5bc3ff6cfe57df312b2677ca83d75 (patch)
tree6a470c926a25457fadab32cffc8373b255b73cbd /src
parent32ee1f63cf9489d47896dfc2e7d294fdfee13d3d (diff)
downloadwabt-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.cc55
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();
}
}