< prev index next >
src/hotspot/share/opto/loopnode.hpp
Print this page
*** 588,607 ****
// Convert one iteration loop into normal code.
bool do_one_iteration_loop( PhaseIdealLoop *phase );
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
! // make some loop-invariant test (usually a null-check) happen before the
! // loop.
! bool policy_peeling( PhaseIdealLoop *phase ) const;
// Return TRUE or FALSE if the loop should be maximally unrolled. Stash any
// known trip count in the counted loop node.
! bool policy_maximally_unroll( PhaseIdealLoop *phase ) const;
! // Return TRUE or FALSE if the loop should be unrolled or not. Unroll if
! // the loop is a CountedLoop and the body is small enough.
bool policy_unroll(PhaseIdealLoop *phase);
// Loop analyses to map to a maximal superword unrolling for vectorization.
void policy_unroll_slp_analysis(CountedLoopNode *cl, PhaseIdealLoop *phase, int future_unroll_ct);
--- 588,608 ----
// Convert one iteration loop into normal code.
bool do_one_iteration_loop( PhaseIdealLoop *phase );
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
! // move some loop-invariant test (usually a null-check) before the loop.
! bool policy_peeling(PhaseIdealLoop *phase);
!
! uint estimate_peeling(PhaseIdealLoop *phase);
// Return TRUE or FALSE if the loop should be maximally unrolled. Stash any
// known trip count in the counted loop node.
! bool policy_maximally_unroll(PhaseIdealLoop *phase) const;
! // Return TRUE or FALSE if the loop should be unrolled or not. Apply unroll
! // if the loop is a counted loop and the loop body is small enough.
bool policy_unroll(PhaseIdealLoop *phase);
// Loop analyses to map to a maximal superword unrolling for vectorization.
void policy_unroll_slp_analysis(CountedLoopNode *cl, PhaseIdealLoop *phase, int future_unroll_ct);
*** 618,627 ****
--- 619,631 ----
bool policy_align( PhaseIdealLoop *phase ) const;
// Return TRUE if "iff" is a range check.
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const;
+ // Estimate the number of nodes required when cloning a loop (body).
+ uint est_loop_clone_sz(uint factor) const;
+
// Compute loop trip count if possible
void compute_trip_count(PhaseIdealLoop* phase);
// Compute loop trip count from profile data
float compute_profile_trip_cnt_helper(Node* n);
*** 1354,1407 ****
// A simplistic node request tracking mechanism, where
// = UINT_MAX Request not valid or made final.
// < UINT_MAX Nodes currently requested (estimate).
uint _nodes_required;
bool exceeding_node_budget(uint required = 0) {
assert(C->live_nodes() < C->max_node_limit(), "sanity");
uint available = C->max_node_limit() - C->live_nodes();
return available < required + _nodes_required;
}
! uint require_nodes(uint require) {
precond(require > 0);
! _nodes_required += MAX2(100u, require); // Keep requests at minimum 100.
return _nodes_required;
}
! bool may_require_nodes(uint require) {
! return !exceeding_node_budget(require) && require_nodes(require) > 0;
}
! void require_nodes_begin() {
assert(_nodes_required == UINT_MAX, "Bad state (begin).");
_nodes_required = 0;
}
! // Final check that the requested nodes did not exceed the limit and that
! // the request was reasonably correct with respect to the number of new
! // nodes introduced by any transform since the last 'begin'.
! void require_nodes_final_check(uint live_at_begin) {
! uint required = _nodes_required;
! require_nodes_final();
! uint delta = C->live_nodes() - live_at_begin;
! // Assert is disabled, see JDK-8223911 and related issues.
! assert(true || delta <= 2 * required, "Bad node estimate (actual: %d, request: %d)",
! delta, required);
! }
!
! void require_nodes_final() {
assert(_nodes_required < UINT_MAX, "Bad state (final).");
! assert(!exceeding_node_budget(), "Too many NODES required!");
_nodes_required = UINT_MAX;
}
bool _created_loop_node;
public:
- uint nodes_required() const { return _nodes_required; }
-
void set_created_loop_node() { _created_loop_node = true; }
bool created_loop_node() { return _created_loop_node; }
void register_new_node( Node *n, Node *blk );
#ifdef ASSERT
--- 1358,1427 ----
// A simplistic node request tracking mechanism, where
// = UINT_MAX Request not valid or made final.
// < UINT_MAX Nodes currently requested (estimate).
uint _nodes_required;
+ enum { REQUIRE_MIN = 70 };
+
+ uint nodes_required() const { return _nodes_required; }
+
+ // Given the _currently_ available number of nodes, check whether there is
+ // "room" for an additional request or not, considering the already required
+ // number of nodes. Return TRUE if the new request is exceeding the node
+ // budget limit, otherwise return FALSE. Note that this interpretation will
+ // act pessimistic on additional requests when new nodes have already been
+ // generated since the 'begin'. This behaviour fits with the intention that
+ // node estimates/requests should be made upfront.
bool exceeding_node_budget(uint required = 0) {
assert(C->live_nodes() < C->max_node_limit(), "sanity");
uint available = C->max_node_limit() - C->live_nodes();
return available < required + _nodes_required;
}
! uint require_nodes(uint require, uint minreq = REQUIRE_MIN) {
precond(require > 0);
! _nodes_required += MAX2(require, minreq);
return _nodes_required;
}
! bool may_require_nodes(uint require, uint minreq = REQUIRE_MIN) {
! return !exceeding_node_budget(require) && require_nodes(require, minreq) > 0;
}
! uint require_nodes_begin() {
assert(_nodes_required == UINT_MAX, "Bad state (begin).");
_nodes_required = 0;
+ return C->live_nodes();
}
! // When a node request is final, optionally check that the requested number
! // of nodes was reasonably correct with respect to the number of new nodes
! // introduced since the last 'begin'. Always check that we have not exceeded
! // the maximum node limit.
! void require_nodes_final(uint live_at_begin, bool check_estimate) {
assert(_nodes_required < UINT_MAX, "Bad state (final).");
!
! if (check_estimate) {
! // Assert that the node budget request was not off by too much (x2).
! // Should this be the case we _surely_ need to improve the estimates
! // used in our budget calculations.
! assert(C->live_nodes() - live_at_begin <= 2 * _nodes_required,
! "Bad node estimate: actual = %d >> request = %d",
! C->live_nodes() - live_at_begin, _nodes_required);
! }
! // Assert that we have stayed within the node budget limit.
! assert(C->live_nodes() < C->max_node_limit(),
! "Exceeding node budget limit: %d + %d > %d (request = %d)",
! C->live_nodes() - live_at_begin, live_at_begin,
! C->max_node_limit(), _nodes_required);
!
_nodes_required = UINT_MAX;
}
bool _created_loop_node;
public:
void set_created_loop_node() { _created_loop_node = true; }
bool created_loop_node() { return _created_loop_node; }
void register_new_node( Node *n, Node *blk );
#ifdef ASSERT
*** 1436,1487 ****
_check_at_final(chk == BUDGET_CHECK),
_nodes_at_begin(0)
{
precond(_phase != NULL);
! _nodes_at_begin = _phase->C->live_nodes();
! _phase->require_nodes_begin();
}
~AutoNodeBudget() {
- if (_check_at_final) {
#ifndef PRODUCT
if (TraceLoopOpts) {
uint request = _phase->nodes_required();
-
- if (request > 0) {
uint delta = _phase->C->live_nodes() - _nodes_at_begin;
if (request < delta) {
tty->print_cr("Exceeding node budget: %d < %d", request, delta);
}
}
}
- #endif
- _phase->require_nodes_final_check(_nodes_at_begin);
- } else {
- _phase->require_nodes_final();
}
}
private:
PhaseIdealLoop* _phase;
bool _check_at_final;
uint _nodes_at_begin;
};
- // The Estimated Loop Clone Size: CloneFactor * (BodySize + BC) + CC, where BC
- // and CC are totally ad-hoc/magic "body" and "clone" constants, respectively,
- // used to ensure that node usage estimates made are on the safe side, for the
- // most part.
- static inline uint est_loop_clone_sz(uint fact, uint size) {
- uint const bc = 31;
- uint const cc = 41;
- uint estimate = fact * (size + bc) + cc;
- return (estimate - cc) / fact == size + bc ? estimate : UINT_MAX;
- }
-
// This kit may be used for making of a reserved copy of a loop before this loop
// goes under non-reversible changes.
//
// Function create_reserve() creates a reserved copy (clone) of the loop.
--- 1456,1497 ----
_check_at_final(chk == BUDGET_CHECK),
_nodes_at_begin(0)
{
precond(_phase != NULL);
! _nodes_at_begin = _phase->require_nodes_begin();
}
~AutoNodeBudget() {
#ifndef PRODUCT
if (TraceLoopOpts) {
uint request = _phase->nodes_required();
uint delta = _phase->C->live_nodes() - _nodes_at_begin;
if (request < delta) {
tty->print_cr("Exceeding node budget: %d < %d", request, delta);
+ } else {
+ uint const REQUIRE_MIN = PhaseIdealLoop::REQUIRE_MIN;
+ // Identify the worst estimates as "poor" ones.
+ if (request > REQUIRE_MIN && delta > 0) {
+ if ((delta > REQUIRE_MIN && request > 3 * delta) ||
+ (delta <= REQUIRE_MIN && request > 10 * delta)) {
+ tty->print_cr("Poor node estimate: %d >> %d", request, delta);
}
}
}
}
+ #endif // PRODUCT
+ _phase->require_nodes_final(_nodes_at_begin, _check_at_final);
}
private:
PhaseIdealLoop* _phase;
bool _check_at_final;
uint _nodes_at_begin;
};
// This kit may be used for making of a reserved copy of a loop before this loop
// goes under non-reversible changes.
//
// Function create_reserve() creates a reserved copy (clone) of the loop.
< prev index next >