summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp49
-rw-r--r--test/lit/passes/optimize-instructions-sign-ext.wast18
-rw-r--r--test/lit/passes/optimize-instructions.wast288
3 files changed, 319 insertions, 36 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 047ed8551..672484c92 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -3564,6 +3564,55 @@ private:
}
}
{
+ // TODO: Add cancelation for some large constants when shrinkLevel > 0
+ // in FinalOptimizer.
+
+ // (x >> C) << C => x & -(1 << C)
+ // (x >>> C) << C => x & -(1 << C)
+ Binary* inner;
+ Const *c1, *c2;
+ if (matches(curr,
+ binary(Shl, binary(&inner, any(), ival(&c1)), ival(&c2))) &&
+ (inner->op == getBinary(inner->type, ShrS) ||
+ inner->op == getBinary(inner->type, ShrU)) &&
+ Bits::getEffectiveShifts(c1) == Bits::getEffectiveShifts(c2)) {
+ auto type = c1->type;
+ if (type == Type::i32) {
+ c1->value = Literal::makeFromInt32(
+ -(1U << Bits::getEffectiveShifts(c1)), Type::i32);
+ } else {
+ c1->value = Literal::makeFromInt64(
+ -(1ULL << Bits::getEffectiveShifts(c1)), Type::i64);
+ }
+ inner->op = getBinary(type, And);
+ return inner;
+ }
+ }
+ {
+ // TODO: Add cancelation for some large constants when shrinkLevel > 0
+ // in FinalOptimizer.
+
+ // (x << C) >>> C => x & (-1 >>> C)
+ // (x << C) >> C => skip
+ Binary* inner;
+ Const *c1, *c2;
+ if (matches(
+ curr,
+ binary(ShrU, binary(&inner, Shl, any(), ival(&c1)), ival(&c2))) &&
+ Bits::getEffectiveShifts(c1) == Bits::getEffectiveShifts(c2)) {
+ auto type = c1->type;
+ if (type == Type::i32) {
+ c1->value = Literal::makeFromInt32(
+ -1U >> Bits::getEffectiveShifts(c1), Type::i32);
+ } else {
+ c1->value = Literal::makeFromInt64(
+ -1ULL >> Bits::getEffectiveShifts(c1), Type::i64);
+ }
+ inner->op = getBinary(type, And);
+ return inner;
+ }
+ }
+ {
// TODO: Add canonicalization rotr to rotl and remove these rules.
// rotl(rotr(x, C1), C2) => rotr(x, C1 - C2)
// rotr(rotl(x, C1), C2) => rotl(x, C1 - C2)
diff --git a/test/lit/passes/optimize-instructions-sign-ext.wast b/test/lit/passes/optimize-instructions-sign-ext.wast
index 70572e616..207703904 100644
--- a/test/lit/passes/optimize-instructions-sign-ext.wast
+++ b/test/lit/passes/optimize-instructions-sign-ext.wast
@@ -87,21 +87,15 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i32.shr_u
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: (i32.const 24)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 24)
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i32.shr_u
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: (i32.const 16)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 16)
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast
index 71d4e7fe3..c0c19395d 100644
--- a/test/lit/passes/optimize-instructions.wast
+++ b/test/lit/passes/optimize-instructions.wast
@@ -2541,12 +2541,9 @@
)
;; CHECK: (func $eq-sext-unsigned-shr (param $0 i32) (result i32)
;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (i32.shr_u
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: (i32.const 24)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 24)
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -3254,14 +3251,11 @@
)
;; CHECK: (func $sext-24-shr_u-wrap-too-big (result i32)
;; CHECK-NEXT: (i32.shr_s
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (i32.shr_u
- ;; CHECK-NEXT: (i32.wrap_i64
- ;; CHECK-NEXT: (i64.const -1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 24)
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (i32.wrap_i64
+ ;; CHECK-NEXT: (i64.const -1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 24)
+ ;; CHECK-NEXT: (i32.const -16777216)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
@@ -3304,12 +3298,9 @@
)
;; CHECK: (func $sext-24-shr_u-wrap-extend-too-big (result i32)
;; CHECK-NEXT: (i32.shr_s
- ;; CHECK-NEXT: (i32.shl
- ;; CHECK-NEXT: (i32.shr_u
- ;; CHECK-NEXT: (i32.const -1)
- ;; CHECK-NEXT: (i32.const 24)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 24)
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (i32.const -1)
+ ;; CHECK-NEXT: (i32.const -16777216)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
@@ -6127,11 +6118,260 @@
;; CHECK-NEXT: )
(func $mix-shifts (result i32)
(i32.shr_s
- (i32.shl
- (i32.const 23)
- (i32.const -61)
- )
- (i32.const 168)
+ (i32.shl
+ (i32.const 23)
+ (i32.const -61)
+ )
+ (i32.const 168)
+ )
+ )
+ ;; CHECK: (func $mix-shifts-with-same-const-signed (param $x i32) (param $y i64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const -16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const -9223372036854775808)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.shl
+ ;; CHECK-NEXT: (i64.shr_s
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const 63)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $mix-shifts-with-same-const-signed (param $x i32) (param $y i64)
+ (drop
+ (i32.shl
+ (i32.shr_s
+ (local.get $x)
+ (i32.const 4)
+ )
+ (i32.const 4)
+ )
+ )
+ (drop
+ (i64.shl
+ (i64.shr_s
+ (local.get $y)
+ (i64.const 63)
+ )
+ (i64.const 127) ;; effective shift is 63
+ )
+ )
+
+ ;; skips
+ (drop
+ (i32.shl
+ (i32.shr_s
+ (local.get $x)
+ (i32.const 4)
+ )
+ (i32.const 5)
+ )
+ )
+ (drop
+ (i64.shl
+ (i64.shr_s
+ (local.get $y)
+ (i64.const 63)
+ )
+ (i64.const 1)
+ )
+ )
+ )
+ ;; CHECK: (func $mix-shifts-with-same-const-unsigned (param $x i32) (param $y i64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const -16)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const -9223372036854775808)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.shl
+ ;; CHECK-NEXT: (i64.shr_u
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const 63)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $mix-shifts-with-same-const-unsigned (param $x i32) (param $y i64)
+ (drop
+ (i32.shl
+ (i32.shr_u
+ (local.get $x)
+ (i32.const 4)
+ )
+ (i32.const 4)
+ )
+ )
+ (drop
+ (i64.shl
+ (i64.shr_u
+ (local.get $y)
+ (i64.const 63)
+ )
+ (i64.const 127) ;; effective shift is 63
+ )
+ )
+
+ ;; skips
+ (drop
+ (i32.shl
+ (i32.shr_u
+ (local.get $x)
+ (i32.const 4)
+ )
+ (i32.const 5)
+ )
+ )
+ (drop
+ (i64.shl
+ (i64.shr_u
+ (local.get $y)
+ (i64.const 63)
+ )
+ (i64.const 1)
+ )
+ )
+ )
+ ;; CHECK: (func $reversed-mix-shifts-with-same-const (param $x i32) (param $y i64)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 268435455)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.and
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.and
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shr_u
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 5)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.shr_u
+ ;; CHECK-NEXT: (i64.shl
+ ;; CHECK-NEXT: (local.get $y)
+ ;; CHECK-NEXT: (i64.const 4)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.const 8)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.shr_s
+ ;; CHECK-NEXT: (i32.shl
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 6)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 6)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $reversed-mix-shifts-with-same-const (param $x i32) (param $y i64)
+ (drop
+ (i32.shr_u
+ (i32.shl
+ (local.get $x)
+ (i32.const 4)
+ )
+ (i32.const 4)
+ )
+ )
+ (drop
+ (i32.shr_u
+ (i32.shl
+ (local.get $x)
+ (i32.const 31)
+ )
+ (i32.const 31)
+ )
+ )
+ (drop
+ (i64.shr_u
+ (i64.shl
+ (local.get $y)
+ (i64.const 127) ;; effective shift is 63
+ )
+ (i64.const 63) ;; effective shift is 63
+ )
+ )
+
+ ;; skips
+ (drop
+ (i32.shr_u
+ (i32.shl
+ (local.get $x)
+ (i32.const 5)
+ )
+ (i32.const 4)
+ )
+ )
+ (drop
+ (i64.shr_u
+ (i64.shl
+ (local.get $y)
+ (i64.const 4)
+ )
+ (i64.const 8)
+ )
+ )
+ (drop
+ (i32.shr_s
+ (i32.shl
+ (local.get $x)
+ (i32.const 6)
+ )
+ (i32.const 6)
+ )
)
)
;; CHECK: (func $actually-no-shifts (result i32)