Skip to content

Commit b1e2f02

Browse files
committed
8253524: C2: Refactor code that clones predicates during loop unswitching
Reviewed-by: chagedorn, kvn, thartmann
1 parent c303fd5 commit b1e2f02

File tree

3 files changed

+65
-94
lines changed

3 files changed

+65
-94
lines changed

src/hotspot/share/opto/loopPredicate.cpp

Lines changed: 56 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node*
210210
}
211211

212212
//--------------------------clone_predicate-----------------------
213-
ProjNode* PhaseIdealLoop::clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
214-
bool is_slow_loop, uint idx_before_clone, Node_List &old_new) {
213+
ProjNode* PhaseIdealLoop::clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason) {
215214
ProjNode* new_predicate_proj = create_new_if_for_predicate(predicate_proj, new_entry, reason, Op_If);
216215
IfNode* iff = new_predicate_proj->in(0)->as_If();
217216
Node* ctrl = iff->in(0);
@@ -225,17 +224,14 @@ ProjNode* PhaseIdealLoop::clone_predicate_to_unswitched_loop(ProjNode* predicate
225224
register_new_node(bol, ctrl);
226225
_igvn.hash_delete(iff);
227226
iff->set_req(1, bol);
228-
clone_skeleton_predicates_to_unswitched_loop(reason, predicate_proj, new_predicate_proj, is_slow_loop, idx_before_clone, old_new);
229227
return new_predicate_proj;
230228
}
231229

232230
// Clones skeleton predicates starting at 'old_predicate_proj' to
233231
// 'new_predicate_proj' and rewires the control edges of data nodes in
234232
// the loop from the old predicates to the new cloned predicates.
235-
void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
236-
ProjNode* new_predicate_proj, bool is_slow_loop, uint idx_before_clone,
237-
Node_List &old_new) {
238-
assert(old_predicate_proj->is_Proj(), "must be projection");
233+
void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, Deoptimization::DeoptReason reason,
234+
ProjNode* old_predicate_proj, ProjNode* iffast, ProjNode* ifslow) {
239235
IfNode* iff = old_predicate_proj->in(0)->as_If();
240236
ProjNode* uncommon_proj = iff->proj_out(1 - old_predicate_proj->as_Proj()->_con);
241237
Node* rgn = uncommon_proj->unique_ctrl_out();
@@ -255,21 +251,11 @@ void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(Deoptimization
255251
// and doing loop unrolling. Push the original predicates on a list to later process them in reverse order to keep the
256252
// original predicate order.
257253
list.push(predicate);
258-
#ifdef ASSERT
259-
} else {
260-
// All other If predicates should not have a control input to nodes belonging to the original loop
261-
for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) {
262-
Node* old_node = predicate->out(i);
263-
Node* new_node = old_new[old_node->_idx];
264-
if (!old_node->is_CFG() && new_node != NULL && old_node->_idx >= idx_before_clone) {
265-
assert(false, "should not be part of the original loop");
266-
}
267-
}
268-
#endif
269254
}
270255
predicate = predicate->in(0)->in(0);
271256
}
272257

258+
Node_List to_process;
273259
// Process in reverse order such that 'create_new_if_for_predicate' can be used and the original order is maintained
274260
for (int i = list.size()-1; i >= 0; i--) {
275261
predicate = list.at(i);
@@ -279,58 +265,41 @@ void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(Deoptimization
279265
IfProjNode* predicate_proj = predicate->as_IfProj();
280266

281267
// cloned_proj is the same type of projection as the original predicate projection (IfTrue or IfFalse)
282-
ProjNode* cloned_proj = create_new_if_for_predicate(new_predicate_proj, NULL, reason, iff->Opcode(), predicate_proj->is_IfTrue());
268+
ProjNode* fast_proj = create_new_if_for_predicate(iffast, NULL, reason, iff->Opcode(), predicate_proj->is_IfTrue());
269+
ProjNode* slow_proj = create_new_if_for_predicate(ifslow, NULL, reason, iff->Opcode(), predicate_proj->is_IfTrue());
283270

284271
// Replace bool input by input from original predicate
285-
_igvn.replace_input_of(cloned_proj->in(0), 1, iff->in(1));
286-
287-
if (is_slow_loop) {
288-
for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) {
289-
Node* slow_node = predicate->out(i);
290-
Node* fast_node = old_new[slow_node->_idx];
291-
if (!slow_node->is_CFG() && fast_node != NULL && slow_node->_idx > idx_before_clone) {
292-
// 'slow_node' is a data node and part of the slow loop. This is a clone of the fast loop node
293-
// which was temporarily added below in order to verify that 'slow_node' is a clone of 'fast_node'.
294-
// Update the control input and reset the mapping for 'slow_node' back to NULL.
295-
_igvn.replace_input_of(slow_node, 0, cloned_proj);
296-
old_new.map(slow_node->_idx, NULL);
297-
--i;
298-
}
299-
assert(slow_node->_idx <= idx_before_clone || old_new[slow_node->_idx] == NULL, "mapping of cloned nodes must be null");
300-
}
301-
} else {
302-
// Fast loop
303-
for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) {
304-
Node* fast_node = predicate->out(i);
272+
_igvn.replace_input_of(fast_proj->in(0), 1, iff->in(1));
273+
_igvn.replace_input_of(slow_proj->in(0), 1, iff->in(1));
274+
275+
for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) {
276+
Node* fast_node = predicate->out(i);
277+
if (loop->is_member(get_loop(ctrl_or_self(fast_node)))) {
278+
assert(fast_node->in(0) == predicate, "only control edge");
305279
Node* slow_node = old_new[fast_node->_idx];
306-
if (!fast_node->is_CFG() && slow_node != NULL && slow_node->_idx > idx_before_clone) {
307-
// 'fast_node' is a data node and part of the fast loop. Add the clone of the fast loop node
308-
// to the 'old_new' mapping in order to verify later when cloning the predicates for the slow loop
309-
// that 'slow_node' is a clone of 'fast_node'. Update the control input for 'fast_node'.
310-
_igvn.replace_input_of(fast_node, 0, cloned_proj);
311-
assert(old_new[slow_node->_idx] == NULL, "mapping must be null for cloned nodes");
312-
old_new.map(slow_node->_idx, fast_node);
313-
--i;
314-
}
280+
assert(slow_node->in(0) == predicate, "only control edge");
281+
_igvn.replace_input_of(fast_node, 0, fast_proj);
282+
to_process.push(slow_node);
283+
--i;
315284
}
316285
}
286+
// Have to delay updates to the slow loop so uses of predicate are
287+
// not modified while we iterate on them.
288+
while (to_process.size() > 0) {
289+
Node* slow_node = to_process.pop();
290+
_igvn.replace_input_of(slow_node, 0, slow_proj);
291+
}
317292
}
318293
}
319294

