Skip to content

Commit 8e1c0bc

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,compiler] Fix incorrect handling of unwrapped phi in constant propagation
When constant propagation evaluates EqualityCompare or StrictCompare, it can unwrap phis (if they are redundant wrt current set of reachable blocks), and calculate value if both lhs and rhs operands are the same. Previously, phi was marked as unwrapped only if that calculation changes the constant value of comparison. This is not correct as calculation based on unwrapped phi needs to be invalidated anyway if more reachable blocks are discovered and unwrapped phi becomes non-redundant. The fix is to mark the unwrapped phis regardless of whether the constant value of comparison has been changed or not. TEST=vm/dart/regress_60349_test Fixes #60349 Change-Id: I01e46d6def67fdc5d4c0bdc3a73aaac94725e221 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417021 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent c0e8f90 commit 8e1c0bc

File tree

2 files changed

+66
-14
lines changed

2 files changed

+66
-14
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--optimization_counter_threshold=100 --deterministic
6+
7+
// Verify that constant propagation doesn't perform an incorrect
8+
// optimization involving unwrapped phi.
9+
// Regression test for https://github.com/dart-lang/sdk/issues/60349
10+
11+
import "package:expect/expect.dart";
12+
13+
@pragma('vm:never-inline')
14+
void foo(int? x, int y) {
15+
List<int> l = [1];
16+
int ll = l.length; // ll = 1
17+
int n = 0;
18+
int? a;
19+
while (true) {
20+
int b = 0;
21+
// As ll == 1, the loop below only ever has one iteration.
22+
for (int i = 0; i < ll; i++) {
23+
// y == 2, and n only reaches 1 in this program, but removing this
24+
// condition makes the bug go away:
25+
if (n == y) {
26+
return;
27+
}
28+
b = 1234 + n * 1111;
29+
}
30+
31+
// On the first iteration, "a" is set to "b" (2025).
32+
if (n == 0) {
33+
a = b;
34+
}
35+
36+
// This condition is false on the first iteration (1234 vs 2025) and true
37+
// on the second (2345 vs 2025):
38+
if (b >= x!) {
39+
// This should never be true.
40+
if (b == a) {
41+
Expect.fail("BUG! $b == $a?!?");
42+
}
43+
return;
44+
}
45+
46+
n++;
47+
}
48+
}
49+
50+
void main() {
51+
for (int i = 0; i < 150; ++i) {
52+
foo(int.parse('2025'), int.parse('2'));
53+
}
54+
}

runtime/vm/compiler/backend/constant_propagator.cc

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -586,13 +586,12 @@ void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) {
586586
Definition* unwrapped_right_defn = UnwrapPhi(right_defn);
587587
if (unwrapped_left_defn == unwrapped_right_defn) {
588588
// Fold x === x, and x !== x to true/false.
589-
if (SetValue(instr, Bool::Get(instr->kind() == Token::kEQ_STRICT))) {
590-
if (unwrapped_left_defn != left_defn) {
591-
MarkUnwrappedPhi(left_defn);
592-
}
593-
if (unwrapped_right_defn != right_defn) {
594-
MarkUnwrappedPhi(right_defn);
595-
}
589+
SetValue(instr, Bool::Get(instr->kind() == Token::kEQ_STRICT));
590+
if (unwrapped_left_defn != left_defn) {
591+
MarkUnwrappedPhi(left_defn);
592+
}
593+
if (unwrapped_right_defn != right_defn) {
594+
MarkUnwrappedPhi(right_defn);
596595
}
597596
return;
598597
}
@@ -711,13 +710,12 @@ void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
711710
Definition* unwrapped_right_defn = UnwrapPhi(right_defn);
712711
if (unwrapped_left_defn == unwrapped_right_defn) {
713712
// Fold x === x, and x !== x to true/false.
714-
if (SetValue(instr, Bool::Get(instr->kind() == Token::kEQ))) {
715-
if (unwrapped_left_defn != left_defn) {
716-
MarkUnwrappedPhi(left_defn);
717-
}
718-
if (unwrapped_right_defn != right_defn) {
719-
MarkUnwrappedPhi(right_defn);
720-
}
713+
SetValue(instr, Bool::Get(instr->kind() == Token::kEQ));
714+
if (unwrapped_left_defn != left_defn) {
715+
MarkUnwrappedPhi(left_defn);
716+
}
717+
if (unwrapped_right_defn != right_defn) {
718+
MarkUnwrappedPhi(right_defn);
721719
}
722720
return;
723721
}

0 commit comments

Comments
 (0)