diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 38 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.txt | 77 | ||||
-rw-r--r-- | test/passes/optimize-instructions_all-features.wast | 67 |
3 files changed, 172 insertions, 10 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index b0d12eb95..1f65ae609 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -243,13 +243,6 @@ struct OptimizeInstructions using namespace Match; Builder builder(*getModule()); { - // X == 0 => eqz X - Expression* x; - if (matches(curr, binary(EqInt32, any(&x), i32(0)))) { - return Builder(*getModule()).makeUnary(EqZInt32, x); - } - } - { // try to get rid of (0 - ..), that is, a zero only used to negate an // int. an add of a subtract can be flipped in order to remove it: // (i32.add @@ -302,6 +295,19 @@ struct OptimizeInstructions } } { + // eqz((signed)x % C_pot) => eqz(x & (C_pot - 1)) + Const* c; + Binary* inner; + if (matches(curr, + unary(Abstract::EqZ, + binary(&inner, Abstract::RemS, any(), ival(&c)))) && + IsPowerOf2((uint64_t)c->value.getInteger())) { + inner->op = Abstract::getBinary(c->type, Abstract::And); + c->value = c->value.sub(Literal::makeFromInt32(1, c->type)); + return curr; + } + } + { // try de-morgan's AND law, // (eqz X) and (eqz Y) === eqz (X or Y) // Note that the OR and XOR laws do not work here, as these @@ -1272,8 +1278,8 @@ private: return right; } // x == 0 ==> eqz x - if ((matches(curr, binary(Abstract::Eq, any(&left), ival(0))))) { - return builder.makeUnary(EqZInt64, left); + if (matches(curr, binary(Abstract::Eq, any(&left), ival(0)))) { + return builder.makeUnary(Abstract::getUnary(type, Abstract::EqZ), left); } // Operations on one // (signed)x % 1 ==> 0 @@ -1281,6 +1287,20 @@ private: right->value = Literal::makeSingleZero(type); return right; } + // (signed)x % C_pot != 0 ==> x & (C_pot - 1) != 0 + { + Const* c; + Binary* inner; + if (matches(curr, + binary(Abstract::Ne, + binary(&inner, Abstract::RemS, any(), ival(&c)), + ival(0))) && + IsPowerOf2((uint64_t)c->value.getInteger())) { + inner->op = Abstract::getBinary(c->type, Abstract::And); + c->value = c->value.sub(Literal::makeFromInt32(1, c->type)); + return curr; + } + } // bool(x) | 1 ==> 1 if (matches(curr, binary(Abstract::Or, pure(&left), ival(1))) && Bits::getMaxBits(left, this) == 1) { diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt index e3ad30a0b..860783f36 100644 --- a/test/passes/optimize-instructions_all-features.txt +++ b/test/passes/optimize-instructions_all-features.txt @@ -2,8 +2,8 @@ (type $i32_i32_=>_none (func (param i32 i32))) (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) - (type $none_=>_none (func)) (type $i32_i64_=>_none (func (param i32 i64))) + (type $none_=>_none (func)) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_=>_none (func (param i32))) (type $none_=>_i64 (func (result i64))) @@ -2744,6 +2744,81 @@ (i64.const 0) ) ) + (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64) + (drop + (i32.eqz + (i32.and + (local.get $x) + (i32.const 3) + ) + ) + ) + (drop + (i64.eqz + (i64.and + (local.get $y) + (i64.const 3) + ) + ) + ) + (drop + (i32.eqz + (i32.and + (local.get $x) + (i32.const 3) + ) + ) + ) + (drop + (i64.eqz + (i64.and + (local.get $y) + (i64.const 1) + ) + ) + ) + (drop + (i32.ne + (i32.and + (local.get $x) + (i32.const 1) + ) + (i32.const 0) + ) + ) + (drop + (i32.wrap_i64 + (i64.and + (local.get $y) + (i64.const 1) + ) + ) + ) + (drop + (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const 3) + ) + ) + ) + (drop + (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const -4) + ) + ) + ) + (drop + (i64.eqz + (i64.rem_s + (local.get $y) + (i64.const 3) + ) + ) + ) + ) (func $orZero (param $0 i32) (result i32) (local.get $0) ) diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast index 8c2cefb53..1afa3e5b5 100644 --- a/test/passes/optimize-instructions_all-features.wast +++ b/test/passes/optimize-instructions_all-features.wast @@ -3104,6 +3104,73 @@ (i64.const 1) )) ) + (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64) + ;; eqz((signed)x % 4) + (drop (i32.eqz + (i32.rem_s + (local.get $x) + (i32.const 4) + ) + )) + (drop (i64.eqz + (i64.rem_s + (local.get $y) + (i64.const 4) + ) + )) + ;; (signed)x % 4 == 0 + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const 4) + ) + (i32.const 0) + )) + (drop (i64.eq + (i64.rem_s + (local.get $y) + (i64.const 2) + ) + (i64.const 0) + )) + ;; ;; (signed)x % 2 != 0 + (drop (i32.ne + (i32.rem_s + (local.get $x) + (i32.const 2) + ) + (i32.const 0) + )) + (drop (i64.ne + (i64.rem_s + (local.get $y) + (i64.const 2) + ) + (i64.const 0) + )) + ;; ;; + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const 3) ;; skip + ) + (i32.const 0) + )) + (drop (i32.eq + (i32.rem_s + (local.get $x) + (i32.const -4) ;; skip + ) + (i32.const 0) + )) + (drop (i64.eq + (i64.rem_s + (local.get $y) + (i64.const 3) ;; skip + ) + (i64.const 0) + )) + ) (func $orZero (param $0 i32) (result i32) (i32.or (local.get $0) |