aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/opto
diff options
context:
space:
mode:
authorjrose <none@none>2011-04-09 21:16:12 -0700
committerjrose <none@none>2011-04-09 21:16:12 -0700
commit3dba0c694c7215ccc865fe0f65352ba4ec5456e8 (patch)
tree95db1c0e4a096f52bef193735e40130d97c3d7e9 /src/share/vm/opto
parent9163142be698cffba17b791f0daaf5208567b9ba (diff)
parent80a1479a9e8ca81e5406e4b030a9433d05419cf9 (diff)
Merge
Diffstat (limited to 'src/share/vm/opto')
-rw-r--r--src/share/vm/opto/callGenerator.cpp28
-rw-r--r--src/share/vm/opto/callGenerator.hpp16
-rw-r--r--src/share/vm/opto/cfgnode.cpp18
-rw-r--r--src/share/vm/opto/compile.cpp17
-rw-r--r--src/share/vm/opto/compile.hpp3
-rw-r--r--src/share/vm/opto/doCall.cpp11
-rw-r--r--src/share/vm/opto/escape.cpp26
-rw-r--r--src/share/vm/opto/graphKit.cpp21
-rw-r--r--src/share/vm/opto/graphKit.hpp2
-rw-r--r--src/share/vm/opto/idealKit.cpp106
-rw-r--r--src/share/vm/opto/idealKit.hpp20
-rw-r--r--src/share/vm/opto/ifnode.cpp32
-rw-r--r--src/share/vm/opto/library_call.cpp91
-rw-r--r--src/share/vm/opto/loopPredicate.cpp960
-rw-r--r--src/share/vm/opto/loopTransform.cpp1037
-rw-r--r--src/share/vm/opto/loopUnswitch.cpp32
-rw-r--r--src/share/vm/opto/loopnode.cpp67
-rw-r--r--src/share/vm/opto/loopnode.hpp90
-rw-r--r--src/share/vm/opto/loopopts.cpp27
-rw-r--r--src/share/vm/opto/phaseX.hpp7
-rw-r--r--src/share/vm/opto/split_if.cpp3
-rw-r--r--src/share/vm/opto/superword.cpp7
-rw-r--r--src/share/vm/opto/vectornode.hpp1
23 files changed, 1681 insertions, 941 deletions
diff --git a/src/share/vm/opto/callGenerator.cpp b/src/share/vm/opto/callGenerator.cpp
index 6d201139e..ed02629d6 100644
--- a/src/share/vm/opto/callGenerator.cpp
+++ b/src/share/vm/opto/callGenerator.cpp
@@ -978,31 +978,19 @@ WarmCallInfo* WarmCallInfo::remove_from(WarmCallInfo* head) {
return head;
}
-WarmCallInfo* WarmCallInfo::_always_hot = NULL;
-WarmCallInfo* WarmCallInfo::_always_cold = NULL;
+WarmCallInfo WarmCallInfo::_always_hot(WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE(),
+ WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE());
+WarmCallInfo WarmCallInfo::_always_cold(WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE(),
+ WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE());
WarmCallInfo* WarmCallInfo::always_hot() {
- if (_always_hot == NULL) {
- static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0};
- WarmCallInfo* ci = (WarmCallInfo*) bits;
- ci->_profit = ci->_count = MAX_VALUE();
- ci->_work = ci->_size = MIN_VALUE();
- _always_hot = ci;
- }
- assert(_always_hot->is_hot(), "must always be hot");
- return _always_hot;
+ assert(_always_hot.is_hot(), "must always be hot");
+ return &_always_hot;
}
WarmCallInfo* WarmCallInfo::always_cold() {
- if (_always_cold == NULL) {
- static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0};
- WarmCallInfo* ci = (WarmCallInfo*) bits;
- ci->_profit = ci->_count = MIN_VALUE();
- ci->_work = ci->_size = MAX_VALUE();
- _always_cold = ci;
- }
- assert(_always_cold->is_cold(), "must always be cold");
- return _always_cold;
+ assert(_always_cold.is_cold(), "must always be cold");
+ return &_always_cold;
}
diff --git a/src/share/vm/opto/callGenerator.hpp b/src/share/vm/opto/callGenerator.hpp
index 75e8ba004..4a50f990e 100644
--- a/src/share/vm/opto/callGenerator.hpp
+++ b/src/share/vm/opto/callGenerator.hpp
@@ -215,8 +215,20 @@ class WarmCallInfo : public ResourceObj {
WarmCallInfo* next() const { return _next; }
void set_next(WarmCallInfo* n) { _next = n; }
- static WarmCallInfo* _always_hot;
- static WarmCallInfo* _always_cold;
+ static WarmCallInfo _always_hot;
+ static WarmCallInfo _always_cold;
+
+ // Constructor intitialization of always_hot and always_cold
+ WarmCallInfo(float c, float p, float w, float s) {
+ _call = NULL;
+ _hot_cg = NULL;
+ _next = NULL;
+ _count = c;
+ _profit = p;
+ _work = w;
+ _size = s;
+ _heat = 0;
+ }
public:
// Because WarmInfo objects live over the entire lifetime of the
diff --git a/src/share/vm/opto/cfgnode.cpp b/src/share/vm/opto/cfgnode.cpp
index f6ca3ce7f..90f0234f0 100644
--- a/src/share/vm/opto/cfgnode.cpp
+++ b/src/share/vm/opto/cfgnode.cpp
@@ -1349,9 +1349,17 @@ static Node* is_absolute( PhaseGVN *phase, PhiNode *phi_root, int true_path) {
static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *newn) {
igvn->hash_delete(n); // Remove from hash before hacking edges
+ Node* predicate_proj = NULL;
uint j = 1;
- for( uint i = phi->req()-1; i > 0; i-- ) {
- if( phi->in(i) == val ) { // Found a path with val?
+ for (uint i = phi->req()-1; i > 0; i--) {
+ if (phi->in(i) == val) { // Found a path with val?
+ if (n->is_Region()) {
+ Node* proj = PhaseIdealLoop::find_predicate(n->in(i));
+ if (proj != NULL) {
+ assert(predicate_proj == NULL, "only one predicate entry expected");
+ predicate_proj = proj;
+ }
+ }
// Add to NEW Region/Phi, no DU info
newn->set_req( j++, n->in(i) );
// Remove from OLD Region/Phi
@@ -1362,6 +1370,12 @@ static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *
// Register the new node but do not transform it. Cannot transform until the
// entire Region/Phi conglomerate has been hacked as a single huge transform.
igvn->register_new_node_with_optimizer( newn );
+
+ // Clone loop predicates
+ if (predicate_proj != NULL) {
+ newn = igvn->clone_loop_predicates(predicate_proj, newn);
+ }
+
// Now I can point to the new node.
n->add_req(newn);
igvn->_worklist.push(n);
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
index 39bcf30bd..e6084be0e 100644
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -1632,7 +1632,6 @@ void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) {
igvn.replace_node(n, n->in(1));
}
assert(predicate_count()==0, "should be clean!");
- igvn.optimize();
}
//------------------------------Optimize---------------------------------------
@@ -1689,7 +1688,7 @@ void Compile::Optimize() {
if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
{
TracePhase t2("idealLoop", &_t_idealLoop, true);
- PhaseIdealLoop ideal_loop( igvn, true, UseLoopPredicate);
+ PhaseIdealLoop ideal_loop( igvn, true );
loop_opts_cnt--;
if (major_progress()) print_method("PhaseIdealLoop 1", 2);
if (failing()) return;
@@ -1697,7 +1696,7 @@ void Compile::Optimize() {
// Loop opts pass if partial peeling occurred in previous pass
if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) {
TracePhase t3("idealLoop", &_t_idealLoop, true);
- PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate);
+ PhaseIdealLoop ideal_loop( igvn, false );
loop_opts_cnt--;
if (major_progress()) print_method("PhaseIdealLoop 2", 2);
if (failing()) return;
@@ -1705,7 +1704,7 @@ void Compile::Optimize() {
// Loop opts pass for loop-unrolling before CCP
if(major_progress() && (loop_opts_cnt > 0)) {
TracePhase t4("idealLoop", &_t_idealLoop, true);
- PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate);
+ PhaseIdealLoop ideal_loop( igvn, false );
loop_opts_cnt--;
if (major_progress()) print_method("PhaseIdealLoop 3", 2);
}
@@ -1743,21 +1742,13 @@ void Compile::Optimize() {
// peeling, unrolling, etc.
if(loop_opts_cnt > 0) {
debug_only( int cnt = 0; );
- bool loop_predication = UseLoopPredicate;
while(major_progress() && (loop_opts_cnt > 0)) {
TracePhase t2("idealLoop", &_t_idealLoop, true);
assert( cnt++ < 40, "infinite cycle in loop optimization" );
- PhaseIdealLoop ideal_loop( igvn, true, loop_predication);
+ PhaseIdealLoop ideal_loop( igvn, true);
loop_opts_cnt--;
if (major_progress()) print_method("PhaseIdealLoop iterations", 2);
if (failing()) return;
- // Perform loop predication optimization during first iteration after CCP.
- // After that switch it off and cleanup unused loop predicates.
- if (loop_predication) {
- loop_predication = false;
- cleanup_loop_predicates(igvn);
- if (failing()) return;
- }
}
}
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
index 5b562ecee..b2d81897a 100644
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -489,6 +489,9 @@ class Compile : public Phase {
// remove the opaque nodes that protect the predicates so that the unused checks and
// uncommon traps will be eliminated from the graph.
void cleanup_loop_predicates(PhaseIterGVN &igvn);
+ bool is_predicate_opaq(Node * n) {
+ return _predicate_opaqs->contains(n);
+ }
// Compilation environment.
Arena* comp_arena() { return &_comp_arena; }
diff --git a/src/share/vm/opto/doCall.cpp b/src/share/vm/opto/doCall.cpp
index e7cdaf47e..de066e992 100644
--- a/src/share/vm/opto/doCall.cpp
+++ b/src/share/vm/opto/doCall.cpp
@@ -63,6 +63,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
JVMState* jvms, bool allow_inline,
float prof_factor) {
CallGenerator* cg;
+ guarantee(call_method != NULL, "failed method resolution");
// Dtrace currently doesn't work unless all calls are vanilla
if (env()->dtrace_method_probes()) {
@@ -130,8 +131,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_method_handle_adapter();
-
- CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
+ CallGenerator* hit_cg = NULL;
+ if (target_method != NULL)
+ hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline())
return hit_cg;
}
@@ -152,8 +154,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_invokedynamic_adapter();
-
- CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
+ CallGenerator* hit_cg = NULL;
+ if (target_method != NULL)
+ hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline()) {
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
diff --git a/src/share/vm/opto/escape.cpp b/src/share/vm/opto/escape.cpp
index 788a79785..a7b509e34 100644
--- a/src/share/vm/opto/escape.cpp
+++ b/src/share/vm/opto/escape.cpp
@@ -594,7 +594,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
//
// Create a new version of orig_phi if necessary. Returns either the newly
-// created phi or an existing phi. Sets create_new to indicate wheter a new
+// created phi or an existing phi. Sets create_new to indicate whether a new
// phi was created. Cache the last newly created phi in the node map.
//
PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created) {
@@ -649,7 +649,7 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
}
//
-// Return a new version of Memory Phi "orig_phi" with the inputs having the
+// Return a new version of Memory Phi "orig_phi" with the inputs having the
// specified alias index.
//
PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn) {
@@ -828,11 +828,15 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
break; // hit one of our sentinels
if (result->is_Mem()) {
const Type *at = phase->type(result->in(MemNode::Address));
- if (at != Type::TOP) {
- assert (at->isa_ptr() != NULL, "pointer type required.");
- int idx = C->get_alias_index(at->is_ptr());
- if (idx == alias_idx)
- break;
+ if (at == Type::TOP)
+ break; // Dead
+ assert (at->isa_ptr() != NULL, "pointer type required.");
+ int idx = C->get_alias_index(at->is_ptr());
+ if (idx == alias_idx)
+ break; // Found
+ if (!is_instance && (at->isa_oopptr() == NULL ||
+ !at->is_oopptr()->is_known_instance())) {
+ break; // Do not skip store to general memory slice.
}
result = result->in(MemNode::Memory);
}
@@ -902,13 +906,13 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
PhiNode *mphi = result->as_Phi();
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
const TypePtr *t = mphi->adr_type();
- if (C->get_alias_index(t) != alias_idx) {
- // Create a new Phi with the specified alias index type.
- result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
- } else if (!is_instance) {
+ if (!is_instance) {
// Push all non-instance Phis on the orig_phis worklist to update inputs
// during Phase 4 if needed.
orig_phis.append_if_missing(mphi);
+ } else if (C->get_alias_index(t) != alias_idx) {
+ // Create a new Phi with the specified alias index type.
+ result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
}
}
// the result is either MemNode, PhiNode, InitializeNode.
diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
index 794a0f717..afa2efff9 100644
--- a/src/share/vm/opto/graphKit.cpp
+++ b/src/share/vm/opto/graphKit.cpp
@@ -3385,12 +3385,17 @@ void GraphKit::add_predicate(int nargs) {
#define __ ideal.
void GraphKit::sync_kit(IdealKit& ideal) {
- // Final sync IdealKit and graphKit.
- __ drain_delay_transform();
set_all_memory(__ merged_memory());
+ set_i_o(__ i_o());
set_control(__ ctrl());
}
+void GraphKit::final_sync(IdealKit& ideal) {
+ // Final sync IdealKit and graphKit.
+ __ drain_delay_transform();
+ sync_kit(ideal);
+}
+
// vanilla/CMS post barrier
// Insert a write-barrier store. This is to let generational GC work; we have
// to flag all oop-stores before the next GC point.
@@ -3435,7 +3440,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
// (Else it's an array (or unknown), and we want more precise card marks.)
assert(adr != NULL, "");
- IdealKit ideal(gvn(), control(), merged_memory(), true);
+ IdealKit ideal(this, true);
// Convert the pointer to an int prior to doing math on it
Node* cast = __ CastPX(__ ctrl(), adr);
@@ -3461,7 +3466,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
}
// Final sync IdealKit and GraphKit.
- sync_kit(ideal);
+ final_sync(ideal);
}
// G1 pre/post barriers
@@ -3471,7 +3476,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
Node* val,
const TypeOopPtr* val_type,
BasicType bt) {
- IdealKit ideal(gvn(), control(), merged_memory(), true);
+ IdealKit ideal(this, true);
Node* tls = __ thread(); // ThreadLocalStorage
@@ -3548,7 +3553,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
} __ end_if(); // (!marking)
// Final sync IdealKit and GraphKit.
- sync_kit(ideal);
+ final_sync(ideal);
}
//
@@ -3614,7 +3619,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
// (Else it's an array (or unknown), and we want more precise card marks.)
assert(adr != NULL, "");
- IdealKit ideal(gvn(), control(), merged_memory(), true);
+ IdealKit ideal(this, true);
Node* tls = __ thread(); // ThreadLocalStorage
@@ -3688,6 +3693,6 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
}
// Final sync IdealKit and GraphKit.
- sync_kit(ideal);
+ final_sync(ideal);
}
#undef __
diff --git a/src/share/vm/opto/graphKit.hpp b/src/share/vm/opto/graphKit.hpp
index 1302184fc..4523326db 100644
--- a/src/share/vm/opto/graphKit.hpp
+++ b/src/share/vm/opto/graphKit.hpp
@@ -662,7 +662,9 @@ class GraphKit : public Phase {
&& Universe::heap()->can_elide_tlab_store_barriers());
}
+ // Sync Ideal and Graph kits.
void sync_kit(IdealKit& ideal);
+ void final_sync(IdealKit& ideal);
// vanilla/CMS post barrier
void write_barrier_post(Node *store, Node* obj,
diff --git a/src/share/vm/opto/idealKit.cpp b/src/share/vm/opto/idealKit.cpp
index a143a6492..c9cb0f855 100644
--- a/src/share/vm/opto/idealKit.cpp
+++ b/src/share/vm/opto/idealKit.cpp
@@ -38,15 +38,16 @@
const uint IdealKit::first_var = TypeFunc::Parms + 1;
//----------------------------IdealKit-----------------------------------------
-IdealKit::IdealKit(PhaseGVN &gvn, Node* control, Node* mem, bool delay_all_transforms, bool has_declarations) :
- _gvn(gvn), C(gvn.C) {
- _initial_ctrl = control;
- _initial_memory = mem;
+IdealKit::IdealKit(GraphKit* gkit, bool delay_all_transforms, bool has_declarations) :
+ _gvn(gkit->gvn()), C(gkit->C) {
+ _initial_ctrl = gkit->control();
+ _initial_memory = gkit->merged_memory();
+ _initial_i_o = gkit->i_o();
_delay_all_transforms = delay_all_transforms;
_var_ct = 0;
_cvstate = NULL;
// We can go memory state free or else we need the entire memory state
- assert(mem == NULL || mem->Opcode() == Op_MergeMem, "memory must be pre-split");
+ assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split");
int init_size = 5;
_pending_cvstates = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
_delay_transform = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
@@ -56,6 +57,13 @@ IdealKit::IdealKit(PhaseGVN &gvn, Node* control, Node* mem, bool delay_all_trans
}
}
+//----------------------------sync_kit-----------------------------------------
+void IdealKit::sync_kit(GraphKit* gkit) {
+ set_all_memory(gkit->merged_memory());
+ set_i_o(gkit->i_o());
+ set_ctrl(gkit->control());
+}
+
//-------------------------------if_then-------------------------------------
// Create: if(left relop right)
// / \
@@ -156,16 +164,14 @@ void IdealKit::end_if() {
// onto the stack.
void IdealKit::loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) {
assert((state() & (BlockS|LoopS|IfThenS|ElseS)), "bad state for new loop");
-
- // Sync IdealKit and graphKit.
- gkit->set_all_memory(this->merged_memory());
- gkit->set_control(this->ctrl());
- // Add loop predicate.
- gkit->add_predicate(nargs);
- // Update IdealKit memory.
- this->set_all_memory(gkit->merged_memory());
- this->set_ctrl(gkit->control());
-
+ if (UseLoopPredicate) {
+ // Sync IdealKit and graphKit.
+ gkit->sync_kit(*this);
+ // Add loop predicate.
+ gkit->add_predicate(nargs);
+ // Update IdealKit memory.
+ sync_kit(gkit);
+ }
set(iv, init);
Node* head = make_label(1);
bind(head);
@@ -280,6 +286,7 @@ void IdealKit::declarations_done() {
_cvstate = new_cvstate(); // initialize current cvstate
set_ctrl(_initial_ctrl); // initialize control in current cvstate
set_all_memory(_initial_memory);// initialize memory in current cvstate
+ set_i_o(_initial_i_o); // initialize i_o in current cvstate
DEBUG_ONLY(_state->push(BlockS));
}
@@ -421,6 +428,9 @@ void IdealKit::do_memory_merge(Node* merging, Node* join) {
// Get the region for the join state
Node* join_region = join->in(TypeFunc::Control);
assert(join_region != NULL, "join region must exist");
+ if (join->in(TypeFunc::I_O) == NULL ) {
+ join->set_req(TypeFunc::I_O, merging->in(TypeFunc::I_O));
+ }
if (join->in(TypeFunc::Memory) == NULL ) {
join->set_req(TypeFunc::Memory, merging->in(TypeFunc::Memory));
return;
@@ -467,6 +477,20 @@ void IdealKit::do_memory_merge(Node* merging, Node* join) {
mms.set_memory(phi);
}
}
+
+ Node* join_io = join->in(TypeFunc::I_O);
+ Node* merging_io = merging->in(TypeFunc::I_O);
+ if (join_io != merging_io) {
+ PhiNode* phi;
+ if (join_io->is_Phi() && join_io->as_Phi()->region() == join_region) {
+ phi = join_io->as_Phi();
+ } else {
+ phi = PhiNode::make(join_region, join_io, Type::ABIO);
+ phi = (PhiNode*) delay_transform(phi);
+ join->set_req(TypeFunc::I_O, phi);
+ }
+ phi->set_req(slot, merging_io);
+ }
}
@@ -477,7 +501,8 @@ void IdealKit::make_leaf_call(const TypeFunc *slow_call_type,
const char *leaf_name,
Node* parm0,
Node* parm1,
- Node* parm2) {
+ Node* parm2,
+ Node* parm3) {
// We only handle taking in RawMem and modifying RawMem
const TypePtr* adr_type = TypeRawPtr::BOTTOM;
@@ -498,6 +523,55 @@ void IdealKit::make_leaf_call(const TypeFunc *slow_call_type,
if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0);
if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1);
if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2);
+ if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3);
+
+ // Node *c = _gvn.transform(call);
+ call = (CallNode *) _gvn.transform(call);
+ Node *c = call; // dbx gets confused with call call->dump()
+
+ // Slow leaf call has no side-effects, sets few values
+
+ set_ctrl(transform( new (C, 1) ProjNode(call,TypeFunc::Control) ));
+
+ // Make memory for the call
+ Node* mem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) );
+
+ // Set the RawPtr memory state only.
+ set_memory(mem, adr_idx);
+
+ assert(C->alias_type(call->adr_type()) == C->alias_type(adr_type),
+ "call node must be constructed correctly");
+}
+
+
+void IdealKit::make_leaf_call_no_fp(const TypeFunc *slow_call_type,
+ address slow_call,
+ const char *leaf_name,
+ const TypePtr* adr_type,
+ Node* parm0,
+ Node* parm1,
+ Node* parm2,
+ Node* parm3) {
+
+ // We only handle taking in RawMem and modifying RawMem
+ uint adr_idx = C->get_alias_index(adr_type);
+
+ // Slow-path leaf call
+ int size = slow_call_type->domain()->cnt();
+ CallNode *call = (CallNode*)new (C, size) CallLeafNoFPNode( slow_call_type, slow_call, leaf_name, adr_type);
+
+ // Set fixed predefined input arguments
+ call->init_req( TypeFunc::Control, ctrl() );
+ call->init_req( TypeFunc::I_O , top() ) ; // does no i/o
+ // Narrow memory as only memory input
+ call->init_req( TypeFunc::Memory , memory(adr_idx));
+ call->init_req( TypeFunc::FramePtr, top() /* frameptr() */ );
+ call->init_req( TypeFunc::ReturnAdr, top() );
+
+ if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0);
+ if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1);
+ if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2);
+ if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3);
// Node *c = _gvn.transform(call);
call = (CallNode *) _gvn.transform(call);
diff --git a/src/share/vm/opto/idealKit.hpp b/src/share/vm/opto/idealKit.hpp
index 1ece14259..6787e533a 100644
--- a/src/share/vm/opto/idealKit.hpp
+++ b/src/share/vm/opto/idealKit.hpp
@@ -108,6 +108,7 @@ class IdealKit: public StackObj {
bool _delay_all_transforms; // flag forcing all transforms to be delayed
Node* _initial_ctrl; // saves initial control until variables declared
Node* _initial_memory; // saves initial memory until variables declared
+ Node* _initial_i_o; // saves initial i_o until variables declared
PhaseGVN& gvn() const { return _gvn; }
// Create a new cvstate filled with nulls
@@ -142,17 +143,21 @@ class IdealKit: public StackObj {
Node* memory(uint alias_idx);
public:
- IdealKit(PhaseGVN &gvn, Node* control, Node* memory, bool delay_all_transforms = false, bool has_declarations = false);
+ IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false);
~IdealKit() {
stop();
drain_delay_transform();
}
+ void sync_kit(GraphKit* gkit);
+
// Control
Node* ctrl() { return _cvstate->in(TypeFunc::Control); }
void set_ctrl(Node* ctrl) { _cvstate->set_req(TypeFunc::Control, ctrl); }
Node* top() { return C->top(); }
MergeMemNode* merged_memory() { return _cvstate->in(TypeFunc::Memory)->as_MergeMem(); }
void set_all_memory(Node* mem) { _cvstate->set_req(TypeFunc::Memory, mem); }
+ Node* i_o() { return _cvstate->in(TypeFunc::I_O); }
+ void set_i_o(Node* c) { _cvstate->set_req(TypeFunc::I_O, c); }
void set(IdealVariable& v, Node* rhs) { _cvstate->set_req(first_var + v.id(), rhs); }
Node* value(IdealVariable& v) { return _cvstate->in(first_var + v.id()); }
void dead(IdealVariable& v) { set(v, (Node*)NULL); }
@@ -239,7 +244,18 @@ class IdealKit: public StackObj {
const char *leaf_name,
Node* parm0,
Node* parm1 = NULL,
- Node* parm2 = NULL);
+ Node* parm2 = NULL,
+ Node* parm3 = NULL);
+
+ void make_leaf_call_no_fp(const TypeFunc *slow_call_type,
+ address slow_call,
+ const char *leaf_name,
+ const TypePtr* adr_type,
+ Node* parm0,
+ Node* parm1,
+ Node* parm2,
+ Node* parm3);
+
};
#endif // SHARE_VM_OPTO_IDEALKIT_HPP
diff --git a/src/share/vm/opto/ifnode.cpp b/src/share/vm/opto/ifnode.cpp
index 25f2e3151..bcdf5ad64 100644
--- a/src/share/vm/opto/ifnode.cpp
+++ b/src/share/vm/opto/ifnode.cpp
@@ -27,6 +27,7 @@
#include "opto/addnode.hpp"
#include "opto/cfgnode.hpp"
#include "opto/connode.hpp"
+#include "opto/loopnode.hpp"
#include "opto/phaseX.hpp"
#include "opto/runtime.hpp"
#include "opto/subnode.hpp"
@@ -222,22 +223,35 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
// Make a region merging constants and a region merging the rest
uint req_c = 0;
+ Node* predicate_proj = NULL;
for (uint ii = 1; ii < r->req(); ii++) {
- if( phi->in(ii) == con1 ) {
+ if (phi->in(ii) == con1) {
req_c++;
}
+ Node* proj = PhaseIdealLoop::find_predicate(r->in(ii));
+ if (proj != NULL) {
+ assert(predicate_proj == NULL, "only one predicate entry expected");
+ predicate_proj = proj;
+ }
}
+ Node* predicate_c = NULL;
+ Node* predicate_x = NULL;
+
Node *region_c = new (igvn->C, req_c + 1) RegionNode(req_c + 1);
Node *phi_c = con1;
uint len = r->req();
- Node *region_x = new (igvn->C, len - req_c + 1) RegionNode(len - req_c + 1);
+ Node *region_x = new (igvn->C, len - req_c) RegionNode(len - req_c);
Node *phi_x = PhiNode::make_blank(region_x, phi);
for (uint i = 1, i_c = 1, i_x = 1; i < len; i++) {
- if( phi->in(i) == con1 ) {
+ if (phi->in(i) == con1) {
region_c->init_req( i_c++, r ->in(i) );
+ if (r->in(i) == predicate_proj)
+ predicate_c = predicate_proj;
} else {
region_x->init_req( i_x, r ->in(i) );
phi_x ->init_req( i_x++, phi->in(i) );
+ if (r->in(i) == predicate_proj)
+ predicate_x = predicate_proj;
}
}
@@ -277,8 +291,20 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
// Make the true/false arms
Node *iff_c_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_c));
Node *iff_c_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_c));
+ if (predicate_c != NULL) {
+ assert(predicate_x == NULL, "only one predicate entry expected");
+ // Clone loop predicates to each path
+ iff_c_t = igvn->clone_loop_predicates(predicate_c, iff_c_t);
+ iff_c_f = igvn->clone_loop_predicates(predicate_c, iff_c_f);
+ }
Node *iff_x_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_x));
Node *iff_x_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_x));
+ if (predicate_x != NULL) {
+ assert(predicate_c == NULL, "only one predicate entry expected");
+ // Clone loop predicates to each path
+ iff_x_t = igvn->clone_loop_predicates(predicate_x, iff_x_t);
+ iff_x_f = igvn->clone_loop_predicates(predicate_x, iff_x_f);
+ }
// Merge the TRUE paths
Node *region_s = new (igvn->C, 3) RegionNode(3);
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
index be8136bf5..0f73e144d 100644
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -1120,7 +1120,7 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar
const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
- IdealKit kit(gvn(), control(), merged_memory(), false, true);
+ IdealKit kit(this, false, true);
#define __ kit.
Node* zero = __ ConI(0);
Node* one = __ ConI(1);
@@ -1171,7 +1171,7 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar
__ bind(return_);
// Final sync IdealKit and GraphKit.
- sync_kit(kit);
+ final_sync(kit);
Node* result = __ value(rtn);
#undef __
C->set_has_loops(true);
@@ -2318,22 +2318,20 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
// of it. So we need to emit code to conditionally do the proper type of
// store.
- IdealKit ideal(gvn(), control(), merged_memory());
+ IdealKit ideal(this);
#define __ ideal.
// QQQ who knows what probability is here??
__ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); {
// Sync IdealKit and graphKit.
- set_all_memory( __ merged_memory());
- set_control(__ ctrl());
+ sync_kit(ideal);
Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type);
// Update IdealKit memory.
- __ set_all_memory(merged_memory());
- __ set_ctrl(control());
+ __ sync_kit(this);
} __ else_(); {
__ store(__ ctrl(), adr, val, type, alias_type->index(), is_volatile);
} __ end_if();
// Final sync IdealKit and GraphKit.
- sync_kit(ideal);
+ final_sync(ideal);
#undef __
}
}
@@ -4294,81 +4292,6 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
return true;
}
-
-// constants for computing the copy function
-enum {
- COPYFUNC_UNALIGNED = 0,
- COPYFUNC_ALIGNED = 1, // src, dest aligned to HeapWordSize
- COPYFUNC_CONJOINT = 0,
- COPYFUNC_DISJOINT = 2 // src != dest, or transfer can descend
-};
-
-// Note: The condition "disjoint" applies also for overlapping copies
-// where an descending copy is permitted (i.e., dest_offset <= src_offset).
-static address
-select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized) {
- int selector =
- (aligned ? COPYFUNC_ALIGNED : COPYFUNC_UNALIGNED) +
- (disjoint ? COPYFUNC_DISJOINT : COPYFUNC_CONJOINT);
-
-#define RETURN_STUB(xxx_arraycopy) { \
- name = #xxx_arraycopy; \
- return StubRoutines::xxx_arraycopy(); }
-
-#define RETURN_STUB_PARM(xxx_arraycopy, parm) { \
- name = #xxx_arraycopy; \
- return StubRoutines::xxx_arraycopy(parm); }
-
- switch (t) {
- case T_BYTE:
- case T_BOOLEAN:
- switch (selector) {
- case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_arraycopy);
- case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_disjoint_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_disjoint_arraycopy);
- }
- case T_CHAR:
- case T_SHORT:
- switch (selector) {
- case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_arraycopy);
- case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_disjoint_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_disjoint_arraycopy);
- }
- case T_INT:
- case T_FLOAT:
- switch (selector) {
- case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_arraycopy);
- case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_disjoint_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_disjoint_arraycopy);
- }
- case T_DOUBLE:
- case T_LONG:
- switch (selector) {
- case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_arraycopy);
- case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_disjoint_arraycopy);
- case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_disjoint_arraycopy);
- }
- case T_ARRAY:
- case T_OBJECT:
- switch (selector) {
- case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_arraycopy, dest_uninitialized);
- case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_arraycopy, dest_uninitialized);
- case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_disjoint_arraycopy, dest_uninitialized);
- case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_disjoint_arraycopy, dest_uninitialized);
- }
- default:
- ShouldNotReachHere();
- return NULL;
- }
-
-#undef RETURN_STUB
-#undef RETURN_STUB_PARM
-}
-
//------------------------------basictype2arraycopy----------------------------
address LibraryCallKit::basictype2arraycopy(BasicType t,
Node* src_offset,
@@ -4401,7 +4324,7 @@ address LibraryCallKit::basictype2arraycopy(BasicType t,
disjoint = true;
}
- return select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized);
+ return StubRoutines::select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized);
}
diff --git a/src/share/vm/opto/loopPredicate.cpp b/src/share/vm/opto/loopPredicate.cpp
new file mode 100644
index 000000000..c5ac2c682
--- /dev/null
+++ b/src/share/vm/opto/loopPredicate.cpp
@@ -0,0 +1,960 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "opto/loopnode.hpp"
+#include "opto/addnode.hpp"
+#include "opto/callnode.hpp"
+#include "opto/connode.hpp"
+#include "opto/loopnode.hpp"
+#include "opto/mulnode.hpp"
+#include "opto/rootnode.hpp"
+#include "opto/subnode.hpp"
+
+/*
+ * The general idea of Loop Predication is to insert a predicate on the entry
+ * path to a loop, and raise a uncommon trap if the check of the condition fails.
+ * The condition checks are promoted from inside the loop body, and thus
+ * the checks inside the loop could be eliminated. Currently, loop predication
+ * optimization has been applied to remove array range check and loop invariant
+ * checks (such as null checks).
+*/
+
+//-------------------------------is_uncommon_trap_proj----------------------------
+// Return true if proj is the form of "proj->[region->..]call_uct"
+bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) {
+ int path_limit = 10;
+ assert(proj, "invalid argument");
+ Node* out = proj;
+ for (int ct = 0; ct < path_limit; ct++) {
+ out = out->unique_ctrl_out();
+ if (out == NULL)
+ return false;
+ if (out->is_CallStaticJava()) {
+ int req = out->as_CallStaticJava()->uncommon_trap_request();
+ if (req != 0) {
+ Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
+ if (trap_reason == reason || reason == Deoptimization::Reason_none) {
+ return true;
+ }
+ }
+ return false; // don't do further after call
+ }
+ if (out->Opcode() != Op_Region)
+ return false;
+ }
+ return false;
+}
+
+//-------------------------------is_uncommon_trap_if_pattern-------------------------
+// Return true for "if(test)-> proj -> ...
+// |
+// V
+// other_proj->[region->..]call_uct"
+//
+// "must_reason_predicate" means the uct reason must be Reason_predicate
+bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) {
+ Node *in0 = proj->in(0);
+ if (!in0->is_If()) return false;
+ // Variation of a dead If node.
+ if (in0->outcnt() < 2) return false;
+ IfNode* iff = in0->as_If();
+
+ // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
+ if (reason != Deoptimization::Reason_none) {
+ if (iff->in(1)->Opcode() != Op_Conv2B ||
+ iff->in(1)->in(1)->Opcode() != Op_Opaque1) {
+ return false;
+ }
+ }
+
+ ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj();
+ if (is_uncommon_trap_proj(other_proj, reason)) {
+ assert(reason == Deoptimization::Reason_none ||
+ Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list");
+ return true;
+ }
+ return false;
+}
+
+//-------------------------------register_control-------------------------
+void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) {
+ assert(n->is_CFG(), "must be control node");
+ _igvn.register_new_node_with_optimizer(n);
+ loop->_body.push(n);
+ set_loop(n, loop);
+ // When called from beautify_loops() idom is not constructed yet.
+ if (_idom != NULL) {
+ set_idom(n, pred, dom_depth(pred));
+ }
+}
+
+//------------------------------create_new_if_for_predicate------------------------
+// create a new if above the uct_if_pattern for the predicate to be promoted.
+//
+// before after
+// ---------- ----------
+// ctrl ctrl
+// | |
+// | |
+// v v
+// iff new_iff
+// / \ / \
+// / \ / \
+// v v v v
+// uncommon_proj cont_proj if_uct if_cont
+// \ | | | |
+// \ | | | |
+// v v v | v
+// rgn loop | iff
+// | | / \
+// | | / \
+// v | v v
+// uncommon_trap | uncommon_proj cont_proj
+// \ \ | |
+// \ \ | |
+// v v v v
+// rgn loop
+// |
+// |
+// v
+// uncommon_trap
+//
+//
+// We will create a region to guard the uct call if there is no one there.
+// The true projecttion (if_cont) of the new_iff is returned.
+// This code is also used to clone predicates to clonned loops.
+ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason) {
+ assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
+ IfNode* iff = cont_proj->in(0)->as_If();
+
+ ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
+ Node *rgn = uncommon_proj->unique_ctrl_out();
+ assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
+
+ uint proj_index = 1; // region's edge corresponding to uncommon_proj
+ if (!rgn->is_Region()) { // create a region to guard the call
+ assert(rgn->is_Call(), "must be call uct");
+ CallNode* call = rgn->as_Call();
+ IdealLoopTree* loop = get_loop(call);
+ rgn = new (C, 1) RegionNode(1);
+ rgn->add_req(uncommon_proj);
+ register_control(rgn, loop, uncommon_proj);
+ _igvn.hash_delete(call);
+ call->set_req(0, rgn);
+ // When called from beautify_loops() idom is not constructed yet.
+ if (_idom != NULL) {
+ set_idom(call, rgn, dom_depth(rgn));
+ }
+ } else {
+ // Find region's edge corresponding to uncommon_proj
+ for (; proj_index < rgn->req(); proj_index++)
+ if (rgn->in(proj_index) == uncommon_proj) break;
+ assert(proj_index < rgn->req(), "sanity");
+ }
+
+ Node* entry = iff->in(0);
+ if (new_entry != NULL) {
+ // Clonning the predicate to new location.
+ entry = new_entry;
+ }
+ // Create new_iff
+ IdealLoopTree* lp = get_loop(entry);
+ IfNode *new_iff = iff->clone()->as_If();
+ new_iff->set_req(0, entry);
+ register_control(new_iff, lp, entry);
+ Node *if_cont = new (C, 1) IfTrueNode(new_iff);
+ Node *if_uct = new (C, 1) IfFalseNode(new_iff);
+ if (cont_proj->is_IfFalse()) {
+ // Swap
+ Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp;
+ }
+ register_control(if_cont, lp, new_iff);
+ register_control(if_uct, get_loop(rgn), new_iff);
+
+ // if_uct to rgn
+ _igvn.hash_delete(rgn);
+ rgn->add_req(if_uct);
+ // When called from beautify_loops() idom is not constructed yet.
+ if (_idom != NULL) {
+ Node* ridom = idom(rgn);
+ Node* nrdom = dom_lca(ridom, new_iff);
+ set_idom(rgn, nrdom, dom_depth(rgn));
+ }
+
+ // If rgn has phis add new edges which has the same
+ // value as on original uncommon_proj pass.
+ assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last");
+ bool has_phi = false;
+ for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) {
+ Node* use = rgn->fast_out(i);
+ if (use->is_Phi() && use->outcnt() > 0) {
+ assert(use->in(0) == rgn, "");
+ _igvn.hash_delete(use);
+ use->add_req(use->in(proj_index));
+ _igvn._worklist.push(use);
+ has_phi = true;
+ }
+ }
+ assert(!has_phi || rgn->req() > 3, "no phis when region is created");
+
+ if (new_entry == NULL) {
+ // Attach if_cont to iff
+ _igvn.hash_delete(iff);
+ iff->set_req(0, if_cont);
+ if (_idom != NULL) {
+ set_idom(iff, if_cont, dom_depth(iff));
+ }
+ }
+ return if_cont->as_Proj();
+}
+
+//------------------------------create_new_if_for_predicate------------------------
+// Create a new if below new_entry for the predicate to be cloned (IGVN optimization)
+ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason) {
+ assert(new_entry != 0, "only used for clone predicate");
+ assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
+ IfNode* iff = cont_proj->in(0)->as_If();
+
+ ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
+ Node *rgn = uncommon_proj->unique_ctrl_out();
+ assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
+
+ uint proj_index = 1; // region's edge corresponding to uncommon_proj
+ if (!rgn->is_Region()) { // create a region to guard the call
+ assert(rgn->is_Call(), "must be call uct");
+ CallNode* call = rgn->as_Call();
+ rgn = new (C, 1) RegionNode(1);
+ register_new_node_with_optimizer(rgn);
+ rgn->add_req(uncommon_proj);
+ hash_delete(call);
+ call->set_req(0, rgn);
+ } else {
+ // Find region's edge corresponding to uncommon_proj
+ for (; proj_index < rgn->req(); proj_index++)
+ if (rgn->in(proj_index) == uncommon_proj) break;
+ assert(proj_index < rgn->req(), "sanity");
+ }
+
+ // Create new_iff in new location.
+ IfNode *new_iff = iff->clone()->as_If();
+ new_iff->set_req(0, new_entry);
+
+ register_new_node_with_optimizer(new_iff);
+ Node *if_cont = new (C, 1) IfTrueNode(new_iff);
+ Node *if_uct = new (C, 1) IfFalseNode(new_iff);
+ if (cont_proj->is_IfFalse()) {
+ // Swap
+ Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp;
+ }
+ register_new_node_with_optimizer(if_cont);
+ register_new_node_with_optimizer(if_uct);
+
+ // if_uct to rgn
+ hash_delete(rgn);
+ rgn->add_req(if_uct);
+
+ // If rgn has phis add corresponding new edges which has the same
+ // value as on original uncommon_proj pass.
+ assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last");
+ bool has_phi = false;
+ for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) {
+ Node* use = rgn->fast_out(i);
+ if (use->is_Phi() && use->outcnt() > 0) {
+ hash_delete(use);
+ use->add_req(use->in(proj_index));
+ _worklist.push(use);
+ has_phi = true;
+ }
+ }
+ assert(!has_phi || rgn->req() > 3, "no phis when region is created");
+
+ return if_cont->as_Proj();
+}
+
+//--------------------------clone_predicate-----------------------
+ProjNode* PhaseIdealLoop::clone_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn) {
+ ProjNode* new_predicate_proj;
+ if (loop_phase != NULL) {
+ new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason);
+ } else {
+ new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason);
+ }
+ IfNode* iff = new_predicate_proj->in(0)->as_If();
+ Node* ctrl = iff->in(0);
+
+ // Match original condition since predicate's projections could be swapped.
+ assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
+ Node* opq = new (igvn->C, 2) Opaque1Node(igvn->C, predicate_proj->in(0)->in(1)->in(1)->in(1));
+ igvn->C->add_predicate_opaq(opq);
+
+ Node* bol = new (igvn->C, 2) Conv2BNode(opq);
+ if (loop_phase != NULL) {
+ loop_phase->register_new_node(opq, ctrl);
+ loop_phase->register_new_node(bol, ctrl);
+ } else {
+ igvn->register_new_node_with_optimizer(opq);
+ igvn->register_new_node_with_optimizer(bol);
+ }
+ igvn->hash_delete(iff);
+ iff->set_req(1, bol);
+ return new_predicate_proj;
+}
+
+//--------------------------move_predicate-----------------------
+// Cut predicate from old place and move it to new.
+ProjNode* PhaseIdealLoop::move_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn) {
+ assert(new_entry != NULL, "must be");
+ assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
+ IfNode* iff = predicate_proj->in(0)->as_If();
+ Node* old_entry = iff->in(0);
+
+ // Cut predicate from old place.
+ Node* old = predicate_proj;
+ igvn->_worklist.push(old);
+ for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) {
+ Node* use = old->last_out(i); // for each use...
+ igvn->hash_delete(use);
+ igvn->_worklist.push(use);
+ // Update use-def info
+ uint uses_found = 0;
+ for (uint j = 0; j < use->req(); j++) {
+ if (use->in(j) == old) {
+ use->set_req(j, old_entry);
+ uses_found++;
+ if (loop_phase != NULL) {
+ if (use->is_CFG()) {
+ // When called from beautify_loops() idom is not constructed yet.
+ if (loop_phase->_idom != NULL)
+ loop_phase->set_idom(use, old_entry, loop_phase->dom_depth(use));
+ } else {
+ loop_phase->set_ctrl(use, old_entry);
+ }
+ }
+ }
+ }
+ i -= uses_found; // we deleted 1 or more copies of this edge
+ }
+
+ // Move predicate.
+ igvn->hash_delete(iff);
+ iff->set_req(0, new_entry);
+ igvn->_worklist.push(iff);
+
+ if (loop_phase != NULL) {
+ // Fix up idom and ctrl.
+ loop_phase->set_ctrl(iff->in(1), new_entry);
+ loop_phase->set_ctrl(iff->in(1)->in(1), new_entry);
+ // When called from beautify_loops() idom is not constructed yet.
+ if (loop_phase->_idom != NULL)
+ loop_phase->set_idom(iff, new_entry, loop_phase->dom_depth(iff));
+ }
+
+ return predicate_proj;
+}
+
+//--------------------------clone_loop_predicates-----------------------
+// Interface from IGVN
+Node* PhaseIterGVN::clone_loop_predicates(Node* old_entry, Node* new_entry) {
+ return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, false, NULL, this);
+}
+Node* PhaseIterGVN::move_loop_predicates(Node* old_entry, Node* new_entry) {
+ return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, true, NULL, this);
+}
+
+// Interface from PhaseIdealLoop
+Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry) {
+ return clone_loop_predicates(old_entry, new_entry, false, this, &this->_igvn);
+}
+Node* PhaseIdealLoop::move_loop_predicates(Node* old_entry, Node* new_entry) {
+ return clone_loop_predicates(old_entry, new_entry, true, this, &this->_igvn);
+}
+
+// Clone loop predicates to cloned loops (peeled, unswitched, split_if).
+Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry,
+ bool move_predicates,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn) {
+#ifdef ASSERT
+ if (new_entry == NULL || !(new_entry->is_Proj() || new_entry->is_Region() || new_entry->is_SafePoint())) {
+ if (new_entry != NULL)
+ new_entry->dump();
+ assert(false, "not IfTrue, IfFalse, Region or SafePoint");
+ }
+#endif
+ // Search original predicates
+ Node* entry = old_entry;
+ if (UseLoopPredicate) {
+ ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
+ if (predicate_proj != NULL) { // right pattern that can be used by loop predication
+ assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
+ if (move_predicates) {
+ new_entry = move_predicate(predicate_proj, new_entry,
+ Deoptimization::Reason_predicate,
+ loop_phase, igvn);
+ assert(new_entry == predicate_proj, "old predicate fall through projection");
+ } else {
+ // clone predicate
+ new_entry = clone_predicate(predicate_proj, new_entry,
+ Deoptimization::Reason_predicate,
+ loop_phase, igvn);
+ assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
+ }
+ if (TraceLoopPredicate) {
+ tty->print_cr("Loop Predicate %s: ", move_predicates ? "moved" : "cloned");
+ debug_only( new_entry->in(0)->dump(); )
+ }
+ }
+ }
+ return new_entry;
+}
+
+//--------------------------eliminate_loop_predicates-----------------------
+void PhaseIdealLoop::eliminate_loop_predicates(Node* entry) {
+ if (UseLoopPredicate) {
+ ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
+ if (predicate_proj != NULL) { // right pattern that can be used by loop predication
+ Node* n = entry->in(0)->in(1)->in(1);
+ assert(n->Opcode()==Op_Opaque1, "must be");
+ // Remove Opaque1 node from predicates list.
+ // IGVN will remove this predicate check.
+ _igvn.replace_node(n, n->in(1));
+ }
+ }
+}
+
+//--------------------------skip_loop_predicates------------------------------
+// Skip related predicates.
+Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) {
+ Node* predicate = NULL;
+ if (UseLoopPredicate) {
+ predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
+ if (predicate != NULL) { // right pattern that can be used by loop predication
+ assert(entry->is_Proj() && entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
+ IfNode* iff = entry->in(0)->as_If();
+ ProjNode* uncommon_proj = iff->proj_out(1 - entry->as_Proj()->_con);
+ Node* rgn = uncommon_proj->unique_ctrl_out();
+ assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
+ entry = entry->in(0)->in(0);
+ while (entry != NULL && entry->is_Proj() && entry->in(0)->is_If()) {
+ uncommon_proj = entry->in(0)->as_If()->proj_out(1 - entry->as_Proj()->_con);
+ if (uncommon_proj->unique_ctrl_out() != rgn)
+ break;
+ entry = entry->in(0)->in(0);
+ }
+ }
+ }
+ return entry;
+}
+
+//--------------------------find_predicate_insertion_point-------------------
+// Find a good location to insert a predicate
+ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) {
+ if (start_c == NULL || !start_c->is_Proj())
+ return NULL;
+ if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) {
+ return start_c->as_Proj();
+ }
+ return NULL;
+}
+
+//--------------------------find_predicate------------------------------------
+// Find a predicate
+Node* PhaseIdealLoop::find_predicate(Node* entry) {
+ Node* predicate = NULL;
+ if (UseLoopPredicate) {
+ predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
+ if (predicate != NULL) { // right pattern that can be used by loop predication
+ assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+//------------------------------Invariance-----------------------------------
+// Helper class for loop_predication_impl to compute invariance on the fly and
+// clone invariants.
+class Invariance : public StackObj {
+ VectorSet _visited, _invariant;
+ Node_Stack _stack;
+ VectorSet _clone_visited;
+ Node_List _old_new; // map of old to new (clone)
+ IdealLoopTree* _lpt;
+ PhaseIdealLoop* _phase;
+
+ // Helper function to set up the invariance for invariance computation
+ // If n is a known invariant, set up directly. Otherwise, look up the
+ // the possibility to push n onto the stack for further processing.
+ void visit(Node* use, Node* n) {
+ if (_lpt->is_invariant(n)) { // known invariant
+ _invariant.set(n->_idx);
+ } else if (!n->is_CFG()) {
+ Node *n_ctrl = _phase->ctrl_or_self(n);
+ Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG
+ if (_phase->is_dominator(n_ctrl, u_ctrl)) {
+ _stack.push(n, n->in(0) == NULL ? 1 : 0);
+ }
+ }
+ }
+
+ // Compute invariance for "the_node" and (possibly) all its inputs recursively
+ // on the fly
+ void compute_invariance(Node* n) {
+ assert(_visited.test(n->_idx), "must be");
+ visit(n, n);
+ while (_stack.is_nonempty()) {
+ Node* n = _stack.node();
+ uint idx = _stack.index();
+ if (idx == n->req()) { // all inputs are processed
+ _stack.pop();
+ // n is invariant if it's inputs are all invariant
+ bool all_inputs_invariant = true;
+ for (uint i = 0; i < n->req(); i++) {
+ Node* in = n->in(i);
+ if (in == NULL) continue;
+ assert(_visited.test(in->_idx), "must have visited input");
+ if (!_invariant.test(in->_idx)) { // bad guy
+ all_inputs_invariant = false;
+ break;
+ }
+ }
+ if (all_inputs_invariant) {
+ _invariant.set(n->_idx); // I am a invariant too
+ }
+ } else { // process next input
+ _stack.set_index(idx + 1);
+ Node* m = n->in(idx);
+ if (m != NULL && !_visited.test_set(m->_idx)) {
+ visit(n, m);
+ }
+ }
+ }
+ }
+
+ // Helper function to set up _old_new map for clone_nodes.
+ // If n is a known invariant, set up directly ("clone" of n == n).
+ // Otherwise, push n onto the stack for real cloning.
+ void clone_visit(Node* n) {
+ assert(_invariant.test(n->_idx), "must be invariant");
+ if (_lpt->is_invariant(n)) { // known invariant
+ _old_new.map(n->_idx, n);
+ } else { // to be cloned
+ assert(!n->is_CFG(), "should not see CFG here");
+ _stack.push(n, n->in(0) == NULL ? 1 : 0);
+ }
+ }
+
+ // Clone "n" and (possibly) all its inputs recursively
+ void clone_nodes(Node* n, Node* ctrl) {
+ clone_visit(n);
+ while (_stack.is_nonempty()) {
+ Node* n = _stack.node();
+ uint idx = _stack.index();
+ if (idx == n->req()) { // all inputs processed, clone n!
+ _stack.pop();
+ // clone invariant node
+ Node* n_cl = n->clone();
+ _old_new.map(n->_idx, n_cl);
+ _phase->register_new_node(n_cl, ctrl);
+ for (uint i = 0; i < n->req(); i++) {
+ Node* in = n_cl->in(i);
+ if (in == NULL) continue;
+ n_cl->set_req(i, _old_new[in->_idx]);
+ }
+ } else { // process next input
+ _stack.set_index(idx + 1);
+ Node* m = n->in(idx);
+ if (m != NULL && !_clone_visited.test_set(m->_idx)) {
+ clone_visit(m); // visit the input
+ }
+ }
+ }
+ }
+
+ public:
+ Invariance(Arena* area, IdealLoopTree* lpt) :
+ _lpt(lpt), _phase(lpt->_phase),
+ _visited(area), _invariant(area), _stack(area, 10 /* guess */),
+ _clone_visited(area), _old_new(area)
+ {}
+
+ // Map old to n for invariance computation and clone
+ void map_ctrl(Node* old, Node* n) {
+ assert(old->is_CFG() && n->is_CFG(), "must be");
+ _old_new.map(old->_idx, n); // "clone" of old is n
+ _invariant.set(old->_idx); // old is invariant
+ _clone_visited.set(old->_idx);
+ }
+
+ // Driver function to compute invariance
+ bool is_invariant(Node* n) {
+ if (!_visited.test_set(n->_idx))
+ compute_invariance(n);
+ return (_invariant.test(n->_idx) != 0);
+ }
+
+ // Driver function to clone invariant
+ Node* clone(Node* n, Node* ctrl) {
+ assert(ctrl->is_CFG(), "must be");
+ assert(_invariant.test(n->_idx), "must be an invariant");
+ if (!_clone_visited.test(n->_idx))
+ clone_nodes(n, ctrl);
+ return _old_new[n->_idx];
+ }
+};
+
+//------------------------------is_range_check_if -----------------------------------
+// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
+// Note: this function is particularly designed for loop predication. We require load_range
+// and offset to be loop invariant computed on the fly by "invar"
+bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const {
+ if (!is_loop_exit(iff)) {
+ return false;
+ }
+ if (!iff->in(1)->is_Bool()) {
+ return false;
+ }
+ const BoolNode *bol = iff->in(1)->as_Bool();
+ if (bol->_test._test != BoolTest::lt) {
+ return false;
+ }
+ if (!bol->in(1)->is_Cmp()) {
+ return false;
+ }
+ const CmpNode *cmp = bol->in(1)->as_Cmp();
+ if (cmp->Opcode() != Op_CmpU) {
+ return false;
+ }
+ Node* range = cmp->in(2);
+ if (range->Opcode() != Op_LoadRange) {
+ const TypeInt* tint = phase->_igvn.type(range)->isa_int();
+ if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) {
+ // Allow predication on positive values that aren't LoadRanges.
+ // This allows optimization of loops where the length of the
+ // array is a known value and doesn't need to be loaded back
+ // from the array.
+ return false;
+ }
+ }
+ if (!invar.is_invariant(range)) {
+ return false;
+ }
+ Node *iv = _head->as_CountedLoop()->phi();
+ int scale = 0;
+ Node *offset = NULL;
+ if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) {
+ return false;
+ }
+ if (offset && !invar.is_invariant(offset)) { // offset must be invariant
+ return false;
+ }
+ return true;
+}
+
+//------------------------------rc_predicate-----------------------------------
+// Create a range check predicate
+//
+// for (i = init; i < limit; i += stride) {
+// a[scale*i+offset]
+// }
+//
+// Compute max(scale*i + offset) for init <= i < limit and build the predicate
+// as "max(scale*i + offset) u< a.length".
+//
+// There are two cases for max(scale*i + offset):
+// (1) stride*scale > 0
+// max(scale*i + offset) = scale*(limit-stride) + offset
+// (2) stride*scale < 0
+// max(scale*i + offset) = scale*init + offset
+BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl,
+ int scale, Node* offset,
+ Node* init, Node* limit, Node* stride,
+ Node* range, bool upper) {
+ DEBUG_ONLY(ttyLocker ttyl);
+ if (TraceLoopPredicate) tty->print("rc_predicate ");
+
+ Node* max_idx_expr = init;
+ int stride_con = stride->get_int();
+ if ((stride_con > 0) == (scale > 0) == upper) {
+ max_idx_expr = new (C, 3) SubINode(limit, stride);
+ register_new_node(max_idx_expr, ctrl);
+ if (TraceLoopPredicate) tty->print("(limit - stride) ");
+ } else {
+ if (TraceLoopPredicate) tty->print("init ");
+ }
+
+ if (scale != 1) {
+ ConNode* con_scale = _igvn.intcon(scale);
+ max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale);
+ register_new_node(max_idx_expr, ctrl);
+ if (TraceLoopPredicate) tty->print("* %d ", scale);
+ }
+
+ if (offset && (!offset->is_Con() || offset->get_int() != 0)){
+ max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset);
+ register_new_node(max_idx_expr, ctrl);
+ if (TraceLoopPredicate)
+ if (offset->is_Con()) tty->print("+ %d ", offset->get_int());
+ else tty->print("+ offset ");
+ }
+
+ CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range);
+ register_new_node(cmp, ctrl);
+ BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt);
+ register_new_node(bol, ctrl);
+
+ if (TraceLoopPredicate) tty->print_cr("<u range");
+ return bol;
+}
+
+//------------------------------ loop_predication_impl--------------------------
+// Insert loop predicates for null checks and range checks
+bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
+ if (!UseLoopPredicate) return false;
+
+ if (!loop->_head->is_Loop()) {
+ // Could be a simple region when irreducible loops are present.
+ return false;
+ }
+
+ if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) {
+ // do nothing for infinite loops
+ return false;
+ }
+
+ CountedLoopNode *cl = NULL;
+ if (loop->_head->is_CountedLoop()) {
+ cl = loop->_head->as_CountedLoop();
+ // do nothing for iteration-splitted loops
+ if (!cl->is_normal_loop()) return false;
+ }
+
+ LoopNode *lpn = loop->_head->as_Loop();
+ Node* entry = lpn->in(LoopNode::EntryControl);
+
+ ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
+ if (!predicate_proj) {
+#ifndef PRODUCT
+ if (TraceLoopPredicate) {
+ tty->print("missing predicate:");
+ loop->dump_head();
+ lpn->dump(1);
+ }
+#endif
+ return false;
+ }
+ ConNode* zero = _igvn.intcon(0);
+ set_ctrl(zero, C->root());
+
+ ResourceArea *area = Thread::current()->resource_area();
+ Invariance invar(area, loop);
+
+ // Create list of if-projs such that a newer proj dominates all older
+ // projs in the list, and they all dominate loop->tail()
+ Node_List if_proj_list(area);
+ LoopNode *head = loop->_head->as_Loop();
+ Node *current_proj = loop->tail(); //start from tail
+ while (current_proj != head) {
+ if (loop == get_loop(current_proj) && // still in the loop ?
+ current_proj->is_Proj() && // is a projection ?
+ current_proj->in(0)->Opcode() == Op_If) { // is a if projection ?
+ if_proj_list.push(current_proj);
+ }
+ current_proj = idom(current_proj);
+ }
+
+ bool hoisted = false; // true if at least one proj is promoted
+ while (if_proj_list.size() > 0) {
+ // Following are changed to nonnull when a predicate can be hoisted
+ ProjNode* new_predicate_proj = NULL;
+
+ ProjNode* proj = if_proj_list.pop()->as_Proj();
+ IfNode* iff = proj->in(0)->as_If();
+
+ if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) {
+ if (loop->is_loop_exit(iff)) {
+ // stop processing the remaining projs in the list because the execution of them
+ // depends on the condition of "iff" (iff->in(1)).
+ break;
+ } else {
+ // Both arms are inside the loop. There are two cases:
+ // (1) there is one backward branch. In this case, any remaining proj
+ // in the if_proj list post-dominates "iff". So, the condition of "iff"
+ // does not determine the execution the remining projs directly, and we
+ // can safely continue.
+ // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj"
+ // does not dominate loop->tail(), so it can not be in the if_proj list.
+ continue;
+ }
+ }
+
+ Node* test = iff->in(1);
+ if (!test->is_Bool()){ //Conv2B, ...
+ continue;
+ }
+ BoolNode* bol = test->as_Bool();
+ if (invar.is_invariant(bol)) {
+ // Invariant test
+ new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL,
+ Deoptimization::Reason_predicate);
+ Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0);
+ BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool();
+
+ // Negate test if necessary
+ bool negated = false;
+ if (proj->_con != predicate_proj->_con) {
+ new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
+ register_new_node(new_predicate_bol, ctrl);
+ negated = true;
+ }
+ IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
+ _igvn.hash_delete(new_predicate_iff);
+ new_predicate_iff->set_req(1, new_predicate_bol);
+#ifndef PRODUCT
+ if (TraceLoopPredicate) {
+ tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx);
+ loop->dump_head();
+ } else if (TraceLoopOpts) {
+ tty->print("Predicate IC ");
+ loop->dump_head();
+ }
+#endif
+ } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
+ assert(proj->_con == predicate_proj->_con, "must match");
+
+ // Range check for counted loops
+ const Node* cmp = bol->in(1)->as_Cmp();
+ Node* idx = cmp->in(1);
+ assert(!invar.is_invariant(idx), "index is variant");
+ assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be");
+ Node* rng = cmp->in(2);
+ assert(invar.is_invariant(rng), "range must be invariant");
+ int scale = 1;
+ Node* offset = zero;
+ bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset);
+ assert(ok, "must be index expression");
+
+ Node* init = cl->init_trip();
+ Node* limit = cl->limit();
+ Node* stride = cl->stride();
+
+ // Build if's for the upper and lower bound tests. The
+ // lower_bound test will dominate the upper bound test and all
+ // cloned or created nodes will use the lower bound test as
+ // their declared control.
+ ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
+ ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
+ assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
+ Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0);
+
+ // Perform cloning to keep Invariance state correct since the
+ // late schedule will place invariant things in the loop.
+ rng = invar.clone(rng, ctrl);
+ if (offset && offset != zero) {
+ assert(invar.is_invariant(offset), "offset must be loop invariant");
+ offset = invar.clone(offset, ctrl);
+ }
+
+ // Test the lower bound
+ Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false);
+ IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
+ _igvn.hash_delete(lower_bound_iff);
+ lower_bound_iff->set_req(1, lower_bound_bol);
+ if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
+
+ // Test the upper bound
+ Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true);
+ IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
+ _igvn.hash_delete(upper_bound_iff);
+ upper_bound_iff->set_req(1, upper_bound_bol);
+ if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
+
+ // Fall through into rest of the clean up code which will move
+ // any dependent nodes onto the upper bound test.
+ new_predicate_proj = upper_bound_proj;
+
+#ifndef PRODUCT
+ if (TraceLoopOpts && !TraceLoopPredicate) {
+ tty->print("Predicate RC ");
+ loop->dump_head();
+ }
+#endif
+ } else {
+ // Loop variant check (for example, range check in non-counted loop)
+ // with uncommon trap.
+ continue;
+ }
+ assert(new_predicate_proj != NULL, "sanity");
+ // Success - attach condition (new_predicate_bol) to predicate if
+ invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate
+
+ // Eliminate the old If in the loop body
+ dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con );
+
+ hoisted = true;
+ C->set_major_progress();
+ } // end while
+
+#ifndef PRODUCT
+ // report that the loop predication has been actually performed
+ // for this loop
+ if (TraceLoopPredicate && hoisted) {
+ tty->print("Loop Predication Performed:");
+ loop->dump_head();
+ }
+#endif
+
+ return hoisted;
+}
+
+//------------------------------loop_predication--------------------------------
+// driver routine for loop predication optimization
+bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) {
+ bool hoisted = false;
+ // Recursively promote predicates
+ if (_child) {
+ hoisted = _child->loop_predication( phase);
+ }
+
+ // self
+ if (!_irreducible && !tail()->is_top()) {
+ hoisted |= phase->loop_predication_impl(this);
+ }
+
+ if (_next) { //sibling
+ hoisted |= _next->loop_predication( phase);
+ }
+
+ return hoisted;
+}
+
diff --git a/src/share/vm/opto/loopTransform.cpp b/src/share/vm/opto/loopTransform.cpp
index 9c5a7e034..b182f4e4f 100644
--- a/src/share/vm/opto/loopTransform.cpp
+++ b/src/share/vm/opto/loopTransform.cpp
@@ -63,6 +63,46 @@ void IdealLoopTree::record_for_igvn() {
}
}
+//------------------------------compute_exact_trip_count-----------------------
+// Compute loop exact trip count if possible. Do not recalculate trip count for
+// split loops (pre-main-post) which have their limits and inits behind Opaque node.
+void IdealLoopTree::compute_exact_trip_count( PhaseIdealLoop *phase ) {
+ if (!_head->as_Loop()->is_valid_counted_loop()) {
+ return;
+ }
+ CountedLoopNode* cl = _head->as_CountedLoop();
+ // Trip count may become nonexact for iteration split loops since
+ // RCE modifies limits. Note, _trip_count value is not reset since
+ // it is used to limit unrolling of main loop.
+ cl->set_nonexact_trip_count();
+
+ // Loop's test should be part of loop.
+ if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue))))
+ return; // Infinite loop
+
+#ifdef ASSERT
+ BoolTest::mask bt = cl->loopexit()->test_trip();
+ assert(bt == BoolTest::lt || bt == BoolTest::gt ||
+ bt == BoolTest::ne, "canonical test is expected");
+#endif
+
+ Node* init_n = cl->init_trip();
+ Node* limit_n = cl->limit();
+ if (init_n != NULL && init_n->is_Con() &&
+ limit_n != NULL && limit_n->is_Con()) {
+ // Use longs to avoid integer overflow.
+ int stride_con = cl->stride_con();
+ long init_con = cl->init_trip()->get_int();
+ long limit_con = cl->limit()->get_int();
+ int stride_m = stride_con - (stride_con > 0 ? 1 : -1);
+ long trip_count = (limit_con - init_con + stride_m)/stride_con;
+ if (trip_count > 0 && (julong)trip_count < (julong)max_juint) {
+ // Set exact trip count.
+ cl->set_exact_trip_count((uint)trip_count);
+ }
+ }
+}
+
//------------------------------compute_profile_trip_cnt----------------------------
// Compute loop trip count from profile data as
// (backedge_count + loop_exit_count) / loop_exit_count
@@ -301,6 +341,132 @@ void PhaseIdealLoop::peeled_dom_test_elim( IdealLoopTree *loop, Node_List &old_n
// peeled-loop backedge has 2 users.
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
+//
+// orig
+//
+// stmt1
+// |
+// v
+// loop predicate
+// |
+// v
+// loop<----+
+// | |
+// stmt2 |
+// | |
+// v |
+// if ^
+// / \ |
+// / \ |
+// v v |
+// false true |
+// / \ |
+// / ----+
+// |
+// v
+// exit
+//
+//
+// after clone loop
+//
+// stmt1
+// |
+// v
+// loop predicate
+// / \
+// clone / \ orig
+// / \
+// / \
+// v v
+// +---->loop clone loop<----+
+// | | | |
+// | stmt2 clone stmt2 |
+// | | | |
+// | v v |
+// ^ if clone If ^
+// | / \ / \ |
+// | / \ / \ |
+// | v v v v |
+// | true false false true |
+// | / \ / \ |
+// +---- \ / ----+
+// \ /
+// 1v v2
+// region
+// |
+// v
+// exit
+//
+//
+// after peel and predicate move
+//
+// stmt1
+// /
+// /
+// clone / orig
+// /
+// / +----------+
+// / | |
+// / loop predicate |
+// / | |
+// v v |
+// TOP-->loop clone loop<----+ |
+// | | | |
+// stmt2 clone stmt2 | |
+// | | | ^
+// v v | |
+// if clone If ^ |
+// / \ / \ | |
+// / \ / \ | |
+// v v v v | |
+// true false false true | |
+// | \ / \ | |
+// | \ / ----+ ^
+// | \ / |
+// | 1v v2 |
+// v region |
+// | | |
+// | v |
+// | exit |
+// | |
+// +--------------->-----------------+
+//
+//
+// final graph
+//
+// stmt1
+// |
+// v
+// stmt2 clone
+// |
+// v
+// if clone
+// / |
+// / |
+// v v
+// false true
+// | |
+// | v
+// | loop predicate
+// | |
+// | v
+// | loop<----+
+// | | |
+// | stmt2 |
+// | | |
+// | v |
+// v if ^
+// | / \ |
+// | / \ |
+// | v v |
+// | false true |
+// | | \ |
+// v v --+
+// region
+// |
+// v
+// exit
+//
void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
C->set_major_progress();
@@ -315,9 +481,10 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
loop->dump_head();
}
#endif
- Node *h = loop->_head;
- if (h->is_CountedLoop()) {
- CountedLoopNode *cl = h->as_CountedLoop();
+ Node* head = loop->_head;
+ bool counted_loop = head->is_CountedLoop();
+ if (counted_loop) {
+ CountedLoopNode *cl = head->as_CountedLoop();
assert(cl->trip_count() > 0, "peeling a fully unrolled loop");
cl->set_trip_count(cl->trip_count() - 1);
if (cl->is_main_loop()) {
@@ -330,11 +497,11 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
#endif
}
}
+ Node* entry = head->in(LoopNode::EntryControl);
// Step 1: Clone the loop body. The clone becomes the peeled iteration.
// The pre-loop illegally has 2 control users (old & new loops).
- clone_loop( loop, old_new, dom_depth(loop->_head) );
-
+ clone_loop( loop, old_new, dom_depth(head) );
// Step 2: Make the old-loop fall-in edges point to the peeled iteration.
// Do this by making the old-loop fall-in edges act as if they came
@@ -342,12 +509,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// backedges) and then map to the new peeled iteration. This leaves
// the pre-loop with only 1 user (the new peeled iteration), but the
// peeled-loop backedge has 2 users.
- for (DUIterator_Fast jmax, j = loop->_head->fast_outs(jmax); j < jmax; j++) {
- Node* old = loop->_head->fast_out(j);
- if( old->in(0) == loop->_head && old->req() == 3 &&
- (old->is_Loop() || old->is_Phi()) ) {
- Node *new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx];
- if( !new_exit_value ) // Backedge value is ALSO loop invariant?
+ Node* new_exit_value = old_new[head->in(LoopNode::LoopBackControl)->_idx];
+ new_exit_value = move_loop_predicates(entry, new_exit_value);
+ _igvn.hash_delete(head);
+ head->set_req(LoopNode::EntryControl, new_exit_value);
+ for (DUIterator_Fast jmax, j = head->fast_outs(jmax); j < jmax; j++) {
+ Node* old = head->fast_out(j);
+ if (old->in(0) == loop->_head && old->req() == 3 && old->is_Phi()) {
+ new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx];
+ if (!new_exit_value ) // Backedge value is ALSO loop invariant?
// Then loop body backedge value remains the same.
new_exit_value = old->in(LoopNode::LoopBackControl);
_igvn.hash_delete(old);
@@ -358,12 +528,12 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
- Node *nnn = old_new[loop->_head->_idx];
- _igvn.hash_delete(nnn);
- nnn->set_req(LoopNode::LoopBackControl, C->top());
- for (DUIterator_Fast j2max, j2 = nnn->fast_outs(j2max); j2 < j2max; j2++) {
- Node* use = nnn->fast_out(j2);
- if( use->in(0) == nnn && use->req() == 3 && use->is_Phi() ) {
+ Node* new_head = old_new[head->_idx];
+ _igvn.hash_delete(new_head);
+ new_head->set_req(LoopNode::LoopBackControl, C->top());
+ for (DUIterator_Fast j2max, j2 = new_head->fast_outs(j2max); j2 < j2max; j2++) {
+ Node* use = new_head->fast_out(j2);
+ if (use->in(0) == new_head && use->req() == 3 && use->is_Phi()) {
_igvn.hash_delete(use);
use->set_req(LoopNode::LoopBackControl, C->top());
}
@@ -371,15 +541,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 4: Correct dom-depth info. Set to loop-head depth.
- int dd = dom_depth(loop->_head);
- set_idom(loop->_head, loop->_head->in(1), dd);
+ int dd = dom_depth(head);
+ set_idom(head, head->in(1), dd);
for (uint j3 = 0; j3 < loop->_body.size(); j3++) {
Node *old = loop->_body.at(j3);
Node *nnn = old_new[old->_idx];
if (!has_ctrl(nnn))
set_idom(nnn, idom(nnn), dd-1);
// While we're at it, remove any SafePoints from the peeled code
- if( old->Opcode() == Op_SafePoint ) {
+ if (old->Opcode() == Op_SafePoint) {
Node *nnn = old_new[old->_idx];
lazy_replace(nnn,nnn->in(TypeFunc::Control));
}
@@ -392,34 +562,26 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
loop->record_for_igvn();
}
+#define EMPTY_LOOP_SIZE 7 // number of nodes in an empty loop
+
//------------------------------policy_maximally_unroll------------------------
-// Return exact loop trip count, or 0 if not maximally unrolling
+// Calculate exact loop trip count and return true if loop can be maximally
+// unrolled.
bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
CountedLoopNode *cl = _head->as_CountedLoop();
assert(cl->is_normal_loop(), "");
+ if (!cl->is_valid_counted_loop())
+ return false; // Malformed counted loop
- Node *init_n = cl->init_trip();
- Node *limit_n = cl->limit();
-
- // Non-constant bounds
- if (init_n == NULL || !init_n->is_Con() ||
- limit_n == NULL || !limit_n->is_Con() ||
- // protect against stride not being a constant
- !cl->stride_is_con()) {
+ if (!cl->has_exact_trip_count()) {
+ // Trip count is not exact.
return false;
}
- int init = init_n->get_int();
- int limit = limit_n->get_int();
- int span = limit - init;
- int stride = cl->stride_con();
- if (init >= limit || stride > span) {
- // return a false (no maximally unroll) and the regular unroll/peel
- // route will make a small mess which CCP will fold away.
- return false;
- }
- uint trip_count = span/stride; // trip_count can be greater than 2 Gig.
- assert( (int)trip_count*stride == span, "must divide evenly" );
+ uint trip_count = cl->trip_count();
+ // Note, max_juint is used to indicate unknown trip count.
+ assert(trip_count > 1, "one iteration loop should be optimized out already");
+ assert(trip_count < max_juint, "exact trip_count should be less than max_uint.");
// Real policy: if we maximally unroll, does it get too big?
// Allow the unrolled mess to get larger than standard loop
@@ -427,15 +589,29 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
uint body_size = _body.size();
uint unroll_limit = (uint)LoopUnrollLimit * 4;
assert( (intx)unroll_limit == LoopUnrollLimit * 4, "LoopUnrollLimit must fit in 32bits");
- cl->set_trip_count(trip_count);
if (trip_count > unroll_limit || body_size > unroll_limit) {
return false;
}
+ // Take into account that after unroll conjoined heads and tails will fold,
+ // otherwise policy_unroll() may allow more unrolling than max unrolling.
+ uint new_body_size = EMPTY_LOOP_SIZE + (body_size - EMPTY_LOOP_SIZE) * trip_count;
+ uint tst_body_size = (new_body_size - EMPTY_LOOP_SIZE) / trip_count + EMPTY_LOOP_SIZE;
+ if (body_size != tst_body_size) // Check for int overflow
+ return false;
+ if (new_body_size > unroll_limit ||
+ // Unrolling can result in a large amount of node construction
+ new_body_size >= MaxNodeLimit - phase->C->unique()) {
+ return false;
+ }
+
// Currently we don't have policy to optimize one iteration loops.
// Maximally unrolling transformation is used for that:
// it is peeled and the original loop become non reachable (dead).
- if (trip_count == 1)
+ // Also fully unroll a loop with few iterations regardless next
+ // conditions since following loop optimizations will split
+ // such loop anyway (pre-main-post).
+ if (trip_count <= 3)
return true;
// Do not unroll a loop with String intrinsics code.
@@ -452,17 +628,7 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
} // switch
}
- if (body_size <= unroll_limit) {
- uint new_body_size = body_size * trip_count;
- if (new_body_size <= unroll_limit &&
- body_size == new_body_size / trip_count &&
- // Unrolling can result in a large amount of node construction
- new_body_size < MaxNodeLimit - phase->C->unique()) {
- return true; // maximally unroll
- }
- }
-
- return false; // Do not maximally unroll
+ return true; // Do maximally unroll
}
@@ -474,12 +640,15 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
CountedLoopNode *cl = _head->as_CountedLoop();
assert(cl->is_normal_loop() || cl->is_main_loop(), "");
- // protect against stride not being a constant
- if (!cl->stride_is_con()) return false;
+ if (!cl->is_valid_counted_loop())
+ return false; // Malformed counted loop
// protect against over-unrolling
if (cl->trip_count() <= 1) return false;
+ // Check for stride being a small enough constant
+ if (abs(cl->stride_con()) > (1<<3)) return false;
+
int future_unroll_ct = cl->unrolled_count() * 2;
// Don't unroll if the next round of unrolling would push us
@@ -560,9 +729,6 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
return false;
}
- // Check for stride being a small enough constant
- if (abs(cl->stride_con()) > (1<<3)) return false;
-
// Unroll once! (Each trip will soon do double iterations)
return true;
}
@@ -956,7 +1122,11 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
tty->print("Unrolling ");
loop->dump_head();
} else if (TraceLoopOpts) {
- tty->print("Unroll %d ", loop_head->unrolled_count()*2);
+ if (loop_head->trip_count() < (uint)LoopUnrollLimit) {
+ tty->print("Unroll %d(%2d) ", loop_head->unrolled_count()*2, loop_head->trip_count());
+ } else {
+ tty->print("Unroll %d ", loop_head->unrolled_count()*2);
+ }
loop->dump_head();
}
#endif
@@ -1631,7 +1801,7 @@ void IdealLoopTree::adjust_loop_exit_prob( PhaseIdealLoop *phase ) {
// have on the last iteration. This will break the loop.
bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
// Minimum size must be empty loop
- if (_body.size() > 7/*number of nodes in an empty loop*/)
+ if (_body.size() > EMPTY_LOOP_SIZE)
return false;
if (!_head->is_CountedLoop())
@@ -1658,8 +1828,19 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
// main and post loops have explicitly created zero trip guard
bool needs_guard = !cl->is_main_loop() && !cl->is_post_loop();
if (needs_guard) {
+ // Skip guard if values not overlap.
+ const TypeInt* init_t = phase->_igvn.type(cl->init_trip())->is_int();
+ const TypeInt* limit_t = phase->_igvn.type(cl->limit())->is_int();
+ int stride_con = cl->stride_con();
+ if (stride_con > 0) {
+ needs_guard = (init_t->_hi >= limit_t->_lo);
+ } else {
+ needs_guard = (init_t->_lo <= limit_t->_hi);
+ }
+ }
+ if (needs_guard) {
// Check for an obvious zero trip guard.
- Node* inctrl = cl->in(LoopNode::EntryControl);
+ Node* inctrl = PhaseIdealLoop::skip_loop_predicates(cl->in(LoopNode::EntryControl));
if (inctrl->Opcode() == Op_IfTrue) {
// The test should look like just the backedge of a CountedLoop
Node* iff = inctrl->in(0);
@@ -1702,12 +1883,49 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
return true;
}
+//------------------------------policy_do_one_iteration_loop-------------------
+// Convert one iteration loop into normal code.
+bool IdealLoopTree::policy_do_one_iteration_loop( PhaseIdealLoop *phase ) {
+ if (!_head->as_Loop()->is_valid_counted_loop())
+ return false; // Only for counted loop
+
+ CountedLoopNode *cl = _head->as_CountedLoop();
+ if (!cl->has_exact_trip_count() || cl->trip_count() != 1) {
+ return false;
+ }
+
+#ifndef PRODUCT
+ if(TraceLoopOpts) {
+ tty->print("OneIteration ");
+ this->dump_head();
+ }
+#endif
+
+ Node *init_n = cl->init_trip();
+#ifdef ASSERT
+ // Loop boundaries should be constant since trip count is exact.
+ assert(init_n->get_int() + cl->stride_con() >= cl->limit()->get_int(), "should be one iteration");
+#endif
+ // Replace the phi at loop head with the value of the init_trip.
+ // Then the CountedLoopEnd will collapse (backedge will not be taken)
+ // and all loop-invariant uses of the exit values will be correct.
+ phase->_igvn.replace_node(cl->phi(), cl->init_trip());
+ phase->C->set_major_progress();
+ return true;
+}
//=============================================================================
//------------------------------iteration_split_impl---------------------------
bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_new ) {
+ // Compute exact loop trip count if possible.
+ compute_exact_trip_count(phase);
+
+ // Convert one iteration loop into normal code.
+ if (policy_do_one_iteration_loop(phase))
+ return true;
+
// Check and remove empty loops (spam micro-benchmarks)
- if( policy_do_remove_empty_loop(phase) )
+ if (policy_do_remove_empty_loop(phase))
return true; // Here we removed an empty loop
bool should_peel = policy_peeling(phase); // Should we peel?
@@ -1716,40 +1934,40 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// Non-counted loops may be peeled; exactly 1 iteration is peeled.
// This removes loop-invariant tests (usually null checks).
- if( !_head->is_CountedLoop() ) { // Non-counted loop
+ if (!_head->is_CountedLoop()) { // Non-counted loop
if (PartialPeelLoop && phase->partial_peel(this, old_new)) {
// Partial peel succeeded so terminate this round of loop opts
return false;
}
- if( should_peel ) { // Should we peel?
+ if (should_peel) { // Should we peel?
#ifndef PRODUCT
if (PrintOpto) tty->print_cr("should_peel");
#endif
phase->do_peeling(this,old_new);
- } else if( should_unswitch ) {
+ } else if (should_unswitch) {
phase->do_unswitching(this, old_new);
}
return true;
}
CountedLoopNode *cl = _head->as_CountedLoop();
- if( !cl->loopexit() ) return true; // Ignore various kinds of broken loops
+ if (!cl->loopexit()) return true; // Ignore various kinds of broken loops
// Do nothing special to pre- and post- loops
- if( cl->is_pre_loop() || cl->is_post_loop() ) return true;
+ if (cl->is_pre_loop() || cl->is_post_loop()) return true;
// Compute loop trip count from profile data
compute_profile_trip_cnt(phase);
// Before attempting fancy unrolling, RCE or alignment, see if we want
// to completely unroll this loop or do loop unswitching.
- if( cl->is_normal_loop() ) {
+ if (cl->is_normal_loop()) {
if (should_unswitch) {
phase->do_unswitching(this, old_new);
return true;
}
bool should_maximally_unroll = policy_maximally_unroll(phase);
- if( should_maximally_unroll ) {
+ if (should_maximally_unroll) {
// Here we did some unrolling and peeling. Eventually we will
// completely unroll this loop and it will no longer be a loop.
phase->do_maximally_unroll(this,old_new);
@@ -1757,6 +1975,12 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
}
}
+ // Skip next optimizations if running low on nodes. Note that
+ // policy_unswitching and policy_maximally_unroll have this check.
+ uint nodes_left = MaxNodeLimit - phase->C->unique();
+ if ((2 * _body.size()) > nodes_left) {
+ return true;
+ }
// Counted loops may be peeled, may need some iterations run up
// front for RCE, and may want to align loop refs to a cache
@@ -1787,14 +2011,14 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// If we have any of these conditions (RCE, alignment, unrolling) met, then
// we switch to the pre-/main-/post-loop model. This model also covers
// peeling.
- if( should_rce || should_align || should_unroll ) {
- if( cl->is_normal_loop() ) // Convert to 'pre/main/post' loops
+ if (should_rce || should_align || should_unroll) {
+ if (cl->is_normal_loop()) // Convert to 'pre/main/post' loops
phase->insert_pre_post_loops(this,old_new, !may_rce_align);
// Adjust the pre- and main-loop limits to let the pre and post loops run
// with full checks, but the main-loop with no checks. Remove said
// checks from the main body.
- if( should_rce )
+ if (should_rce)
phase->do_range_check(this,old_new);
// Double loop body for unrolling. Adjust the minimum-trip test (will do
@@ -1802,16 +2026,16 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// an even number of trips). If we are peeling, we might enable some RCE
// and we'd rather unroll the post-RCE'd loop SO... do not unroll if
// peeling.
- if( should_unroll && !should_peel )
- phase->do_unroll(this,old_new, true);
+ if (should_unroll && !should_peel)
+ phase->do_unroll(this,old_new, true);
// Adjust the pre-loop limits to align the main body
// iterations.
- if( should_align )
+ if (should_align)
Unimplemented();
} else { // Else we have an unchanged counted loop
- if( should_peel ) // Might want to peel but do nothing else
+ if (should_peel) // Might want to peel but do nothing else
phase->do_peeling(this,old_new);
}
return true;
@@ -1861,651 +2085,8 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new )
return true;
}
-//-------------------------------is_uncommon_trap_proj----------------------------
-// Return true if proj is the form of "proj->[region->..]call_uct"
-bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) {
- int path_limit = 10;
- assert(proj, "invalid argument");
- Node* out = proj;
- for (int ct = 0; ct < path_limit; ct++) {
- out = out->unique_ctrl_out();
- if (out == NULL || out->is_Root() || out->is_Start())
- return false;
- if (out->is_CallStaticJava()) {
- int req = out->as_CallStaticJava()->uncommon_trap_request();
- if (req != 0) {
- Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
- if (trap_reason == reason || reason == Deoptimization::Reason_none) {
- return true;
- }
- }
- return false; // don't do further after call
- }
- }
- return false;
-}
-
-//-------------------------------is_uncommon_trap_if_pattern-------------------------
-// Return true for "if(test)-> proj -> ...
-// |
-// V
-// other_proj->[region->..]call_uct"
-//
-// "must_reason_predicate" means the uct reason must be Reason_predicate
-bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) {
- Node *in0 = proj->in(0);
- if (!in0->is_If()) return false;
- // Variation of a dead If node.
- if (in0->outcnt() < 2) return false;
- IfNode* iff = in0->as_If();
-
- // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
- if (reason != Deoptimization::Reason_none) {
- if (iff->in(1)->Opcode() != Op_Conv2B ||
- iff->in(1)->in(1)->Opcode() != Op_Opaque1) {
- return false;
- }
- }
-
- ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj();
- return is_uncommon_trap_proj(other_proj, reason);
-}
-
-//-------------------------------register_control-------------------------
-void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) {
- assert(n->is_CFG(), "must be control node");
- _igvn.register_new_node_with_optimizer(n);
- loop->_body.push(n);
- set_loop(n, loop);
- // When called from beautify_loops() idom is not constructed yet.
- if (_idom != NULL) {
- set_idom(n, pred, dom_depth(pred));
- }
-}
-
-//------------------------------create_new_if_for_predicate------------------------
-// create a new if above the uct_if_pattern for the predicate to be promoted.
-//
-// before after
-// ---------- ----------
-// ctrl ctrl
-// | |
-// | |
-// v v
-// iff new_iff
-// / \ / \
-// / \ / \
-// v v v v
-// uncommon_proj cont_proj if_uct if_cont
-// \ | | | |
-// \ | | | |
-// v v v | v
-// rgn loop | iff
-// | | / \
-// | | / \
-// v | v v
-// uncommon_trap | uncommon_proj cont_proj
-// \ \ | |
-// \ \ | |
-// v v v v
-// rgn loop
-// |
-// |
-// v
-// uncommon_trap
-//
-//
-// We will create a region to guard the uct call if there is no one there.
-// The true projecttion (if_cont) of the new_iff is returned.
-// This code is also used to clone predicates to clonned loops.
-ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
- Deoptimization::DeoptReason reason) {
- assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
- IfNode* iff = cont_proj->in(0)->as_If();
-
- ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
- Node *rgn = uncommon_proj->unique_ctrl_out();
- assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
-
- if (!rgn->is_Region()) { // create a region to guard the call
- assert(rgn->is_Call(), "must be call uct");
- CallNode* call = rgn->as_Call();
- IdealLoopTree* loop = get_loop(call);
- rgn = new (C, 1) RegionNode(1);
- rgn->add_req(uncommon_proj);
- register_control(rgn, loop, uncommon_proj);
- _igvn.hash_delete(call);
- call->set_req(0, rgn);
- // When called from beautify_loops() idom is not constructed yet.
- if (_idom != NULL) {
- set_idom(call, rgn, dom_depth(rgn));
- }
- }
-
- Node* entry = iff->in(0);
- if (new_entry != NULL) {
- // Clonning the predicate to new location.
- entry = new_entry;
- }
- // Create new_iff
- IdealLoopTree* lp = get_loop(entry);
- IfNode *new_iff = new (C, 2) IfNode(entry, NULL, iff->_prob, iff->_fcnt);
- register_control(new_iff, lp, entry);
- Node *if_cont = new (C, 1) IfTrueNode(new_iff);
- Node *if_uct = new (C, 1) IfFalseNode(new_iff);
- if (cont_proj->is_IfFalse()) {
- // Swap
- Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp;
- }
- register_control(if_cont, lp, new_iff);
- register_control(if_uct, get_loop(rgn), new_iff);
-
- // if_uct to rgn
- _igvn.hash_delete(rgn);
- rgn->add_req(if_uct);
- // When called from beautify_loops() idom is not constructed yet.
- if (_idom != NULL) {
- Node* ridom = idom(rgn);
- Node* nrdom = dom_lca(ridom, new_iff);
- set_idom(rgn, nrdom, dom_depth(rgn));
- }
- // rgn must have no phis
- assert(!rgn->as_Region()->has_phi(), "region must have no phis");
-
- if (new_entry == NULL) {
- // Attach if_cont to iff
- _igvn.hash_delete(iff);
- iff->set_req(0, if_cont);
- if (_idom != NULL) {
- set_idom(iff, if_cont, dom_depth(iff));
- }
- }
- return if_cont->as_Proj();
-}
-
-//--------------------------find_predicate_insertion_point-------------------
-// Find a good location to insert a predicate
-ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) {
- if (start_c == NULL || !start_c->is_Proj())
- return NULL;
- if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) {
- return start_c->as_Proj();
- }
- return NULL;
-}
-
-//--------------------------find_predicate------------------------------------
-// Find a predicate
-Node* PhaseIdealLoop::find_predicate(Node* entry) {
- Node* predicate = NULL;
- if (UseLoopPredicate) {
- predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
- if (predicate != NULL) { // right pattern that can be used by loop predication
- assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
- return entry;
- }
- }
- return NULL;
-}
-
-//------------------------------Invariance-----------------------------------
-// Helper class for loop_predication_impl to compute invariance on the fly and
-// clone invariants.
-class Invariance : public StackObj {
- VectorSet _visited, _invariant;
- Node_Stack _stack;
- VectorSet _clone_visited;
- Node_List _old_new; // map of old to new (clone)
- IdealLoopTree* _lpt;
- PhaseIdealLoop* _phase;
-
- // Helper function to set up the invariance for invariance computation
- // If n is a known invariant, set up directly. Otherwise, look up the
- // the possibility to push n onto the stack for further processing.
- void visit(Node* use, Node* n) {
- if (_lpt->is_invariant(n)) { // known invariant
- _invariant.set(n->_idx);
- } else if (!n->is_CFG()) {
- Node *n_ctrl = _phase->ctrl_or_self(n);
- Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG
- if (_phase->is_dominator(n_ctrl, u_ctrl)) {
- _stack.push(n, n->in(0) == NULL ? 1 : 0);
- }
- }
- }
-
- // Compute invariance for "the_node" and (possibly) all its inputs recursively
- // on the fly
- void compute_invariance(Node* n) {
- assert(_visited.test(n->_idx), "must be");
- visit(n, n);
- while (_stack.is_nonempty()) {
- Node* n = _stack.node();
- uint idx = _stack.index();
- if (idx == n->req()) { // all inputs are processed
- _stack.pop();
- // n is invariant if it's inputs are all invariant
- bool all_inputs_invariant = true;
- for (uint i = 0; i < n->req(); i++) {
- Node* in = n->in(i);
- if (in == NULL) continue;
- assert(_visited.test(in->_idx), "must have visited input");
- if (!_invariant.test(in->_idx)) { // bad guy
- all_inputs_invariant = false;
- break;
- }
- }
- if (all_inputs_invariant) {
- _invariant.set(n->_idx); // I am a invariant too
- }
- } else { // process next input
- _stack.set_index(idx + 1);
- Node* m = n->in(idx);
- if (m != NULL && !_visited.test_set(m->_idx)) {
- visit(n, m);
- }
- }
- }
- }
-
- // Helper function to set up _old_new map for clone_nodes.
- // If n is a known invariant, set up directly ("clone" of n == n).
- // Otherwise, push n onto the stack for real cloning.
- void clone_visit(Node* n) {
- assert(_invariant.test(n->_idx), "must be invariant");
- if (_lpt->is_invariant(n)) { // known invariant
- _old_new.map(n->_idx, n);
- } else{ // to be cloned
- assert (!n->is_CFG(), "should not see CFG here");
- _stack.push(n, n->in(0) == NULL ? 1 : 0);
- }
- }
-
- // Clone "n" and (possibly) all its inputs recursively
- void clone_nodes(Node* n, Node* ctrl) {
- clone_visit(n);
- while (_stack.is_nonempty()) {
- Node* n = _stack.node();
- uint idx = _stack.index();
- if (idx == n->req()) { // all inputs processed, clone n!
- _stack.pop();
- // clone invariant node
- Node* n_cl = n->clone();
- _old_new.map(n->_idx, n_cl);
- _phase->register_new_node(n_cl, ctrl);
- for (uint i = 0; i < n->req(); i++) {
- Node* in = n_cl->in(i);
- if (in == NULL) continue;
- n_cl->set_req(i, _old_new[in->_idx]);
- }
- } else { // process next input
- _stack.set_index(idx + 1);
- Node* m = n->in(idx);
- if (m != NULL && !_clone_visited.test_set(m->_idx)) {
- clone_visit(m); // visit the input
- }
- }
- }
- }
-
- public:
- Invariance(Arena* area, IdealLoopTree* lpt) :
- _lpt(lpt), _phase(lpt->_phase),
- _visited(area), _invariant(area), _stack(area, 10 /* guess */),
- _clone_visited(area), _old_new(area)
- {}
-
- // Map old to n for invariance computation and clone
- void map_ctrl(Node* old, Node* n) {
- assert(old->is_CFG() && n->is_CFG(), "must be");
- _old_new.map(old->_idx, n); // "clone" of old is n
- _invariant.set(old->_idx); // old is invariant
- _clone_visited.set(old->_idx);
- }
-
- // Driver function to compute invariance
- bool is_invariant(Node* n) {
- if (!_visited.test_set(n->_idx))
- compute_invariance(n);
- return (_invariant.test(n->_idx) != 0);
- }
-
- // Driver function to clone invariant
- Node* clone(Node* n, Node* ctrl) {
- assert(ctrl->is_CFG(), "must be");
- assert(_invariant.test(n->_idx), "must be an invariant");
- if (!_clone_visited.test(n->_idx))
- clone_nodes(n, ctrl);
- return _old_new[n->_idx];
- }
-};
-
-//------------------------------is_range_check_if -----------------------------------
-// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
-// Note: this function is particularly designed for loop predication. We require load_range
-// and offset to be loop invariant computed on the fly by "invar"
-bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const {
- if (!is_loop_exit(iff)) {
- return false;
- }
- if (!iff->in(1)->is_Bool()) {
- return false;
- }
- const BoolNode *bol = iff->in(1)->as_Bool();
- if (bol->_test._test != BoolTest::lt) {
- return false;
- }
- if (!bol->in(1)->is_Cmp()) {
- return false;
- }
- const CmpNode *cmp = bol->in(1)->as_Cmp();
- if (cmp->Opcode() != Op_CmpU ) {
- return false;
- }
- Node* range = cmp->in(2);
- if (range->Opcode() != Op_LoadRange) {
- const TypeInt* tint = phase->_igvn.type(range)->isa_int();
- if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) {
- // Allow predication on positive values that aren't LoadRanges.
- // This allows optimization of loops where the length of the
- // array is a known value and doesn't need to be loaded back
- // from the array.
- return false;
- }
- }
- if (!invar.is_invariant(range)) {
- return false;
- }
- Node *iv = _head->as_CountedLoop()->phi();
- int scale = 0;
- Node *offset = NULL;
- if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) {
- return false;
- }
- if(offset && !invar.is_invariant(offset)) { // offset must be invariant
- return false;
- }
- return true;
-}
-
-//------------------------------rc_predicate-----------------------------------
-// Create a range check predicate
-//
-// for (i = init; i < limit; i += stride) {
-// a[scale*i+offset]
-// }
-//
-// Compute max(scale*i + offset) for init <= i < limit and build the predicate
-// as "max(scale*i + offset) u< a.length".
-//
-// There are two cases for max(scale*i + offset):
-// (1) stride*scale > 0
-// max(scale*i + offset) = scale*(limit-stride) + offset
-// (2) stride*scale < 0
-// max(scale*i + offset) = scale*init + offset
-BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl,
- int scale, Node* offset,
- Node* init, Node* limit, Node* stride,
- Node* range, bool upper) {
- DEBUG_ONLY(ttyLocker ttyl);
- if (TraceLoopPredicate) tty->print("rc_predicate ");
-
- Node* max_idx_expr = init;
- int stride_con = stride->get_int();
- if ((stride_con > 0) == (scale > 0) == upper) {
- max_idx_expr = new (C, 3) SubINode(limit, stride);
- register_new_node(max_idx_expr, ctrl);
- if (TraceLoopPredicate) tty->print("(limit - stride) ");
- } else {
- if (TraceLoopPredicate) tty->print("init ");
- }
-
- if (scale != 1) {
- ConNode* con_scale = _igvn.intcon(scale);
- max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale);
- register_new_node(max_idx_expr, ctrl);
- if (TraceLoopPredicate) tty->print("* %d ", scale);
- }
-
- if (offset && (!offset->is_Con() || offset->get_int() != 0)){
- max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset);
- register_new_node(max_idx_expr, ctrl);
- if (TraceLoopPredicate)
- if (offset->is_Con()) tty->print("+ %d ", offset->get_int());
- else tty->print("+ offset ");
- }
-
- CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range);
- register_new_node(cmp, ctrl);
- BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt);
- register_new_node(bol, ctrl);
-
- if (TraceLoopPredicate) tty->print_cr("<u range");
- return bol;
-}
-
-//------------------------------ loop_predication_impl--------------------------
-// Insert loop predicates for null checks and range checks
-bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
- if (!UseLoopPredicate) return false;
-
- if (!loop->_head->is_Loop()) {
- // Could be a simple region when irreducible loops are present.
- return false;
- }
-
- if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) {
- // do nothing for infinite loops
- return false;
- }
-
- CountedLoopNode *cl = NULL;
- if (loop->_head->is_CountedLoop()) {
- cl = loop->_head->as_CountedLoop();
- // do nothing for iteration-splitted loops
- if (!cl->is_normal_loop()) return false;
- }
-
- LoopNode *lpn = loop->_head->as_Loop();
- Node* entry = lpn->in(LoopNode::EntryControl);
-
- ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
- if (!predicate_proj) {
-#ifndef PRODUCT
- if (TraceLoopPredicate) {
- tty->print("missing predicate:");
- loop->dump_head();
- lpn->dump(1);
- }
-#endif
- return false;
- }
- ConNode* zero = _igvn.intcon(0);
- set_ctrl(zero, C->root());
-
- ResourceArea *area = Thread::current()->resource_area();
- Invariance invar(area, loop);
-
- // Create list of if-projs such that a newer proj dominates all older
- // projs in the list, and they all dominate loop->tail()
- Node_List if_proj_list(area);
- LoopNode *head = loop->_head->as_Loop();
- Node *current_proj = loop->tail(); //start from tail
- while ( current_proj != head ) {
- if (loop == get_loop(current_proj) && // still in the loop ?
- current_proj->is_Proj() && // is a projection ?
- current_proj->in(0)->Opcode() == Op_If) { // is a if projection ?
- if_proj_list.push(current_proj);
- }
- current_proj = idom(current_proj);
- }
-
- bool hoisted = false; // true if at least one proj is promoted
- while (if_proj_list.size() > 0) {
- // Following are changed to nonnull when a predicate can be hoisted
- ProjNode* new_predicate_proj = NULL;
-
- ProjNode* proj = if_proj_list.pop()->as_Proj();
- IfNode* iff = proj->in(0)->as_If();
-
- if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) {
- if (loop->is_loop_exit(iff)) {
- // stop processing the remaining projs in the list because the execution of them
- // depends on the condition of "iff" (iff->in(1)).
- break;
- } else {
- // Both arms are inside the loop. There are two cases:
- // (1) there is one backward branch. In this case, any remaining proj
- // in the if_proj list post-dominates "iff". So, the condition of "iff"
- // does not determine the execution the remining projs directly, and we
- // can safely continue.
- // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj"
- // does not dominate loop->tail(), so it can not be in the if_proj list.
- continue;
- }
- }
-
- Node* test = iff->in(1);
- if (!test->is_Bool()){ //Conv2B, ...
- continue;
- }
- BoolNode* bol = test->as_Bool();
- if (invar.is_invariant(bol)) {
- // Invariant test
- new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL,
- Deoptimization::Reason_predicate);
- Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0);
- BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool();
-
- // Negate test if necessary
- bool negated = false;
- if (proj->_con != predicate_proj->_con) {
- new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
- register_new_node(new_predicate_bol, ctrl);
- negated = true;
- }
- IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
- _igvn.hash_delete(new_predicate_iff);
- new_predicate_iff->set_req(1, new_predicate_bol);
-#ifndef PRODUCT
- if (TraceLoopPredicate) {
- tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx);
- loop->dump_head();
- } else if (TraceLoopOpts) {
- tty->print("Predicate IC ");
- loop->dump_head();
- }
-#endif
- } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
- assert(proj->_con == predicate_proj->_con, "must match");
-
- // Range check for counted loops
- const Node* cmp = bol->in(1)->as_Cmp();
- Node* idx = cmp->in(1);
- assert(!invar.is_invariant(idx), "index is variant");
- assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be");
- Node* rng = cmp->in(2);
- assert(invar.is_invariant(rng), "range must be invariant");
- int scale = 1;
- Node* offset = zero;
- bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset);
- assert(ok, "must be index expression");
-
- Node* init = cl->init_trip();
- Node* limit = cl->limit();
- Node* stride = cl->stride();
-
- // Build if's for the upper and lower bound tests. The
- // lower_bound test will dominate the upper bound test and all
- // cloned or created nodes will use the lower bound test as
- // their declared control.
- ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
- ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
- assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
- Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0);
-
- // Perform cloning to keep Invariance state correct since the
- // late schedule will place invariant things in the loop.
- rng = invar.clone(rng, ctrl);
- if (offset && offset != zero) {
- assert(invar.is_invariant(offset), "offset must be loop invariant");
- offset = invar.clone(offset, ctrl);
- }
-
- // Test the lower bound
- Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false);
- IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
- _igvn.hash_delete(lower_bound_iff);
- lower_bound_iff->set_req(1, lower_bound_bol);
- if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
-
- // Test the upper bound
- Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true);
- IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
- _igvn.hash_delete(upper_bound_iff);
- upper_bound_iff->set_req(1, upper_bound_bol);
- if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
-
- // Fall through into rest of the clean up code which will move
- // any dependent nodes onto the upper bound test.
- new_predicate_proj = upper_bound_proj;
-
-#ifndef PRODUCT
- if (TraceLoopOpts && !TraceLoopPredicate) {
- tty->print("Predicate RC ");
- loop->dump_head();
- }
-#endif
- } else {
- // Loop variant check (for example, range check in non-counted loop)
- // with uncommon trap.
- continue;
- }
- assert(new_predicate_proj != NULL, "sanity");
- // Success - attach condition (new_predicate_bol) to predicate if
- invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate
-
- // Eliminate the old If in the loop body
- dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con );
-
- hoisted = true;
- C->set_major_progress();
- } // end while
-
-#ifndef PRODUCT
- // report that the loop predication has been actually performed
- // for this loop
- if (TraceLoopPredicate && hoisted) {
- tty->print("Loop Predication Performed:");
- loop->dump_head();
- }
-#endif
-
- return hoisted;
-}
-
-//------------------------------loop_predication--------------------------------
-// driver routine for loop predication optimization
-bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) {
- bool hoisted = false;
- // Recursively promote predicates
- if ( _child ) {
- hoisted = _child->loop_predication( phase);
- }
-
- // self
- if (!_irreducible && !tail()->is_top()) {
- hoisted |= phase->loop_predication_impl(this);
- }
-
- if ( _next ) { //sibling
- hoisted |= _next->loop_predication( phase);
- }
-
- return hoisted;
-}
-
+//=============================================================================
// Process all the loops in the loop tree and replace any fill
// patterns with an intrisc version.
bool PhaseIdealLoop::do_intrinsify_fill() {
@@ -2625,9 +2206,12 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
if (value != head->phi()) {
msg = "unhandled shift in address";
} else {
- found_index = true;
- shift = n;
- assert(type2aelembytes(store->as_Mem()->memory_type(), true) == 1 << shift->in(2)->get_int(), "scale should match");
+ if (type2aelembytes(store->as_Mem()->memory_type(), true) != (1 << n->in(2)->get_int())) {
+ msg = "scale doesn't match";
+ } else {
+ found_index = true;
+ shift = n;
+ }
}
} else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
if (n->in(1) == head->phi()) {
@@ -2762,6 +2346,13 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
return false;
}
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("ArrayFill ");
+ lpt->dump_head();
+ }
+#endif
+
// Now replace the whole loop body by a call to a fill routine that
// covers the same region as the loop.
Node* base = store->in(MemNode::Address)->as_AddP()->in(AddPNode::Base);
diff --git a/src/share/vm/opto/loopUnswitch.cpp b/src/share/vm/opto/loopUnswitch.cpp
index 544b845f8..8a103b228 100644
--- a/src/share/vm/opto/loopUnswitch.cpp
+++ b/src/share/vm/opto/loopUnswitch.cpp
@@ -32,15 +32,17 @@
//
// orig: transformed:
// if (invariant-test) then
+// predicate predicate
// loop loop
// stmt1 stmt1
// if (invariant-test) then stmt2
// stmt2 stmt4
// else endloop
// stmt3 else
-// endif loop [clone]
-// stmt4 stmt1 [clone]
-// endloop stmt3
+// endif predicate [clone]
+// stmt4 loop [clone]
+// endloop stmt1 [clone]
+// stmt3
// stmt4 [clone]
// endloop
// endif
@@ -124,8 +126,15 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
ProjNode* proj_true = create_slow_version_of_loop(loop, old_new);
- assert(proj_true->is_IfTrue() && proj_true->unique_ctrl_out() == head, "by construction");
-
+#ifdef ASSERT
+ Node* uniqc = proj_true->unique_ctrl_out();
+ Node* entry = head->in(LoopNode::EntryControl);
+ Node* predicate = find_predicate(entry);
+ if (predicate != NULL) predicate = predicate->in(0);
+ assert(proj_true->is_IfTrue() &&
+ (predicate == NULL && uniqc == head ||
+ predicate != NULL && uniqc == predicate), "by construction");
+#endif
// Increment unswitch count
LoopNode* head_clone = old_new[head->_idx]->as_Loop();
int nct = head->unswitch_count() + 1;
@@ -227,21 +236,24 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop,
register_node(ifslow, outer_loop, iff, dom_depth(iff));
// Clone the loop body. The clone becomes the fast loop. The
- // original pre-header will (illegally) have 2 control users (old & new loops).
+ // original pre-header will (illegally) have 3 control users
+ // (old & new loops & new if).
clone_loop(loop, old_new, dom_depth(head), iff);
assert(old_new[head->_idx]->is_Loop(), "" );
// Fast (true) control
+ Node* iffast_pred = clone_loop_predicates(entry, iffast);
_igvn.hash_delete(head);
- head->set_req(LoopNode::EntryControl, iffast);
- set_idom(head, iffast, dom_depth(head));
+ head->set_req(LoopNode::EntryControl, iffast_pred);
+ set_idom(head, iffast_pred, dom_depth(head));
_igvn._worklist.push(head);
// Slow (false) control
+ Node* ifslow_pred = move_loop_predicates(entry, ifslow);
LoopNode* slow_head = old_new[head->_idx]->as_Loop();
_igvn.hash_delete(slow_head);
- slow_head->set_req(LoopNode::EntryControl, ifslow);
- set_idom(slow_head, ifslow, dom_depth(slow_head));
+ slow_head->set_req(LoopNode::EntryControl, ifslow_pred);
+ set_idom(slow_head, ifslow_pred, dom_depth(slow_head));
_igvn._worklist.push(slow_head);
recompute_dom_depth();
diff --git a/src/share/vm/opto/loopnode.cpp b/src/share/vm/opto/loopnode.cpp
index 894a105e8..cd6948712 100644
--- a/src/share/vm/opto/loopnode.cpp
+++ b/src/share/vm/opto/loopnode.cpp
@@ -341,7 +341,12 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
//
assert(x->Opcode() == Op_Loop, "regular loops only");
C->print_method("Before CountedLoop", 3);
-
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("Counted ");
+ loop->dump_head();
+ }
+#endif
// If compare points to incr, we are ok. Otherwise the compare
// can directly point to the phi; in this case adjust the compare so that
// it points to the incr by adjusting the limit.
@@ -864,8 +869,10 @@ void IdealLoopTree::split_outer_loop( PhaseIdealLoop *phase ) {
Node *outer = new (phase->C, 3) LoopNode( ctl, _head->in(outer_idx) );
outer = igvn.register_new_node_with_optimizer(outer, _head);
phase->set_created_loop_node();
+
+ Node* pred = phase->clone_loop_predicates(ctl, outer);
// Outermost loop falls into '_head' loop
- _head->set_req(LoopNode::EntryControl, outer);
+ _head->set_req(LoopNode::EntryControl, pred);
_head->del_req(outer_idx);
// Split all the Phis up between '_head' loop and 'outer' loop.
for (DUIterator_Fast jmax, j = _head->fast_outs(jmax); j < jmax; j++) {
@@ -1103,12 +1110,13 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
// backedges into a private merge point and use the merge point as
// the one true backedge.
if( _head->req() > 3 ) {
- // Merge the many backedges into a single backedge.
+ // Merge the many backedges into a single backedge but leave
+ // the hottest backedge as separate edge for the following peel.
merge_many_backedges( phase );
result = true;
}
- // If I am a shared header (multiple backedges), peel off myself loop.
+ // If I have one hot backedge, peel off myself loop.
// I better be the outermost loop.
if( _head->req() > 3 ) {
split_outer_loop( phase );
@@ -1433,15 +1441,30 @@ void IdealLoopTree::dump_head( ) const {
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
if (_irreducible) tty->print(" IRREDUCIBLE");
if (UseLoopPredicate) {
- Node* entry = _head->in(LoopNode::EntryControl);
- if (entry != NULL && entry->is_Proj() &&
- PhaseIdealLoop::is_uncommon_trap_if_pattern(entry->as_Proj(), Deoptimization::Reason_predicate)) {
+ Node* entry = PhaseIdealLoop::find_predicate_insertion_point(_head->in(LoopNode::EntryControl),
+ Deoptimization::Reason_predicate);
+ if (entry != NULL) {
tty->print(" predicated");
}
}
if (_head->is_CountedLoop()) {
CountedLoopNode *cl = _head->as_CountedLoop();
tty->print(" counted");
+
+ Node* init_n = cl->init_trip();
+ if (init_n != NULL && init_n->is_Con())
+ tty->print(" [%d,", cl->init_trip()->get_int());
+ else
+ tty->print(" [int,");
+ Node* limit_n = cl->limit();
+ if (limit_n != NULL && limit_n->is_Con())
+ tty->print("%d),", cl->limit()->get_int());
+ else
+ tty->print("int),");
+ int stride_con = cl->stride_con();
+ if (stride_con > 0) tty->print("+");
+ tty->print("%d", stride_con);
+
if (cl->is_pre_loop ()) tty->print(" pre" );
if (cl->is_main_loop()) tty->print(" main");
if (cl->is_post_loop()) tty->print(" post");
@@ -1541,7 +1564,7 @@ void PhaseIdealLoop::eliminate_useless_predicates() {
//----------------------------build_and_optimize-------------------------------
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
-void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
+void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) {
ResourceMark rm;
int old_progress = C->major_progress();
@@ -1573,6 +1596,13 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
// Do not need a safepoint at the top level
_ltree_root->_has_sfpt = 1;
+ // Initialize Dominators.
+ // Checked in clone_loop_predicate() during beautify_loops().
+ _idom_size = 0;
+ _idom = NULL;
+ _dom_depth = NULL;
+ _dom_stk = NULL;
+
// Empty pre-order array
allocate_preorders();
@@ -1698,8 +1728,9 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
return;
}
- // some parser-inserted loop predicates could never be used by loop
- // predication. Eliminate them before loop optimization
+ // Some parser-inserted loop predicates could never be used by loop
+ // predication or they were moved away from loop during some optimizations.
+ // For example, peeling. Eliminate them before next loop optimizations.
if (UseLoopPredicate) {
eliminate_useless_predicates();
}
@@ -1750,7 +1781,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
}
// Perform loop predication before iteration splitting
- if (do_loop_pred && C->has_loops() && !C->major_progress()) {
+ if (C->has_loops() && !C->major_progress() && (C->predicate_count() > 0)) {
_ltree_root->_child->loop_predication(this);
}
@@ -1793,8 +1824,20 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
C->set_major_progress();
}
- // Convert scalar to superword operations
+ // Keep loop predicates and perform optimizations with them
+ // until no more loop optimizations could be done.
+ // After that switch predicates off and do more loop optimizations.
+ if (!C->major_progress() && (C->predicate_count() > 0)) {
+ C->cleanup_loop_predicates(_igvn);
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print_cr("PredicatesOff");
+ }
+#endif
+ C->set_major_progress();
+ }
+ // Convert scalar to superword operations at the end of all loop opts.
if (UseSuperWord && C->has_loops() && !C->major_progress()) {
// SuperWord transform
SuperWord sw(this);
diff --git a/src/share/vm/opto/loopnode.hpp b/src/share/vm/opto/loopnode.hpp
index 9edcdf292..2b6ea369a 100644
--- a/src/share/vm/opto/loopnode.hpp
+++ b/src/share/vm/opto/loopnode.hpp
@@ -57,7 +57,12 @@ class LoopNode : public RegionNode {
protected:
short _loop_flags;
// Names for flag bitfields
- enum { pre_post_main=0, inner_loop=8, partial_peel_loop=16, partial_peel_failed=32 };
+ enum { Normal=0, Pre=1, Main=2, Post=3, PreMainPostFlagsMask=3,
+ MainHasNoPreLoop=4,
+ HasExactTripCount=8,
+ InnerLoop=16,
+ PartialPeelLoop=32,
+ PartialPeelFailed=64 };
char _unswitch_count;
enum { _unswitch_max=3 };
@@ -65,13 +70,13 @@ public:
// Names for edge indices
enum { Self=0, EntryControl, LoopBackControl };
- int is_inner_loop() const { return _loop_flags & inner_loop; }
- void set_inner_loop() { _loop_flags |= inner_loop; }
+ int is_inner_loop() const { return _loop_flags & InnerLoop; }
+ void set_inner_loop() { _loop_flags |= InnerLoop; }
- int is_partial_peel_loop() const { return _loop_flags & partial_peel_loop; }
- void set_partial_peel_loop() { _loop_flags |= partial_peel_loop; }
- int partial_peel_has_failed() const { return _loop_flags & partial_peel_failed; }
- void mark_partial_peel_failed() { _loop_flags |= partial_peel_failed; }
+ int is_partial_peel_loop() const { return _loop_flags & PartialPeelLoop; }
+ void set_partial_peel_loop() { _loop_flags |= PartialPeelLoop; }
+ int partial_peel_has_failed() const { return _loop_flags & PartialPeelFailed; }
+ void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; }
int unswitch_max() { return _unswitch_max; }
int unswitch_count() { return _unswitch_count; }
@@ -137,8 +142,8 @@ class CountedLoopNode : public LoopNode {
// the Main CountedLoop. Used to assert that we understand the graph shape.
node_idx_t _main_idx;
- // Known trip count calculated by policy_maximally_unroll
- int _trip_count;
+ // Known trip count calculated by compute_exact_trip_count()
+ uint _trip_count;
// Expected trip count from profile data
float _profile_trip_cnt;
@@ -152,7 +157,7 @@ class CountedLoopNode : public LoopNode {
public:
CountedLoopNode( Node *entry, Node *backedge )
- : LoopNode(entry, backedge), _trip_count(max_jint),
+ : LoopNode(entry, backedge), _main_idx(0), _trip_count(max_juint),
_profile_trip_cnt(COUNT_UNKNOWN), _unrolled_count_log2(0),
_node_count_before_unroll(0) {
init_class_id(Class_CountedLoop);
@@ -194,13 +199,12 @@ public:
// A 'main' loop that is ONLY unrolled or peeled, never RCE'd or
// Aligned, may be missing it's pre-loop.
- enum { Normal=0, Pre=1, Main=2, Post=3, PrePostFlagsMask=3, Main_Has_No_Pre_Loop=4 };
- int is_normal_loop() const { return (_loop_flags&PrePostFlagsMask) == Normal; }
- int is_pre_loop () const { return (_loop_flags&PrePostFlagsMask) == Pre; }
- int is_main_loop () const { return (_loop_flags&PrePostFlagsMask) == Main; }
- int is_post_loop () const { return (_loop_flags&PrePostFlagsMask) == Post; }
- int is_main_no_pre_loop() const { return _loop_flags & Main_Has_No_Pre_Loop; }
- void set_main_no_pre_loop() { _loop_flags |= Main_Has_No_Pre_Loop; }
+ int is_normal_loop() const { return (_loop_flags&PreMainPostFlagsMask) == Normal; }
+ int is_pre_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Pre; }
+ int is_main_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Main; }
+ int is_post_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Post; }
+ int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
+ void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
int main_idx() const { return _main_idx; }
@@ -208,10 +212,19 @@ public:
void set_pre_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Pre ; _main_idx = main->_idx; }
void set_main_loop ( ) { assert(is_normal_loop(),""); _loop_flags |= Main; }
void set_post_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Post; _main_idx = main->_idx; }
- void set_normal_loop( ) { _loop_flags &= ~PrePostFlagsMask; }
+ void set_normal_loop( ) { _loop_flags &= ~PreMainPostFlagsMask; }
- void set_trip_count(int tc) { _trip_count = tc; }
- int trip_count() { return _trip_count; }
+ void set_trip_count(uint tc) { _trip_count = tc; }
+ uint trip_count() { return _trip_count; }
+
+ bool has_exact_trip_count() const { return (_loop_flags & HasExactTripCount) != 0; }
+ void set_exact_trip_count(uint tc) {
+ _trip_count = tc;
+ _loop_flags |= HasExactTripCount;
+ }
+ void set_nonexact_trip_count() {
+ _loop_flags &= ~HasExactTripCount;
+ }
void set_profile_trip_cnt(float ptc) { _profile_trip_cnt = ptc; }
float profile_trip_cnt() { return _profile_trip_cnt; }
@@ -384,6 +397,9 @@ public:
// Micro-benchmark spamming. Remove empty loops.
bool policy_do_remove_empty_loop( PhaseIdealLoop *phase );
+ // Convert one iteration loop into normal code.
+ bool policy_do_one_iteration_loop( PhaseIdealLoop *phase );
+
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
// make some loop-invariant test (usually a null-check) happen before the
// loop.
@@ -412,6 +428,9 @@ public:
// Return TRUE if "iff" is a range check.
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const;
+ // Compute loop exact trip count if possible
+ void compute_exact_trip_count( PhaseIdealLoop *phase );
+
// Compute loop trip count from profile data
void compute_profile_trip_cnt( PhaseIdealLoop *phase );
@@ -706,11 +725,11 @@ private:
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(true) {
- build_and_optimize(false, false);
+ build_and_optimize(false);
}
// build the loop tree and perform any requested optimizations
- void build_and_optimize(bool do_split_if, bool do_loop_pred);
+ void build_and_optimize(bool do_split_if);
public:
// Dominators for the sea of nodes
@@ -721,13 +740,13 @@ public:
Node *dom_lca_internal( Node *n1, Node *n2 ) const;
// Compute the Ideal Node to Loop mapping
- PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs, bool do_loop_pred) :
+ PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) :
PhaseTransform(Ideal_Loop),
_igvn(igvn),
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(false) {
- build_and_optimize(do_split_ifs, do_loop_pred);
+ build_and_optimize(do_split_ifs);
}
// Verify that verify_me made the same decisions as a fresh run.
@@ -737,7 +756,7 @@ public:
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(verify_me),
_verify_only(false) {
- build_and_optimize(false, false);
+ build_and_optimize(false);
}
// Build and verify the loop tree without modifying the graph. This
@@ -830,7 +849,26 @@ public:
Deoptimization::DeoptReason reason);
void register_control(Node* n, IdealLoopTree *loop, Node* pred);
- // Find a good location to insert a predicate
+ // Clone loop predicates to cloned loops (peeled, unswitched)
+ static ProjNode* clone_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ static ProjNode* move_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ static Node* clone_loop_predicates(Node* old_entry, Node* new_entry,
+ bool move_predicates,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ Node* clone_loop_predicates(Node* old_entry, Node* new_entry);
+ Node* move_loop_predicates(Node* old_entry, Node* new_entry);
+
+ void eliminate_loop_predicates(Node* entry);
+ static Node* skip_loop_predicates(Node* entry);
+
+ // Find a good location to insert a predicate
static ProjNode* find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason);
// Find a predicate
static Node* find_predicate(Node* entry);
diff --git a/src/share/vm/opto/loopopts.cpp b/src/share/vm/opto/loopopts.cpp
index 831c6cb6e..1be374206 100644
--- a/src/share/vm/opto/loopopts.cpp
+++ b/src/share/vm/opto/loopopts.cpp
@@ -2139,9 +2139,12 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
// orig
//
-// stmt1
-// |
-// v
+// stmt1
+// |
+// v
+// loop predicate
+// |
+// v
// loop<----+
// | |
// stmt2 |
@@ -2172,6 +2175,9 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after clone loop
//
// stmt1
+// |
+// v
+// loop predicate
// / \
// clone / \ orig
// / \
@@ -2210,12 +2216,15 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after partial peel
//
// stmt1
+// |
+// v
+// loop predicate
// /
// clone / orig
// / TOP
// / \
// v v
-// TOP->region region----+
+// TOP->loop loop----+
// | | |
// stmt2 stmt2 |
// | | |
@@ -2253,13 +2262,17 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// stmt1
// |
// v
+// stmt2 clone
+// |
+// v
// ........> ifA clone
// : / |
// dom / |
// : v v
// : false true
// : | |
-// : | stmt2 clone
+// : | v
+// : | loop predicate
// : | |
// : | v
// : | newloop<-----+
@@ -2289,6 +2302,7 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
+ assert(!loop->_head->is_CountedLoop(), "Non-counted loop only");
if (!loop->_head->is_Loop()) {
return false; }
@@ -2316,6 +2330,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
}
}
+ Node* entry = head->in(LoopNode::EntryControl);
int dd = dom_depth(head);
// Step 1: find cut point
@@ -2612,6 +2627,8 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
// Backedge of the surviving new_head (the clone) is original last_peel
_igvn.hash_delete(new_head_clone);
+ Node* new_entry = move_loop_predicates(entry, new_head_clone->in(LoopNode::EntryControl));
+ new_head_clone->set_req(LoopNode::EntryControl, new_entry);
new_head_clone->set_req(LoopNode::LoopBackControl, last_peel);
_igvn._worklist.push(new_head_clone);
diff --git a/src/share/vm/opto/phaseX.hpp b/src/share/vm/opto/phaseX.hpp
index 7f1060c05..4d19708ed 100644
--- a/src/share/vm/opto/phaseX.hpp
+++ b/src/share/vm/opto/phaseX.hpp
@@ -471,6 +471,13 @@ public:
_delay_transform = delay;
}
+ // Clone loop predicates. Defined in loopTransform.cpp.
+ Node* clone_loop_predicates(Node* old_entry, Node* new_entry);
+ Node* move_loop_predicates(Node* old_entry, Node* new_entry);
+ // Create a new if below new_entry for the predicate to be cloned
+ ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason);
+
#ifndef PRODUCT
protected:
// Sub-quadratic implementation of VerifyIterativeGVN.
diff --git a/src/share/vm/opto/split_if.cpp b/src/share/vm/opto/split_if.cpp
index 91792368f..dba6ed1f2 100644
--- a/src/share/vm/opto/split_if.cpp
+++ b/src/share/vm/opto/split_if.cpp
@@ -399,6 +399,9 @@ void PhaseIdealLoop::do_split_if( Node *iff ) {
#ifndef PRODUCT
if( PrintOpto && VerifyLoopOptimizations )
tty->print_cr("Split-if");
+ if (TraceLoopOpts) {
+ tty->print_cr("SplitIf");
+ }
#endif
C->set_major_progress();
Node *region = iff->in(0);
diff --git a/src/share/vm/opto/superword.cpp b/src/share/vm/opto/superword.cpp
index 1230ebe51..6e1be24dd 100644
--- a/src/share/vm/opto/superword.cpp
+++ b/src/share/vm/opto/superword.cpp
@@ -1132,6 +1132,13 @@ void SuperWord::co_locate_pack(Node_List* pk) {
void SuperWord::output() {
if (_packset.length() == 0) return;
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("SuperWord ");
+ lpt()->dump_head();
+ }
+#endif
+
// MUST ENSURE main loop's initial value is properly aligned:
// (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
diff --git a/src/share/vm/opto/vectornode.hpp b/src/share/vm/opto/vectornode.hpp
index b4915ddfd..4d28703c8 100644
--- a/src/share/vm/opto/vectornode.hpp
+++ b/src/share/vm/opto/vectornode.hpp
@@ -32,6 +32,7 @@
//------------------------------VectorNode--------------------------------------
// Vector Operation
class VectorNode : public Node {
+ virtual uint size_of() const { return sizeof(*this); }
protected:
uint _length; // vector length
virtual BasicType elt_basic_type() const = 0; // Vector element basic type