blob: 2181e498bd42ac78812b243be92d748f9c623bd8 [file] [edit]
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_OPTO_PREDICATES_HPP
#define SHARE_OPTO_PREDICATES_HPP
#include "opto/cfgnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/predicates_enums.hpp"
class IdealLoopTree;
class InitializedAssertionPredicate;
class ParsePredicate;
class PredicateVisitor;
class RuntimePredicate;
class TemplateAssertionPredicate;
/*
* There are different kinds of predicates throughout the code. We differentiate between the following predicates:
*
* - Regular Predicate: This term is used to refer to a Runtime Predicate or an Assertion Predicate and can be used to
* distinguish from any Parse Predicate which is not a real predicate but rather a placeholder.
* - Parse Predicate: Added during parsing to capture the current JVM state. This predicate represents a "placeholder"
* above which Regular Predicates can be created later after parsing.
*
* There are initially three Parse Predicates for each loop:
* - Loop Parse Predicate: The Parse Predicate added for Loop Predicates.
* - Profiled Loop Parse Predicate: The Parse Predicate added for Profiled Loop Predicates.
* - Loop Limit Check Parse Predicate: The Parse Predicate added for a Loop Limit Check Predicate.
* - Runtime Predicate: This term is used to refer to a Hoisted Check Predicate (either a Loop Predicate or a Profiled
* Loop Predicate) or a Loop Limit Check Predicate. These predicates will be checked at runtime while
* the Parse and Assertion Predicates are always removed before code generation (except for
* Initialized Assertion Predicates which are kept in debug builds while being removed in product
* builds).
* - Hoisted Check Predicate: Either a Loop Predicate or a Profiled Loop Predicate that is created during Loop
* Predication to hoist a check out of a loop.
* - Loop Predicate: This predicate is created to hoist a loop-invariant check or a range check of the
* form "a[i*scale + offset]", where scale and offset are loop-invariant, out of a
* counted loop. The hoisted check must be executed in each loop iteration. This predicate
* is created during Loop Predication and is inserted above the Loop Parse Predicate. Each
* predicate for a range check is accompanied by additional Assertion Predicates (see below).
* - Profiled Loop: This predicate is very similar to a Loop Predicate but the check to be hoisted does not
* Predicate need to be executed in each loop iteration. By using profiling information, only checks
* with a high execution frequency are chosen to be replaced by a Profiled Loop Predicate.
* This predicate is created during Loop Predication and is inserted above the Profiled
* Loop Parse Predicate.
* - Loop Limit Check: This predicate is created when transforming a loop to a counted loop to protect against
* Predicate the case when adding the stride to the induction variable would cause an overflow which
* will not satisfy the loop limit exit condition. This overflow is unexpected for further
* counted loop optimizations and could lead to wrong results. Therefore, when this predicate
* fails at runtime, we must trap and recompile the method without turning the loop into a
* counted loop to avoid these overflow problems.
* The predicate does not replace an actual check inside the loop. This predicate can only
* be added once above the Loop Limit Check Parse Predicate for a loop.
* - Assertion Predicate: An always true predicate which will never fail (its range is already covered by an earlier
* Hoisted Check Predicate or the main-loop entry guard) but is required in order to fold away a
* dead sub loop in which some data could be proven to be dead (by the type system) and replaced
* by top. Without such Assertion Predicates, we could find that type ranges in Cast and ConvX2Y
* data nodes become impossible and are replaced by top. This is an indicator that the sub loop
* is never executed and must be dead. But there is no way for C2 to prove that the sub loop is
* actually dead. Assertion Predicates come to the rescue to fold such seemingly dead sub loops
* away to avoid a broken graph. Assertion Predicates are left in the graph as a sanity checks in
* debug builds (they must never fail at runtime) while they are being removed in product builds.
* We use special OpaqueTemplateAssertionPredicateNode nodes to block some optimizations and replace
* the Assertion Predicates later in product builds.
*
* There are two kinds of Assertion Predicates:
* - Template Assertion Predicate: A template for an Assertion Predicate that uses OpaqueLoop*
* nodes as placeholders for the init and stride value of a loop.
* This predicate does not represent an actual check, yet, and
* just serves as a template to create an Initialized Assertion
* Predicate for a (sub) loop.
* - Initialized Assertion Predicate: An Assertion Predicate that represents an actual check for a
* (sub) loop that was initialized by cloning a Template
* Assertion Predicate. The check is always true and is covered
* by an earlier check (a Hoisted Check Predicate or the
* main-loop entry guard).
*
* Assertion Predicates are required when removing a range check from a loop. These are inserted
* either at Loop Predication or at Range Check Elimination:
* - Loop Predication: A range check inside a loop is replaced by a Hoisted Check Predicate
* before the loop. We add two additional Template Assertion Predicates
* from which we can later create Initialized Assertion Predicates. One
* would have been enough if the number of array accesses inside a sub
* loop does not change. But when unrolling the sub loop, we are
* doubling the number of array accesses - we need to cover them all.
* To do that, we only need to create an Initialized Assertion Predicate
* for the first, initial value and for the last value:
* Let a[i] be an array access in the original, not-yet unrolled loop
* with stride 1. When unrolling this loop, we double the stride
* (i.e. stride 2) and have now two accesses a[i] and a[i+1]. We need
* checks for both. When further unrolling this loop, we only need to
* keep the checks on the first and last access (e.g. a[i] and a[i+3]
* on the next unrolling step as they cover the checks in the middle
* for a[i+1] and a[i+2]).
* Therefore, we just need to cover:
* - Initial value: a[init]
* - Last value: a[init + new stride - original stride]
* (We could still only use one Template Assertion Predicate to create
* both Initialized Assertion Predicates from - might be worth doing
* at some point).
* When later splitting a loop (pre/main/post, peeling, unrolling),
* we create two Initialized Assertion Predicates from the Template
* Assertion Predicates by replacing the OpaqueLoop* nodes by actual
* values. Initially (before unrolling), both Assertion Predicates are
* equal. The Initialized Assertion Predicates are always true because
* their range is covered by a corresponding Hoisted Check Predicate.
* - Range Check Elimination: A range check is removed from the main-loop by changing the pre
* and main-loop iterations. We add two additional Template Assertion
* Predicates (see explanation in section above) and one Initialized
* Assertion Predicate for the just removed range check. When later
* unrolling the main-loop, we create two Initialized Assertion
* Predicates from the Template Assertion Predicates by replacing the
* OpaqueLoop* nodes by actual values for the unrolled loop.
* The Initialized Assertion Predicates are always true: They are true
* when entering the main-loop (because we adjusted the pre-loop exit
* condition), when executing the last iteration of the main-loop
* (because we adjusted the main-loop exit condition), and during all
* other iterations of the main-loop in-between by implication.
* Note that Range Check Elimination could remove additional range
* checks which were not possible to remove with Loop Predication
* before (for example, because no Parse Predicates were available
* before the loop to create Hoisted Check Predicates with).
*
*
* In order to group predicates and refer to them throughout the code, we introduce the following additional term:
* - Predicate Block: A block containing all Runtime Predicates, including the Assertion Predicates for Range Check
* Predicates, and the associated Parse Predicate which all share the same uncommon trap. This block
* could be empty if there were no Runtime Predicates created and the Parse Predicate was already
* removed.
* There are three different Predicate Blocks:
* - Loop Predicate Block: Groups the Loop Predicates (if any), including the Assertion Predicates,
* and the Loop Parse Predicate (if not removed, yet) together.
* - Profiled Loop Groups the Profiled Loop Predicates (if any), including the Assertion
* Predicate Block: Predicates, and the Profiled Loop Parse Predicate (if not removed, yet)
* together.
* - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit
* Predicate Block: Check Parse Predicate (if not removed, yet) together.
* - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the
* Parse Predicate.
*
* Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication
* (predicates inside square brackets [] do not need to exist if there are no checks to hoist):
*
* [Loop Predicate 1 + two Template Assertion Predicates] \
* [Loop Predicate 2 + two Template Assertion Predicates] |
* ... | Loop Predicate Block
* [Loop Predicate n + two Template Assertion Predicates] |
* Loop Parse Predicate /
*
* [Profiled Loop Predicate 1 + two Template Assertion Predicates] \
* [Profiled Loop Predicate 2 + two Template Assertion Predicates] | Profiled Loop
* ... | Predicate Block
* [Profiled Loop Predicate m + two Template Assertion Predicates] |
* Profiled Loop Parse Predicate /
*
* [Loop Limit Check Predicate] (at most one) \ Loop Limit Check
* Loop Limit Check Parse Predicate / Predicate Block
* Loop Head
*
* As an example, let's look at how the predicate structure looks for the main-loop after creating pre/main/post loops
* and applying Range Check Elimination (the order is insignificant):
*
* Main Loop entry (zero-trip) guard
* [For Loop Predicate 1: Two Template + two Initialized Assertion Predicates]
* [For Loop Predicate 2: Two Template + two Initialized Assertion Predicates]
* ...
* [For Loop Predicate n: Two Template + two Initialized Assertion Predicates]
*
* [For Profiled Loop Predicate 1: Two Template + two Initialized Assertion Predicates]
* [For Profiled Loop Predicate 2: Two Template + two Initialized Assertion Predicates]
* ...
* [For Profiled Loop Predicate m: Two Template + two Initialized Assertion Predicates]
*
* (after unrolling, we have two Initialized Assertion Predicates for the Assertion Predicates of Range Check Elimination)
* [For Range Check Elimination Check 1: Two Templates + one Initialized Assertion Predicate]
* [For Range Check Elimination Check 2: Two Templates + one Initialized Assertion Predicate]
* ...
* [For Range Check Elimination Check k: Two Templates + one Initialized Assertion Predicate]
* Main Loop Head
*/
// Interface to represent a C2 predicate. A predicate is always represented by two CFG nodes:
// - An If node (head)
// - An IfProj node representing the success projection of the If node (tail).
class Predicate : public StackObj {
public:
// Return the unique entry CFG node into the predicate.
virtual Node* entry() const = 0;
// Return the head node of the predicate which is either:
// - A ParsePredicateNode if the predicate is a Parse Predicate
// - An IfNode or RangeCheckNode, otherwise.
virtual IfNode* head() const = 0;
// Return the tail node of the predicate. Runtime Predicates can either have a true of false projection as success
// projection while Parse Predicates and Assertion Predicates always have a true projection as success projection.
virtual IfProjNode* tail() const = 0;
};
// Generic predicate visitor that does nothing. Subclass this visitor to add customized actions for each predicate.
// The visit methods of this visitor are called from the predicate iterator classes which walk the predicate chain.
// Use the UnifiedPredicateVisitor if the type of the predicate does not matter.
class PredicateVisitor : public StackObj {
public:
virtual void visit(const ParsePredicate& parse_predicate) {}
virtual void visit(const RuntimePredicate& runtime_predicate) {}
virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) {}
virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) {}
// This method can be overridden to stop the predicate iterators from visiting more predicates further up in the
// predicate chain.
virtual bool should_continue() const {
return true;
}
};
// Interface to check whether a node is in a loop body or not.
class NodeInLoopBody : public StackObj {
public:
virtual bool check_node_in_loop_body(Node* node) const = 0;
};
// Class to represent Assertion Predicates (i.e. either Initialized and/or Template Assertion Predicates).
class AssertionPredicates : public StackObj {
Node* const _entry;
static Node* find_entry(Node* start_proj);
public:
explicit AssertionPredicates(Node* assertion_predicate_proj) : _entry(find_entry(assertion_predicate_proj)) {}
NONCOPYABLE(AssertionPredicates);
// Returns the control input node into the first assertion predicate If. If there are no assertion predicates, it
// returns the same node initially passed to the constructor.
Node* entry() const {
return _entry;
}
};
// Class to represent a single Assertion Predicate. This could either be:
// - A Template Assertion Predicate.
// - An Initialized Assertion Predicate.
class AssertionPredicate : public StackObj {
static bool has_assertion_predicate_opaque(const Node* predicate_proj);
public:
static bool is_predicate(const Node* maybe_success_proj);
static bool has_halt(const IfTrueNode* success_proj);
};
// Utility class representing a Regular Predicate which is either a Runtime Predicate or an Assertion Predicate.
class RegularPredicate : public StackObj {
public:
static bool may_be_predicate_if(const Node* node);
};
// Class to represent a Parse Predicate.
class ParsePredicate : public Predicate {
ParsePredicateSuccessProj* _success_proj;
ParsePredicateNode* _parse_predicate_node;
Node* _entry;
static IfTrueNode* init_success_proj(const Node* parse_predicate_proj) {
assert(parse_predicate_proj != nullptr, "must not be null");
return parse_predicate_proj->isa_IfTrue();
}
static ParsePredicateNode* init_parse_predicate(const Node* parse_predicate_proj, Deoptimization::DeoptReason deopt_reason);
NOT_PRODUCT(static void trace_cloned_parse_predicate(bool is_false_path_loop,
const ParsePredicateSuccessProj* success_proj);)
public:
ParsePredicate(Node* parse_predicate_proj, Deoptimization::DeoptReason deopt_reason)
: _success_proj(init_success_proj(parse_predicate_proj)),
_parse_predicate_node(init_parse_predicate(parse_predicate_proj, deopt_reason)),
_entry(_parse_predicate_node != nullptr ? _parse_predicate_node->in(0) : parse_predicate_proj) {}
// Returns the control input node into this Parse Predicate if it is valid. Otherwise, it returns the passed node
// into the constructor of this class.
Node* entry() const override {
return _entry;
}
// This Parse Predicate is valid if the node passed to the constructor is a projection of a ParsePredicateNode, the
// deopt_reason of the uncommon trap of the ParsePredicateNode matches the passed deopt_reason to the constructor and
// the ParsePredicateNode is not marked useless.
bool is_valid() const {
return _parse_predicate_node != nullptr && !_parse_predicate_node->is_useless();
}
ParsePredicateNode* head() const override {
assert(is_valid(), "must be valid");
return _parse_predicate_node;
}
ParsePredicateSuccessProj* tail() const override {
assert(is_valid(), "must be valid");
return _success_proj;
}
ParsePredicate clone_to_unswitched_loop(Node* new_control, bool is_false_path_loop,
PhaseIdealLoop* phase) const;
void kill(PhaseIterGVN& igvn) const;
};
// Class to represent a Runtime Predicate which always has an associated UCT on the failing path.
class RuntimePredicate : public Predicate {
IfProjNode* _success_proj;
IfNode* _if_node;
public:
explicit RuntimePredicate(IfProjNode* success_proj)
: _success_proj(success_proj),
_if_node(success_proj->in(0)->as_If()) {
assert(is_predicate(success_proj), "must be valid");
}
NONCOPYABLE(RuntimePredicate);
private:
static bool is_predicate(const Node* maybe_success_proj);
static bool has_valid_uncommon_trap(const Node* success_proj);
static Deoptimization::DeoptReason uncommon_trap_reason(const IfProjNode* if_proj);
public:
Node* entry() const override {
return _if_node->in(0);
}
IfNode* head() const override {
return _if_node;
}
IfProjNode* tail() const override {
return _success_proj;
}
static bool is_predicate(const Node* node, Deoptimization::DeoptReason deopt_reason);
};
// Class to represent a Template Assertion Predicate.
class TemplateAssertionPredicate : public Predicate {
IfTrueNode* const _success_proj;
IfNode* const _if_node;
public:
explicit TemplateAssertionPredicate(IfTrueNode* success_proj)
: _success_proj(success_proj),
_if_node(success_proj->in(0)->as_If()) {
assert(is_predicate(success_proj), "must be valid");
}
Node* entry() const override {
return _if_node->in(0);
}
OpaqueTemplateAssertionPredicateNode* opaque_node() const {
return _if_node->in(1)->as_OpaqueTemplateAssertionPredicate();
}
IfNode* head() const override {
return _if_node;
}
IfTrueNode* tail() const override {
return _success_proj;
}
bool is_last_value() const {
return _if_node->assertion_predicate_type() == AssertionPredicateType::LastValue;
}
bool is_useless() const {
return opaque_node()->is_useless();
}
TemplateAssertionPredicate clone(Node* new_control, CountedLoopNode* new_loop_node, PhaseIdealLoop* phase) const;
TemplateAssertionPredicate clone_and_replace_opaque_input(Node* new_control, Node* new_opaque_input,
CountedLoopNode* new_loop_node, PhaseIdealLoop* phase) const;
void replace_opaque_stride_input(Node* new_stride, PhaseIterGVN& igvn) const;
InitializedAssertionPredicate initialize(PhaseIdealLoop* phase) const;
void rewire_loop_data_dependencies(IfTrueNode* target_predicate, const NodeInLoopBody& data_in_loop_body,
const PhaseIdealLoop* phase) const;
void kill(PhaseIterGVN& igvn) const;
// Should only be called during Loop Unrolling when we only update the OpaqueLoopStride input but don't require a full
// clone of the Template Assertion Expression.
void update_associated_loop_node(CountedLoopNode* loop_node) const {
opaque_node()->update_loop_node(loop_node);
}
static bool is_predicate(const Node* maybe_success_proj);
#ifdef ASSERT
static void verify(IfTrueNode* template_assertion_predicate_success_proj) {
TemplateAssertionPredicate template_assertion_predicate(template_assertion_predicate_success_proj);
template_assertion_predicate.verify();
}
void verify() const;
#endif // ASSERT
};
// Class to represent an Initialized Assertion Predicate which always has a halt node on the failing path.
// This predicate should never fail at runtime by design.
class InitializedAssertionPredicate : public Predicate {
IfTrueNode* const _success_proj;
IfNode* const _if_node;
DEBUG_ONLY(static bool has_halt(const IfTrueNode* success_proj);)
public:
explicit InitializedAssertionPredicate(IfTrueNode* success_proj)
: _success_proj(success_proj),
_if_node(success_proj->in(0)->as_If()) {
assert(is_predicate(success_proj), "must be valid");
}
Node* entry() const override {
return _if_node->in(0);
}
OpaqueInitializedAssertionPredicateNode* opaque_node() const {
return _if_node->in(1)->as_OpaqueInitializedAssertionPredicate();
}
IfNode* head() const override {
return _if_node;
}
IfTrueNode* tail() const override {
return _success_proj;
}
bool is_last_value() const {
return _if_node->assertion_predicate_type() == AssertionPredicateType::LastValue;
}
bool is_useless() const {
return opaque_node()->is_useless();
}
void kill(PhaseIterGVN& igvn) const;
static bool is_predicate(const Node* maybe_success_proj);
#ifdef ASSERT
static void verify(IfTrueNode* initialized_assertion_predicate_success_proj) {
InitializedAssertionPredicate initialized_assertion_predicate(initialized_assertion_predicate_success_proj);
initialized_assertion_predicate.verify();
}
void verify() const;
#endif // ASSERT
};
// Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Expression.
class TransformStrategyForOpaqueLoopNodes : public StackObj {
public:
virtual Node* transform_opaque_init(OpaqueLoopInitNode* opaque_init) const = 0;
virtual Node* transform_opaque_stride(OpaqueLoopStrideNode* opaque_stride) const = 0;
};
// A Template Assertion Predicate represents the OpaqueTemplateAssertionPredicateNode for the initial value or the last
// value of a Template Assertion Predicate and all the nodes up to and including the OpaqueLoop* nodes.
class TemplateAssertionExpression : public StackObj {
OpaqueTemplateAssertionPredicateNode* const _opaque_node;
PhaseIdealLoop* const _phase;
public:
TemplateAssertionExpression(OpaqueTemplateAssertionPredicateNode* opaque_node, PhaseIdealLoop* phase)
: _opaque_node(opaque_node),
_phase(phase) {}
NONCOPYABLE(TemplateAssertionExpression);
private:
OpaqueTemplateAssertionPredicateNode* clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy,
Node* new_control, CountedLoopNode* new_loop_node) const;
public:
OpaqueTemplateAssertionPredicateNode* clone(Node* new_control, CountedLoopNode* new_loop_node) const;
OpaqueTemplateAssertionPredicateNode* clone_and_replace_init(Node* new_control, Node* new_init,
CountedLoopNode* new_loop_node) const;
OpaqueTemplateAssertionPredicateNode* clone_and_replace_init_and_stride(Node* new_control, Node* new_init,
Node* new_stride) const;
OpaqueInitializedAssertionPredicateNode* clone_and_fold_opaque_loop_nodes(Node* new_control) const;
};
// Class to represent a node being part of a Template Assertion Expression. Note that this is not an IR node.
//
// The expression itself can belong to no, one, or two Template Assertion Predicates:
// - None: This node is already dead (i.e. we replaced the Bool condition of the Template Assertion Predicate).
// - Two: A OpaqueLoopInitNode could be part of two Template Assertion Predicates.
// - One: In all other cases.
class TemplateAssertionExpressionNode : public StackObj {
Node* const _node;
public:
explicit TemplateAssertionExpressionNode(Node* node) : _node(node) {
assert(is_in_expression(node), "must be valid");
}
NONCOPYABLE(TemplateAssertionExpressionNode);
private:
static bool is_template_assertion_predicate(const Node* node);
public:
// Check whether the provided node is part of a Template Assertion Expression or not.
static bool is_in_expression(Node* node);
// Check if the opcode of node could be found in a Template Assertion Expression.
// This also provides a fast check whether a node is unrelated.
static bool is_maybe_in_expression(const Node* node) {
const int opcode = node->Opcode();
return (node->is_OpaqueLoopInit() ||
node->is_OpaqueLoopStride() ||
node->is_Bool() ||
node->is_Cmp() ||
opcode == Op_AndL ||
opcode == Op_OrL ||
opcode == Op_RShiftL ||
opcode == Op_LShiftL ||
opcode == Op_LShiftI ||
opcode == Op_AddL ||
opcode == Op_AddI ||
opcode == Op_MulL ||
opcode == Op_MulI ||
opcode == Op_SubL ||
opcode == Op_SubI ||
opcode == Op_ConvI2L ||
opcode == Op_CastII);
}
// Apply the given function to all Template Assertion Predicates (if any) to which this Template Assertion Predicate
// Expression Node belongs to.
template <class Callback>
void for_each_template_assertion_predicate(Callback callback) {
ResourceMark rm;
Unique_Node_List list;
list.push(_node);
DEBUG_ONLY(int template_counter = 0;)
for (uint i = 0; i < list.size(); i++) {
Node* next = list.at(i);
if (is_template_assertion_predicate(next)) {
callback(next->as_If());
DEBUG_ONLY(template_counter++;)
} else {
assert(!next->is_CFG(), "no CFG expected in Template Assertion Expression");
list.push_outputs_of(next);
}
}
// Each node inside a Template Assertion Expression is in between a Template Assertion Predicate and its OpaqueLoop*
// nodes (or an OpaqueLoop* node itself). The OpaqueLoop* nodes do not common up. Therefore, each Template Assertion
// Expression node belongs to a single expression - except for OpaqueLoopInitNodes. An OpaqueLoopInitNode is shared
// between the init and last value Template Assertion Predicate at creation. Later, when cloning the expressions,
// they are no longer shared.
assert(template_counter <= 2, "a node cannot be part of more than two templates");
assert(template_counter <= 1 || _node->is_OpaqueLoopInit(), "only OpaqueLoopInit nodes can be part of two templates");
}
};
// This class is used to create the actual If node with a success path and a fail path with a Halt node.
class AssertionPredicateIfCreator : public StackObj {
PhaseIdealLoop* const _phase;
public:
explicit AssertionPredicateIfCreator(PhaseIdealLoop* const phase) : _phase(phase) {}
NONCOPYABLE(AssertionPredicateIfCreator);
IfTrueNode* create_for_initialized(Node* new_control, int if_opcode, Node* assertion_expression,
AssertionPredicateType assertion_predicate_type) const;
IfTrueNode* create_for_template(Node* new_control, int if_opcode, Node* assertion_expression,
AssertionPredicateType assertion_predicate_type) const;
private:
IfTrueNode* create(Node* new_control, int if_opcode, Node* assertion_expression, const char* halt_message,
AssertionPredicateType assertion_predicate_type) const;
IfNode* create_if_node(Node* new_control, int if_opcode, Node* assertion_expression, IdealLoopTree* loop,
AssertionPredicateType assertion_predicate_type) const;
IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop) const;
void create_fail_path(IfNode* if_node, IdealLoopTree* loop, const char* halt_message) const;
void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop, const char* halt_message) const;
};
// This class is used to create a Template Assertion Predicate either with a Halt Node from scratch.
class TemplateAssertionPredicateCreator : public StackObj {
CountedLoopNode* const _loop_head;
const int _scale;
Node* const _offset;
Node* const _range;
PhaseIdealLoop* const _phase;
OpaqueLoopInitNode* create_opaque_init(Node* new_control) const;
OpaqueTemplateAssertionPredicateNode* create_for_init_value(Node* new_control, OpaqueLoopInitNode* opaque_init,
bool& does_overflow) const;
OpaqueTemplateAssertionPredicateNode* create_for_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init,
bool& does_overflow) const;
Node* create_last_value(Node* new_control, OpaqueLoopInitNode* opaque_init) const;
IfTrueNode* create_if_node(Node* new_control,
OpaqueTemplateAssertionPredicateNode* template_assertion_predicate_expression,
bool does_overflow, AssertionPredicateType assertion_predicate_type) const;
public:
TemplateAssertionPredicateCreator(CountedLoopNode* loop_head, int scale, Node* offset, Node* range,
PhaseIdealLoop* phase)
: _loop_head(loop_head),
_scale(scale),
_offset(offset),
_range(range),
_phase(phase) {}
NONCOPYABLE(TemplateAssertionPredicateCreator);
IfTrueNode* create(Node* new_control) const;
};
// This class creates a new Initialized Assertion Predicate either from a template or from scratch.
class InitializedAssertionPredicateCreator : public StackObj {
PhaseIdealLoop* const _phase;
public:
explicit InitializedAssertionPredicateCreator(PhaseIdealLoop* phase);
NONCOPYABLE(InitializedAssertionPredicateCreator);
InitializedAssertionPredicate create_from_template(const IfNode* template_assertion_predicate, Node* new_control,
Node* new_init, Node* new_stride) const;
InitializedAssertionPredicate
create_from_template_and_insert_below(const TemplateAssertionPredicate& template_assertion_predicate) const;
IfTrueNode* create(Node* operand, Node* new_control, jint stride, int scale, Node* offset, Node* range,
AssertionPredicateType assertion_predicate_type) const;
private:
OpaqueInitializedAssertionPredicateNode* create_assertion_expression_from_template(const IfNode* template_assertion_predicate,
Node* new_control, Node* new_init,
Node* new_stride) const;
IfTrueNode* create_control_nodes(Node* new_control, int if_opcode,
OpaqueInitializedAssertionPredicateNode* assertion_expression,
AssertionPredicateType assertion_predicate_type) const;
};
// This class iterates through all predicates of a Regular Predicate Block and applies the given visitor to each.
class RegularPredicateBlockIterator : public StackObj {
Node* _current_node;
const Deoptimization::DeoptReason _deopt_reason;
public:
RegularPredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason)
: _current_node(start_node),
_deopt_reason(deopt_reason) {}
NONCOPYABLE(RegularPredicateBlockIterator);
// Skip all predicates by just following the inputs. We do not call any user provided visitor.
Node* skip_all() {
PredicateVisitor do_nothing; // No real visits, just do nothing.
return for_each(do_nothing);
}
// Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
// Returns the entry to the earliest predicate.
Node* for_each(PredicateVisitor& predicate_visitor) {
while (predicate_visitor.should_continue()) {
if (process_template_assertion_predicate(predicate_visitor)) {
continue;
}
if (process_runtime_predicate(predicate_visitor)) {
continue;
}
if (process_initialized_assertion_predicate(predicate_visitor)) {
continue;
}
// Either a Parse Predicate or not a Regular Predicate. In both cases, the node does not belong to this block.
break;
}
return _current_node;
}
bool process_template_assertion_predicate(PredicateVisitor& predicate_visitor) {
if (!TemplateAssertionPredicate::is_predicate(_current_node)) {
return false;
}
TemplateAssertionPredicate template_assertion_predicate(_current_node->as_IfTrue());
if (!template_assertion_predicate.is_useless()) {
// Only visit if not useless. Otherwise, just skip over it to possibly process other predicates above.
predicate_visitor.visit(template_assertion_predicate);
}
_current_node = template_assertion_predicate.entry();
return true;
}
bool process_runtime_predicate(PredicateVisitor& predicate_visitor) {
if (!RuntimePredicate::is_predicate(_current_node, _deopt_reason)) {
return false;
}
RuntimePredicate runtime_predicate(_current_node->as_IfProj());
predicate_visitor.visit(runtime_predicate);
_current_node = runtime_predicate.entry();
return true;
}
bool process_initialized_assertion_predicate(PredicateVisitor& predicate_visitor) {
if (!InitializedAssertionPredicate::is_predicate(_current_node)) {
return false;
}
InitializedAssertionPredicate initialized_assertion_predicate(_current_node->as_IfTrue());
if (!initialized_assertion_predicate.is_useless()) {
// Only visit if not useless. Otherwise, just skip over it to possibly process other predicates above.
predicate_visitor.visit(initialized_assertion_predicate);
}
_current_node = initialized_assertion_predicate.entry();
return true;
}
};
// This class iterates through all predicates of a Predicate Block and applies the given visitor to each.
class PredicateBlockIterator : public StackObj {
Node* const _start_node;
const ParsePredicate _parse_predicate; // Could be missing.
RegularPredicateBlockIterator _regular_predicate_block_iterator;
public:
PredicateBlockIterator(Node* start_node, Deoptimization::DeoptReason deopt_reason)
: _start_node(start_node),
_parse_predicate(start_node, deopt_reason),
_regular_predicate_block_iterator(_parse_predicate.entry(), deopt_reason) {}
// Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
// Returns the entry to the earliest predicate.
Node* for_each(PredicateVisitor& predicate_visitor) {
if (!predicate_visitor.should_continue()) {
return _start_node;
}
if (_parse_predicate.is_valid()) {
predicate_visitor.visit(_parse_predicate);
}
return _regular_predicate_block_iterator.for_each(predicate_visitor);
}
};
// Class to walk over all predicates starting at a node, which usually is the loop entry node, and following the inputs.
// At each predicate, a PredicateVisitor is applied which the user can implement freely.
class PredicateIterator : public StackObj {
Node* _start_node;
public:
explicit PredicateIterator(Node* start_node)
: _start_node(start_node) {}
NONCOPYABLE(PredicateIterator);
// Apply the 'predicate_visitor' for each predicate found in the predicate chain started at the provided node.
// Returns the entry to the earliest predicate.
Node* for_each(PredicateVisitor& predicate_visitor) const {
Node* current_node = _start_node;
PredicateBlockIterator loop_limit_check_predicate_iterator(current_node, Deoptimization::Reason_loop_limit_check);
current_node = loop_limit_check_predicate_iterator.for_each(predicate_visitor);
PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check);
current_node = auto_vectorization_check_iterator.for_each(predicate_visitor);
if (UseLoopPredicate) {
if (UseProfiledLoopPredicate) {
PredicateBlockIterator profiled_loop_predicate_iterator(current_node, Deoptimization::Reason_profile_predicate);
current_node = profiled_loop_predicate_iterator.for_each(predicate_visitor);
}
PredicateBlockIterator loop_predicate_iterator(current_node, Deoptimization::Reason_predicate);
current_node = loop_predicate_iterator.for_each(predicate_visitor);
}
return current_node;
}
};
// Unified PredicateVisitor which only provides a single visit method for a generic Predicate. This visitor can be used
// when it does not matter what kind of predicate is visited. Note that we override all normal visit methods from
// PredicateVisitor by calling the unified method. These visit methods are marked final such that they cannot be
// overridden by implementors of this class.
class UnifiedPredicateVisitor : public PredicateVisitor {
public:
virtual void visit(const TemplateAssertionPredicate& template_assertion_predicate) override final {
visit_predicate(template_assertion_predicate);
}
virtual void visit(const ParsePredicate& parse_predicate) override final {
visit_predicate(parse_predicate);
}
virtual void visit(const RuntimePredicate& runtime_predicate) override final {
visit_predicate(runtime_predicate);
}
virtual void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override final {
visit_predicate(initialized_assertion_predicate);
}
virtual void visit_predicate(const Predicate& predicate) = 0;
};
// A block of Regular Predicates inside a Predicate Block without its Parse Predicate.
class RegularPredicateBlock : public StackObj {
const Deoptimization::DeoptReason _deopt_reason;
Node* const _entry;
public:
RegularPredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason)
: _deopt_reason(deopt_reason),
_entry(skip_all(tail)) {
DEBUG_ONLY(verify_block(tail);)
}
NONCOPYABLE(RegularPredicateBlock);
private:
// Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block
// anymore (i.e. entry to the first Regular Predicate in this block if any or `tail` otherwise).
Node* skip_all(Node* tail) const {
RegularPredicateBlockIterator iterator(tail, _deopt_reason);
return iterator.skip_all();
}
DEBUG_ONLY(void verify_block(Node* tail) const;)
public:
Node* entry() const {
return _entry;
}
};
#ifndef PRODUCT
// Visitor class to print all the visited predicates. Used by the Predicates class which does the printing starting
// at the loop node and then following the inputs to the earliest predicate.
class PredicatePrinter : public PredicateVisitor {
const char* _prefix; // Prefix added to each dumped string.
public:
explicit PredicatePrinter(const char* prefix) : _prefix(prefix) {}
NONCOPYABLE(PredicatePrinter);
void visit(const ParsePredicate& parse_predicate) override {
print_predicate_node("Parse Predicate", parse_predicate);
}
void visit(const RuntimePredicate& runtime_predicate) override {
print_predicate_node("Runtime Predicate", runtime_predicate);
}
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override {
print_predicate_node("Template Assertion Predicate", template_assertion_predicate);
}
void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override {
print_predicate_node("Initialized Assertion Predicate", initialized_assertion_predicate);
}
private:
void print_predicate_node(const char* predicate_name, const Predicate& predicate) const {
tty->print_cr("%s- %s: %d %s", _prefix, predicate_name, predicate.head()->_idx, predicate.head()->Name());
}
};
#endif // NOT PRODUCT
// This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block,
// or a Loop Limit Check Predicate Block). It contains zero or more Regular Predicates followed by a Parse Predicate
// which, however, does not need to exist (we could already have decided to remove Parse Predicates for this loop).
class PredicateBlock : public StackObj {
const ParsePredicate _parse_predicate; // Could be missing.
const RegularPredicateBlock _regular_predicate_block;
Node* const _entry;
#ifndef PRODUCT
// Used for dumping.
Node* const _tail;
const Deoptimization::DeoptReason _deopt_reason;
#endif // NOT PRODUCT
public:
PredicateBlock(Node* tail, Deoptimization::DeoptReason deopt_reason)
: _parse_predicate(tail, deopt_reason),
_regular_predicate_block(_parse_predicate.entry(), deopt_reason),
_entry(_regular_predicate_block.entry())
#ifndef PRODUCT
, _tail(tail)
, _deopt_reason(deopt_reason)
#endif // NOT PRODUCT
{}
NONCOPYABLE(PredicateBlock);
// Returns the control input node into this Regular Predicate block. This is either:
// - The control input to the first If node in the block representing a Runtime Predicate if there is at least one
// Runtime Predicate.
// - The control input node into the ParsePredicate node if there is only a Parse Predicate and no Runtime Predicate.
// - The same node initially passed to the constructor if this Regular Predicate block is empty (i.e. no Parse
// Predicate or Runtime Predicate).
Node* entry() const {
return _entry;
}
bool is_non_empty() const {
return has_parse_predicate() || has_runtime_predicates();
}
bool has_parse_predicate() const {
return _parse_predicate.is_valid();
}
ParsePredicateNode* parse_predicate() const {
return _parse_predicate.head();
}
ParsePredicateSuccessProj* parse_predicate_success_proj() const {
return _parse_predicate.tail();
}
bool has_runtime_predicates() const {
return _parse_predicate.entry() != _entry;
}
// Returns either:
// - The entry to the Parse Predicate if present.
// - The last Runtime Predicate success projection if Parse Predicate is not present.
// - The entry to this Regular Predicate Block if the block is empty.
Node* skip_parse_predicate() const {
return _parse_predicate.entry();
}
#ifndef PRODUCT
void dump() const;
void dump(const char* prefix) const;
#endif // NOT PRODUCT
};
// This class takes a loop entry node and finds all the available predicates for the loop.
class Predicates : public StackObj {
Node* const _tail;
const PredicateBlock _loop_limit_check_predicate_block;
const PredicateBlock _auto_vectorization_check_block;
const PredicateBlock _profiled_loop_predicate_block;
const PredicateBlock _loop_predicate_block;
Node* const _entry;
public:
explicit Predicates(Node* loop_entry)
: _tail(loop_entry),
_loop_limit_check_predicate_block(loop_entry, Deoptimization::Reason_loop_limit_check),
_auto_vectorization_check_block(_loop_limit_check_predicate_block.entry(),
Deoptimization::Reason_auto_vectorization_check),
_profiled_loop_predicate_block(_auto_vectorization_check_block.entry(),
Deoptimization::Reason_profile_predicate),
_loop_predicate_block(_profiled_loop_predicate_block.entry(),
Deoptimization::Reason_predicate),
_entry(_loop_predicate_block.entry()) {}
NONCOPYABLE(Predicates);
// Returns the control input the first predicate if there are any predicates. If there are no predicates, the same
// node initially passed to the constructor is returned.
Node* entry() const {
return _entry;
}
const PredicateBlock* loop_predicate_block() const {
return &_loop_predicate_block;
}
const PredicateBlock* profiled_loop_predicate_block() const {
return &_profiled_loop_predicate_block;
}
const PredicateBlock* auto_vectorization_check_block() const {
return &_auto_vectorization_check_block;
}
const PredicateBlock* loop_limit_check_predicate_block() const {
return &_loop_limit_check_predicate_block;
}
bool has_any() const {
return _entry != _tail;
}
#ifndef PRODUCT
/*
* Debug printing functions.
*/
void dump() const;
static void dump_at(Node* node);
static void dump_for_loop(LoopNode* loop_node);
#endif // NOT PRODUCT
};
// This class checks whether a node is in the original loop body and not the cloned one.
class NodeInOriginalLoopBody : public NodeInLoopBody {
const uint _first_node_index_in_cloned_loop_body;
const Node_List& _old_new;
public:
NodeInOriginalLoopBody(const uint first_node_index_in_cloned_loop_body, const Node_List& old_new)
: _first_node_index_in_cloned_loop_body(first_node_index_in_cloned_loop_body),
_old_new(old_new) {}
NONCOPYABLE(NodeInOriginalLoopBody);
// Check if 'node' is not a cloned node (i.e. "< _first_node_index_in_cloned_loop_body") and if we've created a
// clone from 'node' (i.e. _old_new entry is non-null). Then we know that 'node' belongs to the original loop body.
bool check_node_in_loop_body(Node* node) const override {
if (node->_idx < _first_node_index_in_cloned_loop_body) {
Node* cloned_node = _old_new[node->_idx];
// Check that the clone is actually part of the cloned loop body and not from some earlier cloning.
return cloned_node != nullptr && cloned_node->_idx >= _first_node_index_in_cloned_loop_body;
}
return false;
}
};
// This class checks whether a node is in the main loop body and not the pre loop body. We cannot use the
// NodeInOriginalLoopBody class because PhaseIdealLoop::clone_up_backedge_goo() could clone additional nodes that
// should be pinned at the main loop body entry. The check in NodeInOriginalLoopBody will ignore these.
class NodeInMainLoopBody : public NodeInLoopBody {
const uint _first_node_index_in_pre_loop_body;
const uint _last_node_index_in_pre_loop_body;
DEBUG_ONLY(const uint _last_node_index_from_backedge_goo;)
const Node_List& _old_new;
public:
NodeInMainLoopBody(const uint first_node_index_in_pre_loop_body, const uint last_node_index_in_pre_loop_body,
DEBUG_ONLY(const uint last_node_index_from_backedge_goo COMMA) const Node_List& old_new)
: _first_node_index_in_pre_loop_body(first_node_index_in_pre_loop_body),
_last_node_index_in_pre_loop_body(last_node_index_in_pre_loop_body),
DEBUG_ONLY(_last_node_index_from_backedge_goo(last_node_index_from_backedge_goo) COMMA)
_old_new(old_new) {}
NONCOPYABLE(NodeInMainLoopBody);
// Check if 'node' is not a cloned node (i.e. "< _first_node_index_in_cloned_loop_body") and if we've created a
// clone from 'node' (i.e. _old_new entry is non-null). Then we know that 'node' belongs to the original loop body.
// Additionally check if a node was cloned after the pre loop was created. This indicates that it was created by
// PhaseIdealLoop::clone_up_backedge_goo(). These nodes should also be pinned at the main loop entry.
bool check_node_in_loop_body(Node* node) const override {
if (node->_idx < _first_node_index_in_pre_loop_body) {
Node* cloned_node = _old_new[node->_idx];
// Check that the clone is actually part of the cloned loop body and not from some earlier cloning.
bool cloned_node_in_pre_loop_body = cloned_node != nullptr && cloned_node->_idx >= _first_node_index_in_pre_loop_body;
assert(!cloned_node_in_pre_loop_body || cloned_node->_idx <= _last_node_index_in_pre_loop_body,
"clone must be part of pre loop body");
return cloned_node_in_pre_loop_body;
}
// Created in PhaseIdealLoop::clone_up_backedge_goo()?
bool node_created_by_backedge_goo = node->_idx > _last_node_index_in_pre_loop_body;
assert(!node_created_by_backedge_goo || node->_idx <= _last_node_index_from_backedge_goo,
"cloned node must have been created in PhaseIdealLoop::clone_up_backedge_goo()");
return node_created_by_backedge_goo;
}
};
// This class checks whether a node is in the cloned loop body and not the original one from which the loop was cloned.
class NodeInClonedLoopBody : public NodeInLoopBody {
const uint _first_node_index_in_cloned_loop_body;
public:
explicit NodeInClonedLoopBody(const uint first_node_index_in_cloned_loop_body)
: _first_node_index_in_cloned_loop_body(first_node_index_in_cloned_loop_body) {}
NONCOPYABLE(NodeInClonedLoopBody);
// Check if 'node' is a clone. This can easily be achieved by comparing its node index to the first node index
// inside the cloned loop body (all of them are clones).
bool check_node_in_loop_body(Node* node) const override {
return node->_idx >= _first_node_index_in_cloned_loop_body;
}
};
// Visitor to create Initialized Assertion Predicates at a target loop from Template Assertion Predicates from a source
// loop. This visitor can be used in combination with a PredicateIterator.
class CreateAssertionPredicatesVisitor : public PredicateVisitor {
Node* const _init;
Node* const _stride;
CountedLoopNode* const _target_loop_head;
Node* const _old_target_loop_entry;
Node* _current_predicate_chain_head;
PhaseIdealLoop* const _phase;
const NodeInLoopBody& _node_in_loop_body;
const bool _kill_old_template;
TemplateAssertionPredicate
clone_template_and_replace_init_input(const TemplateAssertionPredicate& template_assertion_predicate) const;
InitializedAssertionPredicate initialize_from_template(const TemplateAssertionPredicate& template_assertion_predicate,
IfTrueNode* cloned_template_predicate_tail) const;
void rewire_to_old_predicate_chain_head(Node* initialized_assertion_predicate_success_proj) const;
public:
CreateAssertionPredicatesVisitor(CountedLoopNode* target_loop_head, PhaseIdealLoop* phase,
const NodeInLoopBody& node_in_loop_body, bool kill_old_template);
NONCOPYABLE(CreateAssertionPredicatesVisitor);
using PredicateVisitor::visit;
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override;
};
// This class establishes a predicate chain at the target loop by rewiring newly cloned predicates to the current head
// of the predicate chain.
class TargetLoopPredicateChain : public StackObj {
DEBUG_ONLY(const Node* const _old_target_loop_entry;)
DEBUG_ONLY(const node_idx_t _node_index_before_cloning;)
Node* _current_predicate_chain_head;
PhaseIdealLoop* const _phase;
void rewire_to_target_chain_head(IfTrueNode* template_assertion_predicate_success_proj) const;
public:
TargetLoopPredicateChain(LoopNode* loop_head, PhaseIdealLoop* phase);
NONCOPYABLE(TargetLoopPredicateChain);
void insert_predicate(const Predicate& predicate);
};
// This class clones Parse and Template Assertion Predicates to the provided target loop. This also involves rewiring
// of any data pinned to Template Assertion Predicates. The Template Assertion Predicate Expressions are cloned
// without applying any changes to them.
//
// Each time a predicate is cloned, it is inserted at the top of previously cloned predicates. This ensures that the
// target loop predicate chain order of the newly cloned predicates is the same as in the source loop from which the
// predicates were cloned from.
//
// Template Assertion Predicate Example:
//
// x _old_target_loop_entry _old_target_loop_entry
// | | | |
// Template Assertion | Cloned Template 2. rewire data Cloned Template
// Predicate 1. clone | Assertion Predicate and predicate Assertion Predicate
// | \ =======> | ===============> | \
// | data | | data
// | | |
// source loop head target loop head target loop head
class ClonePredicateToTargetLoop : public StackObj {
LoopNode* const _target_loop_head;
LoopNode* const _target_outer_loop_head;
Node* const _old_target_loop_entry; // Used as control for each newly cloned predicate.
TargetLoopPredicateChain _target_loop_predicate_chain;
const NodeInLoopBody& _node_in_loop_body;
PhaseIdealLoop* const _phase;
public:
ClonePredicateToTargetLoop(LoopNode* target_loop_head, const NodeInLoopBody& node_in_loop_body, PhaseIdealLoop* phase);
// Clones the provided Parse Predicate to the head of the current predicate chain at the target loop.
void clone_parse_predicate(const ParsePredicate& parse_predicate, bool is_false_path_loop) {
ParsePredicate cloned_parse_predicate = parse_predicate.clone_to_unswitched_loop(_old_target_loop_entry,
is_false_path_loop, _phase);
_target_loop_predicate_chain.insert_predicate(cloned_parse_predicate);
}
void clone_template_assertion_predicate(const TemplateAssertionPredicate& template_assertion_predicate);
};
// Visitor to clone Parse and Template Assertion Predicates from a loop to its unswitched true and false path loop.
// The cloned predicates are not updated in any way. Thus, an Initialized Assertion Predicate is also not required to
// be created. Note that the data dependencies from the Template Assertion Predicates are also updated to the newly
// cloned Template Assertion Predicates, depending on whether they belong to the true or false path loop.
class CloneUnswitchedLoopPredicatesVisitor : public PredicateVisitor {
ClonePredicateToTargetLoop _clone_predicate_to_true_path_loop;
ClonePredicateToTargetLoop _clone_predicate_to_false_path_loop;
PhaseIdealLoop* const _phase;
const bool _is_counted_loop;
public:
CloneUnswitchedLoopPredicatesVisitor(LoopNode* true_path_loop_head,
LoopNode* false_path_loop_head,
const NodeInOriginalLoopBody& node_in_true_path_loop_body,
const NodeInClonedLoopBody& node_in_false_path_loop_body,
PhaseIdealLoop* phase);
NONCOPYABLE(CloneUnswitchedLoopPredicatesVisitor);
using PredicateVisitor::visit;
void visit(const ParsePredicate& parse_predicate) override;
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override;
};
// This visitor collects all OpaqueTemplateAssertionNodes of Template Assertion Predicates. This is used for cleaning
// up unused Template Assertion Predicates.
class OpaqueTemplateAssertionPredicateCollector : public PredicateVisitor {
Unique_Node_List& _list;
public:
explicit OpaqueTemplateAssertionPredicateCollector(Unique_Node_List& list) : _list(list) {}
using PredicateVisitor::visit;
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override {
_list.push(template_assertion_predicate.opaque_node());
}
};
// This visitor updates the stride for an Assertion Predicate during Loop Unrolling. The inputs to the OpaqueLoopStride
// nodes Template of Template Assertion Predicates are updated and new Initialized Assertion Predicates are created
// from the updated templates. The old Initialized Assertion Predicates are killed.
class UpdateStrideForAssertionPredicates : public PredicateVisitor {
Node* const _new_stride;
CountedLoopNode* const _loop_node;
PhaseIdealLoop* const _phase;
void replace_opaque_stride_input(const TemplateAssertionPredicate& template_assertion_predicate) const;
InitializedAssertionPredicate
initialize_from_updated_template(const TemplateAssertionPredicate& template_assertion_predicate) const;
void connect_initialized_assertion_predicate(Node* new_control_out, const InitializedAssertionPredicate& initialized_assertion_predicate) const;
public:
UpdateStrideForAssertionPredicates(Node* const new_stride, CountedLoopNode* loop_node, PhaseIdealLoop* phase)
: _new_stride(new_stride),
_loop_node(loop_node),
_phase(phase) {}
NONCOPYABLE(UpdateStrideForAssertionPredicates);
using PredicateVisitor::visit;
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override;
void visit(const InitializedAssertionPredicate& initialized_assertion_predicate) override;
};
// Eliminate all useless Parse and Template Assertion Predicates. They become useless when they can no longer be found
// from a loop head. We mark these useless to clean them up later during IGVN. A Predicate that is marked useless will
// no longer be visited by a PredicateVisitor.
class EliminateUselessPredicates : public StackObj {
Compile* const C;
const GrowableArray<ParsePredicateNode*>& _parse_predicates;
const GrowableArray<OpaqueTemplateAssertionPredicateNode*>& _template_assertion_predicate_opaques;
PhaseIterGVN& _igvn;
IdealLoopTree* const _ltree_root;
void mark_all_predicates_maybe_useful() const;
template <class PredicateList>
static void mark_predicates_on_list_maybe_useful(const PredicateList& predicate_list);
void mark_loop_associated_predicates_useful() const;
static void mark_useful_predicates_for_loop(IdealLoopTree* loop);
void mark_maybe_useful_predicates_useless() const;
template <class PredicateList>
void mark_maybe_useful_predicates_on_list_useless(const PredicateList& predicate_list) const;
#ifdef ASSERT
void verify_loop_nodes_of_useless_templates_assertion_predicates_are_dead() const;
Unique_Node_List collect_loop_nodes_of_useless_template_assertion_predicates() const;
void verify_associated_loop_nodes_are_dead(const Unique_Node_List& loop_nodes_of_useless_template_assertion_predicates) const;
#endif // ASSERT
public:
EliminateUselessPredicates(PhaseIterGVN& igvn, IdealLoopTree* ltree_root)
: C(igvn.C), _parse_predicates(igvn.C->parse_predicates()),
_template_assertion_predicate_opaques(igvn.C->template_assertion_predicate_opaques()),
_igvn(igvn),
_ltree_root(ltree_root) {}
void eliminate() const;
};
#endif // SHARE_OPTO_PREDICATES_HPP