diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index ac15d5a490a..247c59e1dcf 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -856,13 +856,11 @@ struct OptimizeInstructions if (auto* ret = replaceZeroBitsWithZero(curr)) { return replaceCurrent(ret); } - // finally, try more expensive operations on the curr in - // the case that they have no side effects - if (!effects(curr->left).hasSideEffects()) { - if (ExpressionAnalyzer::equal(curr->left, curr->right)) { - if (auto* ret = optimizeBinaryWithEqualEffectlessChildren(curr)) { - return replaceCurrent(ret); - } + // finally, try more expensive operations on the curr + // regardless of whether they have side effects or not. + if (areConsecutiveInputsEqual(curr->left, curr->right)) { + if (auto* ret = optimizeBinaryWithEqualChildren(curr)) { + return replaceCurrent(ret); } } @@ -5177,16 +5175,17 @@ struct OptimizeInstructions return nullptr; } - // given a binary expression with equal children and no side effects in - // either, we can fold various things - Expression* optimizeBinaryWithEqualEffectlessChildren(Binary* binary) { + // given a binary expression with equal children, we can fold various things + // regardless of side effects. + Expression* optimizeBinaryWithEqualChildren(Binary* binary) { // TODO add: perhaps worth doing 2*x if x is quite large? switch (binary->op) { case SubInt32: case XorInt32: case SubInt64: case XorInt64: - return LiteralUtils::makeZero(binary->left->type, *getModule()); + return getDroppedChildrenAndAppend( + binary, LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5197,12 +5196,19 @@ struct OptimizeInstructions case LtUInt64: case GtSInt64: case GtUInt64: - return LiteralUtils::makeZero(Type::i32, *getModule()); + return getDroppedChildrenAndAppend( + binary, LiteralUtils::makeZero(Type::i32, *getModule())); case AndInt32: case OrInt32: case AndInt64: - case OrInt64: - return binary->left; + case OrInt64: { + if (!effects(binary->left).hasSideEffects()) { + if (ExpressionAnalyzer::equal(binary->left, binary->right)) { + return binary->left; + } + } + return nullptr; + }; case EqInt32: case LeSInt32: case LeUInt32: @@ -5213,7 +5219,8 @@ struct OptimizeInstructions case LeUInt64: case GeSInt64: case GeUInt64: - return LiteralUtils::makeFromInt32(1, Type::i32, *getModule()); + return getDroppedChildrenAndAppend( + binary, LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } diff --git a/test/lit/ctor-eval/return_call.wast b/test/lit/ctor-eval/return_call.wast index d3bf96f27ab..41d0a6fa2cd 100644 --- a/test/lit/ctor-eval/return_call.wast +++ b/test/lit/ctor-eval/return_call.wast @@ -448,40 +448,15 @@ ;; CHECK-NEXT: ) (module ;; Return call to self with different params, then stop evaluating. - ;; CHECK: (type $0 (func (param i32))) + ;; CHECK: (type $0 (func)) - ;; CHECK: (type $1 (func)) + ;; CHECK: (type $1 (func (param i32))) - ;; CHECK: (import "env" "import" (func $import (type $1))) + ;; CHECK: (import "env" "import" (func $import (type $0))) (import "env" "import" (func $import)) - ;; CHECK: (global $g (mut i32) (i32.const 42)) (global $g (mut i32) (i32.const 0)) - ;; CHECK: (export "test" (func $test_2)) - - ;; CHECK: (func $test (type $0) (param $0 i32) - ;; CHECK-NEXT: (global.set $g - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (i32.eq - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (call $import) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (return_call $test - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) (func $test (export "test") (param i32) (global.set $g (local.get 0) @@ -506,24 +481,11 @@ ) ) -;; CHECK: (func $test_2 (type $0) (param $0 i32) -;; CHECK-NEXT: (if -;; CHECK-NEXT: (i32.eq -;; CHECK-NEXT: (local.tee $0 -;; CHECK-NEXT: (i32.const 42) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (i32.const 42) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (then -;; CHECK-NEXT: (call $import) -;; CHECK-NEXT: ) -;; CHECK-NEXT: (else -;; CHECK-NEXT: (return_call $test -;; CHECK-NEXT: (i32.add -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: (i32.const 1) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) +;; CHECK: (export "test" (func $test_2)) + +;; CHECK: (func $test_2 (type $1) (param $0 i32) +;; CHECK-NEXT: (local.set $0 +;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) +;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/optimize-instructions-ignore-traps.wast b/test/lit/passes/optimize-instructions-ignore-traps.wast index 8902cbc28f5..9e5e7964c72 100644 --- a/test/lit/passes/optimize-instructions-ignore-traps.wast +++ b/test/lit/passes/optimize-instructions-ignore-traps.wast @@ -563,9 +563,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.ne - ;; CHECK-NEXT: (local.tee $1 - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) @@ -618,26 +620,26 @@ ;; CHECK: (func $invalidate-conditionalizeExpensiveOnBitwise-ok (type $0) (param $0 i32) (param $1 i32) (result i32) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (i32.lt_u - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (i32.extend8_s - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.lt_u + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (i32.extend8_s + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 255) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: (i32.const 255) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index 5b137afa989..2ebc44b554e 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -10541,11 +10541,13 @@ ) ;; CHECK: (func $add-sub-zero-reorder-2 (param $temp i32) (result i32) ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $temp) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) @@ -10556,8 +10558,8 @@ (local.tee $temp ;; in this order, the tee already comes first, so all is good for the optimization (i32.const 1) ) - (i32.sub - (i32.const 0) + (i32.sub ;; replace optimized sub with a const zero because the operations are identical + (i32.const 0) ;; while preserving the side effect (local.get $temp) ) ) @@ -13896,11 +13898,13 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.xor ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.xor - ;; CHECK-NEXT: (local.tee $x - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: )