Skip to content

Commit ca5a438

Browse files
committed
8334571: Extract control dependency rewiring out of PhaseIdealLoop::dominated_by() into separate method
Reviewed-by: roland, kvn
1 parent 05ff318 commit ca5a438

File tree

3 files changed

+56
-39
lines changed

3 files changed

+56
-39
lines changed

src/hotspot/share/opto/loopPredicate.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,6 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
11521152
ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl,
11531153
ConNode* zero, Invariance& invar, Deoptimization::DeoptReason reason) {
11541154
// Following are changed to nonnull when a predicate can be hoisted
1155-
IfProjNode* new_predicate_proj = nullptr;
11561155
IfNode* iff = if_success_proj->in(0)->as_If();
11571156
Node* test = iff->in(1);
11581157
if (!test->is_Bool()) { //Conv2B, ...
@@ -1163,10 +1162,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
11631162
if (invar.is_invariant(bol)) {
11641163
C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff);
11651164
// Invariant test
1166-
new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr,
1167-
reason,
1168-
iff->Opcode());
1169-
Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0);
1165+
IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason,
1166+
iff->Opcode());
1167+
Node* ctrl = hoisted_check_predicate_proj->in(0)->as_If()->in(0);
11701168
BoolNode* hoisted_check_predicate_bool = invar.clone(bol, ctrl)->as_Bool();
11711169

11721170
// Negate test if necessary (Parse Predicates always have IfTrue as success projection and IfFalse as uncommon trap)
@@ -1177,11 +1175,16 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
11771175
register_new_node(hoisted_check_predicate_bool, ctrl);
11781176
negated = true;
11791177
}
1180-
IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
1178+
IfNode* new_predicate_iff = hoisted_check_predicate_proj->in(0)->as_If();
11811179
_igvn.hash_delete(new_predicate_iff);
11821180
new_predicate_iff->set_req(1, hoisted_check_predicate_bool);
11831181

1184-
C->print_method(PHASE_AFTER_LOOP_PREDICATION_IC, 4, new_predicate_proj->in(0));
1182+
invar.map_ctrl(if_success_proj, hoisted_check_predicate_proj); // Mark hoisted check as invariant
1183+
1184+
// Eliminate the old If in the loop body.
1185+
dominated_by(hoisted_check_predicate_proj, iff, negated);
1186+
1187+
C->print_method(PHASE_AFTER_LOOP_PREDICATION_IC, 4, hoisted_check_predicate_proj->in(0));
11851188

