8214172: GC interface entry points for loop opts
authorroland
Tue, 27 Nov 2018 09:35:02 +0100
changeset 52711 f480ad035c73
parent 52710 70adb0f573a7
child 52712 d17e09494308
8214172: GC interface entry points for loop opts Reviewed-by: kvn, rkennke
src/hotspot/share/gc/shared/c2/barrierSetC2.hpp
src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp
src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp
src/hotspot/share/opto/compile.cpp
src/hotspot/share/opto/compile.hpp
src/hotspot/share/opto/loopnode.cpp
src/hotspot/share/opto/macro.cpp
src/hotspot/share/opto/phase.cpp
src/hotspot/share/opto/phase.hpp
src/hotspot/share/opto/phasetype.hpp
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Tue Nov 27 09:35:02 2018 +0100
@@ -60,6 +60,7 @@
 class GraphKit;
 class IdealKit;
 class Node;
+class PhaseIdealLoop;
 class PhaseGVN;
 class PhaseMacroExpand;
 class Type;
@@ -277,9 +278,12 @@
   // Allow barrier sets to have shared state that is preserved across a compilation unit.
   // This could for example comprise macro nodes to be expanded during macro expansion.
   virtual void* create_barrier_state(Arena* comp_arena) const { return NULL; }
-  // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be
-  // expanded later, then now is the time to do so.
-  virtual bool expand_macro_nodes(PhaseMacroExpand* macro) const { return false; }
+  // If the BarrierSetC2 state has barrier nodes in its compilation
+  // unit state to be expanded later, then now is the time to do so.
+  virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const { return false; }
+  virtual bool optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const { return false; }
+  virtual bool strip_mined_loops_expanded(LoopOptsMode mode) const { return false; }
+  virtual bool is_gc_specific_loop_opts_pass(LoopOptsMode mode) const { return false; }
 
   virtual bool has_special_unique_user(const Node* node) const { return false; }
 
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Tue Nov 27 09:35:02 2018 +0100
@@ -996,9 +996,8 @@
   return;
 }
 
-bool ZBarrierSetC2::expand_macro_nodes(PhaseMacroExpand* macro) const {
-  Compile* C = Compile::current();
-  PhaseIterGVN &igvn = macro->igvn();
+bool ZBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const {
+  PhaseMacroExpand macro(igvn);
   ZBarrierSetC2State* s = state();
   if (s->load_barrier_count() > 0) {
 #ifdef ASSERT
@@ -1018,7 +1017,7 @@
         skipped++;
         continue;
       }
-      expand_loadbarrier_node(macro, n);
+      expand_loadbarrier_node(&macro, n);
       assert(s->load_barrier_count() < load_barrier_count, "must have deleted a node from load barrier list");
       if (C->failing())  return true;
     }
@@ -1027,7 +1026,7 @@
       LoadBarrierNode* n = s->load_barrier_node(load_barrier_count - 1);
       assert(!(igvn.type(n) == Type::TOP || (n->in(0) != NULL && n->in(0)->is_top())), "should have been processed already");
       assert(!n->can_be_eliminated(), "should have been processed already");
-      expand_loadbarrier_node(macro, n);
+      expand_loadbarrier_node(&macro, n);
       assert(s->load_barrier_count() < load_barrier_count, "must have deleted a node from load barrier list");
       if (C->failing())  return true;
     }
@@ -1623,4 +1622,4 @@
       break;
   }
   return false;
-}
\ No newline at end of file
+}
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Tue Nov 27 09:35:02 2018 +0100
@@ -200,9 +200,9 @@
   virtual void unregister_potential_barrier_node(Node* node) const;
   virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const;
   virtual Node* step_over_gc_barrier(Node* c) const;
-  // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be
+  // If the BarrierSetC2 state has kept barrier nodes in its compilation unit state to be
   // expanded later, then now is the time to do so.
