Skip to content

Commit e57b272

Browse files
committed
8350578: Refactor useless Parse and Template Assertion Predicate elimination code by using a PredicateVisitor
Reviewed-by: epeter, kvn, roland
1 parent 577ede7 commit e57b272

12 files changed

+317
-197
lines changed

src/hotspot/share/opto/cfgnode.hpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "opto/multnode.hpp"
2929
#include "opto/node.hpp"
3030
#include "opto/opcodes.hpp"
31+
#include "opto/predicates_enums.hpp"
3132
#include "opto/type.hpp"
3233

3334
// Portions of code courtesy of Clifford Click
@@ -58,10 +59,7 @@ class JumpProjNode;
5859
class SCMemProjNode;
5960
class PhaseIdealLoop;
6061
enum class AssertionPredicateType;
61-
62-
// The success projection of a Parse Predicate is always an IfTrueNode and the uncommon projection an IfFalseNode
63-
typedef IfTrueNode ParsePredicateSuccessProj;
64-
typedef IfFalseNode ParsePredicateUncommonProj;
62+
enum class PredicateState;
6563

6664
//------------------------------RegionNode-------------------------------------
6765
// The class of RegionNodes, which can be mapped to basic blocks in the
@@ -488,7 +486,11 @@ class RangeCheckNode : public IfNode {
488486
// More information about predicates can be found in loopPredicate.cpp.
489487
class ParsePredicateNode : public IfNode {
490488
Deoptimization::DeoptReason _deopt_reason;
491-
bool _useless; // If the associated loop dies, this parse predicate becomes useless and can be cleaned up by Value().
489+
490+
// When a Parse Predicate loses its connection to a loop head, it will be marked useless by
491+
// EliminateUselessPredicates and cleaned up by Value(). It can also become useless when cloning it to both loops
492+
// during Loop Multiversioning - we no longer use the old version.
493+
PredicateState _predicate_state;
492494
public:
493495
ParsePredicateNode(Node* control, Deoptimization::DeoptReason deopt_reason, PhaseGVN* gvn);
494496
virtual int Opcode() const;
@@ -499,15 +501,21 @@ class ParsePredicateNode : public IfNode {
499501
}
500502

501503
bool is_useless() const {
502-
return _useless;
504+
return _predicate_state == PredicateState::Useless;
505+
}
506+
507+
void mark_useless(PhaseIterGVN& igvn);
508+
509+
void mark_maybe_useful() {
510+
_predicate_state = PredicateState::MaybeUseful;
503511
}
504512

505-
void mark_useless() {
506-
_useless = true;
513+
bool is_useful() const {
514+
return _predicate_state == PredicateState::Useful;
507515
}
508516

509517
void mark_useful() {
510-
_useless = false;
518+
_predicate_state = PredicateState::Useful;
511519
}
512520

513521
// Return the uncommon trap If projection of this Parse Predicate.

src/hotspot/share/opto/compile.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "opto/mulnode.hpp"
6868
#include "opto/narrowptrnode.hpp"
6969
#include "opto/node.hpp"
70+
#include "opto/opaquenode.hpp"
7071
#include "opto/opcodes.hpp"
7172
#include "opto/output.hpp"
7273
#include "opto/parse.hpp"
@@ -394,7 +395,7 @@ void Compile::remove_useless_node(Node* dead) {
394395
remove_expensive_node(dead);
395396
}
396397
if (dead->is_OpaqueTemplateAssertionPredicate()) {
397-
remove_template_assertion_predicate_opaq(dead);
398+
remove_template_assertion_predicate_opaque(dead->as_OpaqueTemplateAssertionPredicate());
398399
}
399400
if (dead->is_ParsePredicate()) {
400401
remove_parse_predicate(dead->as_ParsePredicate());
@@ -453,7 +454,8 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis
453454

454455
remove_useless_nodes(_macro_nodes, useful); // remove useless macro nodes
455456
remove_useless_nodes(_parse_predicates, useful); // remove useless Parse Predicate nodes
456-
remove_useless_nodes(_template_assertion_predicate_opaqs, useful); // remove useless Assertion Predicate opaque nodes
457+
// Remove useless Template Assertion Predicate opaque nodes
458+
remove_useless_nodes(_template_assertion_predicate_opaques, useful);
457459
remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes
458460
remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass
459461
remove_useless_nodes(_for_merge_stores_igvn, useful); // remove useless node recorded for merge stores IGVN pass
@@ -653,7 +655,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
653655
_intrinsics(comp_arena(), 0, 0, nullptr),
654656
_macro_nodes(comp_arena(), 8, 0, nullptr),
655657
_parse_predicates(comp_arena(), 8, 0, nullptr),
656-
_template_assertion_predicate_opaqs(comp_arena(), 8, 0, nullptr),
658+
_template_assertion_predicate_opaques(comp_arena(), 8, 0, nullptr),
657659
_expensive_nodes(comp_arena(), 8, 0, nullptr),
658660
_for_post_loop_igvn(comp_arena(), 8, 0, nullptr),
659661
_for_merge_stores_igvn(comp_arena(), 8, 0, nullptr),
@@ -1832,8 +1834,7 @@ void Compile::mark_parse_predicate_nodes_useless(PhaseIterGVN& igvn) {
18321834
}
18331835
for (int i = 0; i < parse_predicate_count(); i++) {
18341836
ParsePredicateNode* parse_predicate = _parse_predicates.at(i);
1835-
parse_predicate->mark_useless();
1836-
igvn._worklist.push(parse_predicate);
1837+
parse_predicate->mark_useless(igvn);
18371838
}
18381839
_parse_predicates.clear();
18391840
}

src/hotspot/share/opto/compile.hpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Node_List;
7171
class Node_Notes;
7272
class NodeHash;
7373
class NodeCloneInfo;
74+
class OpaqueTemplateAssertionPredicateNode;
7475
class OptoReg;
7576
class ParsePredicateNode;
7677
class PhaseCFG;
@@ -371,8 +372,9 @@ class Compile : public Phase {
371372
GrowableArray<CallGenerator*> _intrinsics; // List of intrinsics.
372373
GrowableArray<Node*> _macro_nodes; // List of nodes which need to be expanded before matching.
373374
GrowableArray<ParsePredicateNode*> _parse_predicates; // List of Parse Predicates.
374-
// List of OpaqueTemplateAssertionPredicateNode nodes for Template Assertion Predicates.
375-
GrowableArray<Node*> _template_assertion_predicate_opaqs;
375+
// List of OpaqueTemplateAssertionPredicateNode nodes for Template Assertion Predicates which can be seen as list
376+
// of Template Assertion Predicates themselves.
377+
GrowableArray<OpaqueTemplateAssertionPredicateNode*> _template_assertion_predicate_opaques;
376378
GrowableArray<Node*> _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
377379
GrowableArray<Node*> _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over
378380
GrowableArray<Node*> _for_merge_stores_igvn; // List of nodes for IGVN merge stores
@@ -683,18 +685,21 @@ class Compile : public Phase {
683685
static IdealGraphPrinter* debug_network_printer() { return _debug_network_printer; }
684686
#endif
685687

688+
const GrowableArray<ParsePredicateNode*>& parse_predicates() const {
689+
return _parse_predicates;
690+
}
691+
692+
const GrowableArray<OpaqueTemplateAssertionPredicateNode*>& template_assertion_predicate_opaques() const {
693+
return _template_assertion_predicate_opaques;
694+
}
695+
686696
int macro_count() const { return _macro_nodes.length(); }
687697
int parse_predicate_count() const { return _parse_predicates.length(); }
688-
int template_assertion_predicate_count() const { return _template_assertion_predicate_opaqs.length(); }
698+
int template_assertion_predicate_count() const { return _template_assertion_predicate_opaques.length(); }
689699
int expensive_count() const { return _expensive_nodes.length(); }
690700
int coarsened_count() const { return _coarsened_locks.length(); }
691701

692702
Node* macro_node(int idx) const { return _macro_nodes.at(idx); }
693-
ParsePredicateNode* parse_predicate(int idx) const { return _parse_predicates.at(idx); }
694-
695-
Node* template_assertion_predicate_opaq_node(int idx) const {
696-
return _template_assertion_predicate_opaqs.at(idx);
697-
}
698703

699704
Node* expensive_node(int idx) const { return _expensive_nodes.at(idx); }
700705

@@ -730,15 +735,15 @@ class Compile : public Phase {
730735
}
731736
}
732737

733-
void add_template_assertion_predicate_opaq(Node* n) {
734-
assert(!_template_assertion_predicate_opaqs.contains(n),
738+
void add_template_assertion_predicate_opaque(OpaqueTemplateAssertionPredicateNode* n) {
739+
assert(!_template_assertion_predicate_opaques.contains(n),
735740
"Duplicate entry in Template Assertion Predicate OpaqueTemplateAssertionPredicate list");
736-
_template_assertion_predicate_opaqs.append(n);
741+
_template_assertion_predicate_opaques.append(n);
737742
}
738743

739-
void remove_template_assertion_predicate_opaq(Node* n) {
744+
void remove_template_assertion_predicate_opaque(OpaqueTemplateAssertionPredicateNode* n) {
740745
if (template_assertion_predicate_count() > 0) {
741-
_template_assertion_predicate_opaqs.remove_if_existing(n);
746+
_template_assertion_predicate_opaques.remove_if_existing(n);
742747
}
743748
}
744749
void add_coarsened_locks(GrowableArray<AbstractLockNode*>& locks);

src/hotspot/share/opto/ifnode.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include "opto/connode.hpp"
3232
#include "opto/loopnode.hpp"
3333
#include "opto/phaseX.hpp"
34-
#include "opto/predicates.hpp"
34+
#include "opto/predicates_enums.hpp"
3535
#include "opto/runtime.hpp"
3636
#include "opto/rootnode.hpp"
3737
#include "opto/subnode.hpp"
@@ -2169,7 +2169,7 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) {
21692169
ParsePredicateNode::ParsePredicateNode(Node* control, Deoptimization::DeoptReason deopt_reason, PhaseGVN* gvn)
21702170
: IfNode(control, gvn->intcon(1), PROB_MAX, COUNT_UNKNOWN),
21712171
_deopt_reason(deopt_reason),
2172-
_useless(false) {
2172+
_predicate_state(PredicateState::Useful) {
21732173
init_class_id(Class_ParsePredicate);
21742174
gvn->C->add_parse_predicate(this);
21752175
gvn->C->record_for_post_loop_opts_igvn(this);
@@ -2186,6 +2186,11 @@ ParsePredicateNode::ParsePredicateNode(Node* control, Deoptimization::DeoptReaso
21862186
#endif // ASSERT
21872187
}
21882188

2189+
void ParsePredicateNode::mark_useless(PhaseIterGVN& igvn) {
2190+
_predicate_state = PredicateState::Useless;
2191+
igvn._worklist.push(this);
2192+
}
2193+
21892194
Node* ParsePredicateNode::uncommon_trap() const {
21902195
ParsePredicateUncommonProj* uncommon_proj = proj_out(0)->as_IfFalse();
21912196
Node* uct_region_or_call = uncommon_proj->unique_ctrl_out();
@@ -2195,14 +2200,15 @@ Node* ParsePredicateNode::uncommon_trap() const {
21952200

21962201
// Fold this node away once it becomes useless or at latest in post loop opts IGVN.
21972202
const Type* ParsePredicateNode::Value(PhaseGVN* phase) const {
2203+
assert(_predicate_state != PredicateState::MaybeUseful, "should only be MaybeUseful when eliminating useless "
2204+
"predicates during loop opts");
21982205
if (phase->type(in(0)) == Type::TOP) {
21992206
return Type::TOP;
22002207
}
2201-
if (_useless || phase->C->post_loop_opts_phase()) {
2208+
if (_predicate_state == PredicateState::Useless || phase->C->post_loop_opts_phase()) {
22022209
return TypeTuple::IFTRUE;
2203-
} else {
2204-
return bottom_type();
22052210
}
2211+
return bottom_type();
22062212
}
22072213

22082214
#ifndef PRODUCT
@@ -2224,7 +2230,7 @@ void ParsePredicateNode::dump_spec(outputStream* st) const {
22242230
default:
22252231
fatal("unknown kind");
22262232
}
2227-
if (_useless) {
2233+
if (_predicate_state == PredicateState::Useless) {
22282234
st->print("#useless ");
22292235
}
22302236
}

src/hotspot/share/opto/loopnode.cpp

Lines changed: 3 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,116 +4399,13 @@ void PhaseIdealLoop::log_loop_tree() {
43994399

44004400
// Eliminate all Parse and Template Assertion Predicates that are not associated with a loop anymore. The eliminated
44014401
// predicates will be removed during the next round of IGVN.
4402-
void PhaseIdealLoop::eliminate_useless_predicates() {
4402+
void PhaseIdealLoop::eliminate_useless_predicates() const {
44034403
if (C->parse_predicate_count() == 0 && C->template_assertion_predicate_count() == 0) {
44044404
return; // No predicates left.
44054405
}
44064406

4407-
eliminate_useless_parse_predicates();
4408-
eliminate_useless_template_assertion_predicates();
4409-
}
4410-
4411-
// Eliminate all Parse Predicates that do not belong to a loop anymore by marking them useless. These will be removed
4412-
// during the next round of IGVN.
4413-
void PhaseIdealLoop::eliminate_useless_parse_predicates() {
4414-
mark_all_parse_predicates_useless();
4415-
if (C->has_loops()) {
4416-
mark_loop_associated_parse_predicates_useful();
4417-
}
4418-
add_useless_parse_predicates_to_igvn_worklist();
4419-
}
4420-
4421-
void PhaseIdealLoop::mark_all_parse_predicates_useless() const {
4422-
for (int i = 0; i < C->parse_predicate_count(); i++) {
4423-
C->parse_predicate(i)->mark_useless();
4424-
}
4425-
}
4426-
4427-
void PhaseIdealLoop::mark_loop_associated_parse_predicates_useful() {
4428-
for (LoopTreeIterator iterator(_ltree_root); !iterator.done(); iterator.next()) {
4429-
IdealLoopTree* loop = iterator.current();
4430-
if (loop->can_apply_loop_predication()) {
4431-
mark_useful_parse_predicates_for_loop(loop);
4432-
}
4433-
}
4434-
}
4435-
4436-
// This visitor marks all visited Parse Predicates useful.
4437-
class ParsePredicateUsefulMarker : public PredicateVisitor {
4438-
public:
4439-
using PredicateVisitor::visit;
4440-
4441-
void visit(const ParsePredicate& parse_predicate) override {
4442-
parse_predicate.head()->mark_useful();
4443-
}
4444-
};
4445-
4446-
void PhaseIdealLoop::mark_useful_parse_predicates_for_loop(IdealLoopTree* loop) {
4447-
Node* entry = loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl);
4448-
const PredicateIterator predicate_iterator(entry);
4449-
ParsePredicateUsefulMarker useful_marker;
4450-
predicate_iterator.for_each(useful_marker);
4451-
}
4452-
4453-
void PhaseIdealLoop::add_useless_parse_predicates_to_igvn_worklist() {
4454-
for (int i = 0; i < C->parse_predicate_count(); i++) {
4455-
ParsePredicateNode* parse_predicate_node = C->parse_predicate(i);
4456-
if (parse_predicate_node->is_useless()) {
4457-
_igvn._worklist.push(parse_predicate_node);
4458-
}
4459-
}
4460-
}
4461-
4462-
4463-
// Eliminate all Template Assertion Predicates that do not belong to their originally associated loop anymore by
4464-
// replacing the OpaqueTemplateAssertionPredicate node of the If node with true. These nodes will be removed during the
4465-
// next round of IGVN.
4466-
void PhaseIdealLoop::eliminate_useless_template_assertion_predicates() {
4467-
Unique_Node_List useful_predicates;
4468-
if (C->has_loops()) {
4469-
collect_useful_template_assertion_predicates(useful_predicates);
4470-
}
4471-
eliminate_useless_template_assertion_predicates(useful_predicates);
4472-
}
4473-
4474-
void PhaseIdealLoop::collect_useful_template_assertion_predicates(Unique_Node_List& useful_predicates) {
4475-
for (LoopTreeIterator iterator(_ltree_root); !iterator.done(); iterator.next()) {
4476-
IdealLoopTree* loop = iterator.current();
4477-
if (loop->can_apply_loop_predication()) {
4478-
collect_useful_template_assertion_predicates_for_loop(loop, useful_predicates);
4479-
}
4480-
}
4481-
}
4482-
4483-
void PhaseIdealLoop::collect_useful_template_assertion_predicates_for_loop(IdealLoopTree* loop,
4484-
Unique_Node_List &useful_predicates) {
4485-
Node* entry = loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl);
4486-
const Predicates predicates(entry);
4487-
if (UseProfiledLoopPredicate) {
4488-
const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block();
4489-
if (profiled_loop_predicate_block->has_parse_predicate()) {
4490-
ParsePredicateSuccessProj* parse_predicate_proj = profiled_loop_predicate_block->parse_predicate_success_proj();
4491-
get_opaque_template_assertion_predicate_nodes(parse_predicate_proj, useful_predicates);
4492-
}
4493-
}
4494-
4495-
if (UseLoopPredicate) {
4496-
const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block();
4497-
if (loop_predicate_block->has_parse_predicate()) {
4498-
ParsePredicateSuccessProj* parse_predicate_proj = loop_predicate_block->parse_predicate_success_proj();
4499-
get_opaque_template_assertion_predicate_nodes(parse_predicate_proj, useful_predicates);
4500-
}
4501-
}
4502-
}
4503-
4504-
void PhaseIdealLoop::eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates) const {
4505-
for (int i = C->template_assertion_predicate_count(); i > 0; i--) {
4506-
OpaqueTemplateAssertionPredicateNode* opaque_node =
4507-
C->template_assertion_predicate_opaq_node(i - 1)->as_OpaqueTemplateAssertionPredicate();
4508-
if (!useful_predicates.member(opaque_node)) { // not in the useful list
4509-
opaque_node->mark_useless(_igvn);
4510-
}
4511-
}
4407+
EliminateUselessPredicates eliminate_useless_predicates(_igvn, _ltree_root);
4408+
eliminate_useless_predicates.eliminate();
45124409
}
45134410

45144411
// If a post or main loop is removed due to an assert predicate, the opaque that guards the loop is not needed anymore

src/hotspot/share/opto/loopnode.hpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,18 +1442,7 @@ class PhaseIdealLoop : public PhaseTransform {
14421442
void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj);
14431443

14441444
// Helper function to collect predicate for eliminating the useless ones
1445-
void eliminate_useless_predicates();
1446-
1447-
void eliminate_useless_parse_predicates();
1448-
void mark_all_parse_predicates_useless() const;
1449-
void mark_loop_associated_parse_predicates_useful();
1450-
static void mark_useful_parse_predicates_for_loop(IdealLoopTree* loop);
1451-
void add_useless_parse_predicates_to_igvn_worklist();
1452-
1453-
void eliminate_useless_template_assertion_predicates();
1454-
void collect_useful_template_assertion_predicates(Unique_Node_List& useful_predicates);
1455-
static void collect_useful_template_assertion_predicates_for_loop(IdealLoopTree* loop, Unique_Node_List& useful_predicates);
1456-
void eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates) const;
1445+
void eliminate_useless_predicates() const;
14571446

14581447
void eliminate_useless_zero_trip_guard();
14591448
void eliminate_useless_multiversion_if();

src/hotspot/share/opto/node.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@ Node *Node::clone() const {
516516
if (n->is_ParsePredicate()) {
517517
C->add_parse_predicate(n->as_ParsePredicate());
518518
}
519+
if (n->is_OpaqueTemplateAssertionPredicate()) {
520+
C->add_template_assertion_predicate_opaque(n->as_OpaqueTemplateAssertionPredicate());
521+
}
519522

520523
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
521524
bs->register_potential_barrier_node(n);
@@ -612,7 +615,7 @@ void Node::destruct(PhaseValues* phase) {
612615
compile->remove_expensive_node(this);
613616
}
614617
if (is_OpaqueTemplateAssertionPredicate()) {
615-
compile->remove_template_assertion_predicate_opaq(this);
618+
compile->remove_template_assertion_predicate_opaque(as_OpaqueTemplateAssertionPredicate());
616619
}
617620
if (is_ParsePredicate()) {
618621
compile->remove_parse_predicate(as_ParsePredicate());

0 commit comments

Comments
 (0)