src/share/vm/opto/loopopts.cpp

Print this page
rev 4533 : 8014811: loopTransform.cpp assert(cmp_end->in(2) == limit) failed
Summary: Stop current iteration of loop opts if partial_peel() failed and it created node clones outside processed loop.
Reviewed-by: roland

@@ -1924,12 +1924,12 @@
 }
 
 
 //------------------------------ clone_for_use_outside_loop -------------------------------------
 // clone "n" for uses that are outside of loop
-void PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ) {
-
+int PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, Node_List& worklist ) {
+  int cloned = 0;
   assert(worklist.size() == 0, "should be empty");
   for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) {
     Node* use = n->fast_out(j);
     if( !loop->is_member(get_loop(has_ctrl(use) ? get_ctrl(use) : use)) ) {
       worklist.push(use);

@@ -1945,10 +1945,11 @@
     assert(j < use->req(), "must be there");
 
     // clone "n" and insert it between the inputs of "n" and the use outside the loop
     Node* n_clone = n->clone();
     _igvn.replace_input_of(use, j, n_clone);
+    cloned++;
     Node* use_c;
     if (!use->is_Phi()) {
       use_c = has_ctrl(use) ? get_ctrl(use) : use->in(0);
     } else {
       // Use in a phi is considered a use in the associated predecessor block

@@ -1962,10 +1963,11 @@
     if (TracePartialPeeling) {
       tty->print_cr("loop exit cloning old: %d new: %d newbb: %d", n->_idx, n_clone->_idx, get_ctrl(n_clone)->_idx);
     }
 #endif
   }
+  return cloned;
 }
 
 
 //------------------------------ clone_for_special_use_inside_loop -------------------------------------
 // clone "n" for special uses that are in the not_peeled region.

@@ -2480,10 +2482,11 @@
   }
 #endif
 
   // Evacuate nodes in peel region into the not_peeled region if possible
   uint new_phi_cnt = 0;
+  uint cloned_for_outside_use = 0;
   for (i = 0; i < peel_list.size();) {
     Node* n = peel_list.at(i);
 #if !defined(PRODUCT)
   if (TracePartialPeeling) n->dump();
 #endif

@@ -2498,12 +2501,11 @@
         if ( !has_use_internal_to_set(n, peel, loop) ) {
 
           // if not pinned and not a load (which maybe anti-dependent on a store)
           // and not a CMove (Matcher expects only bool->cmove).
           if ( n->in(0) == NULL && !n->is_Load() && !n->is_CMove() ) {
-            clone_for_use_outside_loop( loop, n, worklist );
-
+            cloned_for_outside_use += clone_for_use_outside_loop( loop, n, worklist );
             sink_list.push(n);
             peel     >>= n->_idx; // delete n from peel set.
             not_peel <<= n->_idx; // add n to not_peel set.
             peel_list.remove(i);
             incr = false;

@@ -2536,10 +2538,16 @@
       remove_cmpi_loop_exit(new_peel_if, loop);
     }
     // Inhibit more partial peeling on this loop
     assert(!head->is_partial_peel_loop(), "not partial peeled");
     head->mark_partial_peel_failed();
+    if (cloned_for_outside_use > 0) {
+      // Terminate this round of loop opts because
+      // the graph outside this loop was changed.
+      C->set_major_progress();
+      return true;
+    }
     return false;
   }
 
   // Step 3: clone loop, retarget control, and insert new phis