summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Graey <maxgraey@gmail.com>2020-10-26 06:53:17 +0200
committerGitHub <noreply@github.com>2020-10-25 21:53:17 -0700
commitd0032c299695c765e757de5f9482a610bf687d69 (patch)
tree737d4485a6d8652538b89a3d7ddfa9891a67278b /src
parentb8b457ddad939a316cb833a8beb8987ca04fa865 (diff)
downloadbinaryen-d0032c299695c765e757de5f9482a610bf687d69.tar.gz
binaryen-d0032c299695c765e757de5f9482a610bf687d69.tar.bz2
binaryen-d0032c299695c765e757de5f9482a610bf687d69.zip
Optimize relations of subtractions and zero (#3275)
Diffstat (limited to 'src')
-rw-r--r--src/passes/OptimizeInstructions.cpp117
1 files changed, 102 insertions, 15 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 66c5269ff..cc8048511 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -275,6 +275,30 @@ struct OptimizeInstructions
}
}
{
+ // eqz(x - y) => x == y
+ Binary* inner;
+ if (matches(curr,
+ unary(Abstract::EqZ,
+ binary(&inner, Abstract::Sub, any(), any())))) {
+ inner->op = Abstract::getBinary(inner->left->type, Abstract::Eq);
+ inner->type = Type::i32;
+ return inner;
+ }
+ }
+ {
+ // eqz(x + C) => x == -C
+ Const* c;
+ Binary* inner;
+ if (matches(curr,
+ unary(Abstract::EqZ,
+ binary(&inner, Abstract::Add, any(), ival(&c))))) {
+ c->value = c->value.neg();
+ inner->op = Abstract::getBinary(c->type, Abstract::Eq);
+ inner->type = Type::i32;
+ return inner;
+ }
+ }
+ {
// eqz((signed)x % C_pot) => eqz(x & (abs(C_pot) - 1))
Const* c;
Binary* inner;
@@ -362,6 +386,24 @@ struct OptimizeInstructions
}
}
}
+ {
+ // unsigned(x) >= 0 => i32(1)
+ Const* c;
+ Expression* x;
+ if (matches(curr, binary(Abstract::GeU, pure(&x), ival(&c))) &&
+ c->value.isZero()) {
+ c->value = Literal::makeOne(Type::i32);
+ c->type = Type::i32;
+ return c;
+ }
+ // unsigned(x) < 0 => i32(0)
+ if (matches(curr, binary(Abstract::LtU, pure(&x), ival(&c))) &&
+ c->value.isZero()) {
+ c->value = Literal::makeZero(Type::i32);
+ c->type = Type::i32;
+ return c;
+ }
+ }
}
if (auto* select = curr->dynCast<Select>()) {
@@ -1659,31 +1701,31 @@ private:
}
// TODO: templatize on type?
- Expression* optimizeRelational(Binary* binary) {
- // TODO: inequalities can also work, if the constants do not overflow
- auto type = binary->right->type;
- // integer math, even on 2s complement, allows stuff like
- // x + 5 == 7
- // =>
- // x == 2
- if (binary->left->type.isInteger()) {
- if (binary->op == Abstract::getBinary(type, Abstract::Eq) ||
- binary->op == Abstract::getBinary(type, Abstract::Ne)) {
- if (auto* left = binary->left->dynCast<Binary>()) {
+ Expression* optimizeRelational(Binary* curr) {
+ auto type = curr->right->type;
+ if (curr->left->type.isInteger()) {
+ if (curr->op == Abstract::getBinary(type, Abstract::Eq) ||
+ curr->op == Abstract::getBinary(type, Abstract::Ne)) {
+ if (auto* left = curr->left->dynCast<Binary>()) {
+ // TODO: inequalities can also work, if the constants do not overflow
+ // integer math, even on 2s complement, allows stuff like
+ // x + 5 == 7
+ // =>
+ // x == 2
if (left->op == Abstract::getBinary(type, Abstract::Add) ||
left->op == Abstract::getBinary(type, Abstract::Sub)) {
if (auto* leftConst = left->right->dynCast<Const>()) {
- if (auto* rightConst = binary->right->dynCast<Const>()) {
+ if (auto* rightConst = curr->right->dynCast<Const>()) {
return combineRelationalConstants(
- binary, left, leftConst, nullptr, rightConst);
- } else if (auto* rightBinary = binary->right->dynCast<Binary>()) {
+ curr, left, leftConst, nullptr, rightConst);
+ } else if (auto* rightBinary = curr->right->dynCast<Binary>()) {
if (rightBinary->op ==
Abstract::getBinary(type, Abstract::Add) ||
rightBinary->op ==
Abstract::getBinary(type, Abstract::Sub)) {
if (auto* rightConst = rightBinary->right->dynCast<Const>()) {
return combineRelationalConstants(
- binary, left, leftConst, rightBinary, rightConst);
+ curr, left, leftConst, rightBinary, rightConst);
}
}
}
@@ -1691,6 +1733,51 @@ private:
}
}
}
+ // signed(x - y) <=> 0 => x <=> y
+ //
+ // unsigned(x - y) > 0 => x != y
+ // unsigned(x - y) <= 0 => x == y
+ {
+ using namespace Match;
+
+ BinaryOp op;
+ Binary* inner;
+ // unsigned(x - y) > 0 => x != y
+ if (matches(curr,
+ binary(Abstract::GtU,
+ binary(&inner, Abstract::Sub, any(), any()),
+ ival(0)))) {
+ curr->op = Abstract::getBinary(type, Abstract::Ne);
+ curr->right = inner->right;
+ curr->left = inner->left;
+ return curr;
+ }
+ // unsigned(x - y) <= 0 => x == y
+ if (matches(curr,
+ binary(Abstract::LeU,
+ binary(&inner, Abstract::Sub, any(), any()),
+ ival(0)))) {
+ curr->op = Abstract::getBinary(type, Abstract::Eq);
+ curr->right = inner->right;
+ curr->left = inner->left;
+ return curr;
+ }
+ // signed(x - y) <=> 0 => x <=> y
+ if (matches(curr,
+ binary(&op,
+ binary(&inner, Abstract::Sub, any(), any()),
+ ival(0))) &&
+ (op == Abstract::getBinary(type, Abstract::Eq) ||
+ op == Abstract::getBinary(type, Abstract::Ne) ||
+ op == Abstract::getBinary(type, Abstract::LeS) ||
+ op == Abstract::getBinary(type, Abstract::LtS) ||
+ op == Abstract::getBinary(type, Abstract::GeS) ||
+ op == Abstract::getBinary(type, Abstract::GtS))) {
+ curr->right = inner->right;
+ curr->left = inner->left;
+ return curr;
+ }
+ }
}
return nullptr;
}