8148754: C2 loop unrolling fails due to unexpected graph shape
authorzmajo
Mon, 21 Mar 2016 09:51:20 +0100
changeset 36809 6f9362b27d4f
parent 36808 bae14ddeff3b
child 36810 18da75b9b9ab
8148754: C2 loop unrolling fails due to unexpected graph shape Summary: Check if graph shape is appropriate for optimization, bail out optimization if not. Reviewed-by: kvn, twisti, shade, dnsimon
hotspot/src/share/vm/opto/loopTransform.cpp
hotspot/src/share/vm/opto/loopnode.cpp
hotspot/src/share/vm/opto/loopnode.hpp
hotspot/src/share/vm/opto/superword.cpp
--- a/hotspot/src/share/vm/opto/loopTransform.cpp	Mon Mar 21 08:42:20 2016 +0100
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp	Mon Mar 21 09:51:20 2016 +0100
@@ -1453,20 +1453,14 @@
   Node *opaq = NULL;
   if (adjust_min_trip) {       // If not maximally unrolling, need adjustment
     // Search for zero-trip guard.
-    assert( loop_head->is_main_loop(), "" );
-    assert( ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "" );
-    Node *iff = ctrl->in(0);
-    assert( iff->Opcode() == Op_If, "" );
-    Node *bol = iff->in(1);
-    assert( bol->Opcode() == Op_Bool, "" );
-    Node *cmp = bol->in(1);
-    assert( cmp->Opcode() == Op_CmpI, "" );
-    opaq = cmp->in(2);
-    // Occasionally it's possible for a zero-trip guard Opaque1 node to be
-    // optimized away and then another round of loop opts attempted.
-    // We can not optimize this particular loop in that case.
-    if (opaq->Opcode() != Op_Opaque1)
-      return; // Cannot find zero-trip guard!  Bail out!
+
+    // Check the shape of the graph at the loop entry. If an inappropriate
+    // graph shape is encountered, the compiler bails out loop unrolling;
+    // compilation of the method will still succeed.
+    if (!is_canonical_main_loop_entry(loop_head)) {
+      return;
+    }
+    opaq = ctrl->in(0)->in(1)->in(1)->in(2);
     // Zero-trip test uses an 'opaque' node which is not shared.
     assert(opaq->outcnt() == 1 && opaq->in(1) == limit, "");
   }
@@ -2109,7 +2103,6 @@
 #endif
   assert(RangeCheckElimination, "");
   CountedLoopNode *cl = loop->_head->as_CountedLoop();
-  assert(cl->is_main_loop(), "");
 
   // protect against stride not being a constant
   if (!cl->stride_is_con())
@@ -2121,20 +2114,17 @@
   // to not ever trip end tests
   Node *main_limit = cl->limit();
 
+  // Check graph shape. Cannot optimize a loop if zero-trip
+  // Opaque1 node is optimized away and then another round
+  // of loop opts attempted.
+  if (!is_canonical_main_loop_entry(cl)) {
+    return;
+  }
+
   // Need to find the main-loop zero-trip guard
   Node *ctrl  = cl->in(LoopNode::EntryControl);
-  assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "");
   Node *iffm = ctrl->in(0);
-  assert(iffm->Opcode() == Op_If, "");
-  Node *bolzm = iffm->in(1);
-  assert(bolzm->Opcode() == Op_Bool, "");
-  Node *cmpzm = bolzm->in(1);
-  assert(cmpzm->is_Cmp(), "");
-  Node *opqzm = cmpzm->in(2);
-  // Can not optimize a loop if zero-trip Opaque1 node is optimized
-  // away and then another round of loop opts attempted.
-  if (opqzm->Opcode() != Op_Opaque1)
-    return;
+  Node *opqzm = iffm->in(1)->in(1)->in(2);
   assert(opqzm->in(1) == main_limit, "do not understand situation");
 
   // Find the pre-loop limit; we will expand its iterations to
--- a/hotspot/src/share/vm/opto/loopnode.cpp	Mon Mar 21 08:42:20 2016 +0100
+++ b/hotspot/src/share/vm/opto/loopnode.cpp	Mon Mar 21 09:51:20 2016 +0100
@@ -3275,6 +3275,41 @@
   return LCA;
 }
 