11861189
#ifndef PRODUCT
11871190
if (TraceLoopPredicate) {
@@ -1193,10 +1196,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
11931196
}
11941197
#endif
11951198
} else if (cl != nullptr && loop->is_range_check_if(if_success_proj, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) {
1196-
range_check_predicate = true;
11971199
C->print_method(PHASE_BEFORE_LOOP_PREDICATION_RC, 4, iff);
11981200
// Range check for counted loops
11991201
assert(if_success_proj->is_IfTrue(), "trap must be on false projection for a range check");
1202+
IfTrueNode* hoisted_check_proj = if_success_proj->as_IfTrue();
12001203
const Node* cmp = bol->in(1)->as_Cmp();
12011204
Node* idx = cmp->in(1);
12021205
assert(!invar.is_invariant(idx), "index is variant");
@@ -1265,10 +1268,18 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
12651268
// Fall through into rest of the cleanup code which will move any dependent nodes to the skeleton predicates of the
12661269
// upper bound test. We always need to create skeleton predicates in order to properly remove dead loops when later
12671270
// splitting the predicated loop into (unreachable) sub-loops (i.e. done by unrolling, peeling, pre/main/post etc.).
1268-
new_predicate_proj = add_template_assertion_predicate(iff, loop, if_success_proj, parse_predicate_proj, upper_bound_proj, scale,
1269-
offset, init, limit, stride, rng, overflow, reason);
1271+
IfTrueNode* template_assertion_predicate_proj =
1272+
add_template_assertion_predicate(iff, loop, hoisted_check_proj, parse_predicate_proj, upper_bound_proj, scale,
1273+
offset, init, limit, stride, rng, overflow, reason);
1274+
1275+
// Eliminate the old range check in the loop body.
1276+
// When a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2
1277+
// Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control
1278+
// dependency: pin the data dependent nodes.
1279+
eliminate_hoisted_range_check(hoisted_check_proj, template_assertion_predicate_proj);
1280+
invar.map_ctrl(hoisted_check_proj, template_assertion_predicate_proj); // Mark hoisted check as invariant
12701281

1271-
C->print_method(PHASE_AFTER_LOOP_PREDICATION_RC, 4, new_predicate_proj->in(0));
1282+
C->print_method(PHASE_AFTER_LOOP_PREDICATION_RC, 4, template_assertion_predicate_proj->in(0));
12721283

12731284
#ifndef PRODUCT
12741285
if (TraceLoopOpts && !TraceLoopPredicate) {
@@ -1281,24 +1292,21 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod
12811292
// with uncommon trap.
12821293
return false;
12831294
}
1284-
assert(new_predicate_proj != nullptr, "sanity");
1285-
// Success - attach condition (new_predicate_bol) to predicate if
1286-
invar.map_ctrl(if_success_proj, new_predicate_proj); // so that invariance test can be appropriate
1287-
1288-
// Eliminate the old If in the loop body
1289-
// If a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2
1290-
// Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control
1291-
// dependency: pin the data dependent nodes.
1292-
dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con, range_check_predicate);
12931295

12941296
C->set_major_progress();
12951297
return true;
12961298
}
12971299

1300+
void PhaseIdealLoop::eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj,
1301+
IfTrueNode* template_assertion_predicate_proj) {
1302+
_igvn.replace_input_of(hoisted_check_proj->in(0), 1, _igvn.intcon(1));
1303+
rewire_safe_outputs_to_dominator(hoisted_check_proj, template_assertion_predicate_proj, true);
1304+
}
1305+
12981306
// Each newly created Hoisted Check Predicate is accompanied by two Template Assertion Predicates. Later, we initialize
12991307
// them by making a copy of them when splitting a loop into sub loops. The Assertion Predicates ensure that dead sub
13001308
// loops are removed properly.
1301-
IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
1309+
IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
13021310
ParsePredicateSuccessProj* parse_predicate_proj,
13031311
IfProjNode* upper_bound_proj, const int scale, Node* offset,
13041312
Node* init, Node* limit, const jint stride,
@@ -1312,7 +1320,7 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL
13121320
Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over
13131321
C->add_template_assertion_predicate_opaq(opaque_bol);
13141322
register_new_node(opaque_bol, upper_bound_proj);
1315-
IfProjNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode());
1323+
IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode());
13161324
_igvn.replace_input_of(new_proj->in(0), 1, opaque_bol);
13171325
assert(opaque_init->outcnt() > 0, "should be used");
13181326

src/hotspot/share/opto/loopnode.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1377,10 +1377,11 @@ class PhaseIdealLoop : public PhaseTransform {
13771377
void loop_predication_follow_branches(Node *c, IdealLoopTree *loop, float loop_trip_cnt,
13781378
PathFrequency& pf, Node_Stack& stack, VectorSet& seen,
13791379
Node_List& if_proj_list);
1380-
IfProjNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
1380+
IfTrueNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj,
13811381
ParsePredicateSuccessProj* parse_predicate_proj,
13821382
IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit,
13831383
jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason);
1384+
void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj);
13841385
Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con,
13851386
Node* offset, Node* limit, int stride_con, Node* value,
13861387
bool is_template);
@@ -1535,6 +1536,7 @@ class PhaseIdealLoop : public PhaseTransform {
15351536
// Mark an IfNode as being dominated by a prior test,
15361537
// without actually altering the CFG (and hence IDOM info).
15371538
void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool pin_array_access_nodes = false);
1539+
void rewire_safe_outputs_to_dominator(Node* source, Node* dominator, bool pin_array_access_nodes);
15381540

