Skip to content

Commit aec0377

Browse files
committed
8257498: Remove useless skeleton predicates
Reviewed-by: roland, thartmann
1 parent ab727f0 commit aec0377

File tree

6 files changed

+85
-35
lines changed

6 files changed

+85
-35
lines changed

src/hotspot/share/opto/compile.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ void Compile::remove_useless_node(Node* dead) {
391391
if (dead->is_expensive()) {
392392
remove_expensive_node(dead);
393393
}
394+
if (dead->Opcode() == Op_Opaque4) {
395+
remove_skeleton_predicate_opaq(dead);
396+
}
394397
if (dead->for_post_loop_opts_igvn()) {
395398
remove_from_post_loop_opts_igvn(dead);
396399
}
@@ -566,6 +569,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
566569
_intrinsics (comp_arena(), 0, 0, NULL),
567570
_macro_nodes (comp_arena(), 8, 0, NULL),
568571
_predicate_opaqs (comp_arena(), 8, 0, NULL),
572+
_skeleton_predicate_opaqs (comp_arena(), 8, 0, NULL),
569573
_expensive_nodes (comp_arena(), 8, 0, NULL),
570574
_for_post_loop_igvn(comp_arena(), 8, 0, NULL),
571575
_congraph(NULL),

src/hotspot/share/opto/compile.hpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class Compile : public Phase {
315315
GrowableArray<CallGenerator*> _intrinsics; // List of intrinsics.
316316
GrowableArray<Node*> _macro_nodes; // List of nodes which need to be expanded before matching.
317317
GrowableArray<Node*> _predicate_opaqs; // List of Opaque1 nodes for the loop predicates.
318+
GrowableArray<Node*> _skeleton_predicate_opaqs; // List of Opaque4 nodes for the loop skeleton predicates.
318319
GrowableArray<Node*> _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
319320
GrowableArray<Node*> _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over
320321
ConnectionGraph* _congraph;
@@ -656,11 +657,13 @@ class Compile : public Phase {
656657
void end_method(int level = 1);
657658

658659
int macro_count() const { return _macro_nodes.length(); }
659-
int predicate_count() const { return _predicate_opaqs.length();}
660+
int predicate_count() const { return _predicate_opaqs.length(); }
661+
int skeleton_predicate_count() const { return _skeleton_predicate_opaqs.length(); }
660662
int expensive_count() const { return _expensive_nodes.length(); }
661663

662664
Node* macro_node(int idx) const { return _macro_nodes.at(idx); }
663-
Node* predicate_opaque1_node(int idx) const { return _predicate_opaqs.at(idx);}
665+
Node* predicate_opaque1_node(int idx) const { return _predicate_opaqs.at(idx); }
666+
Node* skeleton_predicate_opaque4_node(int idx) const { return _skeleton_predicate_opaqs.at(idx); }
664667
Node* expensive_node(int idx) const { return _expensive_nodes.at(idx); }
665668

666669
ConnectionGraph* congraph() { return _congraph;}
@@ -688,7 +691,15 @@ class Compile : public Phase {
688691
assert(_macro_nodes.contains(n), "should have already been in macro list");
689692
_predicate_opaqs.append(n);
690693
}
691-
694+
void add_skeleton_predicate_opaq(Node* n) {
695+
assert(!_skeleton_predicate_opaqs.contains(n), "duplicate entry in skeleton predicate opaque4 list");
696+
_skeleton_predicate_opaqs.append(n);
697+
}
698+
void remove_skeleton_predicate_opaq(Node* n) {
699+
if (skeleton_predicate_count() > 0) {
700+
_skeleton_predicate_opaqs.remove_if_existing(n);
701+
}
702+
}
692703
bool post_loop_opts_phase() { return _post_loop_opts_phase; }
693704
void set_post_loop_opts_phase() { _post_loop_opts_phase = true; }
694705
void reset_post_loop_opts_phase() { _post_loop_opts_phase = false; }

src/hotspot/share/opto/loopPredicate.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -231,33 +231,20 @@ ProjNode* PhaseIdealLoop::clone_predicate_to_unswitched_loop(ProjNode* predicate
231231
// the old predicates to the new cloned predicates.
232232
void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, Deoptimization::DeoptReason reason,
233233
ProjNode* old_predicate_proj, ProjNode* iffast_pred, ProjNode* ifslow_pred) {
234-
IfNode* iff = old_predicate_proj->in(0)->as_If();
235234
assert(iffast_pred->in(0)->is_If() && ifslow_pred->in(0)->is_If(), "sanity check");
236-
ProjNode* uncommon_proj = iff->proj_out(1 - old_predicate_proj->as_Proj()->_con);
237-
Node* rgn = uncommon_proj->unique_ctrl_out();
238-
assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
239-
assert(iff->in(1)->in(1)->Opcode() == Op_Opaque1, "unexpected predicate shape");
240-
Node* predicate = iff->in(0);
235+
// Only need to clone range check predicates as those can be changed and duplicated by inserting pre/main/post loops
236+
// and doing loop unrolling. Push the original predicates on a list to later process them in reverse order to keep the
237+
// original predicate order.
241238
Unique_Node_List list;
242-
while (predicate != NULL && predicate->is_Proj() && predicate->in(0)->is_If()) {
243-
iff = predicate->in(0)->as_If();
244-
uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con);
245-
if (uncommon_proj->unique_ctrl_out() != rgn)
246-
break;
247-
if (iff->in(1)->Opcode() == Op_Opaque4 && skeleton_predicate_has_opaque(iff)) {
248-
// Only need to clone range check predicates as those can be changed and duplicated by inserting pre/main/post loops
249-
// and doing loop unrolling. Push the original predicates on a list to later process them in reverse order to keep the
250-
// original predicate order.
251-
list.push(predicate);
252-
}
253-
predicate = predicate->in(0)->in(0);
254-
}
239+
get_skeleton_predicates(old_predicate_proj, list);
255240

256241
Node_List to_process;
242+
IfNode* iff = old_predicate_proj->in(0)->as_If();
243+
ProjNode* uncommon_proj = iff->proj_out(1 - old_predicate_proj->as_Proj()->_con);
257244
// Process in reverse order such that 'create_new_if_for_predicate' can be used in 'clone_skeleton_predicate_for_unswitched_loops'
258245
// and the original order is maintained.
259246
for (int i = list.size() - 1; i >= 0; i--) {
260-
predicate = list.at(i);
247+
Node* predicate = list.at(i);
261248
assert(predicate->in(0)->is_If(), "must be If node");
262249
iff = predicate->in(0)->as_If();
263250
assert(predicate->is_Proj() && predicate->as_Proj()->is_IfProj(), "predicate must be a projection of an if node");
@@ -288,6 +275,34 @@ void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(IdealLoopTree*
288275
}
289276
}
290277

278+
// Put all skeleton predicate projections on a list, starting at 'predicate' and going up in the tree. If 'get_opaque'
279+
// is set, then the Opaque4 nodes of the skeleton predicates are put on the list instead of the projections.
280+
void PhaseIdealLoop::get_skeleton_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque) {
281+
IfNode* iff = predicate->in(0)->as_If();
282+
ProjNode* uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con);
283+
Node* rgn = uncommon_proj->unique_ctrl_out();
284+
assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
285+
assert(iff->in(1)->in(1)->Opcode() == Op_Opaque1, "unexpected predicate shape");
286+
predicate = iff->in(0);
287+
while (predicate != NULL && predicate->is_Proj() && predicate->in(0)->is_If()) {
288+
iff = predicate->in(0)->as_If();
289+
uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con);
290+
if (uncommon_proj->unique_ctrl_out() != rgn) {
291+
break;
292+
}
293+
if (iff->in(1)->Opcode() == Op_Opaque4 && skeleton_predicate_has_opaque(iff)) {
294+
if (get_opaque) {
295+
// Collect the predicate Opaque4 node.
296+
list.push(iff->in(1));
297+
} else {
298+
// Collect the predicate projection.
299+
list.push(predicate);
300+
}
301+
}
302+
predicate = predicate->in(0)->in(0);
303+
}
304+
}
305+
291306
// Clone a skeleton predicate for an unswitched loop. OpaqueLoopInit and OpaqueLoopStride nodes are cloned and uncommon
292307
// traps are kept for the predicate (a Halt node is used later when creating pre/main/post loops and copying this cloned
293308
// predicate again).
@@ -1241,6 +1256,7 @@ ProjNode* PhaseIdealLoop::insert_initial_skeleton_predicate(IfNode* iff, IdealLo
12411256
register_new_node(opaque_init, upper_bound_proj);
12421257
BoolNode* bol = rc_predicate(loop, upper_bound_proj, scale, offset, opaque_init, limit, stride, rng, (stride > 0) != (scale > 0), overflow);
12431258
Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over
1259+
C->add_skeleton_predicate_opaq(opaque_bol);
12441260
register_new_node(opaque_bol, upper_bound_proj);
12451261
ProjNode* new_proj = create_new_if_for_predicate(predicate_proj, NULL, reason, overflow ? Op_If : iff->Opcode());
12461262
_igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
@@ -1258,6 +1274,7 @@ ProjNode* PhaseIdealLoop::insert_initial_skeleton_predicate(IfNode* iff, IdealLo
12581274
register_new_node(max_value, new_proj);
12591275
bol = rc_predicate(loop, new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0), overflow);
12601276
opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1));
1277+
C->add_skeleton_predicate_opaq(opaque_bol);
12611278
register_new_node(opaque_bol, new_proj);
12621279
new_proj = create_new_if_for_predicate(predicate_proj, NULL, reason, overflow ? Op_If : iff->Opcode());
12631280
_igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);

