Skip to content

Commit ed0b555

Browse files
committed
8344035: Replace predicate walking code in Loop Unswitching with a predicate visitor
Reviewed-by: roland, kvn
1 parent b37f123 commit ed0b555

File tree

7 files changed

+253
-216
lines changed

7 files changed

+253
-216
lines changed

src/hotspot/share/opto/loopPredicate.cpp

+8-146
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred,
100100
// is an IfTrue projection. This code is also used to clone predicates to cloned loops.
101101
IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_success_proj,
102102
Node* new_entry, const Deoptimization::DeoptReason reason,
103-
const int opcode, const bool rewire_uncommon_proj_phi_inputs,
104-
AssertionPredicateType assertion_predicate_type) {
103+
const int opcode, const bool rewire_uncommon_proj_phi_inputs) {
105104
assert(parse_predicate_success_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!");
106105
ParsePredicateNode* parse_predicate = parse_predicate_success_proj->in(0)->as_ParsePredicate();
107106
ParsePredicateUncommonProj* uncommon_proj = parse_predicate->uncommon_proj();
@@ -143,12 +142,10 @@ IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessPro
143142
IfNode* new_iff = nullptr;
144143
switch (opcode) {
145144
case Op_If:
146-
new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt
147-
NOT_PRODUCT(COMMA assertion_predicate_type));
145+
new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt);
148146
break;
149147
case Op_RangeCheck:
150-
new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt
151-
NOT_PRODUCT(COMMA assertion_predicate_type));
148+
new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt);
152149
break;
153150
case Op_ParsePredicate:
154151
new_iff = new ParsePredicateNode(entry, reason, &_igvn);
@@ -272,150 +269,15 @@ void PhaseIdealLoop::fix_cloned_data_node_controls(const ProjNode* old_uncommon_
272269
orig_to_clone.iterate_all(orig_clone_action);
273270
}
274271

