From bec4789424d18aae71d64a8164d930290bb2caea Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Thu, 21 Oct 2021 17:58:41 +0300 Subject: [PATCH 1/6] init --- src/passes/OptimizeInstructions.cpp | 104 +++++++++++++--- .../inlining-optimizing_optimize-level=3.wast | 9 +- test/lit/passes/optimize-instructions.wast | 114 ++++++++++++++++++ 3 files changed, 207 insertions(+), 20 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index f23c119eca3..b6ea0ec8412 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -772,17 +772,22 @@ struct OptimizeInstructions return replaceCurrent(ret); } } - // bitwise operations - // for and and or, we can potentially conditionalize if (curr->op == AndInt32 || curr->op == OrInt32) { + // bitwise operations + // for and and or, we can potentially conditionalize if (auto* ret = conditionalizeExpensiveOnBitwise(curr)) { return replaceCurrent(ret); } - } - // for or, we can potentially combine - if (curr->op == OrInt32) { - if (auto* ret = combineOr(curr)) { - return replaceCurrent(ret); + if (curr->op == AndInt32) { + if (auto* ret = combineAnd(curr)) { + return replaceCurrent(ret); + } + } + // for or, we can potentially combine + if (curr->op == OrInt32) { + if (auto* ret = combineOr(curr)) { + return replaceCurrent(ret); + } } } // relation/comparisons allow for math optimizations @@ -2388,12 +2393,53 @@ struct OptimizeInstructions } } + // We can combine `and` operations, e.g. + // (x == 0) & (y == 0) ==> (x | y) == 0 + // (x < 0) & (y < 0) ==> (x & y) < 0 + Expression* combineAnd(Binary* curr) { + using namespace Abstract; + using namespace Match; + { + // (i32(x) == 0) & (i32(y) == 0) ==> i32(x | y) == 0 + // (i64(x) == 0) & (i64(y) == 0) ==> i64(x | y) == 0 + Expression *x, *y; + if (matches(curr, + binary(AndInt32, unary(EqZ, any(&x)), unary(EqZ, any(&y))))) { + auto* inner = curr->left->cast(); + inner->value = + Builder(*getModule()) + .makeBinary(Abstract::getBinary(inner->value->type, Or), x, y); + return curr->left; + } + } + { + // (i32(x) < 0) & (i32(y) < 0) ==> i32(x & y) < 0 + // (i64(x) < 0) & (i64(y) < 0) ==> i64(x & y) < 0 + Expression *x, *y; + if (matches(curr, + binary(AndInt32, + binary(LtS, any(&x), ival(0)), + binary(LtS, any(&y), ival(0))))) { + auto* inner = curr->left->cast(); + inner->left = + Builder(*getModule()) + .makeBinary(Abstract::getBinary(inner->right->type, And), x, y); + return curr->left; + } + } + return nullptr; + } + // We can combine `or` operations, e.g. // (x > y) | (x == y) ==> x >= y - Expression* combineOr(Binary* binary) { - assert(binary->op == OrInt32); - if (auto* left = binary->left->dynCast()) { - if (auto* right = binary->right->dynCast()) { + // (x != 0) | (y != 0) ==> (x | y) != 0 + Expression* combineOr(Binary* curr) { + using namespace Abstract; + using namespace Match; + + assert(curr->op == OrInt32); + if (auto* left = curr->left->dynCast()) { + if (auto* right = curr->right->dynCast()) { if (left->op != right->op && ExpressionAnalyzer::equal(left->left, right->left) && ExpressionAnalyzer::equal(left->right, right->right) && @@ -2414,6 +2460,36 @@ struct OptimizeInstructions } } } + { + // (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0 + // (i64(x) != 0) | (i64(y) != 0) ==> i64(x | y) != 0 + Expression *x, *y; + if (matches(curr, + binary(OrInt32, + binary(Ne, any(&x), ival(0)), + binary(Ne, any(&y), ival(0))))) { + auto* inner = curr->left->cast(); + inner->left = + Builder(*getModule()) + .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); + return curr->left; + } + } + { + // (i32(x) < 0) | (i32(y) < 0) ==> i32(x | y) < 0 + // (i64(x) < 0) | (i64(y) < 0) ==> i64(x | y) < 0 + Expression *x, *y; + if (matches(curr, + binary(OrInt32, + binary(LtS, any(&x), ival(0)), + binary(LtS, any(&y), ival(0))))) { + auto* inner = curr->left->cast(); + inner->left = + Builder(*getModule()) + .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); + return curr->left; + } + } return nullptr; } @@ -2957,14 +3033,14 @@ struct OptimizeInstructions } } } + + using namespace Abstract; + using namespace Match; // x - y == 0 => x == y // x - y != 0 => x != y // unsigned(x - y) > 0 => x != y // unsigned(x - y) <= 0 => x == y { - using namespace Abstract; - using namespace Match; - Binary* inner; // unsigned(x - y) > 0 => x != y if (matches(curr, diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast index 1ae11b22afa..83aeb5824d9 100644 --- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast +++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast @@ -8882,19 +8882,16 @@ ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (local.get $6) ;; CHECK-NEXT: (local.tee $12 - ;; CHECK-NEXT: (i32.or - ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (i32.load ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.ne ;; CHECK-NEXT: (i32.load offset=4 ;; CHECK-NEXT: (local.get $13) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index 76074dadfa5..ebbfe1398d3 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -10880,6 +10880,120 @@ ) )) ) + ;; CHECK: (func $optimize-compaund-relationals (param $x i32) (param $y i32) (param $a i64) (param $b i64) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.eqz + ;; CHECK-NEXT: (i64.or + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.ne + ;; CHECK-NEXT: (i64.or + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.lt_s + ;; CHECK-NEXT: (i64.or + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.lt_s + ;; CHECK-NEXT: (i64.and + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-compaund-relationals (param $x i32) (param $y i32) (param $a i64) (param $b i64) + ;; (i32(x) == 0) & (i32(y) == 0) ==> i32(x | y) == 0 + (drop (i32.and + (i32.eqz (local.get $x)) + (i32.eqz (local.get $y)) + )) + ;; (i64(x) == 0) & (i64(y) == 0) ==> i64(x | y) == 0 + (drop (i32.and + (i64.eqz (local.get $a)) + (i64.eqz (local.get $b)) + )) + ;; (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0 + (drop (i32.or + (i32.ne (local.get $x) (i32.const 0)) + (i32.ne (local.get $y) (i32.const 0)) + )) + ;; (i64(x) != 0) | (i64(y) != 0) ==> i64(x | y) != 0 + (drop (i32.or + (i64.ne (local.get $a) (i64.const 0)) + (i64.ne (local.get $b) (i64.const 0)) + )) + ;; (i32(x) < 0) | (i32(y) < 0) ==> i32(x | y) < 0 + (drop (i32.or + (i32.lt_s (local.get $x) (i32.const 0)) + (i32.lt_s (local.get $y) (i32.const 0)) + )) + ;; (i64(x) < 0) | (i64(y) < 0) ==> i64(x | y) < 0 + (drop (i32.or + (i64.lt_s (local.get $a) (i64.const 0)) + (i64.lt_s (local.get $b) (i64.const 0)) + )) + ;; (i32(x) < 0) & (i32(y) < 0) ==> i32(x & y) < 0 + (drop (i32.and + (i32.lt_s (local.get $x) (i32.const 0)) + (i32.lt_s (local.get $y) (i32.const 0)) + )) + ;; (i64(x) < 0) & (i64(y) < 0) ==> i64(x & y) < 0 + (drop (i32.and + (i64.lt_s (local.get $a) (i64.const 0)) + (i64.lt_s (local.get $b) (i64.const 0)) + )) + ) ;; CHECK: (func $optimize-relationals (param $x i32) (param $y i32) (param $X i64) (param $Y i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.eq From b6a2f3506b846546b7dde7dfc31c5009c90bd2f6 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Thu, 21 Oct 2021 18:41:10 +0300 Subject: [PATCH 2/6] fix --- src/passes/OptimizeInstructions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index b6ea0ec8412..ff5eace0f3d 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2409,7 +2409,7 @@ struct OptimizeInstructions inner->value = Builder(*getModule()) .makeBinary(Abstract::getBinary(inner->value->type, Or), x, y); - return curr->left; + return inner; } } { @@ -2424,7 +2424,7 @@ struct OptimizeInstructions inner->left = Builder(*getModule()) .makeBinary(Abstract::getBinary(inner->right->type, And), x, y); - return curr->left; + return inner; } } return nullptr; @@ -2472,7 +2472,7 @@ struct OptimizeInstructions inner->left = Builder(*getModule()) .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); - return curr->left; + return inner; } } { @@ -2487,7 +2487,7 @@ struct OptimizeInstructions inner->left = Builder(*getModule()) .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); - return curr->left; + return inner; } } return nullptr; From 07effa53b923d264d1589fb20b2684c3e82c612f Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Thu, 21 Oct 2021 18:59:34 +0300 Subject: [PATCH 3/6] fixes --- src/passes/OptimizeInstructions.cpp | 12 ++++-- test/lit/passes/optimize-instructions.wast | 50 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index ff5eace0f3d..db8481efae5 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2404,7 +2404,8 @@ struct OptimizeInstructions // (i64(x) == 0) & (i64(y) == 0) ==> i64(x | y) == 0 Expression *x, *y; if (matches(curr, - binary(AndInt32, unary(EqZ, any(&x)), unary(EqZ, any(&y))))) { + binary(AndInt32, unary(EqZ, any(&x)), unary(EqZ, any(&y)))) && + x->type == y->type) { auto* inner = curr->left->cast(); inner->value = Builder(*getModule()) @@ -2419,7 +2420,8 @@ struct OptimizeInstructions if (matches(curr, binary(AndInt32, binary(LtS, any(&x), ival(0)), - binary(LtS, any(&y), ival(0))))) { + binary(LtS, any(&y), ival(0)))) && + x->type == y->type) { auto* inner = curr->left->cast(); inner->left = Builder(*getModule()) @@ -2467,7 +2469,8 @@ struct OptimizeInstructions if (matches(curr, binary(OrInt32, binary(Ne, any(&x), ival(0)), - binary(Ne, any(&y), ival(0))))) { + binary(Ne, any(&y), ival(0)))) && + x->type == y->type) { auto* inner = curr->left->cast(); inner->left = Builder(*getModule()) @@ -2482,7 +2485,8 @@ struct OptimizeInstructions if (matches(curr, binary(OrInt32, binary(LtS, any(&x), ival(0)), - binary(LtS, any(&y), ival(0))))) { + binary(LtS, any(&y), ival(0)))) && + x->type == y->type) { auto* inner = curr->left->cast(); inner->left = Builder(*getModule()) diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index ebbfe1398d3..26f9bf7f6b3 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -10951,6 +10951,40 @@ ;; CHECK-NEXT: (i64.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.eqz + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.lt_s + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (i32.lt_s + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.lt_s + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $optimize-compaund-relationals (param $x i32) (param $y i32) (param $a i64) (param $b i64) ;; (i32(x) == 0) & (i32(y) == 0) ==> i32(x | y) == 0 @@ -10993,6 +11027,22 @@ (i64.lt_s (local.get $a) (i64.const 0)) (i64.lt_s (local.get $b) (i64.const 0)) )) + + ;; (i32(x) == 0) & (i64(y) == 0) ==> skip + (drop (i32.and + (i32.eqz (local.get $x)) + (i64.eqz (local.get $a)) + )) + ;; (i32(x) < 0) | (i64(y) < 0) ==> skip + (drop (i32.or + (i32.lt_s (local.get $x) (i32.const 0)) + (i64.lt_s (local.get $a) (i64.const 0)) + )) + ;; (i64(x) < 0) & (i32(y) < 0) ==> skip + (drop (i32.and + (i64.lt_s (local.get $a) (i64.const 0)) + (i32.lt_s (local.get $x) (i32.const 0)) + )) ) ;; CHECK: (func $optimize-relationals (param $x i32) (param $y i32) (param $X i64) (param $Y i64) ;; CHECK-NEXT: (drop From 4141109d896ac852d3b1239a06946655da44dd9a Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Fri, 22 Oct 2021 11:16:00 +0300 Subject: [PATCH 4/6] refactor --- src/passes/OptimizeInstructions.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index db8481efae5..1a965eb5e91 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2407,9 +2407,8 @@ struct OptimizeInstructions binary(AndInt32, unary(EqZ, any(&x)), unary(EqZ, any(&y)))) && x->type == y->type) { auto* inner = curr->left->cast(); - inner->value = - Builder(*getModule()) - .makeBinary(Abstract::getBinary(inner->value->type, Or), x, y); + inner->value = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, Or), x, y); return inner; } } @@ -2423,9 +2422,8 @@ struct OptimizeInstructions binary(LtS, any(&y), ival(0)))) && x->type == y->type) { auto* inner = curr->left->cast(); - inner->left = - Builder(*getModule()) - .makeBinary(Abstract::getBinary(inner->right->type, And), x, y); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, And), x, y); return inner; } } @@ -2472,9 +2470,8 @@ struct OptimizeInstructions binary(Ne, any(&y), ival(0)))) && x->type == y->type) { auto* inner = curr->left->cast(); - inner->left = - Builder(*getModule()) - .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, Or), x, y); return inner; } } @@ -2488,9 +2485,8 @@ struct OptimizeInstructions binary(LtS, any(&y), ival(0)))) && x->type == y->type) { auto* inner = curr->left->cast(); - inner->left = - Builder(*getModule()) - .makeBinary(Abstract::getBinary(inner->right->type, Or), x, y); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, Or), x, y); return inner; } } From d2b716f5a55c26645b7519d9b9f62e469e8222ff Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Fri, 22 Oct 2021 13:54:43 +0300 Subject: [PATCH 5/6] add x >= 0 or/and y >= 0 rule --- src/passes/OptimizeInstructions.cpp | 30 ++++++++++++ test/lit/passes/optimize-instructions.wast | 56 ++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 1a965eb5e91..0c441860e5e 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2427,6 +2427,21 @@ struct OptimizeInstructions return inner; } } + { + // (i32(x) >= 0) & (i32(y) >= 0) => i32(x | y) >= 0 + // (i64(x) >= 0) & (i64(y) >= 0) => i64(x | y) >= 0 + Expression *x, *y; + if (matches(curr, + binary(AndInt32, + binary(GeS, any(&x), ival(0)), + binary(GeS, any(&y), ival(0)))) && + x->type == y->type) { + auto* inner = curr->left->cast(); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, Or), x, y); + return inner; + } + } return nullptr; } @@ -2490,6 +2505,21 @@ struct OptimizeInstructions return inner; } } + { + // (i32(x) >= 0) | (i32(y) >= 0) => i32(x & y) >= 0 + // (i64(x) >= 0) | (i64(y) >= 0) => i64(x & y) >= 0 + Expression *x, *y; + if (matches(curr, + binary(OrInt32, + binary(GeS, any(&x), ival(0)), + binary(GeS, any(&y), ival(0)))) && + x->type == y->type) { + auto* inner = curr->left->cast(); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, And), x, y); + return inner; + } + } return nullptr; } diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index 26f9bf7f6b3..b156ae95d4e 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -10952,6 +10952,42 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.ge_s + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.ge_s + ;; CHECK-NEXT: (i64.or + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.ge_s + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.ge_s + ;; CHECK-NEXT: (i64.and + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (local.get $x) @@ -11027,6 +11063,26 @@ (i64.lt_s (local.get $a) (i64.const 0)) (i64.lt_s (local.get $b) (i64.const 0)) )) + ;; (i32(x) >= 0) & (i32(y) >= 0) ==> i32(x | y) >= 0 + (drop (i32.and + (i32.ge_s (local.get $x) (i32.const 0)) + (i32.ge_s (local.get $y) (i32.const 0)) + )) + ;; (i64(x) >= 0) & (i64(y) >= 0) ==> i64(x | y) >= 0 + (drop (i32.and + (i64.ge_s (local.get $a) (i64.const 0)) + (i64.ge_s (local.get $b) (i64.const 0)) + )) + ;; (i32(x) >= 0) | (i32(y) >= 0) ==> i32(x & y) >= 0 + (drop (i32.or + (i32.ge_s (local.get $x) (i32.const 0)) + (i32.ge_s (local.get $y) (i32.const 0)) + )) + ;; (i64(x) >= 0) | (i64(y) >= 0) ==> i64(x & y) >= 0 + (drop (i32.or + (i64.ge_s (local.get $a) (i64.const 0)) + (i64.ge_s (local.get $b) (i64.const 0)) + )) ;; (i32(x) == 0) & (i64(y) == 0) ==> skip (drop (i32.and From 4c48f298c6bd4b840e8c0ccc6eb62f9938814480 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Wed, 27 Oct 2021 23:27:07 +0300 Subject: [PATCH 6/6] more rules --- src/passes/OptimizeInstructions.cpp | 30 ++++++++++ test/lit/passes/gto-mutability.wast | 3 +- test/lit/passes/optimize-instructions.wast | 64 ++++++++++++++++++++-- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index df143a58a28..3bc7b5f405c 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2486,6 +2486,21 @@ struct OptimizeInstructions return inner; } } + { + // (i32(x) == -1) & (i32(y) == -1) ==> i32(x & y) == -1 + // (i64(x) == -1) & (i64(y) == -1) ==> i64(x & y) == -1 + Expression *x, *y; + if (matches(curr, + binary(AndInt32, + binary(Eq, any(&x), ival(-1)), + binary(Eq, any(&y), ival(-1)))) && + x->type == y->type) { + auto* inner = curr->left->cast(); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, And), x, y); + return inner; + } + } return nullptr; } @@ -2564,6 +2579,21 @@ struct OptimizeInstructions return inner; } } + { + // (i32(x) != -1) | (i32(y) != -1) ==> i32(x & y) != -1 + // (i64(x) != -1) | (i64(y) != -1) ==> i64(x & y) != -1 + Expression *x, *y; + if (matches(curr, + binary(OrInt32, + binary(Ne, any(&x), ival(-1)), + binary(Ne, any(&y), ival(-1)))) && + x->type == y->type) { + auto* inner = curr->left->cast(); + inner->left = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, And), x, y); + return inner; + } + } return nullptr; } diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast index 6cb3575d76d..26376e738d2 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -14,6 +14,8 @@ (type $two-params (func (param (ref $struct)) (param (ref $struct)))) ;; Test that we update tag types properly. + (table 0 funcref) + ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) ;; CHECK: (type $none_=>_ref?|$struct| (func_subtype (result (ref null $struct)) func)) @@ -21,7 +23,6 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (table $0 0 funcref) - (table 0 funcref) ;; CHECK: (elem declare func $func-two-params) diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index c79ffff07e1..5353c88e0a3 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -11079,6 +11079,42 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.eq + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.eq + ;; CHECK-NEXT: (i64.and + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i64.ne + ;; CHECK-NEXT: (i64.and + ;; CHECK-NEXT: (local.get $a) + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i64.const -1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (i32.eqz ;; CHECK-NEXT: (local.get $x) @@ -11116,13 +11152,13 @@ (func $optimize-compaund-relationals (param $x i32) (param $y i32) (param $a i64) (param $b i64) ;; (i32(x) == 0) & (i32(y) == 0) ==> i32(x | y) == 0 (drop (i32.and - (i32.eqz (local.get $x)) - (i32.eqz (local.get $y)) + (i32.eq (local.get $x) (i32.const 0)) + (i32.eq (local.get $y) (i32.const 0)) )) ;; (i64(x) == 0) & (i64(y) == 0) ==> i64(x | y) == 0 (drop (i32.and - (i64.eqz (local.get $a)) - (i64.eqz (local.get $b)) + (i64.eq (local.get $a) (i64.const 0)) + (i64.eq (local.get $b) (i64.const 0)) )) ;; (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0 (drop (i32.or @@ -11174,6 +11210,26 @@ (i64.ge_s (local.get $a) (i64.const 0)) (i64.ge_s (local.get $b) (i64.const 0)) )) + ;; (i32(x) == -1) & (i32(y) == -1) ==> i32(x & y) == -1 + (drop (i32.and + (i32.eq (local.get $x) (i32.const -1)) + (i32.eq (local.get $y) (i32.const -1)) + )) + ;; (i64(x) == -1) & (i64(y) == -1) ==> i64(x & y) == -1 + (drop (i32.and + (i64.eq (local.get $a) (i64.const -1)) + (i64.eq (local.get $b) (i64.const -1)) + )) + ;; (i32(x) != -1) | (i32(y) != -1) ==> i32(x & y) != -1 + (drop (i32.or + (i32.ne (local.get $x) (i32.const -1)) + (i32.ne (local.get $y) (i32.const -1)) + )) + ;; (i64(x) != -1) | (i64(y) == -1) ==> i64(x & y) != -1 + (drop (i32.or + (i64.ne (local.get $a) (i64.const -1)) + (i64.ne (local.get $b) (i64.const -1)) + )) ;; (i32(x) == 0) & (i64(y) == 0) ==> skip (drop (i32.and