< prev index next >

src/hotspot/share/opto/opaquenode.cpp

Print this page

        

@@ -21,10 +21,15 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "opto/addnode.hpp"
+#include "opto/cfgnode.hpp"
+#include "opto/connode.hpp"
+#include "opto/divnode.hpp"
+#include "opto/loopnode.hpp"
 #include "opto/opaquenode.hpp"
 #include "opto/phaseX.hpp"
 
 //=============================================================================
 // Do not allow value-numbering

@@ -66,10 +71,301 @@
 
 const Type* Opaque4Node::Value(PhaseGVN* phase) const {
   return phase->type(in(1));
 }
 
+CountedLoopNode* Opaque5Node::inner_loop() const {
+  if (outcnt() != 1) {
+    return NULL;
+  }
+  Node* cmp = unique_out();
+  if (cmp == NULL || cmp->outcnt() != 1 || cmp->Opcode() != Op_CmpI) {
+    return NULL;
+  }
+  Node* test = cmp->unique_out();
+  if (test == NULL || test->outcnt() != 1 || test->Opcode() != Op_Bool) {
+    return NULL;
+  }
+  Node* lex = test->unique_out();
+  if (lex == NULL || lex->Opcode() != Op_If) {
+    return NULL;
+  }
+  IfNode* le = lex->as_If();
+  Node* le_tail = le->proj_out(true);
+  if (le_tail == NULL) {
+    return NULL;
+  }
+  Node* lx = le_tail->unique_ctrl_out();
+  if (lx == NULL || !lx->is_Loop()) {
+    return NULL;
+  }
+  LoopNode* l = lx->as_Loop();
+  if (!lx->as_Loop()->is_strip_mined() ||
+      le->in(0) == NULL ||
+      le->in(0)->in(0) == NULL) {
+    return NULL;
+  }
+  Node* inner_clex = le->in(0)->in(0)->in(0);
+  if (inner_clex == NULL || !inner_clex->is_CountedLoopEnd()) {
+    return NULL;
+  }
+  CountedLoopEndNode* inner_cle = inner_clex->as_CountedLoopEnd();
+  Node* inner_clx = l->unique_ctrl_out();
+  if (inner_clx == NULL || !inner_clx->is_CountedLoop()) {
+    return NULL;
+  }
+  CountedLoopNode* inner_cl = inner_clx->as_CountedLoop();
+  assert(inner_cl->is_strip_mined(), "inner loop should be strip mined");
+  return inner_cl;
+}
+
+
+Node* Opaque5Node::adjust_strip_mined_loop(PhaseGVN* phase) {
+  // Look for the outer & inner strip mined loop, reduce number of
+  // iterations of the inner loop, set exit condition of outer loop,
+  // construct required phi nodes for outer loop.
+  CountedLoopNode* inner_cl = inner_loop();
+  PhaseIterGVN *igvn = phase->is_IterGVN();
+  Node* inner_iv_phi = inner_cl->phi();
+  if (inner_iv_phi == NULL) {
+    return NULL;
+  }
+  CountedLoopEndNode* inner_cle = inner_cl->loopexit();
+  Node* cmp = inner_cl->outer_cmp();
+  BoolNode* bol = inner_cl->outer_bol();
+  assert(cmp->in(1) == inner_cle->cmp_node()->in(1), "broken comparison");
+  assert(bol->_test._test == inner_cle->test_trip(), "broken comparison");
+
+  int stride = inner_cl->stride_con();
+  jlong scaled_iters_long = ((jlong)LoopStripMiningIter) * ABS(stride);
+  int scaled_iters = (int)scaled_iters_long;
+  int short_scaled_iters = LoopStripMiningIterShortLoop* ABS(stride);
+  const TypeInt* inner_iv_t = phase->type(inner_iv_phi)->is_int();
+  jlong iter_estimate = (jlong)inner_iv_t->_hi - (jlong)inner_iv_t->_lo;
+  assert(iter_estimate > 0, "broken");
+  if ((jlong)scaled_iters != scaled_iters_long || iter_estimate <= short_scaled_iters) {
+    // Remove outer loop and safepoint (too few iterations)
+    Node* outer_sfpt = inner_cl->outer_safepoint();
+    Node* outer_out = inner_cl->outer_loop_exit();
+    igvn->replace_node(outer_out, outer_sfpt->in(0));
+    igvn->replace_input_of(outer_sfpt, 0, igvn->C->top());
+    inner_cl->clear_strip_mined();
+    return igvn->C->top();
+  }
+
+  Node* cle_tail = inner_cle->proj_out(true);
+  ResourceMark rm;
+  Node_List old_new;
+  if (cle_tail->outcnt() > 1) {
+    // Look for nodes on backedge of inner loop and clone them
+    Unique_Node_List backedge_nodes;
+    for (DUIterator_Fast imax, i = cle_tail->fast_outs(imax); i < imax; i++) {
+      Node* u = cle_tail->fast_out(i);
+      if (u != inner_cl) {
+        assert(!u->is_CFG(), "control flow on the backedge?");
+        backedge_nodes.push(u);
+      }
+    }
+    uint last = igvn->C->unique();
+    for (uint next = 0; next < backedge_nodes.size(); next++) {
+      Node* n = backedge_nodes.at(next);
+      old_new.map(n->_idx, n->clone());
+      for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+        Node* u = n->fast_out(i);
+        assert(!u->is_CFG(), "broken");
+        if (u->_idx >= last) {
+          continue;
+        }
+        if (!u->is_Phi()) {
+          backedge_nodes.push(u);
+        } else {
+          assert(u->in(0) == inner_cl, "strange phi on the backedge");
+        }
+      }
+    }
+    // Put the clones on the outer loop backedge
+    Node* le_tail = inner_cl->outer_loop_tail();
+    for (uint next = 0; next < backedge_nodes.size(); next++) {
+      Node *n = old_new[backedge_nodes.at(next)->_idx];
+      for (uint i = 1; i < n->req(); i++) {
+        if (n->in(i) != NULL && old_new[n->in(i)->_idx] != NULL) {
+          n->set_req(i, old_new[n->in(i)->_idx]);
+        }
+      }
+      if (n->in(0) != NULL) {
+        assert(n->in(0) == cle_tail, "node not on backedge?");
+        n->set_req(0, le_tail);
+      }
+      igvn->register_new_node_with_optimizer(n);
+    }
+  }
+
+  Node* iv_phi = NULL;
+  // Make a clone of each phi in the inner loop
+  // for the outer loop
+  Node* l = inner_cl->outer_loop();
+  for (uint i = 0; i < inner_cl->outcnt(); i++) {
+    Node* u = inner_cl->raw_out(i);
+    if (u->is_Phi()) {
+      assert(u->in(0) == inner_cl, "inconsistent");
+      Node* phi = u->clone();
+      phi->set_req(0, l);
+      Node* be = old_new[phi->in(LoopNode::LoopBackControl)->_idx];
+      if (be != NULL) {
+        phi->set_req(LoopNode::LoopBackControl, be);
+      }
+      phi = igvn->transform(phi);
+      igvn->replace_input_of(u, LoopNode::EntryControl, phi);
+      if (u == inner_iv_phi) {
+        iv_phi = phi;
+      }
+    }
+  }
+  Node* cle_out = inner_cle->proj_out(false);
+  if (cle_out->outcnt() > 1) {
+    // Look for chains of stores that were sunk
+    // out of the inner loop and are in the outer loop
+    for (DUIterator_Fast imax, i = cle_out->fast_outs(imax); i < imax; i++) {
+      Node* u = cle_out->fast_out(i);
+      if (u->is_Store()) {
+        Node* first = u;
+        for(;;) {
+          Node* next = first->in(MemNode::Memory);
+          if (!next->is_Store() || next->in(0) != cle_out) {
+            break;
+          }
+          first = next;
+        }
+        Node* last = u;
+        for(;;) {
+          Node* next = NULL;
+          for (DUIterator_Fast jmax, j = last->fast_outs(jmax); j < jmax; j++) {
+            Node* uu = last->fast_out(j);
+            if (uu->is_Store() && uu->in(0) == cle_out) {
+              assert(next == NULL, "only one in the outer loop");
+              next = uu;
+            }
+          }
+          if (next == NULL) {
+            break;
+          }
+          last = next;
+        }
+        Node* phi = NULL;
+        for (DUIterator_Fast jmax, j = l->fast_outs(jmax); j < jmax; j++) {
+          Node* uu = l->fast_out(j);
+          if (uu->is_Phi()) {
+            Node* be = uu->in(LoopNode::LoopBackControl);
+            while (be->is_Store() && old_new[be->_idx] != NULL) {
+              ShouldNotReachHere();
+              be = be->in(MemNode::Memory);
+            }
+            if (be == last || be == first->in(MemNode::Memory)) {
+              assert(phi == NULL, "only one phi");
+              phi = uu;
+            }
+          }
+        }
+#ifdef ASSERT
+        for (DUIterator_Fast jmax, j = l->fast_outs(jmax); j < jmax; j++) {
+          Node* uu = l->fast_out(j);
+          if (uu->is_Phi() && uu->bottom_type() == Type::MEMORY) {
+            if (uu->adr_type() == igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))) {
+              assert(phi == uu, "what's that phi?");
+            } else if (uu->adr_type() == TypePtr::BOTTOM) {
+              Node* n = uu->in(LoopNode::LoopBackControl);
+              uint limit = igvn->C->live_nodes();
+              uint i = 0;
+              while (n != uu) {
+                i++;
+                assert(i < limit, "infinite loop");
+                if (n->is_Proj()) {
+                  n = n->in(0);
+                } else if (n->is_SafePoint() || n->is_MemBar()) {
+                  n = n->in(TypeFunc::Memory);
+                } else if (n->is_Phi()) {
+                  n = n->in(1);
+                } else if (n->is_MergeMem()) {
+                  n = n->as_MergeMem()->memory_at(igvn->C->get_alias_index(u->adr_type()));
+                } else if (n->is_Store() || n->is_LoadStore() || n->is_ClearArray()) {
+                  n = n->in(MemNode::Memory);
+                } else {
+                  n->dump();
+                  ShouldNotReachHere();
+                }
+              }
+            }
+          }
+        }
+#endif
+        if (phi == NULL) {
+          // If the an entire chains was sunk, the
+          // inner loop has no phi for that memory
+          // slice, create one for the outer loop
+          phi = PhiNode::make(l, first->in(MemNode::Memory), Type::MEMORY,
+                              igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type())));
+          phi->set_req(LoopNode::LoopBackControl, last);
+          phi = igvn->transform(phi);
+          igvn->replace_input_of(first, MemNode::Memory, phi);
+        } else {
+          // Or fix the outer loop fix to include
+          // that chain of stores.
+          Node* be = phi->in(LoopNode::LoopBackControl);
+          while (be->is_Store() && old_new[be->_idx] != NULL) {
+            ShouldNotReachHere();
+            be = be->in(MemNode::Memory);
+          }
+          if (be == first->in(MemNode::Memory)) {
+            if (be == phi->in(LoopNode::LoopBackControl)) {
+              igvn->replace_input_of(phi, LoopNode::LoopBackControl, last);
+            } else {
+              igvn->replace_input_of(be, MemNode::Memory, last);
+            }
+          } else {
+#ifdef ASSERT
+            if (be == phi->in(LoopNode::LoopBackControl)) {
+              assert(phi->in(LoopNode::LoopBackControl) == last, "");
+            } else {
+              assert(be->in(MemNode::Memory) == last, "");
+            }
+#endif
+          }
+        }
+      }
+    }
+  }
+
+  if (iv_phi != NULL) {
+    // Now adjust the inner loop's exit condition
+    Node* limit = inner_cl->limit();
+    Node* sub = NULL;
+    if (stride > 0) {
+      sub = igvn->transform(new SubINode(limit, iv_phi));
+    } else {
+      sub = igvn->transform(new SubINode(iv_phi, limit));
+    }
+    Node* min = igvn->transform(new MinINode(sub, igvn->intcon(scaled_iters)));
+    Node* new_limit = NULL;
+    if (stride > 0) {
+      new_limit = igvn->transform(new AddINode(min, iv_phi));
+    } else {
+      new_limit = igvn->transform(new SubINode(iv_phi, min));
+    }
+    igvn->replace_input_of(inner_cle->cmp_node(), 2, new_limit);
+    if (iter_estimate <= scaled_iters_long) {
+      // We would only go through one iteration of
+      // the outer loop: drop the outer loop but
+      // keep the safepoint so we don't run for
+      // too long without a safepoint
+      igvn->replace_input_of(inner_cl->outer_loop_end(), 1, igvn->intcon(0));
+      inner_cl->clear_strip_mined();
+    }
+    return limit;
+  }
+  return NULL;
+}
+
 //=============================================================================
 
 uint ProfileBooleanNode::hash() const { return NO_HASH; }
 uint ProfileBooleanNode::cmp( const Node &n ) const {
   return (&n == this);
< prev index next >