Skip to content

Commit 48621ae

Browse files
committed
8331168: Introduce PredicateEntryIterator to iterate through predicate entries
Reviewed-by: roland, kvn
1 parent e227c7e commit 48621ae

File tree

5 files changed

+118
-51
lines changed

5 files changed

+118
-51
lines changed

src/hotspot/share/opto/loopnode.cpp

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,10 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) {
169169
return earliest;
170170
}
171171

172-
while (1) {
173-
Node *next = ctl;
174-
// Moving the node out of a loop on the projection of a If
175-
// confuses loop predication. So once we hit a Loop in a If branch
172+
while (true) {
173+
Node* next = ctl;
174+
// Moving the node out of a loop on the projection of an If
175+
// confuses Loop Predication. So, once we hit a loop in an If branch
176176
// that doesn't branch to an UNC, we stop. The code that process
177177
// expensive nodes will notice the loop and skip over it to try to
178178
// move the node further up.
@@ -6081,20 +6081,27 @@ Node* PhaseIdealLoop::get_late_ctrl_with_anti_dep(LoadNode* n, Node* early, Node
60816081
return LCA;
60826082
}
60836083

6084-
// true if CFG node d dominates CFG node n
6085-
bool PhaseIdealLoop::is_dominator(Node *d, Node *n) {
6086-
if (d == n)
6084+
// Is CFG node 'dominator' dominating node 'n'?
6085+
bool PhaseIdealLoop::is_dominator(Node* dominator, Node* n) {
6086+
if (dominator == n) {
60876087
return true;
6088-
assert(d->is_CFG() && n->is_CFG(), "must have CFG nodes");
6089-
uint dd = dom_depth(d);
6088+
}
6089+
assert(dominator->is_CFG() && n->is_CFG(), "must have CFG nodes");
6090+
uint dd = dom_depth(dominator);
60906091
while (dom_depth(n) >= dd) {
6091-
if (n == d)
6092+
if (n == dominator) {
60926093
return true;
6094+
}
60936095
n = idom(n);
60946096
}
60956097
return false;
60966098
}
60976099

6100+
// Is CFG node 'dominator' strictly dominating node 'n'?
6101+
bool PhaseIdealLoop::is_strict_dominator(Node* dominator, Node* n) {
6102+
return dominator != n && is_dominator(dominator, n);
6103+
}
6104+
60986105
//------------------------------dom_lca_for_get_late_ctrl_internal-------------
60996106
// Pair-wise LCA with tags.
61006107
// Tag each index with the node 'tag' currently being processed
@@ -6377,31 +6384,16 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
63776384

63786385
if (least != early) {
63796386
// Move the node above predicates as far up as possible so a
6380-
// following pass of loop predication doesn't hoist a predicate
6387+
// following pass of Loop Predication doesn't hoist a predicate
63816388
// that depends on it above that node.
6382-
Node* new_ctrl = least;
6383-
for (;;) {
6384-
if (!new_ctrl->is_Proj()) {
6385-
break;
6386-
}
6387-
CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern();
6388-
if (call == nullptr) {
6389-
break;
6390-
}
6391-
int req = call->uncommon_trap_request();
6392-
Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
6393-
if (trap_reason != Deoptimization::Reason_loop_limit_check &&
6394-
trap_reason != Deoptimization::Reason_predicate &&
6395-
trap_reason != Deoptimization::Reason_profile_predicate) {
6396-
break;
6397-
}
6398-
Node* c = new_ctrl->in(0)->in(0);
6399-
if (is_dominator(c, early) && c != early) {
6389+
PredicateEntryIterator predicate_iterator(least);
6390+
while (predicate_iterator.has_next()) {
6391+
Node* next_predicate_entry = predicate_iterator.next_entry();
6392+
if (is_strict_dominator(next_predicate_entry, early)) {
64006393
break;
64016394
}
6402-
new_ctrl = c;
6395+
least = next_predicate_entry;
64036396
}
6404-
least = new_ctrl;
64056397
}
64066398
// Try not to place code on a loop entry projection
64076399
// which can inhibit range check elimination.

src/hotspot/share/opto/loopnode.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,8 +1011,10 @@ class PhaseIdealLoop : public PhaseTransform {
10111011
assert(n == find_non_split_ctrl(n), "must return legal ctrl" );
10121012
return n;
10131013
}
1014-
// true if CFG node d dominates CFG node n
1015-
bool is_dominator(Node *d, Node *n);
1014+
1015+
bool is_dominator(Node* dominator, Node* n);
1016+
bool is_strict_dominator(Node* dominator, Node* n);
1017+
10161018
// return get_ctrl for a data node and self(n) for a CFG node
10171019
Node* ctrl_or_self(Node* n) {
10181020
if (has_ctrl(n))

src/hotspot/share/opto/loopopts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4294,7 +4294,7 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
42944294
} else {
42954295
wq.push(c->in(0));
42964296
}
4297-
assert(!is_dominator(c, region) || c == region, "shouldn't go above region");
4297+
assert(!is_strict_dominator(c, region), "shouldn't go above region");
42984298
}
42994299

43004300
Node* region_dom = idom(region);

src/hotspot/share/opto/predicates.cpp

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,29 @@
3232
// (i.e. not belonging to an Initialized Assertion Predicate anymore)
3333
Node* AssertionPredicatesWithHalt::find_entry(Node* start_proj) {
3434
Node* entry = start_proj;
35-
while (is_assertion_predicate_success_proj(entry)) {
35+
while (AssertionPredicateWithHalt::is_predicate(entry)) {
3636
entry = entry->in(0)->in(0);
3737
}
3838
return entry;
3939
}
4040

41-
bool AssertionPredicatesWithHalt::is_assertion_predicate_success_proj(const Node* predicate_proj) {
42-
if (predicate_proj == nullptr || !predicate_proj->is_IfProj() || !predicate_proj->in(0)->is_If()) {
41+
bool AssertionPredicateWithHalt::is_predicate(const Node* maybe_success_proj) {
42+
if (maybe_success_proj == nullptr || !maybe_success_proj->is_IfProj() || !maybe_success_proj->in(0)->is_If()) {
4343
return false;
4444
}
45-
return has_assertion_predicate_opaque(predicate_proj) && has_halt(predicate_proj);
45+
return has_assertion_predicate_opaque(maybe_success_proj) && has_halt(maybe_success_proj);
4646
}
4747

4848
// Check if the If node of `predicate_proj` has an Opaque4 (Template Assertion Predicate) or an
4949
// OpaqueInitializedAssertionPredicate (Initialized Assertion Predicate) node as input.
50-
bool AssertionPredicatesWithHalt::has_assertion_predicate_opaque(const Node* predicate_proj) {
50+
bool AssertionPredicateWithHalt::has_assertion_predicate_opaque(const Node* predicate_proj) {
5151
IfNode* iff = predicate_proj->in(0)->as_If();
5252
Node* bol = iff->in(1);
5353
return bol->is_Opaque4() || bol->is_OpaqueInitializedAssertionPredicate();
5454
}
5555

5656
// Check if the other projection (UCT projection) of `success_proj` has a Halt node as output.
57-
bool AssertionPredicatesWithHalt::has_halt(const Node* success_proj) {
57+
bool AssertionPredicateWithHalt::has_halt(const Node* success_proj) {
5858
ProjNode* other_proj = success_proj->as_IfProj()->other_if_proj();
5959
return other_proj->outcnt() == 1 && other_proj->unique_out()->Opcode() == Op_Halt;
6060
}
@@ -72,24 +72,44 @@ ParsePredicateNode* ParsePredicate::init_parse_predicate(Node* parse_predicate_p
7272
return nullptr;
7373
}
7474

75-
Deoptimization::DeoptReason RuntimePredicate::uncommon_trap_reason(IfProjNode* if_proj) {
75+
bool ParsePredicate::is_predicate(Node* maybe_success_proj) {
76+
if (!maybe_success_proj->is_IfProj()) {
77+
return false;
78+
}
79+
IfNode* if_node = maybe_success_proj->in(0)->as_If();
80+
return if_node->is_ParsePredicate();
81+
}
82+
83+
Deoptimization::DeoptReason RegularPredicateWithUCT::uncommon_trap_reason(IfProjNode* if_proj) {
7684
CallStaticJavaNode* uct_call = if_proj->is_uncommon_trap_if_pattern();
7785
if (uct_call == nullptr) {
7886
return Deoptimization::Reason_none;
7987
}
8088
return Deoptimization::trap_request_reason(uct_call->uncommon_trap_request());
8189
}
8290

83-
bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason) {
84-
if (may_be_runtime_predicate_if(node)) {
91+
bool RegularPredicateWithUCT::is_predicate(Node* maybe_success_proj) {
92+
if (may_be_predicate_if(maybe_success_proj)) {
93+
IfProjNode* success_proj = maybe_success_proj->as_IfProj();
94+
const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj);
95+
return (deopt_reason == Deoptimization::Reason_loop_limit_check ||
96+
deopt_reason == Deoptimization::Reason_predicate ||
97+
deopt_reason == Deoptimization::Reason_profile_predicate);
98+
} else {
99+
return false;
100+
}
101+
}
102+
103+
bool RegularPredicateWithUCT::is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason) {
104+
if (may_be_predicate_if(node)) {
85105
return deopt_reason == uncommon_trap_reason(node->as_IfProj());
86106
} else {
87107
return false;
88108
}
89109
}
90110

91111
// A Runtime Predicate must have an If or a RangeCheck node, while the If should not be a zero trip guard check.
92-
bool RuntimePredicate::may_be_runtime_predicate_if(Node* node) {
112+
bool RegularPredicateWithUCT::may_be_predicate_if(Node* node) {
93113
if (node->is_IfProj()) {
94114
const IfNode* if_node = node->in(0)->as_If();
95115
const int opcode_if = if_node->Opcode();
@@ -101,6 +121,10 @@ bool RuntimePredicate::may_be_runtime_predicate_if(Node* node) {
101121
return false;
102122
}
103123

124+
bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason) {
125+
return RegularPredicateWithUCT::is_predicate(node, deopt_reason);
126+
}
127+
104128
ParsePredicateIterator::ParsePredicateIterator(const Predicates& predicates) : _current_index(0) {
105129
const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block();
106130
if (loop_limit_check_predicate_block->has_parse_predicate()) {
@@ -356,3 +380,18 @@ bool TemplateAssertionPredicateExpressionNode::is_in_expression(Node* node) {
356380
bool TemplateAssertionPredicateExpressionNode::is_template_assertion_predicate(Node* node) {
357381
return node->is_If() && node->in(1)->is_Opaque4();
358382
}
383+
384+
// Is current node pointed to by iterator a predicate?
385+
bool PredicateEntryIterator::has_next() const {
386+
return ParsePredicate::is_predicate(_current) ||
387+
RegularPredicateWithUCT::is_predicate(_current) ||
388+
AssertionPredicateWithHalt::is_predicate(_current);
389+
}
390+
391+
// Skip the current predicate pointed to by iterator by returning the input into the predicate. This could possibly be
392+
// a non-predicate node.
393+
Node* PredicateEntryIterator::next_entry() {
394+
assert(has_next(), "current must be predicate");
395+
_current = _current->in(0)->in(0);
396+
return _current;
397+
}

src/hotspot/share/opto/predicates.hpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define SHARE_OPTO_PREDICATES_HPP
2727

2828
#include "opto/cfgnode.hpp"
29+
#include "opto/connode.hpp"
2930
#include "opto/opaquenode.hpp"
3031

3132
/*
@@ -199,9 +200,6 @@ class AssertionPredicatesWithHalt : public StackObj {
199200
Node* _entry;
200201

201202
static Node* find_entry(Node* start_proj);
202-
static bool has_assertion_predicate_opaque(const Node* predicate_proj);
203-
static bool has_halt(const Node* success_proj);
204-
static bool is_assertion_predicate_success_proj(const Node* predicate_proj);
205203

206204
public:
207205
AssertionPredicatesWithHalt(Node* assertion_predicate_proj) : _entry(find_entry(assertion_predicate_proj)) {}
@@ -213,13 +211,37 @@ class AssertionPredicatesWithHalt : public StackObj {
213211
}
214212
};
215213

214+
// Class to represent a single Assertion Predicate with a HaltNode. This could either be:
215+
// - A Template Assertion Predicate.
216+
// - An Initialized Assertion Predicate.
217+
// Note that all other Regular Predicates have an UCT node.
218+
class AssertionPredicateWithHalt : public StackObj {
219+
static bool has_assertion_predicate_opaque(const Node* predicate_proj);
220+
static bool has_halt(const Node* success_proj);
221+
public:
222+
static bool is_predicate(const Node* maybe_success_proj);
223+
};
224+
225+
// Class to represent a single Regular Predicate with an UCT. This could either be:
226+
// - A Runtime Predicate
227+
// - A Template Assertion Predicate
228+
// Note that all other Regular Predicates have a Halt node.
229+
class RegularPredicateWithUCT : public StackObj {
230+
static Deoptimization::DeoptReason uncommon_trap_reason(IfProjNode* if_proj);
231+
static bool may_be_predicate_if(Node* node);
232+
233+
public:
234+
static bool is_predicate(Node* maybe_success_proj);
235+
static bool is_predicate(Node* node, Deoptimization::DeoptReason deopt_reason);
236+
};
237+
216238
// Class to represent a Parse Predicate.
217239
class ParsePredicate : public StackObj {
218240
ParsePredicateSuccessProj* _success_proj;
219241
ParsePredicateNode* _parse_predicate_node;
220242
Node* _entry;
221243

222-
IfTrueNode* init_success_proj(const Node* parse_predicate_proj) const {
244+
static IfTrueNode* init_success_proj(const Node* parse_predicate_proj) {
223245
assert(parse_predicate_proj != nullptr, "must not be null");
224246
return parse_predicate_proj->isa_IfTrue();
225247
}
@@ -253,13 +275,12 @@ class ParsePredicate : public StackObj {
253275
assert(is_valid(), "must be valid");
254276
return _success_proj;
255277
}
278+
279+
static bool is_predicate(Node* maybe_success_proj);
256280
};
257281

258282
// Utility class for queries on Runtime Predicates.
259283
class RuntimePredicate : public StackObj {
260-
static Deoptimization::DeoptReason uncommon_trap_reason(IfProjNode* if_proj);
261-
static bool may_be_runtime_predicate_if(Node* node);
262-
263284
public:
264285
static bool is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason);
265286
};
@@ -473,4 +494,17 @@ class ParsePredicateIterator : public StackObj {
473494

474495
ParsePredicateNode* next();
475496
};
497+
498+
// Special predicate iterator that can be used to walk through predicate entries, regardless of whether the predicate
499+
// belongs to the same loop or not (i.e. leftovers from already folded nodes). The iterator returns the next entry
500+
// to a predicate.
501+
class PredicateEntryIterator : public StackObj {
502+
Node* _current;
503+
504+
public:
505+
explicit PredicateEntryIterator(Node* start) : _current(start) {};
506+
507+
bool has_next() const;
508+
Node* next_entry();
509+
};
476510
#endif // SHARE_OPTO_PREDICATES_HPP

0 commit comments

Comments
 (0)