Skip to content

Commit 3fba170

Browse files
committedOct 9, 2024
8340786: Introduce Predicate classes with predicate iterators and visitors for simplified walking
Reviewed-by: roland, thartmann
1 parent 047c2d7 commit 3fba170

File tree

4 files changed

+504
-146
lines changed

4 files changed

+504
-146
lines changed
 

‎src/hotspot/share/opto/loopTransform.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,8 @@ IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* templ
14641464
Node* new_stride, Node* control) {
14651465
assert(assertion_predicate_has_loop_opaque_node(template_assertion_predicate),
14661466
"must find OpaqueLoop* nodes for Template Assertion Predicate");
1467-
InitializedAssertionPredicate initialized_assertion_predicate(template_assertion_predicate, new_init, new_stride, this);
1467+
InitializedAssertionPredicateCreator initialized_assertion_predicate(template_assertion_predicate, new_init,
1468+
new_stride, this);
14681469
IfTrueNode* success_proj = initialized_assertion_predicate.create(control);
14691470
assert(!assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()),
14701471
"Initialized Assertion Predicates do not have OpaqueLoop* nodes in the bool expression anymore");

‎src/hotspot/share/opto/loopnode.cpp

+54-13
Original file line numberDiff line numberDiff line change
@@ -4339,13 +4339,21 @@ void PhaseIdealLoop::mark_loop_associated_parse_predicates_useful() {
43394339
}
43404340
}
43414341

4342+
// This visitor marks all visited Parse Predicates useful.
4343+
class ParsePredicateUsefulMarker : public PredicateVisitor {
4344+
public:
4345+
using PredicateVisitor::visit;
4346+
4347+
void visit(const ParsePredicate& parse_predicate) override {
4348+
parse_predicate.head()->mark_useful();
4349+
}
4350+
};
4351+
43424352
void PhaseIdealLoop::mark_useful_parse_predicates_for_loop(IdealLoopTree* loop) {
43434353
Node* entry = loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl);
4344-
const Predicates predicates(entry);
4345-
ParsePredicateIterator iterator(predicates);
4346-
while (iterator.has_next()) {
4347-
iterator.next()->mark_useful();
4348-
}
4354+
const PredicateIterator predicate_iterator(entry);
4355+
ParsePredicateUsefulMarker useful_marker;
4356+
predicate_iterator.for_each(useful_marker);
43494357
}
43504358

