diff options
author | Heejin Ahn <aheejin@gmail.com> | 2020-04-14 17:27:05 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-14 17:27:05 -0700 |
commit | e04d25e2e6cab2df0dfda5e4a206714a202313bc (patch) | |
tree | 295d25bc3b66ce02035ba4d8381e2ef36365d359 /src/passes/Precompute.cpp | |
parent | 359525bc5c04798e394a6e0a48c40fbfed7366db (diff) | |
download | binaryen-e04d25e2e6cab2df0dfda5e4a206714a202313bc.tar.gz binaryen-e04d25e2e6cab2df0dfda5e4a206714a202313bc.tar.bz2 binaryen-e04d25e2e6cab2df0dfda5e4a206714a202313bc.zip |
Fix reuse of constant nodes in Precompute (#2764)
Previously we tried to reuse `Const` node if a precomputed value is a
constant node. But now we have two more kinds of constant node
(`RefNull` and `RefFunc`), so we shouldn't reuse them interchangeably,
meaning we shouldn't try to reuse a `Const` node when the value at hand
is a `RefNull`. This correctly checks the type of node and tries to
reuse only if the types of nodes match.
Fixes #2759.
Diffstat (limited to 'src/passes/Precompute.cpp')
-rw-r--r-- | src/passes/Precompute.cpp | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 0a4a691f2..d809b8b43 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -174,6 +174,37 @@ struct Precompute } while (propagate && worked); } + template<typename T> void reuseConstantNode(T* curr, Flow flow) { + if (flow.values.isConcrete()) { + // reuse a const / ref.null / ref.func node if there is one + if (curr->value && flow.values.size() == 1) { + Literal singleValue = flow.getSingleValue(); + if (singleValue.type.isNumber()) { + if (auto* c = curr->value->template dynCast<Const>()) { + c->value = singleValue; + c->finalize(); + curr->finalize(); + return; + } + } else if (singleValue.type == Type::nullref && + curr->value->template is<RefNull>()) { + return; + } else if (singleValue.type == Type::funcref) { + if (auto* r = curr->value->template dynCast<RefFunc>()) { + r->func = singleValue.getFunc(); + r->finalize(); + curr->finalize(); + return; + } + } + } + curr->value = flow.getConstExpression(*getModule()); + } else { + curr->value = nullptr; + } + curr->finalize(); + } + void visitExpression(Expression* curr) { // TODO: if local.get, only replace with a constant if we don't care about // size...? @@ -199,19 +230,7 @@ struct Precompute // this expression causes a return. if it's already a return, reuse the // node if (auto* ret = curr->dynCast<Return>()) { - if (flow.values.isConcrete()) { - // reuse a const value if there is one - if (ret->value && flow.values.size() == 1) { - if (auto* value = ret->value->dynCast<Const>()) { - value->value = flow.getSingleValue(); - value->finalize(); - return; - } - } - ret->value = flow.getConstExpression(*getModule()); - } else { - ret->value = nullptr; - } + reuseConstantNode(ret, flow); } else { Builder builder(*getModule()); replaceCurrent(builder.makeReturn( @@ -225,21 +244,7 @@ struct Precompute if (auto* br = curr->dynCast<Break>()) { br->name = flow.breakTo; br->condition = nullptr; - if (flow.values.isConcrete()) { - // reuse a const value if there is one - if (br->value && flow.values.size() == 1) { - if (auto* value = br->value->dynCast<Const>()) { - value->value = flow.getSingleValue(); - value->finalize(); - br->finalize(); - return; - } - } - br->value = flow.getConstExpression(*getModule()); - } else { - br->value = nullptr; - } - br->finalize(); + reuseConstantNode(br, flow); } else { Builder builder(*getModule()); replaceCurrent(builder.makeBreak( |