src/share/vm/opto/replacednodes.cpp

Thu, 24 May 2018 19:26:50 +0800

author
aoqi
date
Thu, 24 May 2018 19:26:50 +0800
changeset 8862
fd13a567f179
parent 8723
9f5da1a1724c
permissions
-rw-r--r--

#7046 C2 supports long branch
Contributed-by: fujie

     1 /*
     2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "precompiled.hpp"
    26 #include "opto/cfgnode.hpp"
    27 #include "opto/phaseX.hpp"
    28 #include "opto/replacednodes.hpp"
    30 void ReplacedNodes::allocate_if_necessary() {
    31   if (_replaced_nodes == NULL) {
    32     _replaced_nodes = new GrowableArray<ReplacedNode>();
    33   }
    34 }
    36 bool ReplacedNodes::is_empty() const {
    37   return _replaced_nodes == NULL || _replaced_nodes->length() == 0;
    38 }
    40 bool ReplacedNodes::has_node(const ReplacedNode& r) const {
    41   return _replaced_nodes->find(r) != -1;
    42 }
    44 bool ReplacedNodes::has_target_node(Node* n) const {
    45   for (int i = 0; i < _replaced_nodes->length(); i++) {
    46     if (_replaced_nodes->at(i).improved() == n) {
    47       return true;
    48     }
    49   }
    50   return false;
    51 }
    53 // Record replaced node if not seen before
    54 void ReplacedNodes::record(Node* initial, Node* improved) {
    55   allocate_if_necessary();
    56   ReplacedNode r(initial, improved);
    57   if (!has_node(r)) {
    58     _replaced_nodes->push(r);
    59   }
    60 }
    62 // Copy replaced nodes from one map to another. idx is used to
    63 // identify nodes that are too new to be of interest in the target
    64 // node list.
    65 void ReplacedNodes::transfer_from(const ReplacedNodes& other, uint idx) {
    66   if (other.is_empty()) {
    67     return;
    68   }
    69   allocate_if_necessary();
    70   for (int i = 0; i < other._replaced_nodes->length(); i++) {
    71     ReplacedNode replaced = other._replaced_nodes->at(i);
    72     // Only transfer the nodes that can actually be useful
    73     if (!has_node(replaced) && (replaced.initial()->_idx < idx || has_target_node(replaced.initial()))) {
    74       _replaced_nodes->push(replaced);
    75     }
    76   }
    77 }
    79 void ReplacedNodes::clone() {
    80   if (_replaced_nodes != NULL) {
    81     GrowableArray<ReplacedNode>* replaced_nodes_clone = new GrowableArray<ReplacedNode>();
    82     replaced_nodes_clone->appendAll(_replaced_nodes);
    83     _replaced_nodes = replaced_nodes_clone;
    84   }
    85 }
    87 void ReplacedNodes::reset() {
    88   if (_replaced_nodes != NULL) {
    89     _replaced_nodes->clear();
    90   }
    91 }
    93 // Perfom node replacement (used when returning to caller)
    94 void ReplacedNodes::apply(Node* n, uint idx) {
    95   if (is_empty()) {
    96     return;
    97   }
    98   for (int i = 0; i < _replaced_nodes->length(); i++) {
    99     ReplacedNode replaced = _replaced_nodes->at(i);
   100     // Only apply if improved node was created in a callee to avoid
   101     // issues with irreducible loops in the caller
   102     if (replaced.improved()->_idx >= idx) {
   103       n->replace_edge(replaced.initial(), replaced.improved());
   104     }
   105   }
   106 }
   108 static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) {
   109   if (use->is_Phi()) {
   110     Node* r = use->in(0);
   111     assert(r->is_Region(), "Phi should have Region");
   112     for (uint i = 1; i < use->req(); i++) {
   113       if (use->in(i) == n) {
   114         work.push(r->in(i));
   115       }
   116     }
   117   } else {
   118     work.push(use);
   119   }
   120 }
   122 // Perfom node replacement following late inlining
   123 void ReplacedNodes::apply(Compile* C, Node* ctl) {
   124   // ctl is the control on exit of the method that was late inlined
   125   if (is_empty()) {
   126     return;
   127   }
   128   for (int i = 0; i < _replaced_nodes->length(); i++) {
   129     ReplacedNode replaced = _replaced_nodes->at(i);
   130     Node* initial = replaced.initial();
   131     Node* improved = replaced.improved();
   132     assert (ctl != NULL && !ctl->is_top(), "replaced node should have actual control");
   134     ResourceMark rm;
   135     Unique_Node_List work;
   136     // Go over all the uses of the node that is considered for replacement...
   137     for (DUIterator j = initial->outs(); initial->has_out(j); j++) {
   138       Node* use = initial->out(j);
   140       if (use == improved || use->outcnt() == 0) {
   141         continue;
   142       }
   143       work.clear();
   144       enqueue_use(initial, use, work);
   145       bool replace = true;
   146       // Check that this use is dominated by ctl. Go ahead with the
   147       // replacement if it is.
   148       while (work.size() != 0 && replace) {
   149         Node* n = work.pop();
   150         if (use->outcnt() == 0) {
   151           continue;
   152         }
   153         if (n->is_CFG() || (n->in(0) != NULL && !n->in(0)->is_top())) {
   154           int depth = 0;
   155           Node *m = n;
   156           if (!n->is_CFG()) {
   157             n = n->in(0);
   158           }
   159           assert(n->is_CFG(), "should be CFG now");
   160           while(n != ctl) {
   161             n = IfNode::up_one_dom(n);
   162             depth++;
   163             // limit search depth
   164             if (depth >= 100 || n == NULL) {
   165               replace = false;
   166               break;
   167             }
   168           }
   169         } else {
   170           for (DUIterator k = n->outs(); n->has_out(k); k++) {
   171             enqueue_use(n, n->out(k), work);
   172           }
   173         }
   174       }
   175       if (replace) {
   176         bool is_in_table = C->initial_gvn()->hash_delete(use);
   177         int replaced = use->replace_edge(initial, improved);
   178         if (is_in_table) {
   179           C->initial_gvn()->hash_find_insert(use);
   180         }
   181         C->record_for_igvn(use);
   183         assert(replaced > 0, "inconsistent");
   184         --j;
   185       }
   186     }
   187   }
   188 }
   190 void ReplacedNodes::dump(outputStream *st) const {
   191   if (!is_empty()) {
   192     st->print("replaced nodes: ");
   193     for (int i = 0; i < _replaced_nodes->length(); i++) {
   194       st->print("%d->%d", _replaced_nodes->at(i).initial()->_idx, _replaced_nodes->at(i).improved()->_idx);
   195       if (i < _replaced_nodes->length()-1) {
   196         st->print(",");
   197       }
   198     }
   199   }
   200 }
   202 // Merge 2 list of replaced node at a point where control flow paths merge
   203 void ReplacedNodes::merge_with(const ReplacedNodes& other) {
   204   if (is_empty()) {
   205     return;
   206   }
   207   if (other.is_empty()) {
   208     reset();
   209     return;
   210   }
   211   int shift = 0;
   212   int len = _replaced_nodes->length();
   213   for (int i = 0; i < len; i++) {
   214     if (!other.has_node(_replaced_nodes->at(i))) {
   215       shift++;
   216     } else if (shift > 0) {
   217       _replaced_nodes->at_put(i-shift, _replaced_nodes->at(i));
   218     }
   219   }
   220   if (shift > 0) {
   221     _replaced_nodes->trunc_to(len - shift);
   222   }
   223 }

mercurial