-  virtual bool expand_macro_nodes(PhaseMacroExpand* macro) const;
+  virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const;
 
   static void find_dominating_barriers(PhaseIterGVN& igvn);
   static void loop_optimize_gc_barrier(PhaseIdealLoop* phase, Node* node, bool last_round);
--- a/src/hotspot/share/opto/compile.cpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/compile.cpp	Tue Nov 27 09:35:02 2018 +0100
@@ -1122,7 +1122,7 @@
   set_decompile_count(0);
 
   set_do_freq_based_layout(_directive->BlockLayoutByFrequencyOption);
-  set_num_loop_opts(LoopOptsCount);
+  _loop_opts_cnt = LoopOptsCount;
   set_do_inlining(Inline);
   set_max_inline_size(MaxInlineSize);
   set_freq_inline_size(FreqInlineSize);
@@ -2169,14 +2169,14 @@
 }
 
 
-bool Compile::optimize_loops(int& loop_opts_cnt, PhaseIterGVN& igvn, LoopOptsMode mode) {
-  if(loop_opts_cnt > 0) {
+bool Compile::optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode) {
+  if(_loop_opts_cnt > 0) {
     debug_only( int cnt = 0; );
-    while(major_progress() && (loop_opts_cnt > 0)) {
+    while(major_progress() && (_loop_opts_cnt > 0)) {
       TracePhase tp("idealLoop", &timers[_t_idealLoop]);
       assert( cnt++ < 40, "infinite cycle in loop optimization" );
       PhaseIdealLoop ideal_loop(igvn, mode);
-      loop_opts_cnt--;
+      _loop_opts_cnt--;
       if (failing())  return false;
       if (major_progress()) print_method(PHASE_PHASEIDEALLOOP_ITERATIONS, 2);
     }
@@ -2202,7 +2202,6 @@
 #endif
 
   ResourceMark rm;
-  int          loop_opts_cnt;
 
   print_inlining_reinit();
 
@@ -2305,28 +2304,27 @@
   // peeling, unrolling, etc.
 
   // Set loop opts counter
-  loop_opts_cnt = num_loop_opts();
-  if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
+  if((_loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
     {
       TracePhase tp("idealLoop", &timers[_t_idealLoop]);
       PhaseIdealLoop ideal_loop(igvn, LoopOptsDefault);
-      loop_opts_cnt--;
+      _loop_opts_cnt--;
       if (major_progress()) print_method(PHASE_PHASEIDEALLOOP1, 2);
       if (failing())  return;
     }
     // Loop opts pass if partial peeling occurred in previous pass
-    if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) {
+    if(PartialPeelLoop && major_progress() && (_loop_opts_cnt > 0)) {
       TracePhase tp("idealLoop", &timers[_t_idealLoop]);
       PhaseIdealLoop ideal_loop(igvn, LoopOptsSkipSplitIf);
-      loop_opts_cnt--;
+      _loop_opts_cnt--;
       if (major_progress()) print_method(PHASE_PHASEIDEALLOOP2, 2);
       if (failing())  return;
     }
     // Loop opts pass for loop-unrolling before CCP
-    if(major_progress() && (loop_opts_cnt > 0)) {
+    if(major_progress() && (_loop_opts_cnt > 0)) {
       TracePhase tp("idealLoop", &timers[_t_idealLoop]);
       PhaseIdealLoop ideal_loop(igvn, LoopOptsSkipSplitIf);
-      loop_opts_cnt--;
+      _loop_opts_cnt--;
       if (major_progress()) print_method(PHASE_PHASEIDEALLOOP3, 2);
     }
     if (!failing()) {
@@ -2361,7 +2359,7 @@
 
   // Loop transforms on the ideal graph.  Range Check Elimination,
   // peeling, unrolling, etc.
-  if (!optimize_loops(loop_opts_cnt, igvn, LoopOptsDefault)) {
+  if (!optimize_loops(igvn, LoopOptsDefault)) {
     return;
   }
 
@@ -2404,6 +2402,16 @@
     }
   }
 
+  {
+    TracePhase tp("barrierExpand", &timers[_t_barrierExpand]);
+    print_method(PHASE_BEFORE_BARRIER_EXPAND, 2);
+    BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
+    if (bs->expand_barriers(this, igvn)) {
+      assert(failing(), "must bail out w/ explicit message");
+      return;
+    }
+  }
+
   if (opaque4_count() > 0) {
     C->remove_opaque4_nodes(igvn);
     igvn.optimize();
--- a/src/hotspot/share/opto/compile.hpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/compile.hpp	Tue Nov 27 09:35:02 2018 +0100
@@ -369,7 +369,6 @@
   address               _stub_entry_point;      // Compile code entry for generated stub, or NULL
 
   // Control of this compilation.
-  int                   _num_loop_opts;         // Number of iterations for doing loop optimiztions
   int                   _max_inline_size;       // Max inline size for this compilation
   int                   _freq_inline_size;      // Max hot method inline size for this compilation
   int                   _fixed_slots;           // count of frame slots not allocated by the register
@@ -413,6 +412,7 @@
   // JSR 292
   bool                  _has_method_handle_invokes; // True if this method has MethodHandle invokes.
   RTMState              _rtm_state;             // State of Restricted Transactional Memory usage
+  int                   _loop_opts_cnt;         // loop opts round
 
   // Compilation environment.
   Arena                 _comp_arena;            // Arena with lifetime equivalent to Compile
@@ -653,8 +653,6 @@
   int               inlining_incrementally() const { return _inlining_incrementally; }
   void          set_major_progress()            { _major_progress++; }
   void        clear_major_progress()            { _major_progress = 0; }
-  int               num_loop_opts() const       { return _num_loop_opts; }
-  void          set_num_loop_opts(int n)        { _num_loop_opts = n; }
   int               max_inline_size() const     { return _max_inline_size; }
   void          set_freq_inline_size(int n)     { _freq_inline_size = n; }
   int               freq_inline_size() const    { return _freq_inline_size; }
@@ -1087,7 +1085,7 @@
   void inline_incrementally(PhaseIterGVN& igvn);
   void inline_string_calls(bool parse_time);
   void inline_boxing_calls(PhaseIterGVN& igvn);
-  bool optimize_loops(int& loop_opts_cnt, PhaseIterGVN& igvn, LoopOptsMode mode);
+  bool optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode);
 
   // Matching, CFG layout, allocation, code generation
   PhaseCFG*         cfg()                       { return _cfg; }
--- a/src/hotspot/share/opto/loopnode.cpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/loopnode.cpp	Tue Nov 27 09:35:02 2018 +0100
@@ -2774,9 +2774,12 @@
     return;
   }
 
+  BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
   // Nothing to do, so get out
-  bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only;
+  bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only &&
+    !bs->is_gc_specific_loop_opts_pass(mode);
   bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn);
+  bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(mode);
   if (stop_early && !do_expensive_nodes) {
     _igvn.optimize();           // Cleanup NeverBranches
     return;
@@ -2854,8 +2857,9 @@
 
   // Given early legal placement, try finding counted loops.  This placement
   // is good enough to discover most loop invariants.
-  if( !_verify_me && !_verify_only )
+  if (!_verify_me && !_verify_only && !strip_mined_loops_expanded) {
     _ltree_root->counted_loop( this );
+  }
 
   // Find latest loop placement.  Find ideal loop placement.
   visited.Clear();
@@ -2926,6 +2930,14 @@
     return;
   }
 
+  if (bs->optimize_loops(this, mode, visited, nstack, worklist)) {
+    _igvn.optimize();
+    if (C->log() != NULL) {
+      log_loop_tree(_ltree_root, _ltree_root, C->log());
+    }
+    return;
+  }
+
   if (ReassociateInvariants) {
     // Reassociate invariants and prep for split_thru_phi
     for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
@@ -4136,7 +4148,7 @@
   }
 }
 
-// Verify that no data node is schedules in the outer loop of a strip
+// Verify that no data node is scheduled in the outer loop of a strip
 // mined loop.
 void PhaseIdealLoop::verify_strip_mined_scheduling(Node *n, Node* least) {
 #ifdef ASSERT
@@ -4145,7 +4157,9 @@
   }
   IdealLoopTree* loop = get_loop(least);
   Node* head = loop->_head;
-  if (head->is_OuterStripMinedLoop()) {
+  if (head->is_OuterStripMinedLoop() &&
+      // Verification can't be applied to fully built strip mined loops
+      head->as_Loop()->outer_loop_end()->in(1)->find_int_con(-1) == 0) {
     Node* sfpt = head->as_Loop()->outer_safepoint();
     ResourceMark rm;
     Unique_Node_List wq;
--- a/src/hotspot/share/opto/macro.cpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/macro.cpp	Tue Nov 27 09:35:02 2018 +0100
@@ -2600,6 +2600,5 @@
   _igvn.set_delay_transform(false);
   _igvn.optimize();
   if (C->failing())  return true;
-  BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
-  return bs->expand_macro_nodes(this);
+  return false;
 }
--- a/src/hotspot/share/opto/phase.cpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/phase.cpp	Tue Nov 27 09:35:02 2018 +0100
@@ -83,6 +83,7 @@
     tty->print_cr ("         Cond Const Prop:     %7.3f s", timers[_t_ccp].seconds());
     tty->print_cr ("         GVN 2:               %7.3f s", timers[_t_iterGVN2].seconds());
     tty->print_cr ("         Macro Expand:        %7.3f s", timers[_t_macroExpand].seconds());
+    tty->print_cr ("         Barrier Expand:      %7.3f s", timers[_t_barrierExpand].seconds());
     tty->print_cr ("         Graph Reshape:       %7.3f s", timers[_t_graphReshaping].seconds());
 
     double other = timers[_t_optimizer].seconds() -
@@ -95,6 +96,7 @@
        timers[_t_ccp].seconds() +
        timers[_t_iterGVN2].seconds() +
        timers[_t_macroExpand].seconds() +
+       timers[_t_barrierExpand].seconds() +
        timers[_t_graphReshaping].seconds());
     if (other > 0) {
       tty->print_cr("         Other:               %7.3f s", other);
--- a/src/hotspot/share/opto/phase.hpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/phase.hpp	Tue Nov 27 09:35:02 2018 +0100
@@ -80,6 +80,7 @@
       _t_ccp,
       _t_iterGVN2,
       _t_macroExpand,
+      _t_barrierExpand,
       _t_graphReshaping,
     _t_matcher,
     _t_scheduler,
--- a/src/hotspot/share/opto/phasetype.hpp	Wed Nov 28 15:34:43 2018 +0800
+++ b/src/hotspot/share/opto/phasetype.hpp	Tue Nov 27 09:35:02 2018 +0100
@@ -52,6 +52,7 @@
   PHASE_MATCHING,
   PHASE_INCREMENTAL_INLINE,
   PHASE_INCREMENTAL_BOXING_INLINE,
+  PHASE_BEFORE_BARRIER_EXPAND,
   PHASE_BEFORE_MACRO_EXPANSION,
   PHASE_END,
   PHASE_FAILURE,
@@ -89,6 +90,7 @@
       case PHASE_MATCHING:                   return "After matching";
       case PHASE_INCREMENTAL_INLINE:         return "Incremental Inline";
       case PHASE_INCREMENTAL_BOXING_INLINE:  return "Incremental Boxing Inline";
+      case PHASE_BEFORE_BARRIER_EXPAND:      return "Before Barrier Expand";
       case PHASE_BEFORE_MACRO_EXPANSION:     return "Before macro expansion";
       case PHASE_END:                        return "End";
       case PHASE_FAILURE:                    return "Failure";