diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 49 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-sign-ext.wast | 18 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions.wast | 288 |
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) |