From 4b2f5f5dd550f11ee8cfcc491c7d7893f13b0f41 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Tue, 16 Nov 2021 17:09:11 +0200 Subject: [PATCH 1/3] init --- src/passes/OptimizeInstructions.cpp | 41 ++++++++++++++++++---- test/lit/passes/optimize-instructions.wast | 31 ++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 7c450ac060a..71daeae298a 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 @@ -2486,6 +2491,28 @@ 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)))) && + x->type == y->type) { + auto* inner = curr->left->cast(); + inner->value = Builder(*getModule()) + .makeBinary(Abstract::getBinary(x->type, Or), x, y); + return inner; + } + } + return nullptr; + } + // We can combine `or` operations, e.g. // (x > y) | (x == y) ==> x >= y Expression* combineOr(Binary* binary) { diff --git a/test/lit/passes/optimize-instructions.wast b/test/lit/passes/optimize-instructions.wast index 26ef699d162..3504ef857cf 100644 --- a/test/lit/passes/optimize-instructions.wast +++ b/test/lit/passes/optimize-instructions.wast @@ -10971,6 +10971,37 @@ ) )) ) + + ;; CHECK: (func $optimize-combined-by-and-equals-to-zero (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: ) + (func $optimize-combined-by-and-equals-to-zero (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.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.eq (local.get $a) (i64.const 0)) + (i64.eq (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 ad2e3464d3ad28a011025fae9b17f31351a54df4 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Wed, 17 Nov 2021 00:07:45 +0200 Subject: [PATCH 2/3] remove comment --- src/passes/OptimizeInstructions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 71daeae298a..a667ee09f77 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2493,7 +2493,6 @@ 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; From 2d9f6711d4d9c094ea4674f78f9b3688fb9b5614 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Wed, 17 Nov 2021 00:10:37 +0200 Subject: [PATCH 3/3] move combineAnd & combineOr before conditionalizeExpensiveOnBitwise --- src/passes/OptimizeInstructions.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index a667ee09f77..c0ba2dc02f3 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -773,11 +773,6 @@ struct OptimizeInstructions } } 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); - } if (curr->op == AndInt32) { if (auto* ret = combineAnd(curr)) { return replaceCurrent(ret); @@ -789,6 +784,11 @@ struct OptimizeInstructions return replaceCurrent(ret); } } + // bitwise operations + // for and and or, we can potentially conditionalize + if (auto* ret = conditionalizeExpensiveOnBitwise(curr)) { + return replaceCurrent(ret); + } } // relation/comparisons allow for math optimizations if (curr->isRelational()) {