275-
IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj,
276-
Node* new_entry, Deoptimization::DeoptReason reason,
277-
const bool slow_loop) {
278-
279-
IfProjNode* new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, new_entry, reason, Op_ParsePredicate,
280-
slow_loop);
281-
assert(new_predicate_proj->is_IfTrue(), "the success projection of a Parse Predicate is a true projection");
282-
ParsePredicateNode* parse_predicate = new_predicate_proj->in(0)->as_ParsePredicate();
283-
return new_predicate_proj;
284-
}
285-
286-
// Clones Template Assertion Predicates to both unswitched loops starting at 'old_predicate_proj' by following its
287-
// control inputs. It also rewires the control edges of data nodes with dependencies in the loop from the old predicates
288-
// to the new cloned predicates.
289-
void PhaseIdealLoop::clone_assertion_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new,
290-
ParsePredicateSuccessProj* old_parse_predicate_proj,
291-
ParsePredicateNode* true_path_loop_parse_predicate,
292-
ParsePredicateNode* false_path_loop_parse_predicate) {
293-
// Push the original Template Assertion Predicates on a list to later process them in reverse order to keep the
294-
// original predicate order.
295-
Unique_Node_List list;
296-
get_template_assertion_predicates(old_parse_predicate_proj, list);
297-
298-
Node_List to_process;
299-
for (int i = list.size() - 1; i >= 0; i--) {
300-
IfTrueNode* template_assertion_predicate_success_proj = list.at(i)->as_IfTrue();
301-
assert(template_assertion_predicate_success_proj->in(0)->is_If(), "must be If node");
302-
303-
IfTrueNode* true_path_loop_proj =
304-
clone_assertion_predicate_for_unswitched_loops(template_assertion_predicate_success_proj,
305-
true_path_loop_parse_predicate);
306-
IfTrueNode* false_path_loop_proj =
307-
clone_assertion_predicate_for_unswitched_loops(template_assertion_predicate_success_proj,
308-
false_path_loop_parse_predicate);
309-
310-
// Update control dependent data nodes.
311-
for (DUIterator j = template_assertion_predicate_success_proj->outs();
312-
template_assertion_predicate_success_proj->has_out(j);
313-
j++) {
314-
Node* true_path_loop_node = template_assertion_predicate_success_proj->out(j);
315-
if (loop->is_member(get_loop(ctrl_or_self(true_path_loop_node)))) {
316-
assert(true_path_loop_node->in(0) == template_assertion_predicate_success_proj, "only control edge");
317-
Node* false_path_loop_node = old_new[true_path_loop_node->_idx];
318-
assert(false_path_loop_node->in(0) == template_assertion_predicate_success_proj, "only control edge");
319-
_igvn.replace_input_of(true_path_loop_node, 0, true_path_loop_proj);
320-
to_process.push(false_path_loop_node);
321-
--j;
322-
}
323-
}
324-
// Have to delay updates to the false path loop so uses of predicate are not modified while we iterate on them.
325-
while (to_process.size() > 0) {
326-
Node* slow_node = to_process.pop();
327-
_igvn.replace_input_of(slow_node, 0, false_path_loop_proj);
328-
}
329-
}
330-
}
331-
332-
// Put all Template Assertion Predicate projections on a list, starting at 'predicate' and going up in the tree. If 'get_opaque'
333-
// is set, then the OpaqueTemplateAssertionPredicateNode nodes of the Assertion Predicates are put on the list instead
334-
// of the projections.
335-
void PhaseIdealLoop::get_template_assertion_predicates(ParsePredicateSuccessProj* parse_predicate_proj, Unique_Node_List& list,
336-
const bool get_opaque) {
272+
// Put all OpaqueTemplateAssertionPredicate nodes on a list, starting at 'predicate' and going up in the tree.
273+
void PhaseIdealLoop::get_opaque_template_assertion_predicate_nodes(ParsePredicateSuccessProj* parse_predicate_proj,
274+
Unique_Node_List& list) {
337275
Deoptimization::DeoptReason deopt_reason = parse_predicate_proj->in(0)->as_ParsePredicate()->deopt_reason();
338276
PredicateBlockIterator predicate_iterator(parse_predicate_proj, deopt_reason);
339-
TemplateAssertionPredicateCollector template_assertion_predicate_collector(list, get_opaque);
340-
predicate_iterator.for_each(template_assertion_predicate_collector);
341-
}
342-
343-
// Clone an Assertion Predicate for an unswitched loop. OpaqueLoopInit and OpaqueLoopStride nodes are cloned and uncommon
344-
// traps are kept for the predicate (a Halt node is used later when creating pre/main/post loops and copying this cloned
345-
// predicate again).
346-
IfTrueNode*
347-
PhaseIdealLoop::clone_assertion_predicate_for_unswitched_loops(IfTrueNode* template_assertion_predicate_success_proj,
348-
ParsePredicateNode* unswitched_loop_parse_predicate) {
349-
TemplateAssertionPredicate template_assertion_predicate(template_assertion_predicate_success_proj);
350-
IfTrueNode* template_success_proj = template_assertion_predicate.clone(unswitched_loop_parse_predicate->in(0), this);
351-
_igvn.replace_input_of(unswitched_loop_parse_predicate, 0, template_success_proj);
352-
set_idom(unswitched_loop_parse_predicate, template_success_proj, dom_depth(template_success_proj));
353-
return template_success_proj;
277+
OpaqueTemplateAssertionPredicateCollector opaque_template_assertion_predicate_collector(list);
278+
predicate_iterator.for_each(opaque_template_assertion_predicate_collector);
354279
}
355280

356-
// Clone the old Parse Predicates and Assertion Predicates before the unswitch If to the unswitched loops after the
357-
// unswitch If.
358-
void PhaseIdealLoop::clone_parse_and_assertion_predicates_to_unswitched_loop(IdealLoopTree* loop, Node_List& old_new,
359-
IfProjNode*& true_path_loop_entry,
360-
IfProjNode*& false_path_loop_entry) {
361-
LoopNode* head = loop->_head->as_Loop();
362-
Node* entry = head->skip_strip_mined()->in(LoopNode::EntryControl);
363-
364-
const Predicates predicates(entry);
365-
clone_loop_predication_predicates_to_unswitched_loop(loop, old_new, predicates.loop_predicate_block(),
366-
Deoptimization::Reason_predicate, true_path_loop_entry, false_path_loop_entry);
367-
clone_loop_predication_predicates_to_unswitched_loop(loop, old_new, predicates.profiled_loop_predicate_block(),
368-
Deoptimization::Reason_profile_predicate, true_path_loop_entry, false_path_loop_entry);
369-
370-
const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block();
371-
if (loop_limit_check_predicate_block->has_parse_predicate() && !head->is_CountedLoop()) {
372-
// Don't clone the Loop Limit Check Parse Predicate if we already have a counted loop (a Loop Limit Check Predicate
373-
// is only created when converting a LoopNode to a CountedLoopNode).
374-
clone_parse_predicate_to_unswitched_loops(loop_limit_check_predicate_block, Deoptimization::Reason_loop_limit_check,
375-
true_path_loop_entry, false_path_loop_entry);
376-
}
377-
}
378-
379-
// Clone the Parse Predicate and Template Assertion Predicates of a Loop Predication related Predicate Block.
380-
void PhaseIdealLoop::clone_loop_predication_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new,
381-
const PredicateBlock* predicate_block,
382-
Deoptimization::DeoptReason reason,
383-
IfProjNode*& true_path_loop_entry,
384-
IfProjNode*& false_path_loop_entry) {
385-
if (predicate_block->has_parse_predicate()) {
386-
// We currently only clone Assertion Predicates if there are Parse Predicates. This is not entirely correct and will
387-
// be changed with the complete fix for Assertion Predicates.
388-
clone_parse_predicate_to_unswitched_loops(predicate_block, reason, true_path_loop_entry, false_path_loop_entry);
389-
assert(true_path_loop_entry->in(0)->is_ParsePredicate() && false_path_loop_entry->in(0)->is_ParsePredicate(),
390-
"must be success projections of the cloned Parse Predicates");
391-
clone_assertion_predicates_to_unswitched_loop(loop, old_new, predicate_block->parse_predicate_success_proj(),
392-
true_path_loop_entry->in(0)->as_ParsePredicate(),
393-
false_path_loop_entry->in(0)->as_ParsePredicate());
394-
}
395-
}
396-
397-
void PhaseIdealLoop::clone_parse_predicate_to_unswitched_loops(const PredicateBlock* predicate_block,
398-
Deoptimization::DeoptReason reason,
399-
IfProjNode*& iffast_pred, IfProjNode*& ifslow_pred) {
400-
assert(predicate_block->has_parse_predicate(), "must have parse predicate");
401-
ParsePredicateSuccessProj* parse_predicate_proj = predicate_block->parse_predicate_success_proj();
402-
iffast_pred = clone_parse_predicate_to_unswitched_loop(parse_predicate_proj, iffast_pred, reason, false);
403-
check_cloned_parse_predicate_for_unswitching(iffast_pred, true);
404-
405-
ifslow_pred = clone_parse_predicate_to_unswitched_loop(parse_predicate_proj, ifslow_pred, reason, true);
406-
check_cloned_parse_predicate_for_unswitching(ifslow_pred, false);
407-
}
408-
409-
#ifndef PRODUCT
410-
void PhaseIdealLoop::check_cloned_parse_predicate_for_unswitching(const Node* new_entry, const bool is_fast_loop) {
411-
assert(new_entry != nullptr, "IfTrue or IfFalse after clone predicate");
412-
if (TraceLoopPredicate) {
413-
tty->print("Parse Predicate cloned to %s loop: ", is_fast_loop ? "fast" : "slow");
414-
new_entry->in(0)->dump();
415-
}
416-
}
417-
#endif
418-
419281
//------------------------------Invariance-----------------------------------
420282
// Helper class for loop_predication_impl to compute invariance on the fly and
421283
// clone invariants.

