hotspot/src/share/vm/opto/ifnode.cpp
changeset 30183 a6588c0a3259
parent 28927 48e4a707e777
child 30309 da3efc8ed2cb
--- a/hotspot/src/share/vm/opto/ifnode.cpp	Sat Mar 14 16:13:48 2015 +0000
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Tue Mar 17 10:06:31 2015 +0100
@@ -25,11 +25,13 @@
 #include "precompiled.hpp"
 #include "memory/allocation.inline.hpp"
 #include "opto/addnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/phaseX.hpp"
 #include "opto/runtime.hpp"
+#include "opto/rootnode.hpp"
 #include "opto/subnode.hpp"
 
 // Portions of code courtesy of Clifford Click
@@ -449,62 +451,59 @@
   return new ConINode(TypeInt::ZERO);
 }
 
-//------------------------------is_range_check---------------------------------
-// Return 0 if not a range check.  Return 1 if a range check and set index and
-// offset.  Return 2 if we had to negate the test.  Index is NULL if the check
-// is versus a constant.
-int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) {
+// if this IfNode follows a range check pattern return the projection
+// for the failed path
+ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) {
   Node* b = in(1);
-  if (b == NULL || !b->is_Bool())  return 0;
+  if (b == NULL || !b->is_Bool())  return NULL;
   BoolNode* bn = b->as_Bool();
   Node* cmp = bn->in(1);
-  if (cmp == NULL)  return 0;
-  if (cmp->Opcode() != Op_CmpU)  return 0;
+  if (cmp == NULL)  return NULL;
+  if (cmp->Opcode() != Op_CmpU)  return NULL;
 
-  Node* l = cmp->in(1);
-  Node* r = cmp->in(2);
-  int flip_test = 1;
+  l = cmp->in(1);
+  r = cmp->in(2);
+  flip_test = 1;
   if (bn->_test._test == BoolTest::le) {
     l = cmp->in(2);
     r = cmp->in(1);
     flip_test = 2;
   } else if (bn->_test._test != BoolTest::lt) {
-    return 0;
+    return NULL;
   }
-  if (l->is_top())  return 0;   // Top input means dead test
-  if (r->Opcode() != Op_LoadRange)  return 0;
+  if (l->is_top())  return NULL;   // Top input means dead test
+  if (r->Opcode() != Op_LoadRange)  return NULL;
 
   // We have recognized one of these forms:
   //  Flip 1:  If (Bool[<] CmpU(l, LoadRange)) ...
   //  Flip 2:  If (Bool[<=] CmpU(LoadRange, l)) ...
 
+  ProjNode* iftrap = proj_out(flip_test == 2 ? true : false);
+  return iftrap;
+}
+
+
+//------------------------------is_range_check---------------------------------
+// Return 0 if not a range check.  Return 1 if a range check and set index and
+// offset.  Return 2 if we had to negate the test.  Index is NULL if the check
+// is versus a constant.
+int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) {
+  int flip_test = 0;
+  Node* l = NULL;
+  Node* r = NULL;
+  ProjNode* iftrap = range_check_trap_proj(flip_test, l, r);
+
+  if (iftrap == NULL) {
+    return 0;
+  }
+
   // Make sure it's a real range check by requiring an uncommon trap
   // along the OOB path.  Otherwise, it's possible that the user wrote
   // something which optimized to look like a range check but behaves
   // in some other way.
-  Node* iftrap = proj_out(flip_test == 2 ? true : false);
-  bool found_trap = false;
-  if (iftrap != NULL) {
-    Node* u = iftrap->unique_ctrl_out();
-    if (u != NULL) {
-      // It could be a merge point (Region) for uncommon trap.
-      if (u->is_Region()) {
-        Node* c = u->unique_ctrl_out();
-        if (c != NULL) {
-          iftrap = u;
-          u = c;
-        }
-      }
-      if (u->in(0) == iftrap && u->is_CallStaticJava()) {
-        int req = u->as_CallStaticJava()->uncommon_trap_request();
-        if (Deoptimization::trap_request_reason(req) ==
-            Deoptimization::Reason_range_check) {
-          found_trap = true;
-        }
-      }
-    }
+  if (iftrap->is_uncommon_trap_proj(Deoptimization::Reason_range_check) == NULL) {
+    return 0;
   }
-  if (!found_trap)  return 0;   // sorry, no cigar
 
   // Look for index+offset form
   Node* ind = l;
@@ -664,11 +663,12 @@
 //------------------------------fold_compares----------------------------
 // See if a pair of CmpIs can be converted into a CmpU.  In some cases
 // the direction of this if is determined by the preceding if so it
-// can be eliminate entirely.  Given an if testing (CmpI n c) check
-// for an immediately control dependent if that is testing (CmpI n c2)
-// and has one projection leading to this if and the other projection
-// leading to a region that merges one of this ifs control
-// projections.
+// can be eliminate entirely.
+//
+// Given an if testing (CmpI n v) check for an immediately control
+// dependent if that is testing (CmpI n v2) and has one projection
+// leading to this if and the other projection leading to a region
+// that merges one of this ifs control projections.
 //
 //                   If
 //                  / |
@@ -680,79 +680,458 @@
 //            /    \  |
 //           /    Region
 //
-Node* IfNode::fold_compares(PhaseGVN* phase) {
-  if (Opcode() != Op_If) return NULL;
+// Or given an if testing (CmpI n v) check for a dominating if that is
+// testing (CmpI n v2), both having one projection leading to an
+// uncommon trap. Allow Another independent guard in between to cover
+// an explicit range check:
+// if (index < 0 || index >= array.length) {
+// which may need a null check to guard the LoadRange
+//
+//                   If
+//                  / \
+//                 /   \
+//                /     \
+//              If      unc
+//              /\
+//             /  \
+//            /    \
+//           /      unc
+//
+
+// Is the comparison for this If suitable for folding?
+bool IfNode::cmpi_folds(PhaseIterGVN* igvn) {
+  return in(1) != NULL &&
+    in(1)->is_Bool() &&
+    in(1)->in(1) != NULL &&
+    in(1)->in(1)->Opcode() == Op_CmpI &&
+    in(1)->in(1)->in(2) != NULL &&
+    in(1)->in(1)->in(2) != igvn->C->top() &&
+    (in(1)->as_Bool()->_test.is_less() ||
+     in(1)->as_Bool()->_test.is_greater());
+}
+
+// Is a dominating control suitable for folding with this if?
+bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) {
+  return ctrl != NULL &&
+    ctrl->is_Proj() &&
+    ctrl->in(0) != NULL &&
+    ctrl->in(0)->is_If() &&
+    ctrl->in(0)->outcnt() == 2 &&
+    ctrl->in(0)->as_If()->cmpi_folds(igvn) &&
+    // Must compare same value
+    ctrl->in(0)->in(1)->in(1)->in(1) != NULL &&
+    ctrl->in(0)->in(1)->in(1)->in(1) == in(1)->in(1)->in(1);
+}
+
+// Do this If and the dominating If share a region?
+bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail) {
+  ProjNode* otherproj = proj->other_if_proj();
+  Node* otherproj_ctrl_use = otherproj->unique_ctrl_out();
+  RegionNode* region = (otherproj_ctrl_use != NULL && otherproj_ctrl_use->is_Region()) ? otherproj_ctrl_use->as_Region() : NULL;
+  success = NULL;
+  fail = NULL;
 
+  if (otherproj->outcnt() == 1 && region != NULL && !region->has_phi()) {
+    for (int i = 0; i < 2; i++) {
+      ProjNode* proj = proj_out(i);
+      if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) {
+        success = proj;
+      } else if (fail == NULL) {
+        fail = proj;
+      } else {
+        success = fail = NULL;
+      }
+    }
+  }
+  return success != NULL && fail != NULL;
+}
+
+// Return projection that leads to an uncommon trap if any
+ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const {
+  for (int i = 0; i < 2; i++) {
+    call = proj_out(i)->is_uncommon_trap_proj(Deoptimization::Reason_none);
+    if (call != NULL) {
+      return proj_out(i);
+    }
+  }
+  return NULL;
+}
+
+// Do this If and the dominating If both branch out to an uncommon trap
+bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) {
+  ProjNode* otherproj = proj->other_if_proj();
+  CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none);
+
+  if (otherproj->outcnt() == 1 && dom_unc != NULL) {
+    CallStaticJavaNode* unc = NULL;
+    ProjNode* unc_proj = uncommon_trap_proj(unc);
+    if (unc_proj != NULL && unc_proj->outcnt() == 1) {
+      if (dom_unc == unc) {
+        // Allow the uncommon trap to be shared through a region
+        RegionNode* r = unc->in(0)->as_Region();
+        if (r->outcnt() != 2 || r->req() != 3 || r->find_edge(otherproj) == -1 || r->find_edge(unc_proj) == -1) {
+          return false;
+        }
+        assert(r->has_phi() == NULL, "simple region shouldn't have a phi");
+      } else if (dom_unc->in(0) != otherproj || unc->in(0) != unc_proj) {
+        return false;
+      }
+      // See merge_uncommon_traps: the reason of the uncommon trap
+      // will be changed and the state of the dominating If will be
+      // used. Checked that we didn't apply this transformation in a
+      // previous compilation and it didn't cause too many traps
+      if (!igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_unstable_fused_if) &&
+          !igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_range_check)) {
+        success = unc_proj;
+        fail = unc_proj->other_if_proj();
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+// Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding
+bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) {
   Node* this_cmp = in(1)->in(1);
-  if (this_cmp != NULL && this_cmp->Opcode() == Op_CmpI &&
-      this_cmp->in(2)->is_Con() && this_cmp->in(2) != phase->C->top()) {
-    Node* ctrl = in(0);
-    BoolNode* this_bool = in(1)->as_Bool();
-    Node* n = this_cmp->in(1);
-    int hi = this_cmp->in(2)->get_int();
-    if (ctrl != NULL && ctrl->is_Proj() && ctrl->outcnt() == 1 &&
-        ctrl->in(0)->is_If() &&
-        ctrl->in(0)->outcnt() == 2 &&
-        ctrl->in(0)->in(1)->is_Bool() &&
-        ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI &&
-        ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() &&
-        ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() &&
-        ctrl->in(0)->in(1)->in(1)->in(1) == n) {
-      IfNode* dom_iff = ctrl->in(0)->as_If();
-      Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con);
-      if (otherproj->outcnt() == 1 && otherproj->unique_out()->is_Region() &&
-          this_bool->_test._test != BoolTest::ne && this_bool->_test._test != BoolTest::eq) {
-        // Identify which proj goes to the region and which continues on
-        RegionNode* region = otherproj->unique_out()->as_Region();
-        Node* success = NULL;
-        Node* fail = NULL;
-        for (int i = 0; i < 2; i++) {
-          Node* proj = proj_out(i);
-          if (success == NULL && proj->outcnt() == 1 && proj->unique_out() == region) {
-            success = proj;
-          } else if (fail == NULL) {
-            fail = proj;
-          } else {
-            success = fail = NULL;
+  BoolNode* this_bool = in(1)->as_Bool();
+  IfNode* dom_iff = proj->in(0)->as_If();
+  BoolNode* dom_bool = dom_iff->in(1)->as_Bool();
+  Node* lo = dom_iff->in(1)->in(1)->in(2);
+  Node* hi = this_cmp->in(2);
+  Node* n = this_cmp->in(1);
+  ProjNode* otherproj = proj->other_if_proj();
+
+  const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj);
+  const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success);
+
+  BoolTest::mask lo_test = dom_bool->_test._test;
+  BoolTest::mask hi_test = this_bool->_test._test;
+  BoolTest::mask cond = hi_test;
+
+  // Figure out which of the two tests sets the upper bound and which
+  // sets the lower bound if any.
+  if (hi_type->_lo > lo_type->_hi && hi_type->_hi == max_jint && lo_type->_lo == min_jint) {
+
+    assert((dom_bool->_test.is_less() && !proj->_con) ||
+           (dom_bool->_test.is_greater() && proj->_con), "incorrect test");
+    // this test was canonicalized
+    assert(this_bool->_test.is_less() && fail->_con, "incorrect test");
+
+    if (lo_test == BoolTest::gt || lo_test == BoolTest::le) {
+      lo = igvn->transform(new AddINode(lo, igvn->intcon(1)));
+    }
+  } else if (lo_type->_lo > hi_type->_hi && lo_type->_hi == max_jint && hi_type->_lo == min_jint) {
+    swap(lo, hi);
+    swap(lo_type, hi_type);
+    swap(lo_test, hi_test);
+
+    assert((this_bool->_test.is_less() && proj->_con) ||
+           (this_bool->_test.is_greater() && !proj->_con), "incorrect test");
+    // this test was canonicalized
+    assert(dom_bool->_test.is_less() && !fail->_con, "incorrect test");
+
+    cond = (hi_test == BoolTest::le || hi_test == BoolTest::gt) ? BoolTest::gt : BoolTest::ge;
+
+    if (lo_test == BoolTest::le) {
+      lo = igvn->transform(new AddINode(lo, igvn->intcon(1)));
+    }
+
+  } else {
+    const TypeInt* failtype  = filtered_int_type(igvn, n, proj);
+    if (failtype != NULL) {
+      const TypeInt* type2 = filtered_int_type(igvn, n, fail);
+      if (type2 != NULL) {
+        failtype = failtype->join(type2)->is_int();
+        if (failtype->_lo > failtype->_hi) {
+          // previous if determines the result of this if so
+          // replace Bool with constant
+          igvn->hash_delete(this);
+          set_req(1, igvn->intcon(success->_con));
+          return true;
+        }
+      }
+    }
+
+    lo = NULL;
+    hi = NULL;
+  }
+
+  if (lo && hi) {
+    // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo))
+    Node* adjusted_val = igvn->transform(new SubINode(n,  lo));
+    Node* adjusted_lim = igvn->transform(new SubINode(hi, lo));
+    Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim));
+    Node* newbool = igvn->transform(new BoolNode(newcmp, cond));
+
+    igvn->is_IterGVN()->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con));
+    igvn->hash_delete(this);
+    set_req(1, newbool);
+
+    return true;
+  }
+  return false;
+}
+
+// Merge the branches that trap for this If and the dominating If into
+// a single region that branches to the uncommon trap for the
+// dominating If
+void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) {
+  ProjNode* otherproj = proj->other_if_proj();
+
+  CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none);
+  CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none);
+
+  if (unc != dom_unc) {
+    Node* r = new RegionNode(3);
+
+    r->set_req(1, otherproj);
+    r->set_req(2, success);
+    r = igvn->transform(r);
+    assert(r->is_Region(), "can't go away");
+
+    // Make both If trap at the state of the first If: once the CmpI
+    // nodes are merged, if we trap we don't know which of the CmpI
+    // nodes would have caused the trap so we have to restart
+    // execution at the first one
+    igvn->replace_input_of(dom_unc, 0, r);
+    igvn->replace_input_of(unc, 0, igvn->C->top());
+  }
+  int trap_request = dom_unc->uncommon_trap_request();
+  Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request);
+  Deoptimization::DeoptAction action = Deoptimization::trap_request_action(trap_request);
+
+  int flip_test = 0;
+  Node* l = NULL;
+  Node* r = NULL;
+
+  if (success->in(0)->as_If()->range_check_trap_proj(flip_test, l, r) != NULL) {
+    // If this looks like a range check, change the trap to
+    // Reason_range_check so the compiler recognizes it as a range
+    // check and applies the corresponding optimizations
+    trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_range_check, action);
+
+    improve_address_types(l, r, fail, igvn);
+  } else if (unc != dom_unc) {
+    // If we trap we won't know what CmpI would have caused the trap
+    // so use a special trap reason to mark this pair of CmpI nodes as
+    // bad candidate for folding. On recompilation we won't fold them
+    // and we may trap again but this time we'll know what branch
+    // traps
+    trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_unstable_fused_if, action);
+  }
+  igvn->replace_input_of(dom_unc, TypeFunc::Parms, igvn->intcon(trap_request));
+}
+
+// If we are turning 2 CmpI nodes into a CmpU that follows the pattern
+// of a rangecheck on index i, on 64 bit the compares may be followed
+// by memory accesses using i as index. In that case, the CmpU tells
+// us something about the values taken by i that can help the compiler
+// (see Compile::conv_I2X_index())
+void IfNode::improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn) {
+#ifdef _LP64
+  ResourceMark rm;
+  Node_Stack stack(2);
+
+  assert(r->Opcode() == Op_LoadRange, "unexpected range check");
+  const TypeInt* array_size = igvn->type(r)->is_int();
+
+  stack.push(l, 0);
+
+  while(stack.size() > 0) {
+    Node* n = stack.node();
+    uint start = stack.index();
+
+    uint i = start;
+    for (; i < n->outcnt(); i++) {
+      Node* use = n->raw_out(i);
+      if (stack.size() == 1) {
+        if (use->Opcode() == Op_ConvI2L) {
+          const TypeLong* bounds = use->as_Type()->type()->is_long();
+          if (bounds->_lo <= array_size->_lo && bounds->_hi >= array_size->_hi &&
+              (bounds->_lo != array_size->_lo || bounds->_hi != array_size->_hi)) {
+            stack.set_index(i+1);
+            stack.push(use, 0);
+            break;
           }
         }
-        if (success != NULL && fail != NULL && !region->has_phi()) {
-          int lo = dom_iff->in(1)->in(1)->in(2)->get_int();
-          BoolNode* dom_bool = dom_iff->in(1)->as_Bool();
-          Node* dom_cmp =  dom_bool->in(1);
-          const TypeInt* failtype  = filtered_int_type(phase, n, ctrl);
-          if (failtype != NULL) {
-            const TypeInt* type2 = filtered_int_type(phase, n, fail);
-            if (type2 != NULL) {
-              failtype = failtype->join(type2)->is_int();
-            } else {
-              failtype = NULL;
-            }
-          }
+      } else if (use->is_Mem()) {
+        Node* ctrl = use->in(0);
+        for (int i = 0; i < 10 && ctrl != NULL && ctrl != fail; i++) {
+          ctrl = up_one_dom(ctrl);
+        }
+        if (ctrl == fail) {
+          Node* init_n = stack.node_at(1);
+          assert(init_n->Opcode() == Op_ConvI2L, "unexpected first node");
+          Node* new_n = igvn->C->conv_I2X_index(igvn, l, array_size);
 
-          if (failtype != NULL &&
-              dom_bool->_test._test != BoolTest::ne && dom_bool->_test._test != BoolTest::eq) {
-            int bound = failtype->_hi - failtype->_lo + 1;
-            if (failtype->_hi != max_jint && failtype->_lo != min_jint && bound > 1) {
-              // Merge the two compares into a single unsigned compare by building  (CmpU (n - lo) hi)
-              BoolTest::mask cond = fail->as_Proj()->_con ? BoolTest::lt : BoolTest::ge;
-              Node* adjusted = phase->transform(new SubINode(n, phase->intcon(failtype->_lo)));
-              Node* newcmp = phase->transform(new CmpUNode(adjusted, phase->intcon(bound)));
-              Node* newbool = phase->transform(new BoolNode(newcmp, cond));
-              phase->is_IterGVN()->replace_input_of(dom_iff, 1, phase->intcon(ctrl->as_Proj()->_con));
-              phase->hash_delete(this);
-              set_req(1, newbool);
-              return this;
-            }
-            if (failtype->_lo > failtype->_hi) {
-              // previous if determines the result of this if so
-              // replace Bool with constant
-              phase->hash_delete(this);
-              set_req(1, phase->intcon(success->as_Proj()->_con));
-              return this;
-            }
+          for (uint j = 2; j < stack.size(); j++) {
+            Node* n = stack.node_at(j);
+            Node* clone = n->clone();
+            int rep = clone->replace_edge(init_n, new_n);
+            assert(rep > 0, "can't find expected node?");
+            clone = igvn->transform(clone);
+            init_n = n;
+            new_n = clone;
+          }
+          igvn->hash_delete(use);
+          int rep = use->replace_edge(init_n, new_n);
+          assert(rep > 0, "can't find expected node?");
+          igvn->transform(use);
+          if (init_n->outcnt() == 0) {
+            igvn->_worklist.push(init_n);
           }
         }
+      } else if (use->in(0) == NULL && (igvn->type(use)->isa_long() ||
+                                        igvn->type(use)->isa_ptr())) {
+        stack.set_index(i+1);
+        stack.push(use, 0);
+        break;
+      }
+    }
+    if (i == n->outcnt()) {
+      stack.pop();
+    }
+  }
+#endif
+}
+
+bool IfNode::is_cmp_with_loadrange(ProjNode* proj) {
+  if (in(1) != NULL &&
+      in(1)->in(1) != NULL &&
+      in(1)->in(1)->in(2) != NULL) {
+    Node* other = in(1)->in(1)->in(2);
+    if (other->Opcode() == Op_LoadRange &&
+        ((other->in(0) != NULL && other->in(0) == proj) ||
+         (other->in(0) == NULL &&
+          other->in(2) != NULL &&
+          other->in(2)->is_AddP() &&
+          other->in(2)->in(1) != NULL &&
+          other->in(2)->in(1)->Opcode() == Op_CastPP &&
+          other->in(2)->in(1)->in(0) == proj))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) {
+  Node* other = in(1)->in(1)->in(2);
+  if (other->in(MemNode::Address) != NULL &&
+      proj->in(0)->in(1) != NULL &&
+      proj->in(0)->in(1)->is_Bool() &&
+      proj->in(0)->in(1)->in(1) != NULL &&
+      proj->in(0)->in(1)->in(1)->Opcode() == Op_CmpP &&
+      proj->in(0)->in(1)->in(1)->in(2) != NULL &&
+      proj->in(0)->in(1)->in(1)->in(1) == other->in(MemNode::Address)->in(AddPNode::Address)->uncast() &&
+      igvn->type(proj->in(0)->in(1)->in(1)->in(2)) == TypePtr::NULL_PTR) {
+    return true;
+  }
+  return false;
+}
+
+// Check that the If that is in between the 2 integer comparisons has
+// no side effect
+bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) {
+  if (proj != NULL &&
+      proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) &&
+      proj->outcnt() <= 2) {
+    if (proj->outcnt() == 1 ||
+        // Allow simple null check from LoadRange
+        (is_cmp_with_loadrange(proj) && is_null_check(proj, igvn))) {
+      CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+      CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+
+      // reroute_side_effect_free_unc changes the state of this
+      // uncommon trap to restart execution at the previous
+      // CmpI. Check that this change in a previous compilation didn't
+      // cause too many traps.
+      int trap_request = unc->uncommon_trap_request();
+      Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request);
+
+      if (igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), reason)) {
+        return false;
+      }
+
+      return true;
+    }
+  }
+  return false;
+}
+
+// Make the If between the 2 integer comparisons trap at the state of
+// the first If: the last CmpI is the one replaced by a CmpU and the
+// first CmpI is eliminated, so the test between the 2 CmpI nodes
+// won't be guarded by the first CmpI anymore. It can trap in cases
+// where the first CmpI would have prevented it from executing: on a
+// trap, we need to restart execution at the state of the first CmpI
+void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) {
+  CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+  ProjNode* otherproj = proj->other_if_proj();
+  CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none);
+  Node* call_proj = dom_unc->unique_ctrl_out();
+  Node* halt = call_proj->unique_ctrl_out();
+
+  Node* new_unc = dom_unc->clone();
+  call_proj = call_proj->clone();
+  halt = halt->clone();
+  Node* c = otherproj->clone();
+
+  c = igvn->transform(c);
+  new_unc->set_req(TypeFunc::Parms, unc->in(TypeFunc::Parms));
+  new_unc->set_req(0, c);
+  new_unc = igvn->transform(new_unc);
+  call_proj->set_req(0, new_unc);
+  call_proj = igvn->transform(call_proj);
+  halt->set_req(0, call_proj);
+  halt = igvn->transform(halt);
+
+  igvn->replace_node(otherproj, igvn->C->top());
+  igvn->C->root()->add_req(halt);
+}
+
+Node* IfNode::fold_compares(PhaseIterGVN* igvn) {
+  if (Opcode() != Op_If) return NULL;
+
+  if (cmpi_folds(igvn)) {
+    Node* ctrl = in(0);
+    if (is_ctrl_folds(ctrl, igvn) &&
+        ctrl->outcnt() == 1) {
+      // A integer comparison immediately dominated by another integer
+      // comparison
+      ProjNode* success = NULL;
+      ProjNode* fail = NULL;
+      ProjNode* dom_cmp = ctrl->as_Proj();
+      if (has_shared_region(dom_cmp, success, fail) &&
+          // Next call modifies graph so must be last
+          fold_compares_helper(dom_cmp, success, fail, igvn)) {
+        return this;
+      }
+      if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
+          // Next call modifies graph so must be last
+          fold_compares_helper(dom_cmp, success, fail, igvn)) {
+        merge_uncommon_traps(dom_cmp, success, fail, igvn);
+        return this;
+      }
+      return NULL;
+    } else if (ctrl->in(0) != NULL &&
+               ctrl->in(0)->in(0) != NULL) {
+      ProjNode* success = NULL;
+      ProjNode* fail = NULL;
+      Node* dom = ctrl->in(0)->in(0);
+      ProjNode* dom_cmp = dom->isa_Proj();
+      ProjNode* other_cmp = ctrl->isa_Proj();
+
+      // Check if it's an integer comparison dominated by another
+      // integer comparison with another test in between
+      if (is_ctrl_folds(dom, igvn) &&
+          has_only_uncommon_traps(dom_cmp, success, fail, igvn) &&
+          is_side_effect_free_test(other_cmp, igvn) &&
+          // Next call modifies graph so must be last
+          fold_compares_helper(dom_cmp, success, fail, igvn)) {
+        reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn);
+        merge_uncommon_traps(dom_cmp, success, fail, igvn);
+        return this;
       }
     }
   }
@@ -1029,7 +1408,7 @@
     // Normal equivalent-test check.
     if( !dom ) return NULL;     // Dead loop?
 
-    Node* result = fold_compares(phase);
+    Node* result = fold_compares(igvn);
     if (result != NULL) {
       return result;
     }
@@ -1089,7 +1468,7 @@
   // be skipped. For example, range check predicate has two checks
   // for lower and upper bounds.
   ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj();
-  if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
+  if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL)
    prev_dom = idom;
 
   // Now walk the current IfNode's projections.