When canonicalizing branch on StrictCompare don't fuse comparisons that can deoptimize or serve as pending deoptimization target for representation changes.

R=fschneider@google.com
BUG=

Review URL: https://codereview.chromium.org//12220150

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18443 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 7b8e997..48edba3 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1821,7 +1821,16 @@
     Definition* replacement = comparison()->Canonicalize(optimizer);
     if (replacement == comparison() || replacement == NULL) return this;
     ComparisonInstr* comp = replacement->AsComparison();
-    if (comp == NULL) return this;
+    if ((comp == NULL) || comp->CanDeoptimize()) return this;
+
+    // Check that comparison is not serving as a pending deoptimization target
+    // for conversions.
+    for (intptr_t i = 0; i < comp->InputCount(); i++) {
+      if (comp->RequiredInputRepresentation(i) !=
+          comp->InputAt(i)->definition()->representation()) {
+        return this;
+      }
+    }
 
     // Replace the comparison if the replacement is used at this branch,
     // and has exactly one use.
diff --git a/tests/language/branch_canonicalization_test.dart b/tests/language/branch_canonicalization_test.dart
new file mode 100644
index 0000000..7e39572
--- /dev/null
+++ b/tests/language/branch_canonicalization_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2013, 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.
+// Test that branch fusion correctly sets branch environment for comparisons
+// that require unboxing and does not fuse branches that can deoptimize.
+
+var sideEffect = true;
+
+barDouble(a, b) {
+  sideEffect = false;
+  final result = (a == b);
+  sideEffect = !sideEffect;
+  return result;
+}
+fooDouble(a, b) => barDouble(a, b) ? 1 : 0;
+
+barMint(a, b) {
+  sideEffect = false;
+  final result = (a == b);
+  sideEffect = !sideEffect;
+  return result;
+}
+fooMint(a, b) => barMint(a, b) ? 1 : 0;
+
+class A {
+  operator == (other) => identical(this, other);
+}
+
+class B extends A {
+}
+
+class C extends A {
+}
+
+barPoly(a, b) {
+  sideEffect = false;
+  final result = a == b;
+  sideEffect = !sideEffect;
+  return result;
+}
+
+fooPoly(a, b) => barPoly(a, b) ? 1 : 0;
+
+main () {
+  final a = 1.0;
+  final b = 1 << 62;
+  final x = new A(), y = new B(), z = new C();
+  for (var i = 0; i < 10000; i++) {
+    Expect.equals(1, fooDouble(a, a));
+    Expect.isTrue(sideEffect);
+    Expect.equals(0, fooMint(b, 0));
+    Expect.isTrue(sideEffect);
+    Expect.equals(1, fooPoly(x, x));
+    Expect.equals(0, fooPoly(y, x));
+  }
+  Expect.equals(1, fooDouble(z, z));
+  Expect.isTrue(sideEffect);
+  Expect.equals(1, fooMint(z, z));
+  Expect.isTrue(sideEffect);
+  Expect.equals(1, fooPoly(z, z));
+  Expect.isTrue(sideEffect);
+}
+
+
+