src/hotspot/share/opto/loopUnswitch.cpp

+41-27
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,47 @@ class OriginalLoop : public StackObj {
236236
_phase(loop->_phase) {}
237237
NONCOPYABLE(OriginalLoop);
238238

239+
// Unswitch the original loop on the invariant loop selector by creating a true-path-loop and a false-path-loop.
240+
// Remove the unswitch candidate If from both unswitched loop versions which are now covered by the loop selector If.
241+
void unswitch(const UnswitchedLoopSelector& unswitched_loop_selector) {
242+
const uint first_false_path_loop_node_index = _phase->C->unique();
243+
clone_loop(unswitched_loop_selector);
244+
245+
move_parse_and_template_assertion_predicates_to_unswitched_loops(unswitched_loop_selector,
246+
first_false_path_loop_node_index);
247+
DEBUG_ONLY(verify_unswitched_loop_versions(_loop->_head->as_Loop(), unswitched_loop_selector);)
248+
249+
_phase->recompute_dom_depth();
250+
remove_unswitch_candidate_from_loops(unswitched_loop_selector);
251+
}
252+
239253
private:
240-
void fix_loop_entries(IfProjNode* true_path_loop_entry, IfProjNode* false_path_loop_entry) {
241-
_phase->replace_loop_entry(_loop_head, true_path_loop_entry);
254+
void clone_loop(const UnswitchedLoopSelector& unswitched_loop_selector) {
255+
_phase->clone_loop(_loop, _old_new, _phase->dom_depth(_loop_head),
256+
PhaseIdealLoop::CloneIncludesStripMined, unswitched_loop_selector.selector());
257+
fix_loop_entries(unswitched_loop_selector);
258+
}
259+
260+
void fix_loop_entries(const UnswitchedLoopSelector& unswitched_loop_selector) {
261+
_phase->replace_loop_entry(_loop_head, unswitched_loop_selector.true_path_loop_proj());
242262
LoopNode* false_path_loop_strip_mined_head = old_to_new(_loop_head)->as_Loop();
243-
_phase->replace_loop_entry(false_path_loop_strip_mined_head, false_path_loop_entry);
263+
_phase->replace_loop_entry(false_path_loop_strip_mined_head,
264+
unswitched_loop_selector.false_path_loop_proj());
244265
}
245266

246-
Node* old_to_new(const Node* old) const {
247-
return _old_new[old->_idx];
267+
// Moves the Parse And Template Assertion Predicates to the true and false path loop. They are inserted between the
268+
// loop heads and the loop selector If projections. The old Parse and Template Assertion Predicates before
269+
// the unswitched loop selector are killed.
270+
void move_parse_and_template_assertion_predicates_to_unswitched_loops(
271+
const UnswitchedLoopSelector& unswitched_loop_selector, const uint first_false_path_loop_node_index) const {
272+
const NodeInOriginalLoopBody node_in_true_path_loop_body(first_false_path_loop_node_index, _old_new);
273+
const NodeInClonedLoopBody node_in_false_path_loop_body(first_false_path_loop_node_index);
274+
CloneUnswitchedLoopPredicatesVisitor
275+
clone_unswitched_loop_predicates_visitor(_loop_head, old_to_new(_loop_head)->as_Loop(), node_in_true_path_loop_body,
276+
node_in_false_path_loop_body, _phase);
277+
Node* source_loop_entry = unswitched_loop_selector.selector()->in(0);
278+
PredicateIterator predicate_iterator(source_loop_entry);
279+
predicate_iterator.for_each(clone_unswitched_loop_predicates_visitor);
248280
}
249281

250282
#ifdef ASSERT
@@ -263,6 +295,10 @@ class OriginalLoop : public StackObj {
263295
}
264296
#endif // ASSERT
265297

298+
Node* old_to_new(const Node* old) const {
299+
return _old_new[old->_idx];
300+
}
301+
266302
// Remove the unswitch candidate If nodes in both unswitched loop versions which are now dominated by the loop selector
267303
// If node. Keep the true-path-path in the true-path-loop and the false-path-path in the false-path-loop by setting
268304
// the bool input accordingly. The unswitch candidate If nodes are folded in the next IGVN round.
@@ -276,28 +312,6 @@ class OriginalLoop : public StackObj {
276312
_phase->dominated_by(unswitched_loop_selector.false_path_loop_proj(), unswitching_candidate_clone);
277313
}
278314

279-
public:
280-
// Unswitch the original loop on the invariant loop selector by creating a true-path-loop and a false-path-loop.
281-
// Remove the unswitch candidate If from both unswitched loop versions which are now covered by the loop selector If.
282-
void unswitch(const UnswitchedLoopSelector& unswitched_loop_selector) {
283-
_phase->clone_loop(_loop, _old_new, _phase->dom_depth(_loop_head),
284-
PhaseIdealLoop::CloneIncludesStripMined, unswitched_loop_selector.selector());
285-
286-
// At this point, the selector If projections are the corresponding loop entries.
287-
// clone_parse_and_assertion_predicates_to_unswitched_loop() could clone additional predicates after the selector
288-
// If projections. The loop entries are updated accordingly.
289-
IfProjNode* true_path_loop_entry = unswitched_loop_selector.true_path_loop_proj();
290-
IfProjNode* false_path_loop_entry = unswitched_loop_selector.false_path_loop_proj();
291-
_phase->clone_parse_and_assertion_predicates_to_unswitched_loop(_loop, _old_new,
292-
true_path_loop_entry, false_path_loop_entry);
293-
294-
fix_loop_entries(true_path_loop_entry, false_path_loop_entry);
295-
296-
DEBUG_ONLY(verify_unswitched_loop_versions(_loop->_head->as_Loop(), unswitched_loop_selector);)
297-
298-
_phase->recompute_dom_depth();
299-
remove_unswitch_candidate_from_loops(unswitched_loop_selector);
300-
}
301315
};
302316

303317
// See comments below file header for more information about Loop Unswitching.

src/hotspot/share/opto/loopnode.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -4458,15 +4458,15 @@ void PhaseIdealLoop::collect_useful_template_assertion_predicates_for_loop(Ideal
44584458
const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block();
44594459
if (profiled_loop_predicate_block->has_parse_predicate()) {
44604460
ParsePredicateSuccessProj* parse_predicate_proj = profiled_loop_predicate_block->parse_predicate_success_proj();
4461-
get_template_assertion_predicates(parse_predicate_proj, useful_predicates, true);
4461+
get_opaque_template_assertion_predicate_nodes(parse_predicate_proj, useful_predicates);
44624462
}
44634463
}
44644464

44654465
if (UseLoopPredicate) {
44664466
const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block();
44674467
if (loop_predicate_block->has_parse_predicate()) {
44684468
ParsePredicateSuccessProj* parse_predicate_proj = loop_predicate_block->parse_predicate_success_proj();
4469-
get_template_assertion_predicates(parse_predicate_proj, useful_predicates, true);
4469+
get_opaque_template_assertion_predicate_nodes(parse_predicate_proj, useful_predicates);
44704470
}
44714471
}
44724472
}

0 commit comments

Comments
 (0)