+// Check the shape of the graph at the loop entry. In some cases,
+// the shape of the graph does not match the shape outlined below.
+// That is caused by the Opaque1 node "protecting" the shape of
+// the graph being removed by, for example, the IGVN performed
+// in PhaseIdealLoop::build_and_optimize().
+//
+// After the Opaque1 node has been removed, optimizations (e.g., split-if,
+// loop unswitching, and IGVN, or a combination of them) can freely change
+// the graph's shape. As a result, the graph shape outlined below cannot
+// be guaranteed anymore.
+bool PhaseIdealLoop::is_canonical_main_loop_entry(CountedLoopNode* cl) {
+  assert(cl->is_main_loop(), "check should be applied to main loops");
+  Node* ctrl = cl->in(LoopNode::EntryControl);
+  if (ctrl == NULL || (!ctrl->is_IfTrue() && !ctrl->is_IfFalse())) {
+    return false;
+  }
+  Node* iffm = ctrl->in(0);
+  if (iffm == NULL || !iffm->is_If()) {
+    return false;
+  }
+  Node* bolzm = iffm->in(1);
+  if (bolzm == NULL || !bolzm->is_Bool()) {
+    return false;
+  }
+  Node* cmpzm = bolzm->in(1);
+  if (cmpzm == NULL || !cmpzm->is_Cmp()) {
+    return false;
+  }
+  Node* opqzm = cmpzm->in(2);
+  if (opqzm == NULL || opqzm->Opcode() != Op_Opaque1) {
+    return false;
+  }
+  return true;
+}
+
 //------------------------------get_late_ctrl----------------------------------
 // Compute latest legal control.
 Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
--- a/hotspot/src/share/vm/opto/loopnode.hpp	Mon Mar 21 08:42:20 2016 +0100
+++ b/hotspot/src/share/vm/opto/loopnode.hpp	Mon Mar 21 09:51:20 2016 +0100
@@ -656,6 +656,9 @@
   bool cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop);
 
 public:
+
+  static bool is_canonical_main_loop_entry(CountedLoopNode* cl);
+
   bool has_node( Node* n ) const {
     guarantee(n != NULL, "No Node.");
     return _nodes[n->_idx] != NULL;
--- a/hotspot/src/share/vm/opto/superword.cpp	Mon Mar 21 08:42:20 2016 +0100
+++ b/hotspot/src/share/vm/opto/superword.cpp	Mon Mar 21 09:51:20 2016 +0100
@@ -3074,21 +3074,13 @@
 //----------------------------get_pre_loop_end---------------------------
 // Find pre loop end from main loop.  Returns null if none.
 CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode* cl) {
-  Node* ctrl = cl->in(LoopNode::EntryControl);
-  if (!ctrl->is_IfTrue() && !ctrl->is_IfFalse()) return NULL;
-  Node* iffm = ctrl->in(0);
-  if (!iffm->is_If()) return NULL;
-  Node* bolzm = iffm->in(1);
-  if (!bolzm->is_Bool()) return NULL;
-  Node* cmpzm = bolzm->in(1);
-  if (!cmpzm->is_Cmp()) return NULL;
-  Node* opqzm = cmpzm->in(2);
-  // Can not optimize a loop if zero-trip Opaque1 node is optimized
-  // away and then another round of loop opts attempted.
-  if (opqzm->Opcode() != Op_Opaque1) {
+  // The loop cannot be optimized if the graph shape at
+  // the loop entry is inappropriate.
+  if (!PhaseIdealLoop::is_canonical_main_loop_entry(cl)) {
     return NULL;
   }
-  Node* p_f = iffm->in(0);
+
+  Node* p_f = cl->in(LoopNode::EntryControl)->in(0)->in(0);
   if (!p_f->is_IfFalse()) return NULL;
   if (!p_f->in(0)->is_CountedLoopEnd()) return NULL;
   CountedLoopEndNode* pre_end = p_f->in(0)->as_CountedLoopEnd();