summaryrefslogtreecommitdiff
path: root/src/passes/OptimizeInstructions.cpp
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2020-02-03 10:44:49 -0800
committerGitHub <noreply@github.com>2020-02-03 10:44:49 -0800
commitc9f2e9b7b24182e830f39c176170d5ca64d3d05e (patch)
treeb9aeb5648997393c474d1e3ebf4513d640395c70 /src/passes/OptimizeInstructions.cpp
parentcd8d82910d229aa8357eb18882745397f6ed87eb (diff)
downloadbinaryen-c9f2e9b7b24182e830f39c176170d5ca64d3d05e.tar.gz
binaryen-c9f2e9b7b24182e830f39c176170d5ca64d3d05e.tar.bz2
binaryen-c9f2e9b7b24182e830f39c176170d5ca64d3d05e.zip
Add EH support for EffectAnalyzer (#2631)
This adds EH support to `EffectAnalyzer`. Before `throw` and `rethrow` conservatively set property. Now `EffectAnalyzer` has a new property `throws` to represent an expression that can throw, and expression that can throw sets `throws` correctly. When EH is enabled, any calls can throw too, so we cannot reorder them with another expression with any side effects, meaning all calls should be treated in the same way as branches when evaluating `invalidate`. This prevents many reorderings, so this patch sets `throws` for calls only when the exception handling features is enabled. This is also why I passed `--disable-exception-handling` to `wasm2js` tests. Most of code changes outside of `EffectAnalyzer` class was made in order to pass `FeatureSet` to it. `throws` isn't always set whenever an expression contains a throwable instruction. When an throwable instruction is within an inner try, it will be caught by the corresponding inner catch, so it does not set `throws`.
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r--src/passes/OptimizeInstructions.cpp62
1 files changed, 40 insertions, 22 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index ef7c17000..90abed825 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -330,6 +330,7 @@ struct OptimizeInstructions
// Optimizations that don't yet fit in the pattern DSL, but could be
// eventually maybe
Expression* handOptimize(Expression* curr) {
+ FeatureSet features = getModule()->features;
// if this contains dead code, don't bother trying to optimize it, the type
// might change (if might not be unreachable if just one arm is, for
// example). this optimization pass focuses on actually executing code. the
@@ -472,7 +473,7 @@ struct OptimizeInstructions
if (auto* subZero = sub->left->dynCast<Const>()) {
if (subZero->value.geti32() == 0) {
if (EffectAnalyzer::canReorder(
- getPassOptions(), sub->right, binary->right)) {
+ getPassOptions(), features, sub->right, binary->right)) {
sub->left = binary->right;
return sub;
}
@@ -630,7 +631,8 @@ struct OptimizeInstructions
}
// finally, try more expensive operations on the binary in
// the case that they have no side effects
- if (!EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
+ if (!EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
if (ExpressionAnalyzer::equal(binary->left, binary->right)) {
return optimizeBinaryWithEqualEffectlessChildren(binary);
}
@@ -750,7 +752,8 @@ struct OptimizeInstructions
// if we can replace the if with one arm, and no side effects in the
// condition, do that
auto needCondition =
- EffectAnalyzer(getPassOptions(), iff->condition).hasSideEffects();
+ EffectAnalyzer(getPassOptions(), features, iff->condition)
+ .hasSideEffects();
auto isSubType = Type::isSubType(iff->ifTrue->type, iff->type);
if (isSubType && !needCondition) {
return iff->ifTrue;
@@ -781,8 +784,8 @@ struct OptimizeInstructions
auto* condition = select->condition->dynCast<Unary>();
if (condition && condition->op == EqZInt32) {
// flip select to remove eqz, if we can reorder
- EffectAnalyzer ifTrue(getPassOptions(), select->ifTrue);
- EffectAnalyzer ifFalse(getPassOptions(), select->ifFalse);
+ EffectAnalyzer ifTrue(getPassOptions(), features, select->ifTrue);
+ EffectAnalyzer ifFalse(getPassOptions(), features, select->ifFalse);
if (!ifTrue.invalidates(ifFalse)) {
select->condition = condition->value;
std::swap(select->ifTrue, select->ifFalse);
@@ -792,7 +795,7 @@ struct OptimizeInstructions
// constant condition, we can just pick the right side (barring side
// effects)
if (c->value.getInteger()) {
- if (!EffectAnalyzer(getPassOptions(), select->ifFalse)
+ if (!EffectAnalyzer(getPassOptions(), features, select->ifFalse)
.hasSideEffects()) {
return select->ifTrue;
} else {
@@ -800,7 +803,7 @@ struct OptimizeInstructions
// local, which is bad
}
} else {
- if (!EffectAnalyzer(getPassOptions(), select->ifTrue)
+ if (!EffectAnalyzer(getPassOptions(), features, select->ifTrue)
.hasSideEffects()) {
return select->ifFalse;
} else {
@@ -812,7 +815,7 @@ struct OptimizeInstructions
}
if (ExpressionAnalyzer::equal(select->ifTrue, select->ifFalse)) {
// sides are identical, fold
- EffectAnalyzer value(getPassOptions(), select->ifTrue);
+ EffectAnalyzer value(getPassOptions(), features, select->ifTrue);
if (value.hasSideEffects()) {
// at best we don't need the condition, but need to execute the value
// twice. a block is larger than a select by 2 bytes, and
@@ -820,7 +823,8 @@ struct OptimizeInstructions
// so it's not clear this is worth it, TODO
} else {
// value has no side effects
- EffectAnalyzer condition(getPassOptions(), select->condition);
+ EffectAnalyzer condition(
+ getPassOptions(), features, select->condition);
if (!condition.hasSideEffects()) {
return select->ifTrue;
} else {
@@ -887,14 +891,15 @@ private:
// write more concise pattern matching code elsewhere.
void canonicalize(Binary* binary) {
assert(Properties::isSymmetric(binary));
+ FeatureSet features = getModule()->features;
auto swap = [&]() {
assert(EffectAnalyzer::canReorder(
- getPassOptions(), binary->left, binary->right));
+ getPassOptions(), features, binary->left, binary->right));
std::swap(binary->left, binary->right);
};
auto maybeSwap = [&]() {
if (EffectAnalyzer::canReorder(
- getPassOptions(), binary->left, binary->right)) {
+ getPassOptions(), features, binary->left, binary->right)) {
swap();
}
};
@@ -1064,6 +1069,7 @@ private:
ZeroRemover(PassOptions& passOptions) : passOptions(passOptions) {}
void visitBinary(Binary* curr) {
+ FeatureSet features = getModule()->features;
auto* left = curr->left->dynCast<Const>();
auto* right = curr->right->dynCast<Const>();
if (curr->op == AddInt32) {
@@ -1086,7 +1092,8 @@ private:
// shift has side effects
if (((left && left->value.geti32() == 0) ||
(right && Bits::getEffectiveShifts(right) == 0)) &&
- !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) {
+ !EffectAnalyzer(passOptions, features, curr->right)
+ .hasSideEffects()) {
replaceCurrent(curr->left);
return;
}
@@ -1094,12 +1101,14 @@ private:
// multiplying by zero is a zero, unless the other side has side
// effects
if (left && left->value.geti32() == 0 &&
- !EffectAnalyzer(passOptions, curr->right).hasSideEffects()) {
+ !EffectAnalyzer(passOptions, features, curr->right)
+ .hasSideEffects()) {
replaceCurrent(left);
return;
}
if (right && right->value.geti32() == 0 &&
- !EffectAnalyzer(passOptions, curr->left).hasSideEffects()) {
+ !EffectAnalyzer(passOptions, features, curr->left)
+ .hasSideEffects()) {
replaceCurrent(right);
return;
}
@@ -1107,7 +1116,9 @@ private:
}
};
Expression* walked = binary;
- ZeroRemover(getPassOptions()).walk(walked);
+ ZeroRemover remover(getPassOptions());
+ remover.setModule(getModule());
+ remover.walk(walked);
if (constant == 0) {
return walked; // nothing more to do
}
@@ -1142,8 +1153,9 @@ private:
if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) {
return nullptr;
}
- auto leftEffects = EffectAnalyzer(getPassOptions(), left);
- auto rightEffects = EffectAnalyzer(getPassOptions(), right);
+ FeatureSet features = getModule()->features;
+ auto leftEffects = EffectAnalyzer(getPassOptions(), features, left);
+ auto rightEffects = EffectAnalyzer(getPassOptions(), features, right);
auto leftHasSideEffects = leftEffects.hasSideEffects();
auto rightHasSideEffects = rightEffects.hasSideEffects();
if (leftHasSideEffects && rightHasSideEffects) {
@@ -1189,13 +1201,16 @@ private:
// (x > y) | (x == y) ==> x >= y
Expression* combineOr(Binary* binary) {
assert(binary->op == OrInt32);
+ FeatureSet features = getModule()->features;
if (auto* left = binary->left->dynCast<Binary>()) {
if (auto* right = binary->right->dynCast<Binary>()) {
if (left->op != right->op &&
ExpressionAnalyzer::equal(left->left, right->left) &&
ExpressionAnalyzer::equal(left->right, right->right) &&
- !EffectAnalyzer(getPassOptions(), left->left).hasSideEffects() &&
- !EffectAnalyzer(getPassOptions(), left->right).hasSideEffects()) {
+ !EffectAnalyzer(getPassOptions(), features, left->left)
+ .hasSideEffects() &&
+ !EffectAnalyzer(getPassOptions(), features, left->right)
+ .hasSideEffects()) {
switch (left->op) {
// (x > y) | (x == y) ==> x >= y
case EqInt32: {
@@ -1296,6 +1311,7 @@ private:
// is a constant
// TODO: templatize on type?
Expression* optimizeWithConstantOnRight(Binary* binary) {
+ FeatureSet features = getModule()->features;
auto type = binary->right->type;
auto* right = binary->right->cast<Const>();
if (type.isInteger()) {
@@ -1309,7 +1325,7 @@ private:
return binary->left;
} else if ((binary->op == Abstract::getBinary(type, Abstract::Mul) ||
binary->op == Abstract::getBinary(type, Abstract::And)) &&
- !EffectAnalyzer(getPassOptions(), binary->left)
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
.hasSideEffects()) {
return binary->right;
} else if (binary->op == EqInt64) {
@@ -1323,7 +1339,7 @@ private:
if (binary->op == Abstract::getBinary(type, Abstract::And)) {
return binary->left;
} else if (binary->op == Abstract::getBinary(type, Abstract::Or) &&
- !EffectAnalyzer(getPassOptions(), binary->left)
+ !EffectAnalyzer(getPassOptions(), features, binary->left)
.hasSideEffects()) {
return binary->right;
}
@@ -1381,7 +1397,9 @@ private:
if ((binary->op == Abstract::getBinary(type, Abstract::Shl) ||
binary->op == Abstract::getBinary(type, Abstract::ShrU) ||
binary->op == Abstract::getBinary(type, Abstract::ShrS)) &&
- !EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) {
+ !EffectAnalyzer(
+ getPassOptions(), getModule()->features, binary->right)
+ .hasSideEffects()) {
return binary->left;
}
}