src/hotspot/share/opto/loopnode.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3531,8 +3531,7 @@ void PhaseIdealLoop::log_loop_tree() {
35313531
//---------------------collect_potentially_useful_predicates-----------------------
35323532
// Helper function to collect potentially useful predicates to prevent them from
35333533
// being eliminated by PhaseIdealLoop::eliminate_useless_predicates
3534-
void PhaseIdealLoop::collect_potentially_useful_predicates(
3535-
IdealLoopTree * loop, Unique_Node_List &useful_predicates) {
3534+
void PhaseIdealLoop::collect_potentially_useful_predicates(IdealLoopTree* loop, Unique_Node_List &useful_predicates) {
35363535
if (loop->_child) { // child
35373536
collect_potentially_useful_predicates(loop->_child, useful_predicates);
35383537
}
@@ -3543,22 +3542,28 @@ void PhaseIdealLoop::collect_potentially_useful_predicates(
35433542
!loop->tail()->is_top()) {
35443543
LoopNode* lpn = loop->_head->as_Loop();
35453544
Node* entry = lpn->in(LoopNode::EntryControl);
3546-
Node* predicate_proj = find_predicate(entry); // loop_limit_check first
3547-
if (predicate_proj != NULL) { // right pattern that can be used by loop predication
3545+
3546+
Node* predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
3547+
if (predicate != NULL) { // right pattern that can be used by loop predication
35483548
assert(entry->in(0)->in(1)->in(1)->Opcode() == Op_Opaque1, "must be");
35493549
useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one
35503550
entry = skip_loop_predicates(entry);
35513551
}
35523552
if (UseProfiledLoopPredicate) {
3553-
predicate_proj = find_predicate(entry); // Predicate
3554-
if (predicate_proj != NULL) {
3553+
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_profile_predicate);
3554+
if (predicate != NULL) { // right pattern that can be used by loop predication
35553555
useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one
3556+
get_skeleton_predicates(entry, useful_predicates, true);
35563557
entry = skip_loop_predicates(entry);
35573558
}
35583559
}
3559-
predicate_proj = find_predicate(entry); // Predicate
3560-
if (predicate_proj != NULL) {
3561-
useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one
3560+
3561+
if (UseLoopPredicate) {
3562+
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
3563+
if (predicate != NULL) { // right pattern that can be used by loop predication
3564+
useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one
3565+
get_skeleton_predicates(entry, useful_predicates, true);
3566+
}
35623567
}
35633568
}
35643569

@@ -3572,21 +3577,30 @@ void PhaseIdealLoop::collect_potentially_useful_predicates(
35723577
// Note: it will also eliminates loop limits check predicate since it also uses
35733578
// Opaque1 node (see Parse::add_predicate()).
35743579
void PhaseIdealLoop::eliminate_useless_predicates() {
3575-
if (C->predicate_count() == 0)
3580+
if (C->predicate_count() == 0 && C->skeleton_predicate_count() == 0) {
35763581
return; // no predicate left
3582+
}
35773583

35783584
Unique_Node_List useful_predicates; // to store useful predicates
35793585
if (C->has_loops()) {
35803586
collect_potentially_useful_predicates(_ltree_root->_child, useful_predicates);
35813587
}
35823588

35833589
for (int i = C->predicate_count(); i > 0; i--) {
3584-
Node * n = C->predicate_opaque1_node(i-1);
3590+
Node* n = C->predicate_opaque1_node(i - 1);
35853591
assert(n->Opcode() == Op_Opaque1, "must be");
35863592
if (!useful_predicates.member(n)) { // not in the useful list
35873593
_igvn.replace_node(n, n->in(1));
35883594
}
35893595
}
3596+
3597+
for (int i = C->skeleton_predicate_count(); i > 0; i--) {
3598+
Node* n = C->skeleton_predicate_opaque4_node(i - 1);
3599+
assert(n->Opcode() == Op_Opaque4, "must be");
3600+
if (!useful_predicates.member(n)) { // not in the useful list
3601+
_igvn.replace_node(n, n->in(2));
3602+
}
3603+
}
35903604
}
35913605

35923606
//------------------------process_expensive_nodes-----------------------------

src/hotspot/share/opto/loopnode.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,8 @@ class PhaseIdealLoop : public PhaseTransform {
914914
IdealLoopTree* outer_loop, Node* input_proj);
915915
Node* clone_skeleton_predicate_bool(Node* iff, Node* new_init, Node* new_stride, Node* predicate, Node* uncommon_proj, Node* control,
916916
IdealLoopTree* outer_loop);
917-
bool skeleton_predicate_has_opaque(IfNode* iff);
917+
static bool skeleton_predicate_has_opaque(IfNode* iff);
918+
static void get_skeleton_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque = false);
918919
void update_main_loop_skeleton_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con);
919920
void insert_loop_limit_check(ProjNode* limit_check_proj, Node* cmp_limit, Node* bol);
920921
#ifdef ASSERT

src/hotspot/share/opto/node.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,9 @@ void Node::destruct(PhaseValues* phase) {
644644
if (is_expensive()) {
645645
compile->remove_expensive_node(this);
646646
}
647+
if (Opcode() == Op_Opaque4) {
648+
compile->remove_skeleton_predicate_opaq(this);
649+
}
647650
if (for_post_loop_opts_igvn()) {
648651
compile->remove_from_post_loop_opts_igvn(this);
649652
}

0 commit comments

Comments
 (0)