< prev index next >

src/hotspot/share/opto/loopnode.hpp

Print this page

        

@@ -587,22 +587,21 @@
   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 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;
+  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.
+  // 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,13 +618,10 @@
   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);

@@ -822,11 +818,10 @@
   // 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" );

@@ -1305,13 +1300,13 @@
   // 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);
+  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 );
+  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,70 +1354,54 @@
   // 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) {
+  uint require_nodes(uint require) {
     precond(require > 0);
-    _nodes_required += MAX2(require, minreq);
+    _nodes_required += MAX2(100u, require); // Keep requests at minimum 100.
     return _nodes_required;
   }
 
-  bool may_require_nodes(uint require, uint minreq = REQUIRE_MIN) {
-    return !exceeding_node_budget(require) && require_nodes(require, minreq) > 0;
+  bool may_require_nodes(uint require) {
+    return !exceeding_node_budget(require) && require_nodes(require) > 0;
   }
 
-  uint require_nodes_begin() {
+  void 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);
+  // 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,42 +1436,52 @@
       _check_at_final(chk == BUDGET_CHECK),
       _nodes_at_begin(0)
   {
     precond(_phase != NULL);
 
-    _nodes_at_begin = _phase->require_nodes_begin();
+    _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();
-      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);
+      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();
     }
-#endif // PRODUCT
-    _phase->require_nodes_final(_nodes_at_begin, _check_at_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 >