43514359
void PhaseIdealLoop::add_useless_parse_predicates_to_igvn_worklist() {
@@ -6289,6 +6297,43 @@ void PhaseIdealLoop::build_loop_late_post(Node *n) {
62896297
build_loop_late_post_work(n, true);
62906298
}
62916299

6300+
// Class to visit all predicates in a predicate chain to find out which are dominated by a given node. Keeps track of
6301+
// the entry to the earliest predicate that is still dominated by the given dominator. This class is used when trying to
6302+
// legally skip all predicates when figuring out the latest placement such that a node does not interfere with Loop
6303+
// Predication or creating a Loop Limit Check Predicate later.
6304+
class DominatedPredicates : public UnifiedPredicateVisitor {
6305+
Node* const _dominator;
6306+
Node* _earliest_dominated_predicate_entry;
6307+
bool _should_continue;
6308+
PhaseIdealLoop* const _phase;
6309+
6310+
public:
6311+
DominatedPredicates(Node* dominator, Node* start_node, PhaseIdealLoop* phase)
6312+
: _dominator(dominator),
6313+
_earliest_dominated_predicate_entry(start_node),
6314+
_should_continue(true),
6315+
_phase(phase) {}
6316+
NONCOPYABLE(DominatedPredicates);
6317+
6318+
bool should_continue() const override {
6319+
return _should_continue;
6320+
}
6321+
6322+
// Returns the entry to the earliest predicate that is still dominated by the given dominator (all could be dominated).
6323+
Node* earliest_dominated_predicate_entry() const {
6324+
return _earliest_dominated_predicate_entry;
6325+
}
6326+
6327+
void visit_predicate(const Predicate& predicate) override {
6328+
Node* entry = predicate.entry();
6329+
if (_phase->is_strict_dominator(entry, _dominator)) {
6330+
_should_continue = false;
6331+
} else {
6332+
_earliest_dominated_predicate_entry = entry;
6333+
}
6334+
}
6335+
};
6336+
62926337
void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
62936338

62946339
if (n->req() == 2 && (n->Opcode() == Op_ConvI2L || n->Opcode() == Op_CastII) && !C->major_progress() && !_verify_only) {
@@ -6400,14 +6445,10 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
64006445
// Move the node above predicates as far up as possible so a
64016446
// following pass of Loop Predication doesn't hoist a predicate
64026447
// that depends on it above that node.
6403-
PredicateEntryIterator predicate_iterator(least);
6404-
while (predicate_iterator.has_next()) {
6405-
Node* next_predicate_entry = predicate_iterator.next_entry();
6406-
if (is_strict_dominator(next_predicate_entry, early)) {
6407-
break;
6408-
}
6409-
least = next_predicate_entry;
6410-
}
6448+
const PredicateIterator predicate_iterator(least);
6449+
DominatedPredicates dominated_predicates(early, least, this);
6450+
predicate_iterator.for_each(dominated_predicates);
6451+
least = dominated_predicates.earliest_dominated_predicate_entry();
64116452
}
64126453
// Try not to place code on a loop entry projection
64136454
// which can inhibit range check elimination.

‎src/hotspot/share/opto/predicates.cpp

+88-71
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,6 @@ ParsePredicateNode* ParsePredicate::init_parse_predicate(Node* parse_predicate_p
7373
return nullptr;
7474
}
7575

76-
bool ParsePredicate::is_predicate(Node* maybe_success_proj) {
77-
if (!maybe_success_proj->is_IfProj()) {
78-
return false;
79-
}
80-
IfNode* if_node = maybe_success_proj->in(0)->as_If();
81-
return if_node->is_ParsePredicate();
82-
}
83-
8476
Deoptimization::DeoptReason RegularPredicateWithUCT::uncommon_trap_reason(IfProjNode* if_proj) {
8577
CallStaticJavaNode* uct_call = if_proj->is_uncommon_trap_if_pattern();
8678
if (uct_call == nullptr) {
@@ -90,27 +82,31 @@ Deoptimization::DeoptReason RegularPredicateWithUCT::uncommon_trap_reason(IfProj
9082
}
9183

9284
bool RegularPredicateWithUCT::is_predicate(Node* maybe_success_proj) {
93-
if (may_be_predicate_if(maybe_success_proj)) {
94-
IfProjNode* success_proj = maybe_success_proj->as_IfProj();
95-
const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj);
96-
return (deopt_reason == Deoptimization::Reason_loop_limit_check ||
97-
deopt_reason == Deoptimization::Reason_predicate ||
98-
deopt_reason == Deoptimization::Reason_profile_predicate);
85+
if (RegularPredicate::may_be_predicate_if(maybe_success_proj)) {
86+
return has_valid_uncommon_trap(maybe_success_proj);
9987
} else {
10088
return false;
10189
}
10290
}
10391

104-
bool RegularPredicateWithUCT::is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason) {
105-
if (may_be_predicate_if(node)) {
92+
bool RegularPredicateWithUCT::has_valid_uncommon_trap(const Node* success_proj) {
93+
assert(RegularPredicate::may_be_predicate_if(success_proj), "must have been checked before");
94+
const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj->as_IfProj());
95+
return (deopt_reason == Deoptimization::Reason_loop_limit_check ||
96+
deopt_reason == Deoptimization::Reason_predicate ||
97+
deopt_reason == Deoptimization::Reason_profile_predicate);
98+
}
99+
100+
bool RegularPredicateWithUCT::is_predicate(const Node* node, Deoptimization::DeoptReason deopt_reason) {
101+
if (RegularPredicate::may_be_predicate_if(node)) {
106102
return deopt_reason == uncommon_trap_reason(node->as_IfProj());
107103
} else {
108104
return false;
109105
}
110106
}
111107

112-
// A Runtime Predicate must have an If or a RangeCheck node, while the If should not be a zero trip guard check.
113-
bool RegularPredicateWithUCT::may_be_predicate_if(Node* node) {
108+
// A Regular Predicate must have an If or a RangeCheck node, while the If should not be a zero trip guard check.
109+
bool RegularPredicate::may_be_predicate_if(const Node* node) {
114110
if (node->is_IfProj()) {
115111
const IfNode* if_node = node->in(0)->as_If();
116112
const int opcode_if = if_node->Opcode();
@@ -122,39 +118,43 @@ bool RegularPredicateWithUCT::may_be_predicate_if(Node* node) {
122118
return false;
123119
}
124120

125-
bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason) {
121+
// Runtime Predicates always have an UCT since they could normally fail at runtime. In this case we execute the trap
122+
// on the failing path.
123+
bool RuntimePredicate::is_predicate(Node* node) {
124+
return RegularPredicateWithUCT::is_predicate(node);
125+
}
126+
127+
bool RuntimePredicate::is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason) {
126128
return RegularPredicateWithUCT::is_predicate(node, deopt_reason);
127129
}
128130

129-
ParsePredicateIterator::ParsePredicateIterator(const Predicates& predicates) : _current_index(0) {
130-
const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block();
131-
if (loop_limit_check_predicate_block->has_parse_predicate()) {
132-
_parse_predicates.push(loop_limit_check_predicate_block->parse_predicate());
133-
}
134-
if (UseProfiledLoopPredicate) {
135-
const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block();
136-
if (profiled_loop_predicate_block->has_parse_predicate()) {
137-
_parse_predicates.push(profiled_loop_predicate_block->parse_predicate());
138-
}
131+
// A Template Assertion Predicate has an If/RangeCheckNode and either an UCT or a halt node depending on where it
132+
// was created.
133+
bool TemplateAssertionPredicate::is_predicate(Node* node) {
134+
if (!RegularPredicate::may_be_predicate_if(node)) {
135+
return false;
139136
}
140-
if (UseLoopPredicate) {
141-
const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block();
142-
if (loop_predicate_block->has_parse_predicate()) {
143-
_parse_predicates.push(loop_predicate_block->parse_predicate());
144-
}
137+
IfNode* if_node = node->in(0)->as_If();
138+
if (if_node->in(1)->is_Opaque4()) {
139+
return RegularPredicateWithUCT::has_valid_uncommon_trap(node) || AssertionPredicateWithHalt::has_halt(node);
145140
}
141+
return false;
146142
}
147143

148-
ParsePredicateNode* ParsePredicateIterator::next() {
149-
assert(has_next(), "always check has_next() first");
150-
return _parse_predicates.at(_current_index++);
144+
// Initialized Assertion Predicates always have the dedicated opaque node and a halt node.
145+
bool InitializedAssertionPredicate::is_predicate(Node* node) {
146+
if (!AssertionPredicateWithHalt::is_predicate(node)) {
147+
return false;
148+
}
149+
IfNode* if_node = node->in(0)->as_If();
150+
return if_node->in(1)->is_OpaqueInitializedAssertionPredicate();
151151
}
152152

153153
#ifdef ASSERT
154154
// Check that the block has at most one Parse Predicate and that we only find Regular Predicate nodes (i.e. IfProj,
155155
// If, or RangeCheck nodes).
156-
void PredicateBlock::verify_block() {
157-
Node* next = _parse_predicate.entry(); // Skip unique Parse Predicate of this block if present
156+
void RegularPredicateBlock::verify_block(Node* tail) {
157+
Node* next = tail;
158158
while (next != _entry) {
159159
assert(!next->is_ParsePredicate(), "can only have one Parse Predicate in a block");
160160
const int opcode = next->Opcode();
@@ -166,17 +166,6 @@ void PredicateBlock::verify_block() {
166166
}
167167
#endif // ASSERT
168168

169-
// Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block
170-
// anymore (i.e. entry to the first Regular Predicate in this block if any or `regular_predicate_proj` otherwise).
171-
Node* PredicateBlock::skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason) {
172-
Node* entry = regular_predicate_proj;
173-
while (RuntimePredicate::is_success_proj(entry, deopt_reason)) {
174-
assert(entry->in(0)->as_If(), "must be If node");
175-
entry = entry->in(0)->in(0);
176-
}
177-
return entry;
178-
}
179-
180169
// This strategy clones the OpaqueLoopInit and OpaqueLoopStride nodes.
181170
class CloneStrategy : public TransformStrategyForOpaqueLoopNodes {
182171
PhaseIdealLoop* const _phase;
@@ -381,8 +370,8 @@ bool TemplateAssertionExpressionNode::is_template_assertion_predicate(Node* node
381370
return node->is_If() && node->in(1)->is_Opaque4();
382371
}
383372

384-
InitializedAssertionPredicate::InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init,
385-
Node* new_stride, PhaseIdealLoop* phase)
373+
InitializedAssertionPredicateCreator::InitializedAssertionPredicateCreator(IfNode* template_assertion_predicate, Node* new_init,
374+
Node* new_stride, PhaseIdealLoop* phase)
386375
: _template_assertion_predicate(template_assertion_predicate),
387376
_new_init(new_init),
388377
_new_stride(new_stride),
@@ -408,7 +397,7 @@ InitializedAssertionPredicate::InitializedAssertionPredicate(IfNode* template_as
408397
// success fail path new success new Halt
409398
// proj (Halt or UCT) proj
410399
//
411-
IfTrueNode* InitializedAssertionPredicate::create(Node* control) {
400+
IfTrueNode* InitializedAssertionPredicateCreator::create(Node* control) {
412401
IdealLoopTree* loop = _phase->get_loop(control);
413402
OpaqueInitializedAssertionPredicateNode* assertion_expression = create_assertion_expression(control);
414403
IfNode* if_node = create_if_node(control, assertion_expression, loop);
@@ -417,7 +406,7 @@ IfTrueNode* InitializedAssertionPredicate::create(Node* control) {
417406
}
418407

419408
// Create a new Assertion Expression to be used as bool input for the Initialized Assertion Predicate IfNode.
420-
OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicate::create_assertion_expression(Node* control) {
409+
OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicateCreator::create_assertion_expression(Node* control) {
421410
Opaque4Node* template_opaque = _template_assertion_predicate->in(1)->as_Opaque4();
422411
TemplateAssertionExpression template_assertion_expression(template_opaque);
423412
Opaque4Node* tmp_opaque = template_assertion_expression.clone_and_replace_init_and_stride(_new_init, _new_stride,
@@ -428,9 +417,9 @@ OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicate::create_a
428417
return assertion_expression;
429418
}
430419

431-
IfNode* InitializedAssertionPredicate::create_if_node(Node* control,
432-
OpaqueInitializedAssertionPredicateNode* assertion_expression,
433-
IdealLoopTree* loop) {
420+
IfNode* InitializedAssertionPredicateCreator::create_if_node(Node* control,
421+
OpaqueInitializedAssertionPredicateNode* assertion_expression,
422+
IdealLoopTree* loop) {
434423
const int if_opcode = _template_assertion_predicate->Opcode();
435424
NOT_PRODUCT(const AssertionPredicateType assertion_predicate_type = _template_assertion_predicate->assertion_predicate_type();)
436425
IfNode* if_node = if_opcode == Op_If ?
@@ -440,19 +429,19 @@ IfNode* InitializedAssertionPredicate::create_if_node(Node* control,
440429
return if_node;
441430
}
442431

443-
IfTrueNode* InitializedAssertionPredicate::create_success_path(IfNode* if_node, IdealLoopTree* loop) {
432+
IfTrueNode* InitializedAssertionPredicateCreator::create_success_path(IfNode* if_node, IdealLoopTree* loop) {
444433
IfTrueNode* success_proj = new IfTrueNode(if_node);
445434
_phase->register_control(success_proj, loop, if_node);
446435
return success_proj;
447436
}
448437

449-
void InitializedAssertionPredicate::create_fail_path(IfNode* if_node, IdealLoopTree* loop) {
438+
void InitializedAssertionPredicateCreator::create_fail_path(IfNode* if_node, IdealLoopTree* loop) {
450439
IfFalseNode* fail_proj = new IfFalseNode(if_node);
451440
_phase->register_control(fail_proj, loop, if_node);
452441
create_halt_node(fail_proj, loop);
453442
}
454443

455-
void InitializedAssertionPredicate::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop) {
444+
void InitializedAssertionPredicateCreator::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop) {
456445
StartNode* start_node = _phase->C->start();
457446
Node* frame = new ParmNode(start_node, TypeFunc::FramePtr);
458447
_phase->register_new_node(frame, start_node);
@@ -461,17 +450,45 @@ void InitializedAssertionPredicate::create_halt_node(IfFalseNode* fail_proj, Ide
461450
_phase->register_control(halt, loop, fail_proj);
462451
}
463452

464-
// Is current node pointed to by iterator a predicate?
465-
bool PredicateEntryIterator::has_next() const {
466-
return ParsePredicate::is_predicate(_current) ||
467-
RegularPredicateWithUCT::is_predicate(_current) ||
468-
AssertionPredicateWithHalt::is_predicate(_current);
453+
#ifndef PRODUCT
454+
void PredicateBlock::dump() const {
455+
dump("");
456+
}
457+
458+
void PredicateBlock::dump(const char* prefix) const {
459+
if (is_non_empty()) {
460+
PredicatePrinter printer(prefix);
461+
PredicateBlockIterator iterator(_tail, _deopt_reason);
462+
iterator.for_each(printer);
463+
} else {
464+
tty->print_cr("%s- <empty>", prefix);
465+
}
466+
}
467+
468+
// Dumps all predicates from the loop to the earliest predicate in a pretty format.
469+
void Predicates::dump() const {
470+
if (has_any()) {
471+
Node* loop_head = _tail->unique_ctrl_out();
472+
tty->print_cr("%d %s:", loop_head->_idx, loop_head->Name());
473+
tty->print_cr("- Loop Limit Check Predicate Block:");
474+
_loop_limit_check_predicate_block.dump(" ");
475+
tty->print_cr("- Profiled Loop Predicate Block:");
476+
_profiled_loop_predicate_block.dump(" ");
477+
tty->print_cr("- Loop Predicate Block:");
478+
_loop_predicate_block.dump(" ");
479+
tty->cr();
480+
} else {
481+
tty->print_cr("<no predicates>");
482+
}
483+
}
484+
485+
void Predicates::dump_at(Node* node) {
486+
Predicates predicates(node);
487+
predicates.dump();
469488
}
470489

471-
// Skip the current predicate pointed to by iterator by returning the input into the predicate. This could possibly be
472-
// a non-predicate node.
473-
Node* PredicateEntryIterator::next_entry() {
474-
assert(has_next(), "current must be predicate");
475-
_current = _current->in(0)->in(0);
476-
return _current;
490+
// Debug method to dump all predicates that are found above 'loop_node'.
491+
void Predicates::dump_for_loop(LoopNode* loop_node) {
492+
dump_at(loop_node->skip_strip_mined()->in(LoopNode::EntryControl));
477493
}
494+
#endif // NOT PRODUCT

‎src/hotspot/share/opto/predicates.hpp

+360-61
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
#include "opto/opaquenode.hpp"
3131

3232
class IdealLoopTree;
33+
class InitializedAssertionPredicate;
34+
class ParsePredicate;
35+
class PredicateVisitor;
36+
class RuntimePredicate;
37+
class TemplateAssertionPredicate;
3338

3439
/*
3540
* There are different kinds of predicates throughout the code. We differentiate between the following predicates:
@@ -152,7 +157,8 @@ class IdealLoopTree;
152157
* together.
153158
* - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit
154159
* Predicate Block: Check Parse Predicate (if not removed, yet) together.
155-
*
160+
* - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the
161+
* Parse Predicate.
156162
*
157163
* Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication
158164
* (predicates inside square brackets [] do not need to exist if there are no checks to hoist):
@@ -205,6 +211,41 @@ enum class AssertionPredicateType {
205211
};
206212
#endif // NOT PRODUCT
207213

214+
// Interface to represent a C2 predicate. A predicate is always represented by two CFG nodes:
215+
// - An If node (head)
216+
// - An IfProj node representing the success projection of the If node (tail).
217+
class Predicate : public StackObj {
218+
public:
219+
// Return the unique entry CFG node into the predicate.
220+
virtual Node* entry() const = 0;
221+
222+
// Return the head node of the predicate which is either:
223+
// - A ParsePredicateNode if the predicate is a Parse Predicate
224+
// - An IfNode or RangeCheckNode, otherwise.
225+
virtual IfNode* head() const = 0;
226+
227+
// Return the tail node of the predicate. Runtime Predicates can either have a true of false projection as success
228+
// projection while Parse Predicates and Assertion Predicates always have a true projection as success projection.
229+
virtual IfProjNode* tail() const = 0;
230+
};
231+
232+
// Generic predicate visitor that does nothing. Subclass this visitor to add customized actions for each predicate.
233+
// The visit methods of this visitor are called from the predicate iterator classes which walk the predicate chain.
234+
// Use the UnifiedPredicateVisitor if the type of the predicate does not matter.
235+
class PredicateVisitor : StackObj {
236+
public:
237+
virtual void visit(const ParsePredicate& parse_predicate) {}
238+
virtual void visit(const RuntimePredicate& runtime_predicate) {}
239+
virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) {}
240+
virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) {}
241+
242+
// This method can be overridden to stop the predicate iterators from visiting more predicates further up in the
243+
// predicate chain.
244+
virtual bool should_continue() const {
245+
return true;
246+
}
247+
};
248+
208249
// Class to represent Assertion Predicates with a HaltNode instead of an UCT (i.e. either an Initialized Assertion
209250
// Predicate or a Template Assertion Predicate created after the initial one at Loop Predication).
210251
class AssertionPredicatesWithHalt : public StackObj {
@@ -228,9 +269,15 @@ class AssertionPredicatesWithHalt : public StackObj {
228269
// Note that all other Regular Predicates have an UCT node.
229270
class AssertionPredicateWithHalt : public StackObj {
230271
static bool has_assertion_predicate_opaque(const Node* predicate_proj);
231-
static bool has_halt(const Node* success_proj);
232272
public:
233273
static bool is_predicate(const Node* maybe_success_proj);
274+
static bool has_halt(const Node* success_proj);
275+
};
276+
277+
// Utility class representing a Regular Predicate which is either a Runtime Predicate or an Assertion Predicate.
278+
class RegularPredicate : public StackObj {
279+
public:
280+
static bool may_be_predicate_if(const Node* node);
234281
};
235282

236283
// Class to represent a single Regular Predicate with an UCT. This could either be:
@@ -239,15 +286,15 @@ class AssertionPredicateWithHalt : public StackObj {
239286
// Note that all other Regular Predicates have a Halt node.
240287
class RegularPredicateWithUCT : public StackObj {
241288
static Deoptimization::DeoptReason uncommon_trap_reason(IfProjNode* if_proj);
242-
static bool may_be_predicate_if(Node* node);
243289

244290
public:
245291
static bool is_predicate(Node* maybe_success_proj);
246-
static bool is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason);
292+
static bool is_predicate(const Node* node, Deoptimization::DeoptReason deopt_reason);
293+
static bool has_valid_uncommon_trap(const Node* success_proj);
247294
};
248295

249296
// Class to represent a Parse Predicate.
250-
class ParsePredicate : public StackObj {
297+
class ParsePredicate : public Predicate {
251298
ParsePredicateSuccessProj* _success_proj;
252299
ParsePredicateNode* _parse_predicate_node;
253300
Node* _entry;
@@ -267,7 +314,7 @@ class ParsePredicate : public StackObj {
267314

268315
// Returns the control input node into this Parse Predicate if it is valid. Otherwise, it returns the passed node
269316
// into the constructor of this class.
270-
Node* entry() const {
317+
Node* entry() const override {
271318
return _entry;
272319
}
273320

@@ -277,23 +324,102 @@ class ParsePredicate : public StackObj {
277324
return _parse_predicate_node != nullptr;
278325
}
279326

280-
ParsePredicateNode* node() const {
327+
ParsePredicateNode* head() const override {
281328
assert(is_valid(), "must be valid");
282329
return _parse_predicate_node;
283330
}
284331

285-
ParsePredicateSuccessProj* success_proj() const {
332+
ParsePredicateSuccessProj* tail() const override {
286333
assert(is_valid(), "must be valid");
287334
return _success_proj;
288335
}
336+
};
337+
338+
// Class to represent a Runtime Predicate which always has an associated UCT on the failing path.
339+
class RuntimePredicate : public Predicate {
340+
IfProjNode* _success_proj;
341+
IfNode* _if_node;
342+
343+
public:
344+
explicit RuntimePredicate(IfProjNode* success_proj)
345+
: _success_proj(success_proj),
346+
_if_node(success_proj->in(0)->as_If()) {
347+
assert(is_predicate(success_proj), "must be valid");
348+
}
349+
NONCOPYABLE(RuntimePredicate);
289350

351+
private:
290352
static bool is_predicate(Node* maybe_success_proj);
353+
354+
public:
355+
Node* entry() const override {
356+
return _if_node->in(0);
357+
}
358+
359+
IfNode* head() const override {
360+
return _if_node;
361+
}
362+
363+
IfProjNode* tail() const override {
364+
return _success_proj;
365+
}
366+
367+
static bool is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason);
291368
};
292369

293-
// Utility class for queries on Runtime Predicates.
294-
class RuntimePredicate : public StackObj {
370+
// Class to represent a Template Assertion Predicate.
371+
class TemplateAssertionPredicate : public Predicate {
372+
IfTrueNode* _success_proj;
373+
IfNode* _if_node;
374+
295375
public:
296-
static bool is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason);
376+
explicit TemplateAssertionPredicate(IfTrueNode* success_proj)
377+
: _success_proj(success_proj),
378+
_if_node(success_proj->in(0)->as_If()) {
379+
assert(is_predicate(success_proj), "must be valid");
380+
}
381+
382+
Node* entry() const override {
383+
return _if_node->in(0);
384+
}
385+
386+
IfNode* head() const override {
387+
return _if_node;
388+
}
389+
390+
IfTrueNode* tail() const override {
391+
return _success_proj;
392+
}
393+
394+
static bool is_predicate(Node* node);
395+
};
396+
397+
// Class to represent an Initialized Assertion Predicate which always has a halt node on the failing path.
398+
// This predicate should never fail at runtime by design.
399+
class InitializedAssertionPredicate : public Predicate {
400+
IfTrueNode* _success_proj;
401+
IfNode* _if_node;
402+
403+
public:
404+
explicit InitializedAssertionPredicate(IfTrueNode* success_proj)
405+
: _success_proj(success_proj),
406+
_if_node(success_proj->in(0)->as_If()) {
407+
assert(is_predicate(success_proj), "must be valid");
408+
}
409+
410+
Node* entry() const override {
411+
return _if_node->in(0);
412+
}
413+
414+
IfNode* head() const override {
415+
return _if_node;
416+
}
417+
418+
IfTrueNode* tail() const override {
419+
return _success_proj;
420+
}
421+
422+
static bool is_predicate(Node* node);
297423
};
298424

299425
// Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Expression.
@@ -395,16 +521,16 @@ class TemplateAssertionExpressionNode : public StackObj {
395521
};
396522

397523
// This class creates a new Initialized Assertion Predicate.
398-
class InitializedAssertionPredicate : public StackObj {
524+
class InitializedAssertionPredicateCreator : public StackObj {
399525
IfNode* const _template_assertion_predicate;
400526
Node* const _new_init;
401527
Node* const _new_stride;
402528
PhaseIdealLoop* const _phase;
403529

404530
public:
405-
InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride,
406-
PhaseIdealLoop* phase);
407-
NONCOPYABLE(InitializedAssertionPredicate);
531+
InitializedAssertionPredicateCreator(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride,
532+
PhaseIdealLoop* phase);
533+
NONCOPYABLE(InitializedAssertionPredicateCreator);
408534

409535
IfTrueNode* create(Node* control);
410536

@@ -416,23 +542,208 @@ class InitializedAssertionPredicate : public StackObj {
416542
IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop);
417543
};
418544

545+
// This class iterates through all predicates of a Regular Predicate Block and applies the given visitor to each.
546+
class RegularPredicateBlockIterator : public StackObj {
547+
Node* const _start_node;
548+
const Deoptimization::DeoptReason _deopt_reason;
549+
550+
public:
551+
RegularPredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason)
552+
: _start_node(start_node),
553+
_deopt_reason(deopt_reason) {}
554+
NONCOPYABLE(RegularPredicateBlockIterator);
555+
556+
// Skip all predicates by just following the inputs. We do not call any user provided visitor.
557+
Node* skip_all() const {
558+
PredicateVisitor do_nothing; // No real visits, just do nothing.
559+
return for_each(do_nothing);
560+
}
561+
562+
// Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
563+
// Returns the entry to the earliest predicate.
564+
Node* for_each(PredicateVisitor& predicate_visitor) const {
565+
Node* current = _start_node;
566+
while (predicate_visitor.should_continue()) {
567+
if (TemplateAssertionPredicate::is_predicate(current)) {
568+
TemplateAssertionPredicate template_assertion_predicate(current->as_IfTrue());
569+
predicate_visitor.visit(template_assertion_predicate);
570+
current = template_assertion_predicate.entry();
571+
} else if (RuntimePredicate::is_predicate(current, _deopt_reason)) {
572+
RuntimePredicate runtime_predicate(current->as_IfProj());
573+
predicate_visitor.visit(runtime_predicate);
574+
current = runtime_predicate.entry();
575+
} else if (InitializedAssertionPredicate::is_predicate(current)) {
576+
InitializedAssertionPredicate initialized_assertion_predicate(current->as_IfTrue());
577+
predicate_visitor.visit(initialized_assertion_predicate);
578+
current = initialized_assertion_predicate.entry();
579+
} else {
580+
// Either a Parse Predicate or not a Regular Predicate. In both cases, the node does not belong to this block.
581+
break;
582+
}
583+
}
584+
return current;
585+
}
586+
};
587+
588+
// This class iterates through all predicates of a Predicate Block and applies the given visitor to each.
589+
class PredicateBlockIterator : public StackObj {
590+
Node* const _start_node;
591+
const ParsePredicate _parse_predicate; // Could be missing.
592+
const RegularPredicateBlockIterator _regular_predicate_block_iterator;
593+
594+
public:
595+
PredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason)
596+
: _start_node(start_node),
597+
_parse_predicate(start_node, deopt_reason),
598+
_regular_predicate_block_iterator(_parse_predicate.entry(), deopt_reason) {}
599+
600+
// Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
601+
// Returns the entry to the earliest predicate.
602+
Node* for_each(PredicateVisitor& predicate_visitor) const {
603+
if (!predicate_visitor.should_continue()) {
604+
return _start_node;
605+
}
606+
if (_parse_predicate.is_valid()) {
607+
predicate_visitor.visit(_parse_predicate);
608+
}
609+
return _regular_predicate_block_iterator.for_each(predicate_visitor);
610+
}
611+
};
612+
613+
// Class to walk over all predicates starting at a node, which usually is the loop entry node, and following the inputs.
614+
// At each predicate, a PredicateVisitor is applied which the user can implement freely.
615+
class PredicateIterator : public StackObj {
616+
Node* _start_node;
617+
618+
public:
619+
explicit PredicateIterator(Node* start_node)
620+
: _start_node(start_node) {}
621+
NONCOPYABLE(PredicateIterator);
622+
623+
// Apply the 'predicate_visitor' for each predicate found in the predicate chain started at the provided node.
624+
// Returns the entry to the earliest predicate.
625+
Node* for_each(PredicateVisitor& predicate_visitor) const {
626+
Node* current = _start_node;
627+
PredicateBlockIterator loop_limit_check_predicate_iterator(current, Deoptimization::Reason_loop_limit_check);
628+
current = loop_limit_check_predicate_iterator.for_each(predicate_visitor);
629+
PredicateBlockIterator profiled_loop_predicate_iterator(current, Deoptimization::Reason_profile_predicate);
630+
current = profiled_loop_predicate_iterator.for_each(predicate_visitor);
631+
PredicateBlockIterator loop_predicate_iterator(current, Deoptimization::Reason_predicate);
632+
return loop_predicate_iterator.for_each(predicate_visitor);
633+
}
634+
};
635+
636+
// Unified PredicateVisitor which only provides a single visit method for a generic Predicate. This visitor can be used
637+
// when it does not matter what kind of predicate is visited. Note that we override all normal visit methods from
638+
// PredicateVisitor by calling the unified method. These visit methods are marked final such that they cannot be
639+
// overridden by implementors of this class.
640+
class UnifiedPredicateVisitor : public PredicateVisitor {
641+
public:
642+
virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) override final {
643+
visit_predicate(template_assertion_predicate);
644+
}
645+
646+
virtual void visit(const ParsePredicate& parse_predicate) override final {
647+
visit_predicate(parse_predicate);
648+
}
649+
650+
virtual void visit(const RuntimePredicate& runtime_predicate) override final {
651+
visit_predicate(runtime_predicate);
652+
}
653+
654+
virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override final {
655+
visit_predicate(initialized_assertion_predicate);
656+
}
657+
658+
virtual void visit_predicate(const Predicate& predicate) = 0;
659+
};
660+
661+
// A block of Regular Predicates inside a Predicate Block without its Parse Predicate.
662+
class RegularPredicateBlock : public StackObj {
663+
const Deoptimization::DeoptReason _deopt_reason;
664+
Node* const _entry;
665+
666+
public:
667+
RegularPredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason)
668+
: _deopt_reason(deopt_reason),
669+
_entry(skip_all(tail)) {
670+
DEBUG_ONLY(verify_block(tail);)
671+
}
672+
NONCOPYABLE(RegularPredicateBlock);
673+
674+
private:
675+
// Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block
676+
// anymore (i.e. entry to the first Regular Predicate in this block if any or `tail` otherwise).
677+
Node* skip_all(Node* tail) const {
678+
RegularPredicateBlockIterator iterator(tail, _deopt_reason);
679+
return iterator.skip_all();
680+
}
681+
682+
DEBUG_ONLY(void verify_block(Node* tail);)
683+
684+
public:
685+
Node* entry() const {
686+
return _entry;
687+
}
688+
};
689+
690+
#ifndef PRODUCT
691+
// Visitor class to print all the visited predicates. Used by the Predicates class which does the printing starting
692+
// at the loop node and then following the inputs to the earliest predicate.
693+
class PredicatePrinter : public PredicateVisitor {
694+
const char* _prefix; // Prefix added to each dumped string.
695+
696+
public:
697+
explicit PredicatePrinter(const char* prefix) : _prefix(prefix) {}
698+
NONCOPYABLE(PredicatePrinter);
699+
700+
void visit(const ParsePredicate& parse_predicate) override {
701+
print_predicate_node("Parse Predicate", parse_predicate);
702+
}
703+
704+
void visit(const RuntimePredicate& runtime_predicate) override {
705+
print_predicate_node("Runtime Predicate", runtime_predicate);
706+
}
707+
708+
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override {
709+
print_predicate_node("Template Assertion Predicate", template_assertion_predicate);
710+
}
711+
712+
void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override {
713+
print_predicate_node("Initialized Assertion Predicate", initialized_assertion_predicate);
714+
}
715+
716+
private:
717+
void print_predicate_node(const char* predicate_name, const Predicate& predicate) const {
718+
tty->print_cr("%s- %s: %d %s", _prefix, predicate_name, predicate.head()->_idx, predicate.head()->Name());
719+
}
720+
};
721+
#endif // NOT PRODUCT
419722

420723
// This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block,
421724
// or a Loop Limit Check Predicate Block). It contains zero or more Regular Predicates followed by a Parse Predicate
422725
// which, however, does not need to exist (we could already have decided to remove Parse Predicates for this loop).
423726
class PredicateBlock : public StackObj {
424-
ParsePredicate _parse_predicate; // Could be missing.
425-
Node* _entry;
426-
427-
static Node* skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason);
428-
DEBUG_ONLY(void verify_block();)
727+
const ParsePredicate _parse_predicate; // Could be missing.
728+
const RegularPredicateBlock _regular_predicate_block;
729+
Node* const _entry;
730+
#ifndef PRODUCT
731+
// Used for dumping.
732+
Node* const _tail;
733+
const Deoptimization::DeoptReason _deopt_reason;
734+
#endif // NOT PRODUCT
429735

430736
public:
431-
PredicateBlock(Node* predicate_proj, Deoptimization::DeoptReason deopt_reason)
432-
: _parse_predicate(predicate_proj, deopt_reason),
433-
_entry(skip_regular_predicates(_parse_predicate.entry(), deopt_reason)) {
434-
DEBUG_ONLY(verify_block();)
435-
}
737+
PredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason)
738+
: _parse_predicate(tail, deopt_reason),
739+
_regular_predicate_block(_parse_predicate.entry(), deopt_reason),
740+
_entry(_regular_predicate_block.entry())
741+
#ifndef PRODUCT
742+
, _tail(tail)
743+
, _deopt_reason(deopt_reason)
744+
#endif // NOT PRODUCT
745+
{}
746+
NONCOPYABLE(PredicateBlock);
436747

437748
// Returns the control input node into this Regular Predicate block. This is either:
438749
// - The control input to the first If node in the block representing a Runtime Predicate if there is at least one
@@ -453,11 +764,11 @@ class PredicateBlock : public StackObj {
453764
}
454765

455766
ParsePredicateNode* parse_predicate() const {
456-
return _parse_predicate.node();
767+
return _parse_predicate.head();
457768
}
458769

459770
ParsePredicateSuccessProj* parse_predicate_success_proj() const {
460-
return _parse_predicate.success_proj();
771+
return _parse_predicate.tail();
461772
}
462773

463774
bool has_runtime_predicates() const {
@@ -471,25 +782,31 @@ class PredicateBlock : public StackObj {
471782
Node* skip_parse_predicate() const {
472783
return _parse_predicate.entry();
473784
}
785+
786+
#ifndef PRODUCT
787+
void dump() const;
788+
void dump(const char* prefix) const;
789+
#endif // NOT PRODUCT
474790
};
475791

476792
// This class takes a loop entry node and finds all the available predicates for the loop.
477793
class Predicates : public StackObj {
478-
Node* _loop_entry;
479-
PredicateBlock _loop_limit_check_predicate_block;
480-
PredicateBlock _profiled_loop_predicate_block;
481-
PredicateBlock _loop_predicate_block;
482-
Node* _entry;
794+
Node* const _tail;
795+
const PredicateBlock _loop_limit_check_predicate_block;
796+
const PredicateBlock _profiled_loop_predicate_block;
797+
const PredicateBlock _loop_predicate_block;
798+
Node* const _entry;
483799

484800
public:
485-
Predicates(Node* loop_entry)
486-
: _loop_entry(loop_entry),
801+
explicit Predicates(Node* loop_entry)
802+
: _tail(loop_entry),
487803
_loop_limit_check_predicate_block(loop_entry, Deoptimization::Reason_loop_limit_check),
488804
_profiled_loop_predicate_block(_loop_limit_check_predicate_block.entry(),
489805
Deoptimization::Reason_profile_predicate),
490806
_loop_predicate_block(_profiled_loop_predicate_block.entry(),
491807
Deoptimization::Reason_predicate),
492808
_entry(_loop_predicate_block.entry()) {}
809+
NONCOPYABLE(Predicates);
493810

494811
// Returns the control input the first predicate if there are any predicates. If there are no predicates, the same
495812
// node initially passed to the constructor is returned.
@@ -510,35 +827,17 @@ class Predicates : public StackObj {
510827
}
511828

512829
bool has_any() const {
513-
return _entry != _loop_entry;
830+
return _entry != _tail;
514831
}
515-
};
516-
517-
// This class iterates over the Parse Predicates of a loop.
518-
class ParsePredicateIterator : public StackObj {
519-
GrowableArray<ParsePredicateNode*> _parse_predicates;
520-
int _current_index;
521-
522-
public:
523-
ParsePredicateIterator(const Predicates& predicates);
524832

525-
bool has_next() const {
526-
return _current_index < _parse_predicates.length();
527-
}
528-
529-
ParsePredicateNode* next();
833+
#ifndef PRODUCT
834+
/*
835+
* Debug printing functions.
836+
*/
837+
void dump() const;
838+
static void dump_at(Node* node);
839+
static void dump_for_loop(LoopNode* loop_node);
840+
#endif // NOT PRODUCT
530841
};
531842

532-
// Special predicate iterator that can be used to walk through predicate entries, regardless of whether the predicate
533-
// belongs to the same loop or not (i.e. leftovers from already folded nodes). The iterator returns the next entry
534-
// to a predicate.
535-
class PredicateEntryIterator : public StackObj {
536-
Node* _current;
537-
538-
public:
539-
explicit PredicateEntryIterator(Node* start) : _current(start) {};
540-
541-
bool has_next() const;
542-
Node* next_entry();
543-
};
544843
#endif // SHARE_OPTO_PREDICATES_HPP

0 commit comments

Comments
 (0)
Please sign in to comment.