summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp55
-rw-r--r--test/passes/O3_low-memory-unused_metrics.txt11
-rw-r--r--test/passes/optimize-instructions_all-features.txt52
-rw-r--r--test/passes/optimize-instructions_all-features.wast69
4 files changed, 167 insertions, 20 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index a3afa58c4..e3d2b3a57 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -235,10 +235,6 @@ struct OptimizeInstructions
}
} else if (binary->op == EqInt32 || binary->op == NeInt32) {
if (auto* c = binary->right->dynCast<Const>()) {
- if (binary->op == EqInt32 && c->value.geti32() == 0) {
- // equal 0 => eqz
- return Builder(*getModule()).makeUnary(EqZInt32, binary->left);
- }
if (auto* ext = Properties::getSignExtValue(binary->left)) {
// we are comparing a sign extend to a constant, which means we can
// use a cheaper zext
@@ -812,8 +808,8 @@ private:
}
} else if (auto* binary = boolean->dynCast<Binary>()) {
if (binary->op == SubInt32) {
- if (auto* num = binary->left->dynCast<Const>()) {
- if (num->value.geti32() == 0) {
+ if (auto* c = binary->left->dynCast<Const>()) {
+ if (c->value.geti32() == 0) {
// bool(0 - x) ==> bool(x)
return binary->right;
}
@@ -824,9 +820,9 @@ private:
binary->left = optimizeBoolean(binary->left);
binary->right = optimizeBoolean(binary->right);
} else if (binary->op == NeInt32) {
- if (auto* num = binary->right->dynCast<Const>()) {
+ if (auto* c = binary->right->dynCast<Const>()) {
// x != 0 is just x if it's used as a bool
- if (num->value.geti32() == 0) {
+ if (c->value.geti32() == 0) {
return binary->left;
}
// TODO: Perhaps use it for separate final pass???
@@ -1220,8 +1216,9 @@ private:
!EffectAnalyzer(getPassOptions(), features, binary->left)
.hasSideEffects()) {
return binary->right;
- } else if (binary->op == EqInt64) {
- return Builder(*getModule()).makeUnary(EqZInt64, binary->left);
+ } else if (binary->op == Abstract::getBinary(type, Abstract::Eq)) {
+ return Builder(*getModule())
+ .makeUnary(Abstract::getUnary(type, Abstract::EqZ), binary->left);
}
}
// operations on one
@@ -1233,6 +1230,44 @@ private:
right->value = Literal::makeSingleZero(type);
return right;
}
+ // bool(x) | 1 ==> 1
+ // bool(x) & 1 ==> bool(x)
+ // bool(x) == 1 ==> bool(x)
+ // bool(x) != 1 ==> !bool(x)
+ if (Bits::getMaxBits(binary->left, this) == 1) {
+ switch (binary->op) {
+ case OrInt32:
+ case OrInt64: {
+ if (!EffectAnalyzer(getPassOptions(), features, binary->left)
+ .hasSideEffects()) {
+ // bool(x) | 1 ==> 1
+ return binary->right;
+ }
+ break;
+ }
+ case AndInt32:
+ case AndInt64:
+ case EqInt32: {
+ // bool(x) & 1 ==> bool(x)
+ // bool(x) == 1 ==> bool(x)
+ return binary->left;
+ }
+ case EqInt64: {
+ // i64(bool(x)) == 1 ==> i32(bool(x))
+ return Builder(*getModule()).makeUnary(WrapInt64, binary->left);
+ }
+ case NeInt32:
+ case NeInt64: {
+ // bool(x) != 1 ==> !bool(x)
+ return Builder(*getModule())
+ .makeUnary(
+ Abstract::getUnary(binary->left->type, Abstract::EqZ),
+ binary->left);
+ }
+ default: {
+ }
+ }
+ }
}
// operations on all 1s
if (constRight == -1LL) {
diff --git a/test/passes/O3_low-memory-unused_metrics.txt b/test/passes/O3_low-memory-unused_metrics.txt
index c1218c4fd..22d72d241 100644
--- a/test/passes/O3_low-memory-unused_metrics.txt
+++ b/test/passes/O3_low-memory-unused_metrics.txt
@@ -6,14 +6,14 @@ total
[imports] : 10
[memory-data] : 0
[table-data] : 0
- [total] : 1965
+ [total] : 1964
[vars] : 9
- binary : 241
+ binary : 240
block : 68
break : 90
call : 22
call_indirect : 1
- const : 176
+ const : 175
drop : 8
if : 27
load : 313
@@ -23,7 +23,7 @@ total
return : 3
select : 11
store : 160
- unary : 28
+ unary : 29
(module
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
@@ -2387,7 +2387,7 @@ total
)
)
(br_if $label$57
- (i32.ne
+ (i32.eqz
(i32.or
(i32.eqz
(local.get $1)
@@ -2397,7 +2397,6 @@ total
(i32.const 666)
)
)
- (i32.const 1)
)
)
(br_if $label$56
diff --git a/test/passes/optimize-instructions_all-features.txt b/test/passes/optimize-instructions_all-features.txt
index 90556f016..8c21b8494 100644
--- a/test/passes/optimize-instructions_all-features.txt
+++ b/test/passes/optimize-instructions_all-features.txt
@@ -4,8 +4,8 @@
(type $none_=>_i32 (func (result i32)))
(type $none_=>_none (func))
(type $i32_i64_=>_none (func (param i32 i64)))
- (type $i32_=>_none (func (param i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
(type $none_=>_i64 (func (result i64)))
(type $i64_=>_i64 (func (param i64) (result i64)))
(type $i32_i64_f32_=>_none (func (param i32 i64 f32)))
@@ -3410,7 +3410,7 @@
)
)
)
- (func $optimize-boolean (param $x i32)
+ (func $optimize-boolean (param $x i32) (param $y i64)
(drop
(select
(i32.const 1)
@@ -3418,6 +3418,54 @@
(local.get $x)
)
)
+ (drop
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (i32.eqz
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ )
+ )
+ (drop
+ (i32.wrap_i64
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ )
+ )
+ (drop
+ (i64.eqz
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ )
+ )
+ (drop
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ )
+ (drop
+ (i32.const 1)
+ )
+ (drop
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ )
+ (drop
+ (i64.const 1)
+ )
)
(func $getFallthrough
(local $x0 i32)
diff --git a/test/passes/optimize-instructions_all-features.wast b/test/passes/optimize-instructions_all-features.wast
index 7dc8cffbf..1b03782e9 100644
--- a/test/passes/optimize-instructions_all-features.wast
+++ b/test/passes/optimize-instructions_all-features.wast
@@ -3960,17 +3960,82 @@
)
)
)
- (func $optimize-boolean (param $x i32)
+ (func $optimize-boolean (param $x i32) (param $y i64)
+ ;; bool(-x) -> bool(x)
(drop
(select
(i32.const 1)
(i32.const 2)
- (i32.sub ;; bool(-x) -> bool(x)
+ (i32.sub
(i32.const 0)
(local.get $x)
)
)
)
+ ;; i32(bool(expr)) == 1 -> bool(expr)
+ (drop (i32.eq
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ (i32.const 1)
+ ))
+ ;; i32(bool(expr)) != 1 -> !bool(expr)
+ (drop (i32.ne
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ (i32.const 1)
+ ))
+ ;; i64(bool(expr)) == 1 -> i64(bool(expr))
+ (drop (i64.eq
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ (i64.const 1)
+ ))
+ ;; i64(bool(expr)) != 1 -> !i64(bool(expr))
+ (drop (i64.ne
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ (i64.const 1)
+ ))
+ ;; i32(bool(expr)) & 1 -> bool(expr)
+ (drop (i32.and
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ (i32.const 1)
+ ))
+ ;; i32(bool(expr)) | 1 -> 1
+ (drop (i32.or
+ (i32.and
+ (local.get $x)
+ (i32.const 1)
+ )
+ (i32.const 1)
+ ))
+ ;; i64(bool(expr)) & 1 -> i64(bool(expr))
+ (drop (i64.and
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ (i64.const 1)
+ ))
+ ;; i64(bool(expr)) | 1 -> 1
+ (drop (i64.or
+ (i64.and
+ (local.get $y)
+ (i64.const 1)
+ )
+ (i64.const 1)
+ ))
)
(func $getFallthrough ;; unit tests for Properties::getFallthrough
(local $x0 i32)