summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp38
-rw-r--r--test/passes/optimize-instructions_all-features.txt77
-rw-r--r--test/passes/optimize-instructions_all-features.wast67
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)