diff options
author | Max Graey <maxgraey@gmail.com> | 2020-10-26 06:53:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-25 21:53:17 -0700 |
commit | d0032c299695c765e757de5f9482a610bf687d69 (patch) | |
tree | 737d4485a6d8652538b89a3d7ddfa9891a67278b /src | |
parent | b8b457ddad939a316cb833a8beb8987ca04fa865 (diff) | |
download | binaryen-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.cpp | 117 |
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; } |