320295
//--------------------------clone_loop_predicates-----------------------
321296
// Clone loop predicates to cloned loops when unswitching a loop.
322-
Node* PhaseIdealLoop::clone_predicates_to_unswitched_loop(Node* old_entry, Node* new_entry, bool clone_limit_check,
323-
bool is_slow_loop, uint idx_before_clone, Node_List &old_new) {
324-
#ifdef ASSERT
325-
assert(LoopUnswitching, "sanity - only called when unswitching a loop");
326-
if (new_entry == NULL || !(new_entry->is_Proj() || new_entry->is_Region() || new_entry->is_SafePoint())) {
327-
if (new_entry != NULL)
328-
new_entry->dump();
329-
assert(false, "not IfTrue, IfFalse, Region or SafePoint");
330-
}
331-
#endif
297+
void PhaseIdealLoop::clone_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, ProjNode*& iffast, ProjNode*& ifslow) {
298+
LoopNode* head = loop->_head->as_Loop();
299+
bool clone_limit_check = !head->is_CountedLoop();
300+
Node* entry = head->skip_strip_mined()->in(LoopNode::EntryControl);
301+
332302
// Search original predicates
333-
Node* entry = old_entry;
334303
ProjNode* limit_check_proj = NULL;
335304
limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check);
336305
if (limit_check_proj != NULL) {
@@ -349,39 +318,45 @@ Node* PhaseIdealLoop::clone_predicates_to_unswitched_loop(Node* old_entry, Node*
349318
}
350319
if (predicate_proj != NULL) { // right pattern that can be used by loop predication
351320
// clone predicate
352-
new_entry = clone_predicate_to_unswitched_loop(predicate_proj, new_entry, Deoptimization::Reason_predicate, is_slow_loop,
353-
idx_before_clone, old_new);
354-
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
355-
if (TraceLoopPredicate) {
356-
tty->print("Loop Predicate cloned: ");
357-
debug_only( new_entry->in(0)->dump(); );
358-
}
321+
iffast = clone_predicate_to_unswitched_loop(predicate_proj, iffast, Deoptimization::Reason_predicate);
322+
ifslow = clone_predicate_to_unswitched_loop(predicate_proj, ifslow, Deoptimization::Reason_predicate);
323+
clone_skeleton_predicates_to_unswitched_loop(loop, old_new, Deoptimization::Reason_predicate, predicate_proj, iffast, ifslow);
324+
325+
check_created_predicate_for_unswitching(iffast);
326+
check_created_predicate_for_unswitching(ifslow);
359327
}
360328
if (profile_predicate_proj != NULL) { // right pattern that can be used by loop predication
361329
// clone predicate
362-
new_entry = clone_predicate_to_unswitched_loop(profile_predicate_proj, new_entry,Deoptimization::Reason_profile_predicate,
363-
is_slow_loop, idx_before_clone, old_new);
364-
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
365-
if (TraceLoopPredicate) {
366-
tty->print("Loop Predicate cloned: ");
367-
debug_only( new_entry->in(0)->dump(); );
368-
}
330+
iffast = clone_predicate_to_unswitched_loop(profile_predicate_proj, iffast, Deoptimization::Reason_profile_predicate);
331+
ifslow = clone_predicate_to_unswitched_loop(profile_predicate_proj, ifslow, Deoptimization::Reason_profile_predicate);
332+
clone_skeleton_predicates_to_unswitched_loop(loop, old_new, Deoptimization::Reason_profile_predicate, profile_predicate_proj, iffast, ifslow);
333+
334+
check_created_predicate_for_unswitching(iffast);
335+
check_created_predicate_for_unswitching(ifslow);
369336
}
370337
if (limit_check_proj != NULL && clone_limit_check) {
371338
// Clone loop limit check last to insert it before loop.
372339
// Don't clone a limit check which was already finalized
373340
// for this counted loop (only one limit check is needed).
374-
new_entry = clone_predicate_to_unswitched_loop(limit_check_proj, new_entry, Deoptimization::Reason_loop_limit_check,
375-
is_slow_loop, idx_before_clone, old_new);
376-
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone limit check");
377-
if (TraceLoopLimitCheck) {
378-
tty->print("Loop Limit Check cloned: ");
379-
debug_only( new_entry->in(0)->dump(); )
380-
}
341+
iffast = clone_predicate_to_unswitched_loop(limit_check_proj, iffast, Deoptimization::Reason_loop_limit_check);
342+
ifslow = clone_predicate_to_unswitched_loop(limit_check_proj, ifslow, Deoptimization::Reason_loop_limit_check);
343+
344+
check_created_predicate_for_unswitching(iffast);
345+
check_created_predicate_for_unswitching(ifslow);
381346
}
382-
return new_entry;
383347
}
384348

