From c3d265b9e110eff919028ccf98cfb0567a008a4e Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 20:50:10 +0800 Subject: [PATCH 01/13] tests --- test/lit/ctor-eval/return_call.wast | 56 +++---------------- .../optimize-instructions-ignore-traps.wast | 38 +++++++------ .../lit/passes/optimize-instructions-mvp.wast | 31 +++++----- 3 files changed, 45 insertions(+), 80 deletions(-) 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..3221ff077ac 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) ) ) @@ -13874,11 +13876,8 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.or - ;; CHECK-NEXT: (local.tee $x - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -13896,11 +13895,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: ) From 4362844a225f4ddb31b129e99e8876fcc6cb56cb Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 21:02:30 +0800 Subject: [PATCH 02/13] opt for 7440 --- src/passes/OptimizeInstructions.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index ac15d5a490a..02bf93ef144 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->left, + LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5197,7 +5196,8 @@ struct OptimizeInstructions case LtUInt64: case GtSInt64: case GtUInt64: - return LiteralUtils::makeZero(Type::i32, *getModule()); + return getDroppedChildrenAndAppend(binary->left, + LiteralUtils::makeZero(Type::i32, *getModule())); case AndInt32: case OrInt32: case AndInt64: @@ -5213,7 +5213,8 @@ struct OptimizeInstructions case LeUInt64: case GeSInt64: case GeUInt64: - return LiteralUtils::makeFromInt32(1, Type::i32, *getModule()); + return getDroppedChildrenAndAppend(binary->left, + LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } From b684076c0c8a563baaa87135af5cdfb27432785b Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 21:35:28 +0800 Subject: [PATCH 03/13] Format the code --- src/passes/OptimizeInstructions.cpp | 32 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 02bf93ef144..468ab7a14ea 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -856,11 +856,13 @@ struct OptimizeInstructions if (auto* ret = replaceZeroBitsWithZero(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); + // 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); + } } } @@ -5175,17 +5177,18 @@ struct OptimizeInstructions return nullptr; } - // given a binary expression with equal children, we can fold various things - // regardless of side effects. - Expression* optimizeBinaryWithEqualChildren(Binary* binary) { + // given a binary expression with equal children and no side effects in + // either, we can fold various things + Expression* optimizeBinaryWithEqualEffectlessChildren(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 getDroppedChildrenAndAppend(binary->left, - LiteralUtils::makeZero(binary->left->type, *getModule())); + return getDroppedChildrenAndAppend( + binary->left, + LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5196,8 +5199,8 @@ struct OptimizeInstructions case LtUInt64: case GtSInt64: case GtUInt64: - return getDroppedChildrenAndAppend(binary->left, - LiteralUtils::makeZero(Type::i32, *getModule())); + return getDroppedChildrenAndAppend( + binary->left, LiteralUtils::makeZero(Type::i32, *getModule())); case AndInt32: case OrInt32: case AndInt64: @@ -5213,8 +5216,9 @@ struct OptimizeInstructions case LeUInt64: case GeSInt64: case GeUInt64: - return getDroppedChildrenAndAppend(binary->left, - LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); + return getDroppedChildrenAndAppend( + binary->left, + LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } From f7b9d49e67ee1d8fb3bd93c7e339cea0321c91f8 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 21:50:08 +0800 Subject: [PATCH 04/13] Update --- src/passes/OptimizeInstructions.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 468ab7a14ea..5ece773133b 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -856,14 +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); } if (auto* ret = deduplicateBinary(curr)) { @@ -5177,9 +5174,9 @@ 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: From 90104084ee672e8fe6c5776783b581dfb5b87a99 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 21:51:58 +0800 Subject: [PATCH 05/13] Update --- src/passes/OptimizeInstructions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 5ece773133b..04866ada968 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -861,6 +861,7 @@ struct OptimizeInstructions if (areConsecutiveInputsEqual(curr->left, curr->right)) { if (auto* ret = optimizeBinaryWithEqualChildren(curr)) { return replaceCurrent(ret); + } } if (auto* ret = deduplicateBinary(curr)) { From 256ce96b08d78a9bb6e8c9cb827968ef3646e923 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 22:42:44 +0800 Subject: [PATCH 06/13] Format the code --- src/passes/OptimizeInstructions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 04866ada968..217d68f1a9e 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -859,8 +859,8 @@ struct OptimizeInstructions // 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); + if (auto *ret = optimizeBinaryWithEqualChildren(curr)) { + return replaceCurrent(ret); } } From 844ec207919927a4e6a762a3108d08afca26fe08 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Mon, 7 Apr 2025 22:51:43 +0800 Subject: [PATCH 07/13] Format the code (I HATE CLANG-FORMAT) --- src/passes/OptimizeInstructions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 217d68f1a9e..0f3b88e49e1 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -859,7 +859,7 @@ struct OptimizeInstructions // 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)) { + if (auto* ret = optimizeBinaryWithEqualChildren(curr)) { return replaceCurrent(ret); } } From e4914943210a55da6e2748de0f0e1ff0848256b2 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 10:43:40 +0800 Subject: [PATCH 08/13] Fix --- src/passes/OptimizeInstructions.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 0f3b88e49e1..e2150068bb8 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -5185,8 +5185,7 @@ struct OptimizeInstructions case SubInt64: case XorInt64: return getDroppedChildrenAndAppend( - binary->left, - LiteralUtils::makeZero(binary->left->type, *getModule())); + binary, LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5198,12 +5197,18 @@ struct OptimizeInstructions case GtSInt64: case GtUInt64: return getDroppedChildrenAndAppend( - binary->left, LiteralUtils::makeZero(Type::i32, *getModule())); + 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 binary; + }; case EqInt32: case LeSInt32: case LeUInt32: @@ -5215,8 +5220,7 @@ struct OptimizeInstructions case GeSInt64: case GeUInt64: return getDroppedChildrenAndAppend( - binary->left, - LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); + binary, LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } From 1b764762c1d0a053c8695bf40b4907aa515fbec2 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 10:43:50 +0800 Subject: [PATCH 09/13] Revert "tests" This reverts commit c3d265b9e110eff919028ccf98cfb0567a008a4e. --- test/lit/ctor-eval/return_call.wast | 56 ++++++++++++++++--- .../optimize-instructions-ignore-traps.wast | 38 ++++++------- .../lit/passes/optimize-instructions-mvp.wast | 31 +++++----- 3 files changed, 80 insertions(+), 45 deletions(-) diff --git a/test/lit/ctor-eval/return_call.wast b/test/lit/ctor-eval/return_call.wast index 41d0a6fa2cd..d3bf96f27ab 100644 --- a/test/lit/ctor-eval/return_call.wast +++ b/test/lit/ctor-eval/return_call.wast @@ -448,15 +448,40 @@ ;; CHECK-NEXT: ) (module ;; Return call to self with different params, then stop evaluating. - ;; CHECK: (type $0 (func)) + ;; CHECK: (type $0 (func (param i32))) - ;; CHECK: (type $1 (func (param i32))) + ;; CHECK: (type $1 (func)) - ;; CHECK: (import "env" "import" (func $import (type $0))) + ;; CHECK: (import "env" "import" (func $import (type $1))) (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) @@ -481,11 +506,24 @@ ) ) -;; 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: (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-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 9e5e7964c72..8902cbc28f5 100644 --- a/test/lit/passes/optimize-instructions-ignore-traps.wast +++ b/test/lit/passes/optimize-instructions-ignore-traps.wast @@ -563,11 +563,9 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $1 - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.ne + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) @@ -620,26 +618,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: (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: (if (result i32) + ;; CHECK-NEXT: (local.tee $1 ;; CHECK-NEXT: (i32.const 0) ;; 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: (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: ) + ;; CHECK-NEXT: (i32.const 255) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 255) + ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (i32.const 0) ;; 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 3221ff077ac..5b137afa989 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -10541,13 +10541,11 @@ ) ;; CHECK: (func $add-sub-zero-reorder-2 (param $temp i32) (result i32) ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (local.get $temp) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) @@ -10558,8 +10556,8 @@ (local.tee $temp ;; in this order, the tee already comes first, so all is good for the optimization (i32.const 1) ) - (i32.sub ;; replace optimized sub with a const zero because the operations are identical - (i32.const 0) ;; while preserving the side effect + (i32.sub + (i32.const 0) (local.get $temp) ) ) @@ -13876,8 +13874,11 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.or ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (local.tee $x - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.or + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -13895,13 +13896,11 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.xor ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $x - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.xor + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) From 4a3bdf07ae2eb587aeace4d53616118c4806a71f Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 11:05:32 +0800 Subject: [PATCH 10/13] Fix replaceCurrent: avoid self-replacement --- src/passes/OptimizeInstructions.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index e2150068bb8..7b1ddb51d25 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -46,6 +46,7 @@ #include #include +#include "asmjs/shared-constants.h" #include "call-utils.h" // TODO: Use the new sign-extension opcodes where appropriate. This needs to be @@ -264,6 +265,11 @@ struct OptimizeInstructions bool inReplaceCurrent = false; void replaceCurrent(Expression* rep) { + // Avoid self-replacement; + if (rep == getCurrent()) { + return; + } + if (rep->type != getCurrent()->type) { // This operation will change the type, so refinalize. refinalize = true; @@ -5185,7 +5191,8 @@ struct OptimizeInstructions case SubInt64: case XorInt64: return getDroppedChildrenAndAppend( - binary, LiteralUtils::makeZero(binary->left->type, *getModule())); + binary->left, + LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5197,7 +5204,7 @@ struct OptimizeInstructions case GtSInt64: case GtUInt64: return getDroppedChildrenAndAppend( - binary, LiteralUtils::makeZero(Type::i32, *getModule())); + binary->left, LiteralUtils::makeZero(Type::i32, *getModule())); case AndInt32: case OrInt32: case AndInt64: @@ -5220,7 +5227,8 @@ struct OptimizeInstructions case GeSInt64: case GeUInt64: return getDroppedChildrenAndAppend( - binary, LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); + binary->left, + LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } From 3967445219a97b81199c1f2aff73b9e73000f180 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 11:31:04 +0800 Subject: [PATCH 11/13] Fix --- src/passes/OptimizeInstructions.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 7b1ddb51d25..deef0175a8b 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -265,11 +265,6 @@ struct OptimizeInstructions bool inReplaceCurrent = false; void replaceCurrent(Expression* rep) { - // Avoid self-replacement; - if (rep == getCurrent()) { - return; - } - if (rep->type != getCurrent()->type) { // This operation will change the type, so refinalize. refinalize = true; @@ -5191,8 +5186,7 @@ struct OptimizeInstructions case SubInt64: case XorInt64: return getDroppedChildrenAndAppend( - binary->left, - LiteralUtils::makeZero(binary->left->type, *getModule())); + binary, LiteralUtils::makeZero(binary->left->type, *getModule())); case NeInt32: case LtSInt32: case LtUInt32: @@ -5204,7 +5198,7 @@ struct OptimizeInstructions case GtSInt64: case GtUInt64: return getDroppedChildrenAndAppend( - binary->left, LiteralUtils::makeZero(Type::i32, *getModule())); + binary, LiteralUtils::makeZero(Type::i32, *getModule())); case AndInt32: case OrInt32: case AndInt64: @@ -5214,7 +5208,7 @@ struct OptimizeInstructions return binary->left; } } - return binary; + return nullptr; }; case EqInt32: case LeSInt32: @@ -5227,8 +5221,7 @@ struct OptimizeInstructions case GeSInt64: case GeUInt64: return getDroppedChildrenAndAppend( - binary->left, - LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); + binary, LiteralUtils::makeFromInt32(1, Type::i32, *getModule())); default: return nullptr; } From b240e1da2c87b09da711ed6a18365bdc49795fcb Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 11:37:23 +0800 Subject: [PATCH 12/13] Update test --- test/lit/ctor-eval/return_call.wast | 56 +++---------------- .../optimize-instructions-ignore-traps.wast | 38 +++++++------ .../lit/passes/optimize-instructions-mvp.wast | 24 ++++---- 3 files changed, 43 insertions(+), 75 deletions(-) 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: ) From 53c9116a528a5b31f6f77b9d861c6680f944d3c9 Mon Sep 17 00:00:00 2001 From: Ruiyang Xu Date: Wed, 9 Apr 2025 11:39:04 +0800 Subject: [PATCH 13/13] Remove unused include --- src/passes/OptimizeInstructions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index deef0175a8b..247c59e1dcf 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -46,7 +46,6 @@ #include #include -#include "asmjs/shared-constants.h" #include "call-utils.h" // TODO: Use the new sign-extension opcodes where appropriate. This needs to be