diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 28d5ae68153..770cf75c391 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2793,6 +2793,7 @@ struct OptimizeInstructions // Ignore extraneous things and compare them syntactically. We can also // look at the full fallthrough for both sides now. + auto* originalLeft = left; left = getFallthrough(left); auto* originalRight = right; right = getFallthrough(right); @@ -2821,6 +2822,26 @@ struct OptimizeInstructions } } + // The same, with left, as we can have this situation: + // + // (local.tee $x ..) + // (something using $x) + // ) + // (something using $x) + // + // The fallthroughs are identical, but the tee may cause us to read a + // different value. + if (originalLeft != left) { + auto originalLeftEffects = effects(originalLeft); + // |left == right| here (we would have exited early, otherwise, above), so + // we could compute either. Compute |left| as it might have better cache + // locality. + auto leftEffects = effects(left); + if (originalLeftEffects.invalidates(leftEffects)) { + return false; + } + } + // To be equal, they must also be known to return the same result // deterministically. We check the right side, as if the right is marked // idempotent, that is enough (that tells us it does not generate a new diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index 8a4b729fa9c..c744c0eb3ad 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -16451,6 +16451,43 @@ ) ) ) + + ;; CHECK: (func $ternary-tee-with-identical-values (param $x i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ternary-tee-with-identical-values (param $x i32) + (drop + ;; The tee's value, and the select's condition, are equal. If we just + ;; look at them, we could think they are equal, and simplify this. + ;; However, the tee modifies $x, so we cannot fold those two + ;; expressions together while removing the select. (We can, though, + ;; remove the select and the const, and use an and, but we do remain with + ;; two copies of the eq, as those interact.) + (select + (local.tee $x + (i32.eqz + (local.get $x) + ) + ) + (i32.const 0) + (i32.eqz + (local.get $x) + ) + ) + ) + ) + ;; CHECK: (func $send-i32 (param $0 i32) ;; CHECK-NEXT: ) (func $send-i32 (param i32))