349+
#ifndef PRODUCT
350+
void PhaseIdealLoop::check_created_predicate_for_unswitching(const Node* new_entry) const {
351+
assert(new_entry != NULL, "IfTrue or IfFalse after clone predicate");
352+
if (TraceLoopPredicate) {
353+
tty->print("Loop Predicate cloned: ");
354+
debug_only(new_entry->in(0)->dump(););
355+
}
356+
}
357+
#endif
358+
359+
385360
//--------------------------skip_loop_predicates------------------------------
386361
// Skip related predicates.
387362
Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) {

src/hotspot/share/opto/loopUnswitch.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,19 +275,17 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop,
275275
register_node(iffast, outer_loop, iff, dom_depth(iff));
276276
ProjNode* ifslow = new IfFalseNode(iff);
277277
register_node(ifslow, outer_loop, iff, dom_depth(iff));
278-
uint idx_before_clone = Compile::current()->unique();
279278

280279
// Clone the loop body. The clone becomes the slow loop. The
281280
// original pre-header will (illegally) have 3 control users
282281
// (old & new loops & new if).
283282
clone_loop(loop, old_new, dom_depth(head->skip_strip_mined()), mode, iff);
284283
assert(old_new[head->_idx]->is_Loop(), "" );
285284

286-
// Fast (true) control
287-
Node* iffast_pred = clone_predicates_to_unswitched_loop(entry, iffast, !counted_loop, false, idx_before_clone, old_new);
288-
289-
// Slow (false) control
290-
Node* ifslow_pred = clone_predicates_to_unswitched_loop(entry, ifslow, !counted_loop, true, idx_before_clone, old_new);
285+
// Fast (true) and Slow (false) control
286+
ProjNode* iffast_pred = iffast;
287+
ProjNode* ifslow_pred = ifslow;
288+
clone_predicates_to_unswitched_loop(loop, old_new, iffast_pred, ifslow_pred);
291289

292290
Node* l = head->skip_strip_mined();
293291
_igvn.replace_input_of(l, LoopNode::EntryControl, iffast_pred);

src/hotspot/share/opto/loopnode.hpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,13 +1431,11 @@ class PhaseIdealLoop : public PhaseTransform {
14311431
}
14321432

14331433
// Clone loop predicates to slow and fast loop when unswitching a loop
1434-
Node* clone_predicates_to_unswitched_loop(Node* old_entry, Node* new_entry, bool clone_limit_check, bool is_slow_loop,
1435-
uint idx_before_clone, Node_List &old_new);
1436-
ProjNode* clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
1437-
bool is_slow_loop, uint idx_before_clone, Node_List &old_new);
1438-
void clone_skeleton_predicates_to_unswitched_loop(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
1439-
ProjNode* new_predicate_proj, bool is_slow_loop,
1440-
uint idx_before_clone, Node_List &old_new);
1434+
void clone_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, ProjNode*& iffast, ProjNode*& ifslow);
1435+
ProjNode* clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason);
1436+
void clone_skeleton_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, Deoptimization::DeoptReason reason,
1437+
ProjNode* old_predicate_proj, ProjNode* iffast, ProjNode* ifslow);
1438+
void check_created_predicate_for_unswitching(const Node* new_entry) const PRODUCT_RETURN;
14411439

14421440
bool _created_loop_node;
14431441
#ifdef ASSERT

0 commit comments

Comments
 (0)