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