Index: runtime/tests/vm/dart/regress29620_test.dart |
diff --git a/runtime/tests/vm/dart/regress29620_test.dart b/runtime/tests/vm/dart/regress29620_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b6d4e37d414574624376406940332b9b26cadf7d |
--- /dev/null |
+++ b/runtime/tests/vm/dart/regress29620_test.dart |
@@ -0,0 +1,61 @@ |
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+// Regression test for dartbug.com/29620: check that decision to deoptimize |
+// and decisions which parts of the instruction to emit use the same |
+// range information for instruction inputs. |
+ |
+// VMOptions=--enable-inlining-annotations --optimization_counter_threshold=10 --no-use-osr --no-background-compilation |
+ |
+import "package:expect/expect.dart"; |
+ |
+const alwaysInline = "AlwaysInline"; |
+const neverInline = "NeverInline"; |
+ |
+class Flag { |
+ var value; |
+ Flag(this.value); |
+ |
+ static final FLAG = new Flag(0); |
+} |
+ |
+@alwaysInline |
+void checkRange(bit) { |
+ if (bit < 0 || bit > 31) { |
+ throw "bit must be in [0, 31]"; |
+ } |
+} |
+ |
+@alwaysInline |
+bool isSet(flags, bit) { |
+ checkRange(bit); |
+ // Note: > 0 here instead of == 0 to prevent merging into |
+ // TestSmi instruction. |
+ return (flags & (1 << bit)) > 0; |
+} |
+ |
+@neverInline |
+bool bug(flags) { |
+ var bit = Flag.FLAG.value; |
+ checkRange(bit); |
+ for (var i = 0; i < 1; i++) { |
+ bit = Flag.FLAG.value; |
+ checkRange(bit); |
+ } |
+ |
+ // In early optimization stages `bit` would be a Phi(...). This Phi would be |
+ // dominated by checkRange and thus range analysis will infer [0, 31] range |
+ // for it - and thus a EliminateEnvironment will make decision that |
+ // (1 << bit) can't deoptimize and will detach environment from it. Later |
+ // passes will eliminate Phi for `bit` as it is redundant and as a result we |
+ // will loose precise range information for `bit` and backend will try |
+ // to emit a range check and a deoptimization. |
+ return isSet(flags, bit); |
+} |
+ |
+main() { |
+ for (var i = 0; i < 100; i++) { |
+ bug(1); |
+ } |
+} |