8148754: C2 loop unrolling fails due to unexpected graph shape jdk8u272-b03

Mon, 21 Mar 2016 09:51:20 +0100

author
zmajo
date
Mon, 21 Mar 2016 09:51:20 +0100
changeset 9977
e649f2136368
parent 9976
f415b5fea90d
child 9978
0943ff57e154

8148754: C2 loop unrolling fails due to unexpected graph shape
Summary: Check if graph shape is appropriate for optimization, bail out optimization if not.
Reviewed-by: kvn, twisti, shade, dnsimon

src/share/vm/opto/loopTransform.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/loopnode.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/loopnode.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/superword.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/opto/loopTransform.cpp	Thu Jun 06 20:19:03 2019 +0200
     1.2 +++ b/src/share/vm/opto/loopTransform.cpp	Mon Mar 21 09:51:20 2016 +0100
     1.3 @@ -1223,20 +1223,14 @@
     1.4    Node *opaq = NULL;
     1.5    if (adjust_min_trip) {       // If not maximally unrolling, need adjustment
     1.6      // Search for zero-trip guard.
     1.7 -    assert( loop_head->is_main_loop(), "" );
     1.8 -    assert( ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "" );
     1.9 -    Node *iff = ctrl->in(0);
    1.10 -    assert( iff->Opcode() == Op_If, "" );
    1.11 -    Node *bol = iff->in(1);
    1.12 -    assert( bol->Opcode() == Op_Bool, "" );
    1.13 -    Node *cmp = bol->in(1);
    1.14 -    assert( cmp->Opcode() == Op_CmpI, "" );
    1.15 -    opaq = cmp->in(2);
    1.16 -    // Occasionally it's possible for a zero-trip guard Opaque1 node to be
    1.17 -    // optimized away and then another round of loop opts attempted.
    1.18 -    // We can not optimize this particular loop in that case.
    1.19 -    if (opaq->Opcode() != Op_Opaque1)
    1.20 -      return; // Cannot find zero-trip guard!  Bail out!
    1.21 +
    1.22 +    // Check the shape of the graph at the loop entry. If an inappropriate
    1.23 +    // graph shape is encountered, the compiler bails out loop unrolling;
    1.24 +    // compilation of the method will still succeed.
    1.25 +    if (!is_canonical_main_loop_entry(loop_head)) {
    1.26 +      return;
    1.27 +    }
    1.28 +    opaq = ctrl->in(0)->in(1)->in(1)->in(2);
    1.29      // Zero-trip test uses an 'opaque' node which is not shared.
    1.30      assert(opaq->outcnt() == 1 && opaq->in(1) == limit, "");
    1.31    }
    1.32 @@ -1806,7 +1800,6 @@
    1.33  #endif
    1.34    assert(RangeCheckElimination, "");
    1.35    CountedLoopNode *cl = loop->_head->as_CountedLoop();
    1.36 -  assert(cl->is_main_loop(), "");
    1.37  
    1.38    // protect against stride not being a constant
    1.39    if (!cl->stride_is_con())
    1.40 @@ -1818,20 +1811,17 @@
    1.41    // to not ever trip end tests
    1.42    Node *main_limit = cl->limit();
    1.43  
    1.44 +  // Check graph shape. Cannot optimize a loop if zero-trip
    1.45 +  // Opaque1 node is optimized away and then another round
    1.46 +  // of loop opts attempted.
    1.47 +  if (!is_canonical_main_loop_entry(cl)) {
    1.48 +    return;
    1.49 +  }
    1.50 +
    1.51    // Need to find the main-loop zero-trip guard
    1.52    Node *ctrl  = cl->in(LoopNode::EntryControl);
    1.53 -  assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "");
    1.54    Node *iffm = ctrl->in(0);
    1.55 -  assert(iffm->Opcode() == Op_If, "");
    1.56 -  Node *bolzm = iffm->in(1);
    1.57 -  assert(bolzm->Opcode() == Op_Bool, "");
    1.58 -  Node *cmpzm = bolzm->in(1);
    1.59 -  assert(cmpzm->is_Cmp(), "");
    1.60 -  Node *opqzm = cmpzm->in(2);
    1.61 -  // Can not optimize a loop if zero-trip Opaque1 node is optimized
    1.62 -  // away and then another round of loop opts attempted.
    1.63 -  if (opqzm->Opcode() != Op_Opaque1)
    1.64 -    return;
    1.65 +  Node *opqzm = iffm->in(1)->in(1)->in(2);
    1.66    assert(opqzm->in(1) == main_limit, "do not understand situation");
    1.67  
    1.68    // Find the pre-loop limit; we will expand it's iterations to
     2.1 --- a/src/share/vm/opto/loopnode.cpp	Thu Jun 06 20:19:03 2019 +0200
     2.2 +++ b/src/share/vm/opto/loopnode.cpp	Mon Mar 21 09:51:20 2016 +0100
     2.3 @@ -3282,6 +3282,41 @@
     2.4    return LCA;
     2.5  }
     2.6  
     2.7 +// Check the shape of the graph at the loop entry. In some cases,
     2.8 +// the shape of the graph does not match the shape outlined below.
     2.9 +// That is caused by the Opaque1 node "protecting" the shape of
    2.10 +// the graph being removed by, for example, the IGVN performed
    2.11 +// in PhaseIdealLoop::build_and_optimize().
    2.12 +//
    2.13 +// After the Opaque1 node has been removed, optimizations (e.g., split-if,
    2.14 +// loop unswitching, and IGVN, or a combination of them) can freely change
    2.15 +// the graph's shape. As a result, the graph shape outlined below cannot
    2.16 +// be guaranteed anymore.
    2.17 +bool PhaseIdealLoop::is_canonical_main_loop_entry(CountedLoopNode* cl) {
    2.18 +  assert(cl->is_main_loop(), "check should be applied to main loops");
    2.19 +  Node* ctrl = cl->in(LoopNode::EntryControl);
    2.20 +  if (ctrl == NULL || (!ctrl->is_IfTrue() && !ctrl->is_IfFalse())) {
    2.21 +    return false;
    2.22 +  }
    2.23 +  Node* iffm = ctrl->in(0);
    2.24 +  if (iffm == NULL || !iffm->is_If()) {
    2.25 +    return false;
    2.26 +  }
    2.27 +  Node* bolzm = iffm->in(1);
    2.28 +  if (bolzm == NULL || !bolzm->is_Bool()) {
    2.29 +    return false;
    2.30 +  }
    2.31 +  Node* cmpzm = bolzm->in(1);
    2.32 +  if (cmpzm == NULL || !cmpzm->is_Cmp()) {
    2.33 +    return false;
    2.34 +  }
    2.35 +  Node* opqzm = cmpzm->in(2);
    2.36 +  if (opqzm == NULL || opqzm->Opcode() != Op_Opaque1) {
    2.37 +    return false;
    2.38 +  }
    2.39 +  return true;
    2.40 +}
    2.41 +
    2.42  //------------------------------get_late_ctrl----------------------------------
    2.43  // Compute latest legal control.
    2.44  Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
     3.1 --- a/src/share/vm/opto/loopnode.hpp	Thu Jun 06 20:19:03 2019 +0200
     3.2 +++ b/src/share/vm/opto/loopnode.hpp	Mon Mar 21 09:51:20 2016 +0100
     3.3 @@ -619,6 +619,9 @@
     3.4    bool cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop);
     3.5  
     3.6  public:
     3.7 +
     3.8 +  static bool is_canonical_main_loop_entry(CountedLoopNode* cl);
     3.9 +
    3.10    bool has_node( Node* n ) const {
    3.11      guarantee(n != NULL, "No Node.");
    3.12      return _nodes[n->_idx] != NULL;
     4.1 --- a/src/share/vm/opto/superword.cpp	Thu Jun 06 20:19:03 2019 +0200
     4.2 +++ b/src/share/vm/opto/superword.cpp	Mon Mar 21 09:51:20 2016 +0100
     4.3 @@ -2209,21 +2209,13 @@
     4.4  //----------------------------get_pre_loop_end---------------------------
     4.5  // Find pre loop end from main loop.  Returns null if none.
     4.6  CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode* cl) {
     4.7 -  Node* ctrl = cl->in(LoopNode::EntryControl);
     4.8 -  if (!ctrl->is_IfTrue() && !ctrl->is_IfFalse()) return NULL;
     4.9 -  Node* iffm = ctrl->in(0);
    4.10 -  if (!iffm->is_If()) return NULL;
    4.11 -  Node* bolzm = iffm->in(1);
    4.12 -  if (!bolzm->is_Bool()) return NULL;
    4.13 -  Node* cmpzm = bolzm->in(1);
    4.14 -  if (!cmpzm->is_Cmp()) return NULL;
    4.15 -  Node* opqzm = cmpzm->in(2);
    4.16 -  // Can not optimize a loop if zero-trip Opaque1 node is optimized
    4.17 -  // away and then another round of loop opts attempted.
    4.18 -  if (opqzm->Opcode() != Op_Opaque1) {
    4.19 +  // The loop cannot be optimized if the graph shape at
    4.20 +  // the loop entry is inappropriate.
    4.21 +  if (!PhaseIdealLoop::is_canonical_main_loop_entry(cl)) {
    4.22      return NULL;
    4.23    }
    4.24 -  Node* p_f = iffm->in(0);
    4.25 +
    4.26 +  Node* p_f = cl->in(LoopNode::EntryControl)->in(0)->in(0);
    4.27    if (!p_f->is_IfFalse()) return NULL;
    4.28    if (!p_f->in(0)->is_CountedLoopEnd()) return NULL;
    4.29    CountedLoopEndNode* pre_end = p_f->in(0)->as_CountedLoopEnd();

mercurial