< prev index next >

src/hotspot/share/opto/loopnode.hpp

Print this page

        

*** 587,608 **** bool do_remove_empty_loop( PhaseIdealLoop *phase ); // 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); --- 587,607 ---- bool do_remove_empty_loop( PhaseIdealLoop *phase ); // 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);
*** 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); --- 618,627 ----
*** 822,832 **** // get their replacement Node in slot 1. Instead of updating the block // location of all Nodes in the subsumed block, we lazily do it. As we // pull such a subsumed block out of the array, we write back the final // correct block. Node *get_ctrl( Node *i ) { - assert(has_node(i), ""); Node *n = get_ctrl_no_update(i); _nodes.map( i->_idx, (Node*)((intptr_t)n + 1) ); assert(has_node(i) && has_ctrl(i), ""); assert(n == find_non_split_ctrl(n), "must return legal ctrl" ); --- 818,827 ----
*** 1305,1317 **** // forcing an extra register move) void reorg_offsets( IdealLoopTree *loop ); // Check for aggressive application of 'split-if' optimization, // using basic block level info. ! void split_if_with_blocks ( VectorSet &visited, Node_Stack &nstack); Node *split_if_with_blocks_pre ( Node *n ); ! void split_if_with_blocks_post( Node *n ); Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). void dominated_by( Node *prevdom, Node *iff, bool flip = false, bool exclude_loop_predicate = false ); --- 1300,1312 ---- // forcing an extra register move) void reorg_offsets( IdealLoopTree *loop ); // Check for aggressive application of 'split-if' optimization, // using basic block level info. ! void split_if_with_blocks ( VectorSet &visited, Node_Stack &nstack, bool last_round ); Node *split_if_with_blocks_pre ( Node *n ); ! void split_if_with_blocks_post( Node *n, bool last_round ); Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). void dominated_by( Node *prevdom, Node *iff, bool flip = false, bool exclude_loop_predicate = false );
*** 1359,1428 **** // 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 --- 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
*** 1457,1498 **** _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. --- 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.
< prev index next >