--- a/src/hotspot/share/opto/loopnode.cpp Tue Nov 28 21:04:42 2017 +0530
+++ b/src/hotspot/share/opto/loopnode.cpp Tue Nov 28 11:59:16 2017 +0100
@@ -261,8 +261,68 @@
set_early_ctrl( n );
}
+// Create a skeleton strip mined outer loop: a Loop head before the
+// inner strip mined loop, a safepoint and an exit condition guarded
+// by an opaque node after the inner strip mined loop with a backedge
+// to the loop head. The inner strip mined loop is left as it is. Only
+// once loop optimizations are over, do we adjust the inner loop exit
+// condition to limit its number of iterations, set the outer loop
+// exit condition and add Phis to the outer loop head. Some loop
+// optimizations that operate on the inner strip mined loop need to be
+// aware of the outer strip mined loop: loop unswitching needs to
+// clone the outer loop as well as the inner, unrolling needs to only
+// clone the inner loop etc. No optimizations need to change the outer
+// strip mined loop as it is only a skeleton.
+IdealLoopTree* PhaseIdealLoop::create_outer_strip_mined_loop(BoolNode *test, Node *cmp, Node *init_control,
+ IdealLoopTree* loop, float cl_prob, float le_fcnt,
+ Node*& entry_control, Node*& iffalse) {
+ Node* outer_test = _igvn.intcon(0);
+ set_ctrl(outer_test, C->root());
+ Node *orig = iffalse;
+ iffalse = iffalse->clone();
+ _igvn.register_new_node_with_optimizer(iffalse);
+ set_idom(iffalse, idom(orig), dom_depth(orig));
+
+ IfNode *outer_le = new OuterStripMinedLoopEndNode(iffalse, outer_test, cl_prob, le_fcnt);
+ Node *outer_ift = new IfTrueNode (outer_le);
+ Node* outer_iff = orig;
+ _igvn.replace_input_of(outer_iff, 0, outer_le);
+
+ LoopNode *outer_l = new OuterStripMinedLoopNode(C, init_control, outer_ift);
+ entry_control = outer_l;
+
+ IdealLoopTree* outer_ilt = new IdealLoopTree(this, outer_l, outer_ift);
+ IdealLoopTree* parent = loop->_parent;
+ IdealLoopTree* sibling = parent->_child;
+ if (sibling == loop) {
+ parent->_child = outer_ilt;
+ } else {
+ while (sibling->_next != loop) {
+ sibling = sibling->_next;
+ }
+ sibling->_next = outer_ilt;
+ }
+ outer_ilt->_next = loop->_next;
+ outer_ilt->_parent = parent;
+ outer_ilt->_child = loop;
+ outer_ilt->_nest = loop->_nest;
+ loop->_parent = outer_ilt;
+ loop->_next = NULL;
+ loop->_nest++;
+
+ set_loop(iffalse, outer_ilt);
+ register_control(outer_le, outer_ilt, iffalse);
+ register_control(outer_ift, outer_ilt, outer_le);
+ set_idom(outer_iff, outer_le, dom_depth(outer_le));
+ _igvn.register_new_node_with_optimizer(outer_l);
+ set_loop(outer_l, outer_ilt);
+ set_idom(outer_l, init_control, dom_depth(init_control)+1);
+
+ return outer_ilt;
+}
+
//------------------------------is_counted_loop--------------------------------
-bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*& loop) {
PhaseGVN *gvn = &_igvn;
// Counted loop head must be a good RegionNode with only 3 not NULL
@@ -280,7 +340,7 @@
// Allow funny placement of Safepoint
if (back_control->Opcode() == Op_SafePoint) {
- if (UseCountedLoopSafepoints) {
+ if (LoopStripMiningIter != 0) {
// Leaving the safepoint on the backedge and creating a
// CountedLoop will confuse optimizations. We can't move the
// safepoint around because its jvm state wouldn't match a new
@@ -600,7 +660,7 @@
}
set_subtree_ctrl( limit );
- if (!UseCountedLoopSafepoints) {
+ if (LoopStripMiningIter == 0) {
// Check for SafePoint on backedge and remove
Node *sfpt = x->in(LoopNode::LoopBackControl);
if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) {
@@ -683,8 +743,20 @@
assert(iff->outcnt() == 0, "should be dead now");
lazy_replace( iff, le ); // fix 'get_ctrl'
+ Node *sfpt2 = le->in(0);
+
+ Node* entry_control = init_control;
+ bool strip_mine_loop = LoopStripMiningIter > 1 && loop->_child == NULL &&
+ sfpt2->Opcode() == Op_SafePoint && !loop->_has_call;
+ IdealLoopTree* outer_ilt = NULL;
+ if (strip_mine_loop) {
+ outer_ilt = create_outer_strip_mined_loop(test, cmp, init_control, loop,
+ cl_prob, le->_fcnt, entry_control,
+ iffalse);
+ }
+
// Now setup a new CountedLoopNode to replace the existing LoopNode
- CountedLoopNode *l = new CountedLoopNode(init_control, back_control);
+ CountedLoopNode *l = new CountedLoopNode(entry_control, back_control);
l->set_unswitch_count(x->as_Loop()->unswitch_count()); // Preserve
// The following assert is approximately true, and defines the intention
// of can_be_counted_loop. It fails, however, because phase->type
@@ -696,12 +768,19 @@
// Fix all data nodes placed at the old loop head.
// Uses the lazy-update mechanism of 'get_ctrl'.
lazy_replace( x, l );
- set_idom(l, init_control, dom_depth(x));
-
- if (!UseCountedLoopSafepoints) {
+ set_idom(l, entry_control, dom_depth(entry_control) + 1);
+
+ if (LoopStripMiningIter == 0 || strip_mine_loop) {
// Check for immediately preceding SafePoint and remove
- Node *sfpt2 = le->in(0);
- if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) {
+ if (sfpt2->Opcode() == Op_SafePoint && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt2))) {
+ if (strip_mine_loop) {
+ Node* outer_le = outer_ilt->_tail->in(0);
+ Node* sfpt = sfpt2->clone();
+ sfpt->set_req(0, iffalse);
+ outer_le->set_req(0, sfpt);
+ register_control(sfpt, outer_ilt, iffalse);
+ set_idom(outer_le, sfpt, dom_depth(sfpt));
+ }
lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
if (loop->_safepts != NULL) {
loop->_safepts->yank(sfpt2);
@@ -730,6 +809,13 @@
// bounds
l->phi()->as_Phi()->set_type(l->phi()->Value(&_igvn));
+ if (strip_mine_loop) {
+ l->mark_strip_mined();
+ l->verify_strip_mined(1);
+ outer_ilt->_head->as_Loop()->verify_strip_mined(1);
+ loop = outer_ilt;
+ }
+
return true;
}
@@ -776,12 +862,93 @@
// Return a node which is more "ideal" than the current node.
// Attempt to convert into a counted-loop.
Node *LoopNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- if (!can_be_counted_loop(phase)) {
+ if (!can_be_counted_loop(phase) && !is_OuterStripMinedLoop()) {
phase->C->set_major_progress();
}
return RegionNode::Ideal(phase, can_reshape);
}
+void LoopNode::verify_strip_mined(int expect_skeleton) const {
+#ifdef ASSERT
+ const OuterStripMinedLoopNode* outer = NULL;
+ const CountedLoopNode* inner = NULL;
+ if (is_strip_mined()) {
+ assert(is_CountedLoop(), "no Loop should be marked strip mined");
+ inner = as_CountedLoop();
+ outer = inner->in(LoopNode::EntryControl)->as_OuterStripMinedLoop();
+ } else if (is_OuterStripMinedLoop()) {
+ outer = this->as_OuterStripMinedLoop();
+ inner = outer->unique_ctrl_out()->as_CountedLoop();
+ assert(!is_strip_mined(), "outer loop shouldn't be marked strip mined");
+ }
+ if (inner != NULL || outer != NULL) {
+ assert(inner != NULL && outer != NULL, "missing loop in strip mined nest");
+ Node* outer_tail = outer->in(LoopNode::LoopBackControl);
+ Node* outer_le = outer_tail->in(0);
+ assert(outer_le->Opcode() == Op_OuterStripMinedLoopEnd, "tail of outer loop should be an If");
+ Node* sfpt = outer_le->in(0);
+ assert(sfpt->Opcode() == Op_SafePoint, "where's the safepoint?");
+ Node* inner_out = sfpt->in(0);
+ if (inner_out->outcnt() != 1) {
+ ResourceMark rm;
+ Unique_Node_List wq;
+
+ for (DUIterator_Fast imax, i = inner_out->fast_outs(imax); i < imax; i++) {
+ Node* u = inner_out->fast_out(i);
+ if (u == sfpt) {
+ continue;
+ }
+ wq.clear();
+ wq.push(u);
+ bool found_sfpt = false;
+ for (uint next = 0; next < wq.size() && !found_sfpt; next++) {
+ Node *n = wq.at(next);
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax && !found_sfpt; i++) {
+ Node* u = n->fast_out(i);
+ if (u == sfpt) {
+ found_sfpt = true;
+ }
+ if (!u->is_CFG()) {
+ wq.push(u);
+ }
+ }
+ }
+ assert(found_sfpt, "no node in loop that's not input to safepoint");
+ }
+ }
+ CountedLoopEndNode* cle = inner_out->in(0)->as_CountedLoopEnd();
+ assert(cle == inner->loopexit(), "mismatch");
+ bool has_skeleton = outer_le->in(1)->bottom_type()->singleton() && outer_le->in(1)->bottom_type()->is_int()->get_con() == 0;
+ if (has_skeleton) {
+ assert(expect_skeleton == 1 || expect_skeleton == -1, "unexpected skeleton node");
+ assert(outer->outcnt() == 2, "only phis");
+ } else {
+ assert(expect_skeleton == 0 || expect_skeleton == -1, "no skeleton node?");
+ uint phis = 0;
+ for (DUIterator_Fast imax, i = inner->fast_outs(imax); i < imax; i++) {
+ Node* u = inner->fast_out(i);
+ if (u->is_Phi()) {
+ phis++;
+ }
+ }
+ for (DUIterator_Fast imax, i = outer->fast_outs(imax); i < imax; i++) {
+ Node* u = outer->fast_out(i);
+ assert(u == outer || u == inner || u->is_Phi(), "nothing between inner and outer loop");
+ }
+ uint stores = 0;
+ for (DUIterator_Fast imax, i = inner_out->fast_outs(imax); i < imax; i++) {
+ Node* u = inner_out->fast_out(i);
+ if (u->is_Store()) {
+ stores++;
+ }
+ }
+ assert(outer->outcnt() >= phis + 2 && outer->outcnt() <= phis + 2 + stores + 1, "only phis");
+ }
+ assert(sfpt->outcnt() == 1, "no data node");
+ assert(outer_tail->outcnt() == 1 || !has_skeleton, "no data node");
+ }
+#endif
+}
//=============================================================================
//------------------------------Ideal------------------------------------------
@@ -802,6 +969,7 @@
if (is_pre_loop ()) st->print("pre of N%d" , _main_idx);
if (is_main_loop()) st->print("main of N%d", _idx);
if (is_post_loop()) st->print("post of N%d", _main_idx);
+ if (is_strip_mined()) st->print(" strip mined");
}
#endif
@@ -990,6 +1158,365 @@
return NULL;
}
+LoopNode* CountedLoopNode::skip_strip_mined(int expect_opaq) {
+ if (is_strip_mined()) {
+ verify_strip_mined(expect_opaq);
+ return in(EntryControl)->as_Loop();
+ }
+ return this;
+}
+
+OuterStripMinedLoopNode* CountedLoopNode::outer_loop() const {
+ assert(is_strip_mined(), "not a strip mined loop");
+ Node* c = in(EntryControl);
+ if (c == NULL || c->is_top() || !c->is_OuterStripMinedLoop()) {
+ return NULL;
+ }
+ return c->as_OuterStripMinedLoop();
+}
+
+IfTrueNode* OuterStripMinedLoopNode::outer_loop_tail() const {
+ Node* c = in(LoopBackControl);
+ if (c == NULL || c->is_top()) {
+ return NULL;
+ }
+ return c->as_IfTrue();
+}
+
+IfTrueNode* CountedLoopNode::outer_loop_tail() const {
+ LoopNode* l = outer_loop();
+ if (l == NULL) {
+ return NULL;
+ }
+ return l->outer_loop_tail();
+}
+
+OuterStripMinedLoopEndNode* OuterStripMinedLoopNode::outer_loop_end() const {
+ IfTrueNode* proj = outer_loop_tail();
+ if (proj == NULL) {
+ return NULL;
+ }
+ Node* c = proj->in(0);
+ if (c == NULL || c->is_top() || c->outcnt() != 2) {
+ return NULL;
+ }
+ return c->as_OuterStripMinedLoopEnd();
+}
+
+OuterStripMinedLoopEndNode* CountedLoopNode::outer_loop_end() const {
+ LoopNode* l = outer_loop();
+ if (l == NULL) {
+ return NULL;
+ }
+ return l->outer_loop_end();
+}
+
+IfFalseNode* OuterStripMinedLoopNode::outer_loop_exit() const {
+ IfNode* le = outer_loop_end();
+ if (le == NULL) {
+ return NULL;
+ }
+ Node* c = le->proj_out(false);
+ if (c == NULL) {
+ return NULL;
+ }
+ return c->as_IfFalse();
+}
+
+IfFalseNode* CountedLoopNode::outer_loop_exit() const {
+ LoopNode* l = outer_loop();
+ if (l == NULL) {
+ return NULL;
+ }
+ return l->outer_loop_exit();
+}
+
+SafePointNode* OuterStripMinedLoopNode::outer_safepoint() const {
+ IfNode* le = outer_loop_end();
+ if (le == NULL) {
+ return NULL;
+ }
+ Node* c = le->in(0);
+ if (c == NULL || c->is_top()) {
+ return NULL;
+ }
+ assert(c->Opcode() == Op_SafePoint, "broken outer loop");
+ return c->as_SafePoint();
+}
+
+SafePointNode* CountedLoopNode::outer_safepoint() const {
+ LoopNode* l = outer_loop();
+ if (l == NULL) {
+ return NULL;
+ }
+ return l->outer_safepoint();
+}
+
+void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) {
+ // 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 = unique_ctrl_out()->as_CountedLoop();
+ assert(inner_cl->is_strip_mined(), "inner loop should be strip mined");
+ Node* inner_iv_phi = inner_cl->phi();
+ if (inner_iv_phi == NULL) {
+ return;
+ }
+ CountedLoopEndNode* inner_cle = inner_cl->loopexit();
+
+ 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 = igvn->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 = outer_safepoint();
+ Node* outer_out = 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;
+ }
+ 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
+ IfNode* outer_le = outer_loop_end();
+ Node* iff = igvn->transform(new IfNode(outer_le->in(0), outer_le->in(1), outer_le->_prob, outer_le->_fcnt));
+ igvn->replace_node(outer_le, iff);
+ inner_cl->clear_strip_mined();
+ return;
+ }
+
+ 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 = 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
+ 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, this);
+ 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 = fast_outs(jmax); j < jmax; j++) {
+ Node* uu = 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 = fast_outs(jmax); j < jmax; j++) {
+ Node* uu = 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(this, 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);
+ Node* cmp = inner_cle->cmp_node()->clone();
+ Node* bol = inner_cle->in(CountedLoopEndNode::TestValue)->clone();
+ cmp->set_req(2, limit);
+ bol->set_req(1, igvn->transform(cmp));
+ igvn->replace_input_of(outer_loop_end(), 1, igvn->transform(bol));
+ } else {
+ assert(false, "should be able to adjust outer loop");
+ IfNode* outer_le = outer_loop_end();
+ Node* iff = igvn->transform(new IfNode(outer_le->in(0), outer_le->in(1), outer_le->_prob, outer_le->_fcnt));
+ igvn->replace_node(outer_le, iff);
+ inner_cl->clear_strip_mined();
+ }
+}
+
+const Type* OuterStripMinedLoopEndNode::Value(PhaseGVN* phase) const {
+ if (!in(0)) return Type::TOP;
+ if (phase->type(in(0)) == Type::TOP)
+ return Type::TOP;
+
+ return TypeTuple::IFBOTH;
+}
+
+Node *OuterStripMinedLoopEndNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+ if (remove_dead_region(phase, can_reshape)) return this;
+
+ return NULL;
+}
//------------------------------filtered_type--------------------------------
// Return a type based on condition control flow
@@ -1778,10 +2305,11 @@
if (_head->is_Loop()) _head->as_Loop()->set_inner_loop();
}
+ IdealLoopTree* loop = this;
if (_head->is_CountedLoop() ||
- phase->is_counted_loop(_head, this)) {
-
- if (!UseCountedLoopSafepoints) {
+ phase->is_counted_loop(_head, loop)) {
+
+ if (LoopStripMiningIter == 0 || (LoopStripMiningIter > 1 && _child == NULL)) {
// Indicate we do not need a safepoint here
_has_sfpt = 1;
}
@@ -1800,8 +2328,10 @@
}
// Recursively
- if (_child) _child->counted_loop( phase );
- if (_next) _next ->counted_loop( phase );
+ assert(loop->_child != this || (loop->_head->as_Loop()->is_OuterStripMinedLoop() && _head->as_CountedLoop()->is_strip_mined()), "what kind of loop was added?");
+ assert(loop->_child != this || (loop->_child->_child == NULL && loop->_child->_next == NULL), "would miss some loops");
+ if (loop->_child && loop->_child != this) loop->_child->counted_loop(phase);
+ if (loop->_next) loop->_next ->counted_loop(phase);
}
#ifndef PRODUCT
@@ -1812,7 +2342,7 @@
tty->print(" ");
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
if (_irreducible) tty->print(" IRREDUCIBLE");
- Node* entry = _head->in(LoopNode::EntryControl);
+ Node* entry = _head->as_Loop()->skip_strip_mined(-1)->in(LoopNode::EntryControl);
Node* predicate = PhaseIdealLoop::find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
if (predicate != NULL ) {
tty->print(" limit_check");
@@ -1863,6 +2393,9 @@
if (Verbose) {
tty->print(" body={"); _body.dump_simple(); tty->print(" }");
}
+ if (_head->as_Loop()->is_strip_mined()) {
+ tty->print(" strip_mined");
+ }
tty->cr();
}
@@ -3232,7 +3765,7 @@
if (!cl->is_main_loop() && !cl->is_post_loop()) {
return false;
}
- Node* ctrl = cl->in(LoopNode::EntryControl);
+ Node* ctrl = cl->skip_strip_mined()->in(LoopNode::EntryControl);
if (ctrl == NULL || (!ctrl->is_IfTrue() && !ctrl->is_IfFalse())) {
return false;
}
@@ -3292,7 +3825,7 @@
}
while(worklist.size() != 0 && LCA != early) {
Node* s = worklist.pop();
- if (s->is_Load()) {
+ if (s->is_Load() || s->Opcode() == Op_SafePoint) {
continue;
} else if (s->is_MergeMem()) {
for (DUIterator_Fast imax, i = s->fast_outs(imax); i < imax; i++) {
@@ -3471,6 +4004,38 @@
}
}
+// Verify that no data node is schedules in the outer loop of a strip
+// mined loop.
+void PhaseIdealLoop::verify_strip_mined_scheduling(Node *n, Node* least) {
+#ifdef ASSERT
+ if (get_loop(least)->_nest == 0) {
+ return;
+ }
+ IdealLoopTree* loop = get_loop(least);
+ Node* head = loop->_head;
+ if (head->is_OuterStripMinedLoop()) {
+ Node* sfpt = head->as_Loop()->outer_safepoint();
+ ResourceMark rm;
+ Unique_Node_List wq;
+ wq.push(sfpt);
+ for (uint i = 0; i < wq.size(); i++) {
+ Node *m = wq.at(i);
+ for (uint i = 1; i < m->req(); i++) {
+ Node* nn = m->in(i);
+ if (nn == n) {
+ return;
+ }
+ if (nn != NULL && has_ctrl(nn) && get_loop(get_ctrl(nn)) == loop) {
+ wq.push(nn);
+ }
+ }
+ }
+ ShouldNotReachHere();
+ }
+#endif
+}
+
+
//------------------------------build_loop_late_post---------------------------
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
// Second pass finds latest legal placement, and ideal loop placement.
@@ -3580,8 +4145,9 @@
// which can inhibit range check elimination.
if (least != early) {
Node* ctrl_out = least->unique_ctrl_out();
- if (ctrl_out && ctrl_out->is_CountedLoop() &&
- least == ctrl_out->in(LoopNode::EntryControl)) {
+ if (ctrl_out && ctrl_out->is_Loop() &&
+ least == ctrl_out->in(LoopNode::EntryControl) &&
+ (ctrl_out->is_CountedLoop() || ctrl_out->is_OuterStripMinedLoop())) {
Node* least_dom = idom(least);
if (get_loop(least_dom)->is_member(get_loop(least))) {
least = least_dom;
@@ -3606,6 +4172,7 @@
// Assign discovered "here or above" point
least = find_non_split_ctrl(least);
+ verify_strip_mined_scheduling(n, least);
set_ctrl(n, least);
// Collect inner loop bodies