15391541
// Split Node 'n' through merge point
15401542
RegionNode* split_thru_region(Node* n, RegionNode* region);

src/hotspot/share/opto/loopopts.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -340,46 +340,53 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b
340340
// I can assume this path reaches an infinite loop. In this case it's not
341341
// important to optimize the data Nodes - either the whole compilation will
342342
// be tossed or this path (and all data Nodes) will go dead.
343-
if (iff->outcnt() != 2) return;
343+
if (iff->outcnt() != 2) {
344+
return;
345+
}
344346

345347
// Make control-dependent data Nodes on the live path (path that will remain
346348
// once the dominated IF is removed) become control-dependent on the
347349
// dominating projection.
348350
Node* dp = iff->proj_out_or_null(pop == Op_IfTrue);
349351

350-
if (dp == nullptr)
352+
if (dp == nullptr) {
351353
return;
354+
}
355+
356+
rewire_safe_outputs_to_dominator(dp, prevdom, pin_array_access_nodes);
357+
}
352358

353-
IdealLoopTree* old_loop = get_loop(dp);
359+
void PhaseIdealLoop::rewire_safe_outputs_to_dominator(Node* source, Node* dominator, const bool pin_array_access_nodes) {
360+
IdealLoopTree* old_loop = get_loop(source);
354361

355-
for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
356-
Node* cd = dp->fast_out(i); // Control-dependent node
362+
for (DUIterator_Fast imax, i = source->fast_outs(imax); i < imax; i++) {
363+
Node* out = source->fast_out(i); // Control-dependent node
357364
// Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check.
358-
if (cd->depends_only_on_test() && _igvn.no_dependent_zero_check(cd)) {
359-
assert(cd->in(0) == dp, "");
360-
_igvn.replace_input_of(cd, 0, prevdom);
365+
if (out->depends_only_on_test() && _igvn.no_dependent_zero_check(out)) {
366+
assert(out->in(0) == source, "must be control dependent on source");
367+
_igvn.replace_input_of(out, 0, dominator);
361368
if (pin_array_access_nodes) {
362369
// Because of Loop Predication, Loads and range check Cast nodes that are control dependent on this range
363370
// check (that is about to be removed) now depend on multiple dominating Hoisted Check Predicates. After the
364371
// removal of this range check, these control dependent nodes end up at the lowest/nearest dominating predicate
365372
// in the graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the
366373
// lowest dominating check is later replaced by yet another dominating check), we need to pin them at the lowest
367374
// dominating check.
368-
Node* clone = cd->pin_array_access_node();
375+
Node* clone = out->pin_array_access_node();
369376
if (clone != nullptr) {
370-
clone = _igvn.register_new_node_with_optimizer(clone, cd);
371-
_igvn.replace_node(cd, clone);
372-
cd = clone;
377+
clone = _igvn.register_new_node_with_optimizer(clone, out);
378+
_igvn.replace_node(out, clone);
379+
out = clone;
373380
}
374381
}
375-
set_early_ctrl(cd, false);
376-
IdealLoopTree* new_loop = get_loop(get_ctrl(cd));
382+
set_early_ctrl(out, false);
383+
IdealLoopTree* new_loop = get_loop(get_ctrl(out));
377384
if (old_loop != new_loop) {
378385
if (!old_loop->_child) {
379-
old_loop->_body.yank(cd);
386+
old_loop->_body.yank(out);
380387
}
381388
if (!new_loop->_child) {
382-
new_loop->_body.push(cd);
389+
new_loop->_body.push(out);
383390
}
384391
}
385392
--i;

0 commit comments

Comments
 (0)