Mercurial > hg > truffle
annotate src/share/vm/opto/loopPredicate.cpp @ 4710:41406797186b
7113012: G1: rename not-fully-young GCs as "mixed"
Summary: Renamed partially-young GCs as mixed and fully-young GCs as young. Change all external output that includes those terms (GC log and GC ergo log) as well as any comments, fields, methods, etc. The changeset also includes very minor code tidying up (added some curly brackets).
Reviewed-by: johnc, brutisso
author | tonyp |
---|---|
date | Fri, 16 Dec 2011 02:14:27 -0500 |
parents | 6987871cfb9b |
children | 5e990493719e |
rev | line source |
---|---|
2445 | 1 /* |
2 * Copyright (c) 2011, 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 */ | |
24 | |
25 #include "precompiled.hpp" | |
26 #include "opto/loopnode.hpp" | |
27 #include "opto/addnode.hpp" | |
28 #include "opto/callnode.hpp" | |
29 #include "opto/connode.hpp" | |
30 #include "opto/loopnode.hpp" | |
31 #include "opto/mulnode.hpp" | |
32 #include "opto/rootnode.hpp" | |
33 #include "opto/subnode.hpp" | |
34 | |
35 /* | |
36 * The general idea of Loop Predication is to insert a predicate on the entry | |
37 * path to a loop, and raise a uncommon trap if the check of the condition fails. | |
38 * The condition checks are promoted from inside the loop body, and thus | |
39 * the checks inside the loop could be eliminated. Currently, loop predication | |
40 * optimization has been applied to remove array range check and loop invariant | |
41 * checks (such as null checks). | |
42 */ | |
43 | |
44 //-------------------------------is_uncommon_trap_proj---------------------------- | |
45 // Return true if proj is the form of "proj->[region->..]call_uct" | |
46 bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { | |
47 int path_limit = 10; | |
48 assert(proj, "invalid argument"); | |
49 Node* out = proj; | |
50 for (int ct = 0; ct < path_limit; ct++) { | |
51 out = out->unique_ctrl_out(); | |
52 if (out == NULL) | |
53 return false; | |
54 if (out->is_CallStaticJava()) { | |
55 int req = out->as_CallStaticJava()->uncommon_trap_request(); | |
56 if (req != 0) { | |
57 Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); | |
58 if (trap_reason == reason || reason == Deoptimization::Reason_none) { | |
59 return true; | |
60 } | |
61 } | |
62 return false; // don't do further after call | |
63 } | |
64 if (out->Opcode() != Op_Region) | |
65 return false; | |
66 } | |
67 return false; | |
68 } | |
69 | |
70 //-------------------------------is_uncommon_trap_if_pattern------------------------- | |
71 // Return true for "if(test)-> proj -> ... | |
72 // | | |
73 // V | |
74 // other_proj->[region->..]call_uct" | |
75 // | |
76 // "must_reason_predicate" means the uct reason must be Reason_predicate | |
77 bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { | |
78 Node *in0 = proj->in(0); | |
79 if (!in0->is_If()) return false; | |
80 // Variation of a dead If node. | |
81 if (in0->outcnt() < 2) return false; | |
82 IfNode* iff = in0->as_If(); | |
83 | |
84 // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate | |
85 if (reason != Deoptimization::Reason_none) { | |
86 if (iff->in(1)->Opcode() != Op_Conv2B || | |
87 iff->in(1)->in(1)->Opcode() != Op_Opaque1) { | |
88 return false; | |
89 } | |
90 } | |
91 | |
92 ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); | |
93 if (is_uncommon_trap_proj(other_proj, reason)) { | |
94 assert(reason == Deoptimization::Reason_none || | |
95 Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); | |
96 return true; | |
97 } | |
98 return false; | |
99 } | |
100 | |
101 //-------------------------------register_control------------------------- | |
102 void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { | |
103 assert(n->is_CFG(), "must be control node"); | |
104 _igvn.register_new_node_with_optimizer(n); | |
105 loop->_body.push(n); | |
106 set_loop(n, loop); | |
107 // When called from beautify_loops() idom is not constructed yet. | |
108 if (_idom != NULL) { | |
109 set_idom(n, pred, dom_depth(pred)); | |
110 } | |
111 } | |
112 | |
113 //------------------------------create_new_if_for_predicate------------------------ | |
114 // create a new if above the uct_if_pattern for the predicate to be promoted. | |
115 // | |
116 // before after | |
117 // ---------- ---------- | |
118 // ctrl ctrl | |
119 // | | | |
120 // | | | |
121 // v v | |
122 // iff new_iff | |
123 // / \ / \ | |
124 // / \ / \ | |
125 // v v v v | |
126 // uncommon_proj cont_proj if_uct if_cont | |
127 // \ | | | | | |
128 // \ | | | | | |
129 // v v v | v | |
130 // rgn loop | iff | |
131 // | | / \ | |
132 // | | / \ | |
133 // v | v v | |
134 // uncommon_trap | uncommon_proj cont_proj | |
135 // \ \ | | | |
136 // \ \ | | | |
137 // v v v v | |
138 // rgn loop | |
139 // | | |
140 // | | |
141 // v | |
142 // uncommon_trap | |
143 // | |
144 // | |
145 // We will create a region to guard the uct call if there is no one there. | |
146 // The true projecttion (if_cont) of the new_iff is returned. | |
147 // This code is also used to clone predicates to clonned loops. | |
148 ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, | |
149 Deoptimization::DeoptReason reason) { | |
150 assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); | |
151 IfNode* iff = cont_proj->in(0)->as_If(); | |
152 | |
153 ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); | |
154 Node *rgn = uncommon_proj->unique_ctrl_out(); | |
155 assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); | |
156 | |
157 uint proj_index = 1; // region's edge corresponding to uncommon_proj | |
158 if (!rgn->is_Region()) { // create a region to guard the call | |
159 assert(rgn->is_Call(), "must be call uct"); | |
160 CallNode* call = rgn->as_Call(); | |
161 IdealLoopTree* loop = get_loop(call); | |
162 rgn = new (C, 1) RegionNode(1); | |
163 rgn->add_req(uncommon_proj); | |
164 register_control(rgn, loop, uncommon_proj); | |
165 _igvn.hash_delete(call); | |
166 call->set_req(0, rgn); | |
167 // When called from beautify_loops() idom is not constructed yet. | |
168 if (_idom != NULL) { | |
169 set_idom(call, rgn, dom_depth(rgn)); | |
170 } | |
171 } else { | |
172 // Find region's edge corresponding to uncommon_proj | |
173 for (; proj_index < rgn->req(); proj_index++) | |
174 if (rgn->in(proj_index) == uncommon_proj) break; | |
175 assert(proj_index < rgn->req(), "sanity"); | |
176 } | |
177 | |
178 Node* entry = iff->in(0); | |
179 if (new_entry != NULL) { | |
180 // Clonning the predicate to new location. | |
181 entry = new_entry; | |
182 } | |
183 // Create new_iff | |
184 IdealLoopTree* lp = get_loop(entry); | |
185 IfNode *new_iff = iff->clone()->as_If(); | |
186 new_iff->set_req(0, entry); | |
187 register_control(new_iff, lp, entry); | |
188 Node *if_cont = new (C, 1) IfTrueNode(new_iff); | |
189 Node *if_uct = new (C, 1) IfFalseNode(new_iff); | |
190 if (cont_proj->is_IfFalse()) { | |
191 // Swap | |
192 Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; | |
193 } | |
194 register_control(if_cont, lp, new_iff); | |
195 register_control(if_uct, get_loop(rgn), new_iff); | |
196 | |
197 // if_uct to rgn | |
198 _igvn.hash_delete(rgn); | |
199 rgn->add_req(if_uct); | |
200 // When called from beautify_loops() idom is not constructed yet. | |
201 if (_idom != NULL) { | |
202 Node* ridom = idom(rgn); | |
203 Node* nrdom = dom_lca(ridom, new_iff); | |
204 set_idom(rgn, nrdom, dom_depth(rgn)); | |
205 } | |
206 | |
207 // If rgn has phis add new edges which has the same | |
208 // value as on original uncommon_proj pass. | |
209 assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last"); | |
210 bool has_phi = false; | |
211 for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) { | |
212 Node* use = rgn->fast_out(i); | |
213 if (use->is_Phi() && use->outcnt() > 0) { | |
214 assert(use->in(0) == rgn, ""); | |
215 _igvn.hash_delete(use); | |
216 use->add_req(use->in(proj_index)); | |
217 _igvn._worklist.push(use); | |
218 has_phi = true; | |
219 } | |
220 } | |
221 assert(!has_phi || rgn->req() > 3, "no phis when region is created"); | |
222 | |
223 if (new_entry == NULL) { | |
224 // Attach if_cont to iff | |
225 _igvn.hash_delete(iff); | |
226 iff->set_req(0, if_cont); | |
227 if (_idom != NULL) { | |
228 set_idom(iff, if_cont, dom_depth(iff)); | |
229 } | |
230 } | |
231 return if_cont->as_Proj(); | |
232 } | |
233 | |
234 //------------------------------create_new_if_for_predicate------------------------ | |
235 // Create a new if below new_entry for the predicate to be cloned (IGVN optimization) | |
236 ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, | |
237 Deoptimization::DeoptReason reason) { | |
238 assert(new_entry != 0, "only used for clone predicate"); | |
239 assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); | |
240 IfNode* iff = cont_proj->in(0)->as_If(); | |
241 | |
242 ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); | |
243 Node *rgn = uncommon_proj->unique_ctrl_out(); | |
244 assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); | |
245 | |
246 uint proj_index = 1; // region's edge corresponding to uncommon_proj | |
247 if (!rgn->is_Region()) { // create a region to guard the call | |
248 assert(rgn->is_Call(), "must be call uct"); | |
249 CallNode* call = rgn->as_Call(); | |
250 rgn = new (C, 1) RegionNode(1); | |
251 register_new_node_with_optimizer(rgn); | |
252 rgn->add_req(uncommon_proj); | |
253 hash_delete(call); | |
254 call->set_req(0, rgn); | |
255 } else { | |
256 // Find region's edge corresponding to uncommon_proj | |
257 for (; proj_index < rgn->req(); proj_index++) | |
258 if (rgn->in(proj_index) == uncommon_proj) break; | |
259 assert(proj_index < rgn->req(), "sanity"); | |
260 } | |
261 | |
262 // Create new_iff in new location. | |
263 IfNode *new_iff = iff->clone()->as_If(); | |
264 new_iff->set_req(0, new_entry); | |
265 | |
266 register_new_node_with_optimizer(new_iff); | |
267 Node *if_cont = new (C, 1) IfTrueNode(new_iff); | |
268 Node *if_uct = new (C, 1) IfFalseNode(new_iff); | |
269 if (cont_proj->is_IfFalse()) { | |
270 // Swap | |
271 Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; | |
272 } | |
273 register_new_node_with_optimizer(if_cont); | |
274 register_new_node_with_optimizer(if_uct); | |
275 | |
276 // if_uct to rgn | |
277 hash_delete(rgn); | |
278 rgn->add_req(if_uct); | |
279 | |
280 // If rgn has phis add corresponding new edges which has the same | |
281 // value as on original uncommon_proj pass. | |
282 assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last"); | |
283 bool has_phi = false; | |
284 for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) { | |
285 Node* use = rgn->fast_out(i); | |
286 if (use->is_Phi() && use->outcnt() > 0) { | |
287 hash_delete(use); | |
288 use->add_req(use->in(proj_index)); | |
289 _worklist.push(use); | |
290 has_phi = true; | |
291 } | |
292 } | |
293 assert(!has_phi || rgn->req() > 3, "no phis when region is created"); | |
294 | |
295 return if_cont->as_Proj(); | |
296 } | |
297 | |
298 //--------------------------clone_predicate----------------------- | |
299 ProjNode* PhaseIdealLoop::clone_predicate(ProjNode* predicate_proj, Node* new_entry, | |
300 Deoptimization::DeoptReason reason, | |
301 PhaseIdealLoop* loop_phase, | |
302 PhaseIterGVN* igvn) { | |
303 ProjNode* new_predicate_proj; | |
304 if (loop_phase != NULL) { | |
305 new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason); | |
306 } else { | |
307 new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason); | |
308 } | |
309 IfNode* iff = new_predicate_proj->in(0)->as_If(); | |
310 Node* ctrl = iff->in(0); | |
311 | |
312 // Match original condition since predicate's projections could be swapped. | |
313 assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); | |
314 Node* opq = new (igvn->C, 2) Opaque1Node(igvn->C, predicate_proj->in(0)->in(1)->in(1)->in(1)); | |
315 igvn->C->add_predicate_opaq(opq); | |
316 | |
317 Node* bol = new (igvn->C, 2) Conv2BNode(opq); | |
318 if (loop_phase != NULL) { | |
319 loop_phase->register_new_node(opq, ctrl); | |
320 loop_phase->register_new_node(bol, ctrl); | |
321 } else { | |
322 igvn->register_new_node_with_optimizer(opq); | |
323 igvn->register_new_node_with_optimizer(bol); | |
324 } | |
325 igvn->hash_delete(iff); | |
326 iff->set_req(1, bol); | |
327 return new_predicate_proj; | |
328 } | |
329 | |
330 | |
331 //--------------------------clone_loop_predicates----------------------- | |
332 // Interface from IGVN | |
3345 | 333 Node* PhaseIterGVN::clone_loop_predicates(Node* old_entry, Node* new_entry, bool clone_limit_check) { |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
334 return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, clone_limit_check, NULL, this); |
2445 | 335 } |
336 | |
337 // Interface from PhaseIdealLoop | |
3345 | 338 Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, bool clone_limit_check) { |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
339 return clone_loop_predicates(old_entry, new_entry, clone_limit_check, this, &this->_igvn); |
2445 | 340 } |
341 | |
342 // Clone loop predicates to cloned loops (peeled, unswitched, split_if). | |
343 Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, | |
3345 | 344 bool clone_limit_check, |
2445 | 345 PhaseIdealLoop* loop_phase, |
346 PhaseIterGVN* igvn) { | |
347 #ifdef ASSERT | |
348 if (new_entry == NULL || !(new_entry->is_Proj() || new_entry->is_Region() || new_entry->is_SafePoint())) { | |
349 if (new_entry != NULL) | |
350 new_entry->dump(); | |
351 assert(false, "not IfTrue, IfFalse, Region or SafePoint"); | |
352 } | |
353 #endif | |
354 // Search original predicates | |
355 Node* entry = old_entry; | |
3345 | 356 ProjNode* limit_check_proj = NULL; |
357 if (LoopLimitCheck) { | |
358 limit_check_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); | |
359 if (limit_check_proj != NULL) { | |
360 entry = entry->in(0)->in(0); | |
361 } | |
362 } | |
2445 | 363 if (UseLoopPredicate) { |
364 ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); | |
365 if (predicate_proj != NULL) { // right pattern that can be used by loop predication | |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
366 // clone predicate |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
367 new_entry = clone_predicate(predicate_proj, new_entry, |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
368 Deoptimization::Reason_predicate, |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
369 loop_phase, igvn); |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
370 assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate"); |
2445 | 371 if (TraceLoopPredicate) { |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
372 tty->print("Loop Predicate cloned: "); |
2445 | 373 debug_only( new_entry->in(0)->dump(); ) |
374 } | |
375 } | |
376 } | |
3345 | 377 if (limit_check_proj != NULL && clone_limit_check) { |
378 // Clone loop limit check last to insert it before loop. | |
379 // Don't clone a limit check which was already finalized | |
380 // for this counted loop (only one limit check is needed). | |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
381 new_entry = clone_predicate(limit_check_proj, new_entry, |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
382 Deoptimization::Reason_loop_limit_check, |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
383 loop_phase, igvn); |
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
384 assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone limit check"); |
3345 | 385 if (TraceLoopLimitCheck) { |
3845
c96c3eb1efae
7068051: SIGSEGV in PhaseIdealLoop::build_loop_late_post
kvn
parents:
3840
diff
changeset
|
386 tty->print("Loop Limit Check cloned: "); |
3345 | 387 debug_only( new_entry->in(0)->dump(); ) |
388 } | |
389 } | |
2445 | 390 return new_entry; |
391 } | |
392 | |
393 //--------------------------skip_loop_predicates------------------------------ | |
394 // Skip related predicates. | |
395 Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) { | |
396 Node* predicate = NULL; | |
3345 | 397 if (LoopLimitCheck) { |
398 predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); | |
399 if (predicate != NULL) { | |
400 entry = entry->in(0)->in(0); | |
401 } | |
402 } | |
2445 | 403 if (UseLoopPredicate) { |
404 predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); | |
405 if (predicate != NULL) { // right pattern that can be used by loop predication | |
406 IfNode* iff = entry->in(0)->as_If(); | |
407 ProjNode* uncommon_proj = iff->proj_out(1 - entry->as_Proj()->_con); | |
408 Node* rgn = uncommon_proj->unique_ctrl_out(); | |
409 assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); | |
410 entry = entry->in(0)->in(0); | |
411 while (entry != NULL && entry->is_Proj() && entry->in(0)->is_If()) { | |
412 uncommon_proj = entry->in(0)->as_If()->proj_out(1 - entry->as_Proj()->_con); | |
413 if (uncommon_proj->unique_ctrl_out() != rgn) | |
414 break; | |
415 entry = entry->in(0)->in(0); | |
416 } | |
417 } | |
418 } | |
419 return entry; | |
420 } | |
421 | |
422 //--------------------------find_predicate_insertion_point------------------- | |
423 // Find a good location to insert a predicate | |
424 ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { | |
425 if (start_c == NULL || !start_c->is_Proj()) | |
426 return NULL; | |
427 if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { | |
428 return start_c->as_Proj(); | |
429 } | |
430 return NULL; | |
431 } | |
432 | |
433 //--------------------------find_predicate------------------------------------ | |
434 // Find a predicate | |
435 Node* PhaseIdealLoop::find_predicate(Node* entry) { | |
436 Node* predicate = NULL; | |
3345 | 437 if (LoopLimitCheck) { |
438 predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); | |
439 if (predicate != NULL) { // right pattern that can be used by loop predication | |
440 return entry; | |
441 } | |
442 } | |
2445 | 443 if (UseLoopPredicate) { |
444 predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); | |
445 if (predicate != NULL) { // right pattern that can be used by loop predication | |
446 return entry; | |
447 } | |
448 } | |
449 return NULL; | |
450 } | |
451 | |
452 //------------------------------Invariance----------------------------------- | |
453 // Helper class for loop_predication_impl to compute invariance on the fly and | |
454 // clone invariants. | |
455 class Invariance : public StackObj { | |
456 VectorSet _visited, _invariant; | |
457 Node_Stack _stack; | |
458 VectorSet _clone_visited; | |
459 Node_List _old_new; // map of old to new (clone) | |
460 IdealLoopTree* _lpt; | |
461 PhaseIdealLoop* _phase; | |
462 | |
463 // Helper function to set up the invariance for invariance computation | |
464 // If n is a known invariant, set up directly. Otherwise, look up the | |
465 // the possibility to push n onto the stack for further processing. | |
466 void visit(Node* use, Node* n) { | |
467 if (_lpt->is_invariant(n)) { // known invariant | |
468 _invariant.set(n->_idx); | |
469 } else if (!n->is_CFG()) { | |
470 Node *n_ctrl = _phase->ctrl_or_self(n); | |
471 Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG | |
472 if (_phase->is_dominator(n_ctrl, u_ctrl)) { | |
473 _stack.push(n, n->in(0) == NULL ? 1 : 0); | |
474 } | |
475 } | |
476 } | |
477 | |
478 // Compute invariance for "the_node" and (possibly) all its inputs recursively | |
479 // on the fly | |
480 void compute_invariance(Node* n) { | |
481 assert(_visited.test(n->_idx), "must be"); | |
482 visit(n, n); | |
483 while (_stack.is_nonempty()) { | |
484 Node* n = _stack.node(); | |
485 uint idx = _stack.index(); | |
486 if (idx == n->req()) { // all inputs are processed | |
487 _stack.pop(); | |
488 // n is invariant if it's inputs are all invariant | |
489 bool all_inputs_invariant = true; | |
490 for (uint i = 0; i < n->req(); i++) { | |
491 Node* in = n->in(i); | |
492 if (in == NULL) continue; | |
493 assert(_visited.test(in->_idx), "must have visited input"); | |
494 if (!_invariant.test(in->_idx)) { // bad guy | |
495 all_inputs_invariant = false; | |
496 break; | |
497 } | |
498 } | |
499 if (all_inputs_invariant) { | |
500 _invariant.set(n->_idx); // I am a invariant too | |
501 } | |
502 } else { // process next input | |
503 _stack.set_index(idx + 1); | |
504 Node* m = n->in(idx); | |
505 if (m != NULL && !_visited.test_set(m->_idx)) { | |
506 visit(n, m); | |
507 } | |
508 } | |
509 } | |
510 } | |
511 | |
512 // Helper function to set up _old_new map for clone_nodes. | |
513 // If n is a known invariant, set up directly ("clone" of n == n). | |
514 // Otherwise, push n onto the stack for real cloning. | |
515 void clone_visit(Node* n) { | |
516 assert(_invariant.test(n->_idx), "must be invariant"); | |
517 if (_lpt->is_invariant(n)) { // known invariant | |
518 _old_new.map(n->_idx, n); | |
519 } else { // to be cloned | |
520 assert(!n->is_CFG(), "should not see CFG here"); | |
521 _stack.push(n, n->in(0) == NULL ? 1 : 0); | |
522 } | |
523 } | |
524 | |
525 // Clone "n" and (possibly) all its inputs recursively | |
526 void clone_nodes(Node* n, Node* ctrl) { | |
527 clone_visit(n); | |
528 while (_stack.is_nonempty()) { | |
529 Node* n = _stack.node(); | |
530 uint idx = _stack.index(); | |
531 if (idx == n->req()) { // all inputs processed, clone n! | |
532 _stack.pop(); | |
533 // clone invariant node | |
534 Node* n_cl = n->clone(); | |
535 _old_new.map(n->_idx, n_cl); | |
536 _phase->register_new_node(n_cl, ctrl); | |
537 for (uint i = 0; i < n->req(); i++) { | |
538 Node* in = n_cl->in(i); | |
539 if (in == NULL) continue; | |
540 n_cl->set_req(i, _old_new[in->_idx]); | |
541 } | |
542 } else { // process next input | |
543 _stack.set_index(idx + 1); | |
544 Node* m = n->in(idx); | |
545 if (m != NULL && !_clone_visited.test_set(m->_idx)) { | |
546 clone_visit(m); // visit the input | |
547 } | |
548 } | |
549 } | |
550 } | |
551 | |
552 public: | |
553 Invariance(Arena* area, IdealLoopTree* lpt) : | |
554 _lpt(lpt), _phase(lpt->_phase), | |
555 _visited(area), _invariant(area), _stack(area, 10 /* guess */), | |
556 _clone_visited(area), _old_new(area) | |
557 {} | |
558 | |
559 // Map old to n for invariance computation and clone | |
560 void map_ctrl(Node* old, Node* n) { | |
561 assert(old->is_CFG() && n->is_CFG(), "must be"); | |
562 _old_new.map(old->_idx, n); // "clone" of old is n | |
563 _invariant.set(old->_idx); // old is invariant | |
564 _clone_visited.set(old->_idx); | |
565 } | |
566 | |
567 // Driver function to compute invariance | |
568 bool is_invariant(Node* n) { | |
569 if (!_visited.test_set(n->_idx)) | |
570 compute_invariance(n); | |
571 return (_invariant.test(n->_idx) != 0); | |
572 } | |
573 | |
574 // Driver function to clone invariant | |
575 Node* clone(Node* n, Node* ctrl) { | |
576 assert(ctrl->is_CFG(), "must be"); | |
577 assert(_invariant.test(n->_idx), "must be an invariant"); | |
578 if (!_clone_visited.test(n->_idx)) | |
579 clone_nodes(n, ctrl); | |
580 return _old_new[n->_idx]; | |
581 } | |
582 }; | |
583 | |
584 //------------------------------is_range_check_if ----------------------------------- | |
585 // Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format | |
586 // Note: this function is particularly designed for loop predication. We require load_range | |
587 // and offset to be loop invariant computed on the fly by "invar" | |
588 bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const { | |
589 if (!is_loop_exit(iff)) { | |
590 return false; | |
591 } | |
592 if (!iff->in(1)->is_Bool()) { | |
593 return false; | |
594 } | |
595 const BoolNode *bol = iff->in(1)->as_Bool(); | |
596 if (bol->_test._test != BoolTest::lt) { | |
597 return false; | |
598 } | |
599 if (!bol->in(1)->is_Cmp()) { | |
600 return false; | |
601 } | |
602 const CmpNode *cmp = bol->in(1)->as_Cmp(); | |
603 if (cmp->Opcode() != Op_CmpU) { | |
604 return false; | |
605 } | |
606 Node* range = cmp->in(2); | |
607 if (range->Opcode() != Op_LoadRange) { | |
608 const TypeInt* tint = phase->_igvn.type(range)->isa_int(); | |
3345 | 609 if (tint == NULL || tint->empty() || tint->_lo < 0) { |
2445 | 610 // Allow predication on positive values that aren't LoadRanges. |
611 // This allows optimization of loops where the length of the | |
612 // array is a known value and doesn't need to be loaded back | |
613 // from the array. | |
614 return false; | |
615 } | |
616 } | |
617 if (!invar.is_invariant(range)) { | |
618 return false; | |
619 } | |
620 Node *iv = _head->as_CountedLoop()->phi(); | |
621 int scale = 0; | |
622 Node *offset = NULL; | |
623 if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) { | |
624 return false; | |
625 } | |
626 if (offset && !invar.is_invariant(offset)) { // offset must be invariant | |
627 return false; | |
628 } | |
629 return true; | |
630 } | |
631 | |
632 //------------------------------rc_predicate----------------------------------- | |
633 // Create a range check predicate | |
634 // | |
635 // for (i = init; i < limit; i += stride) { | |
636 // a[scale*i+offset] | |
637 // } | |
638 // | |
639 // Compute max(scale*i + offset) for init <= i < limit and build the predicate | |
640 // as "max(scale*i + offset) u< a.length". | |
641 // | |
642 // There are two cases for max(scale*i + offset): | |
643 // (1) stride*scale > 0 | |
644 // max(scale*i + offset) = scale*(limit-stride) + offset | |
645 // (2) stride*scale < 0 | |
646 // max(scale*i + offset) = scale*init + offset | |
3345 | 647 BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl, |
2445 | 648 int scale, Node* offset, |
649 Node* init, Node* limit, Node* stride, | |
650 Node* range, bool upper) { | |
3336
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
651 stringStream* predString = NULL; |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
652 if (TraceLoopPredicate) { |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
653 predString = new stringStream(); |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
654 predString->print("rc_predicate "); |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
655 } |
2445 | 656 |
657 Node* max_idx_expr = init; | |
658 int stride_con = stride->get_int(); | |
659 if ((stride_con > 0) == (scale > 0) == upper) { | |
3345 | 660 if (LoopLimitCheck) { |
661 // With LoopLimitCheck limit is not exact. | |
662 // Calculate exact limit here. | |
663 // Note, counted loop's test is '<' or '>'. | |
664 limit = exact_limit(loop); | |
665 max_idx_expr = new (C, 3) SubINode(limit, stride); | |
666 register_new_node(max_idx_expr, ctrl); | |
667 if (TraceLoopPredicate) predString->print("(limit - stride) "); | |
668 } else { | |
669 max_idx_expr = new (C, 3) SubINode(limit, stride); | |
670 register_new_node(max_idx_expr, ctrl); | |
671 if (TraceLoopPredicate) predString->print("(limit - stride) "); | |
672 } | |
2445 | 673 } else { |
3336
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
674 if (TraceLoopPredicate) predString->print("init "); |
2445 | 675 } |
676 | |
677 if (scale != 1) { | |
678 ConNode* con_scale = _igvn.intcon(scale); | |
679 max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale); | |
680 register_new_node(max_idx_expr, ctrl); | |
3336
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
681 if (TraceLoopPredicate) predString->print("* %d ", scale); |
2445 | 682 } |
683 | |
684 if (offset && (!offset->is_Con() || offset->get_int() != 0)){ | |
685 max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset); | |
686 register_new_node(max_idx_expr, ctrl); | |
687 if (TraceLoopPredicate) | |
3336
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
688 if (offset->is_Con()) predString->print("+ %d ", offset->get_int()); |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
689 else predString->print("+ offset "); |
2445 | 690 } |
691 | |
692 CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range); | |
693 register_new_node(cmp, ctrl); | |
694 BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt); | |
695 register_new_node(bol, ctrl); | |
696 | |
3336
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
697 if (TraceLoopPredicate) { |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
698 predString->print_cr("<u range"); |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
699 tty->print(predString->as_string()); |
2e038ad0c1d0
7009361: JSR 292 Invalid value on stack on solaris-sparc with -Xcomp
never
parents:
2445
diff
changeset
|
700 } |
2445 | 701 return bol; |
702 } | |
703 | |
704 //------------------------------ loop_predication_impl-------------------------- | |
705 // Insert loop predicates for null checks and range checks | |
706 bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { | |
707 if (!UseLoopPredicate) return false; | |
708 | |
709 if (!loop->_head->is_Loop()) { | |
710 // Could be a simple region when irreducible loops are present. | |
711 return false; | |
712 } | |
3345 | 713 LoopNode* head = loop->_head->as_Loop(); |
2445 | 714 |
3345 | 715 if (head->unique_ctrl_out()->Opcode() == Op_NeverBranch) { |
2445 | 716 // do nothing for infinite loops |
717 return false; | |
718 } | |
719 | |
720 CountedLoopNode *cl = NULL; | |
3850
6987871cfb9b
7077439: Possible reference through NULL in loopPredicate.cpp:726
kvn
parents:
3845
diff
changeset
|
721 if (head->is_valid_counted_loop()) { |
3345 | 722 cl = head->as_CountedLoop(); |
2445 | 723 // do nothing for iteration-splitted loops |
724 if (!cl->is_normal_loop()) return false; | |
3840
4e761e7e6e12
7070134: Hotspot crashes with sigsegv from PorterStemmer
kvn
parents:
3345
diff
changeset
|
725 // Avoid RCE if Counted loop's test is '!='. |
4e761e7e6e12
7070134: Hotspot crashes with sigsegv from PorterStemmer
kvn
parents:
3345
diff
changeset
|
726 BoolTest::mask bt = cl->loopexit()->test_trip(); |
4e761e7e6e12
7070134: Hotspot crashes with sigsegv from PorterStemmer
kvn
parents:
3345
diff
changeset
|
727 if (bt != BoolTest::lt && bt != BoolTest::gt) |
4e761e7e6e12
7070134: Hotspot crashes with sigsegv from PorterStemmer
kvn
parents:
3345
diff
changeset
|
728 cl = NULL; |
2445 | 729 } |
730 | |
3345 | 731 Node* entry = head->in(LoopNode::EntryControl); |
732 ProjNode *predicate_proj = NULL; | |
733 // Loop limit check predicate should be near the loop. | |
734 if (LoopLimitCheck) { | |
735 predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_loop_limit_check); | |
736 if (predicate_proj != NULL) | |
737 entry = predicate_proj->in(0)->in(0); | |
738 } | |
2445 | 739 |
3345 | 740 predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); |
2445 | 741 if (!predicate_proj) { |
742 #ifndef PRODUCT | |
743 if (TraceLoopPredicate) { | |
744 tty->print("missing predicate:"); | |
745 loop->dump_head(); | |
3345 | 746 head->dump(1); |
2445 | 747 } |
748 #endif | |
749 return false; | |
750 } | |
751 ConNode* zero = _igvn.intcon(0); | |
752 set_ctrl(zero, C->root()); | |
753 | |
754 ResourceArea *area = Thread::current()->resource_area(); | |
755 Invariance invar(area, loop); | |
756 | |
757 // Create list of if-projs such that a newer proj dominates all older | |
758 // projs in the list, and they all dominate loop->tail() | |
759 Node_List if_proj_list(area); | |
760 Node *current_proj = loop->tail(); //start from tail | |
761 while (current_proj != head) { | |
762 if (loop == get_loop(current_proj) && // still in the loop ? | |
763 current_proj->is_Proj() && // is a projection ? | |
764 current_proj->in(0)->Opcode() == Op_If) { // is a if projection ? | |
765 if_proj_list.push(current_proj); | |
766 } | |
767 current_proj = idom(current_proj); | |
768 } | |
769 | |
770 bool hoisted = false; // true if at least one proj is promoted | |
771 while (if_proj_list.size() > 0) { | |
772 // Following are changed to nonnull when a predicate can be hoisted | |
773 ProjNode* new_predicate_proj = NULL; | |
774 | |
775 ProjNode* proj = if_proj_list.pop()->as_Proj(); | |
776 IfNode* iff = proj->in(0)->as_If(); | |
777 | |
778 if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { | |
779 if (loop->is_loop_exit(iff)) { | |
780 // stop processing the remaining projs in the list because the execution of them | |
781 // depends on the condition of "iff" (iff->in(1)). | |
782 break; | |
783 } else { | |
784 // Both arms are inside the loop. There are two cases: | |
785 // (1) there is one backward branch. In this case, any remaining proj | |
786 // in the if_proj list post-dominates "iff". So, the condition of "iff" | |
787 // does not determine the execution the remining projs directly, and we | |
788 // can safely continue. | |
789 // (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj" | |
790 // does not dominate loop->tail(), so it can not be in the if_proj list. | |
791 continue; | |
792 } | |
793 } | |
794 | |
795 Node* test = iff->in(1); | |
796 if (!test->is_Bool()){ //Conv2B, ... | |
797 continue; | |
798 } | |
799 BoolNode* bol = test->as_Bool(); | |
800 if (invar.is_invariant(bol)) { | |
801 // Invariant test | |
802 new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL, | |
803 Deoptimization::Reason_predicate); | |
804 Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); | |
805 BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); | |
806 | |
807 // Negate test if necessary | |
808 bool negated = false; | |
809 if (proj->_con != predicate_proj->_con) { | |
810 new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate()); | |
811 register_new_node(new_predicate_bol, ctrl); | |
812 negated = true; | |
813 } | |
814 IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); | |
815 _igvn.hash_delete(new_predicate_iff); | |
816 new_predicate_iff->set_req(1, new_predicate_bol); | |
817 #ifndef PRODUCT | |
818 if (TraceLoopPredicate) { | |
819 tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx); | |
820 loop->dump_head(); | |
821 } else if (TraceLoopOpts) { | |
822 tty->print("Predicate IC "); | |
823 loop->dump_head(); | |
824 } | |
825 #endif | |
826 } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { | |
827 assert(proj->_con == predicate_proj->_con, "must match"); | |
828 | |
829 // Range check for counted loops | |
830 const Node* cmp = bol->in(1)->as_Cmp(); | |
831 Node* idx = cmp->in(1); | |
832 assert(!invar.is_invariant(idx), "index is variant"); | |
833 Node* rng = cmp->in(2); | |
3345 | 834 assert(rng->Opcode() == Op_LoadRange || _igvn.type(rng)->is_int() >= 0, "must be"); |
2445 | 835 assert(invar.is_invariant(rng), "range must be invariant"); |
836 int scale = 1; | |
837 Node* offset = zero; | |
838 bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset); | |
839 assert(ok, "must be index expression"); | |
840 | |
841 Node* init = cl->init_trip(); | |
842 Node* limit = cl->limit(); | |
843 Node* stride = cl->stride(); | |
844 | |
845 // Build if's for the upper and lower bound tests. The | |
846 // lower_bound test will dominate the upper bound test and all | |
847 // cloned or created nodes will use the lower bound test as | |
848 // their declared control. | |
849 ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); | |
850 ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); | |
851 assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); | |
852 Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); | |
853 | |
854 // Perform cloning to keep Invariance state correct since the | |
855 // late schedule will place invariant things in the loop. | |
856 rng = invar.clone(rng, ctrl); | |
857 if (offset && offset != zero) { | |
858 assert(invar.is_invariant(offset), "offset must be loop invariant"); | |
859 offset = invar.clone(offset, ctrl); | |
860 } | |
861 | |
862 // Test the lower bound | |
3345 | 863 Node* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false); |
2445 | 864 IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If(); |
865 _igvn.hash_delete(lower_bound_iff); | |
866 lower_bound_iff->set_req(1, lower_bound_bol); | |
867 if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx); | |
868 | |
869 // Test the upper bound | |
3840
4e761e7e6e12
7070134: Hotspot crashes with sigsegv from PorterStemmer
kvn
parents:
3345
diff
changeset
|
870 Node* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true); |
2445 | 871 IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If(); |
872 _igvn.hash_delete(upper_bound_iff); | |
873 upper_bound_iff->set_req(1, upper_bound_bol); | |
874 if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx); | |
875 | |
876 // Fall through into rest of the clean up code which will move | |
877 // any dependent nodes onto the upper bound test. | |
878 new_predicate_proj = upper_bound_proj; | |
879 | |
880 #ifndef PRODUCT | |
881 if (TraceLoopOpts && !TraceLoopPredicate) { | |
882 tty->print("Predicate RC "); | |
883 loop->dump_head(); | |
884 } | |
885 #endif | |
886 } else { | |
887 // Loop variant check (for example, range check in non-counted loop) | |
888 // with uncommon trap. | |
889 continue; | |
890 } | |
891 assert(new_predicate_proj != NULL, "sanity"); | |
892 // Success - attach condition (new_predicate_bol) to predicate if | |
893 invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate | |
894 | |
895 // Eliminate the old If in the loop body | |
896 dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); | |
897 | |
898 hoisted = true; | |
899 C->set_major_progress(); | |
900 } // end while | |
901 | |
902 #ifndef PRODUCT | |
903 // report that the loop predication has been actually performed | |
904 // for this loop | |
905 if (TraceLoopPredicate && hoisted) { | |
906 tty->print("Loop Predication Performed:"); | |
907 loop->dump_head(); | |
908 } | |
909 #endif | |
910 | |
911 return hoisted; | |
912 } | |
913 | |
914 //------------------------------loop_predication-------------------------------- | |
915 // driver routine for loop predication optimization | |
916 bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { | |
917 bool hoisted = false; | |
918 // Recursively promote predicates | |
919 if (_child) { | |
920 hoisted = _child->loop_predication( phase); | |
921 } | |
922 | |
923 // self | |
924 if (!_irreducible && !tail()->is_top()) { | |
925 hoisted |= phase->loop_predication_impl(this); | |
926 } | |
927 | |
928 if (_next) { //sibling | |
929 hoisted |= _next->loop_predication( phase); | |
930 } | |
931 | |
932 return hoisted; | |
933 } |