Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
ac8ab5ce
D
dragonwell8_hotspot
项目概览
openanolis
/
dragonwell8_hotspot
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_hotspot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
ac8ab5ce
编写于
4月 02, 2011
作者:
K
kvn
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
7004535: Clone loop predicate during loop unswitch
Summary: Clone loop predicate for clonned loops Reviewed-by: never
上级
9d449b34
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
1298 addition
and
716 deletion
+1298
-716
src/share/vm/opto/cfgnode.cpp
src/share/vm/opto/cfgnode.cpp
+16
-2
src/share/vm/opto/compile.cpp
src/share/vm/opto/compile.cpp
+4
-13
src/share/vm/opto/compile.hpp
src/share/vm/opto/compile.hpp
+3
-0
src/share/vm/opto/ifnode.cpp
src/share/vm/opto/ifnode.cpp
+29
-3
src/share/vm/opto/loopPredicate.cpp
src/share/vm/opto/loopPredicate.cpp
+960
-0
src/share/vm/opto/loopTransform.cpp
src/share/vm/opto/loopTransform.cpp
+159
-665
src/share/vm/opto/loopUnswitch.cpp
src/share/vm/opto/loopUnswitch.cpp
+22
-10
src/share/vm/opto/loopnode.cpp
src/share/vm/opto/loopnode.cpp
+40
-12
src/share/vm/opto/loopnode.hpp
src/share/vm/opto/loopnode.hpp
+25
-6
src/share/vm/opto/loopopts.cpp
src/share/vm/opto/loopopts.cpp
+22
-5
src/share/vm/opto/phaseX.hpp
src/share/vm/opto/phaseX.hpp
+7
-0
src/share/vm/opto/split_if.cpp
src/share/vm/opto/split_if.cpp
+3
-0
src/share/vm/opto/superword.cpp
src/share/vm/opto/superword.cpp
+7
-0
src/share/vm/opto/vectornode.hpp
src/share/vm/opto/vectornode.hpp
+1
-0
未找到文件。
src/share/vm/opto/cfgnode.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -1349,9 +1349,17 @@ static Node* is_absolute( PhaseGVN *phase, PhiNode *phi_root, int true_path) {
static
void
split_once
(
PhaseIterGVN
*
igvn
,
Node
*
phi
,
Node
*
val
,
Node
*
n
,
Node
*
newn
)
{
igvn
->
hash_delete
(
n
);
// Remove from hash before hacking edges
Node
*
predicate_proj
=
NULL
;
uint
j
=
1
;
for
(
uint
i
=
phi
->
req
()
-
1
;
i
>
0
;
i
--
)
{
if
(
phi
->
in
(
i
)
==
val
)
{
// Found a path with val?
for
(
uint
i
=
phi
->
req
()
-
1
;
i
>
0
;
i
--
)
{
if
(
phi
->
in
(
i
)
==
val
)
{
// Found a path with val?
if
(
n
->
is_Region
())
{
Node
*
proj
=
PhaseIdealLoop
::
find_predicate
(
n
->
in
(
i
));
if
(
proj
!=
NULL
)
{
assert
(
predicate_proj
==
NULL
,
"only one predicate entry expected"
);
predicate_proj
=
proj
;
}
}
// Add to NEW Region/Phi, no DU info
newn
->
set_req
(
j
++
,
n
->
in
(
i
)
);
// Remove from OLD Region/Phi
...
...
@@ -1362,6 +1370,12 @@ static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *
// Register the new node but do not transform it. Cannot transform until the
// entire Region/Phi conglomerate has been hacked as a single huge transform.
igvn
->
register_new_node_with_optimizer
(
newn
);
// Clone loop predicates
if
(
predicate_proj
!=
NULL
)
{
newn
=
igvn
->
clone_loop_predicates
(
predicate_proj
,
newn
);
}
// Now I can point to the new node.
n
->
add_req
(
newn
);
igvn
->
_worklist
.
push
(
n
);
...
...
src/share/vm/opto/compile.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -1632,7 +1632,6 @@ void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) {
igvn
.
replace_node
(
n
,
n
->
in
(
1
));
}
assert
(
predicate_count
()
==
0
,
"should be clean!"
);
igvn
.
optimize
();
}
//------------------------------Optimize---------------------------------------
...
...
@@ -1689,7 +1688,7 @@ void Compile::Optimize() {
if
((
loop_opts_cnt
>
0
)
&&
(
has_loops
()
||
has_split_ifs
()))
{
{
TracePhase
t2
(
"idealLoop"
,
&
_t_idealLoop
,
true
);
PhaseIdealLoop
ideal_loop
(
igvn
,
true
,
UseLoopPredicate
);
PhaseIdealLoop
ideal_loop
(
igvn
,
true
);
loop_opts_cnt
--
;
if
(
major_progress
())
print_method
(
"PhaseIdealLoop 1"
,
2
);
if
(
failing
())
return
;
...
...
@@ -1697,7 +1696,7 @@ void Compile::Optimize() {
// Loop opts pass if partial peeling occurred in previous pass
if
(
PartialPeelLoop
&&
major_progress
()
&&
(
loop_opts_cnt
>
0
))
{
TracePhase
t3
(
"idealLoop"
,
&
_t_idealLoop
,
true
);
PhaseIdealLoop
ideal_loop
(
igvn
,
false
,
UseLoopPredicate
);
PhaseIdealLoop
ideal_loop
(
igvn
,
false
);
loop_opts_cnt
--
;
if
(
major_progress
())
print_method
(
"PhaseIdealLoop 2"
,
2
);
if
(
failing
())
return
;
...
...
@@ -1705,7 +1704,7 @@ void Compile::Optimize() {
// Loop opts pass for loop-unrolling before CCP
if
(
major_progress
()
&&
(
loop_opts_cnt
>
0
))
{
TracePhase
t4
(
"idealLoop"
,
&
_t_idealLoop
,
true
);
PhaseIdealLoop
ideal_loop
(
igvn
,
false
,
UseLoopPredicate
);
PhaseIdealLoop
ideal_loop
(
igvn
,
false
);
loop_opts_cnt
--
;
if
(
major_progress
())
print_method
(
"PhaseIdealLoop 3"
,
2
);
}
...
...
@@ -1743,21 +1742,13 @@ void Compile::Optimize() {
// peeling, unrolling, etc.
if
(
loop_opts_cnt
>
0
)
{
debug_only
(
int
cnt
=
0
;
);
bool
loop_predication
=
UseLoopPredicate
;
while
(
major_progress
()
&&
(
loop_opts_cnt
>
0
))
{
TracePhase
t2
(
"idealLoop"
,
&
_t_idealLoop
,
true
);
assert
(
cnt
++
<
40
,
"infinite cycle in loop optimization"
);
PhaseIdealLoop
ideal_loop
(
igvn
,
true
,
loop_predication
);
PhaseIdealLoop
ideal_loop
(
igvn
,
true
);
loop_opts_cnt
--
;
if
(
major_progress
())
print_method
(
"PhaseIdealLoop iterations"
,
2
);
if
(
failing
())
return
;
// Perform loop predication optimization during first iteration after CCP.
// After that switch it off and cleanup unused loop predicates.
if
(
loop_predication
)
{
loop_predication
=
false
;
cleanup_loop_predicates
(
igvn
);
if
(
failing
())
return
;
}
}
}
...
...
src/share/vm/opto/compile.hpp
浏览文件 @
ac8ab5ce
...
...
@@ -489,6 +489,9 @@ class Compile : public Phase {
// remove the opaque nodes that protect the predicates so that the unused checks and
// uncommon traps will be eliminated from the graph.
void
cleanup_loop_predicates
(
PhaseIterGVN
&
igvn
);
bool
is_predicate_opaq
(
Node
*
n
)
{
return
_predicate_opaqs
->
contains
(
n
);
}
// Compilation environment.
Arena
*
comp_arena
()
{
return
&
_comp_arena
;
}
...
...
src/share/vm/opto/ifnode.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -27,6 +27,7 @@
#include "opto/addnode.hpp"
#include "opto/cfgnode.hpp"
#include "opto/connode.hpp"
#include "opto/loopnode.hpp"
#include "opto/phaseX.hpp"
#include "opto/runtime.hpp"
#include "opto/subnode.hpp"
...
...
@@ -222,22 +223,35 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
// Make a region merging constants and a region merging the rest
uint
req_c
=
0
;
Node
*
predicate_proj
=
NULL
;
for
(
uint
ii
=
1
;
ii
<
r
->
req
();
ii
++
)
{
if
(
phi
->
in
(
ii
)
==
con1
)
{
if
(
phi
->
in
(
ii
)
==
con1
)
{
req_c
++
;
}
Node
*
proj
=
PhaseIdealLoop
::
find_predicate
(
r
->
in
(
ii
));
if
(
proj
!=
NULL
)
{
assert
(
predicate_proj
==
NULL
,
"only one predicate entry expected"
);
predicate_proj
=
proj
;
}
}
Node
*
predicate_c
=
NULL
;
Node
*
predicate_x
=
NULL
;
Node
*
region_c
=
new
(
igvn
->
C
,
req_c
+
1
)
RegionNode
(
req_c
+
1
);
Node
*
phi_c
=
con1
;
uint
len
=
r
->
req
();
Node
*
region_x
=
new
(
igvn
->
C
,
len
-
req_c
+
1
)
RegionNode
(
len
-
req_c
+
1
);
Node
*
region_x
=
new
(
igvn
->
C
,
len
-
req_c
)
RegionNode
(
len
-
req_c
);
Node
*
phi_x
=
PhiNode
::
make_blank
(
region_x
,
phi
);
for
(
uint
i
=
1
,
i_c
=
1
,
i_x
=
1
;
i
<
len
;
i
++
)
{
if
(
phi
->
in
(
i
)
==
con1
)
{
if
(
phi
->
in
(
i
)
==
con1
)
{
region_c
->
init_req
(
i_c
++
,
r
->
in
(
i
)
);
if
(
r
->
in
(
i
)
==
predicate_proj
)
predicate_c
=
predicate_proj
;
}
else
{
region_x
->
init_req
(
i_x
,
r
->
in
(
i
)
);
phi_x
->
init_req
(
i_x
++
,
phi
->
in
(
i
)
);
if
(
r
->
in
(
i
)
==
predicate_proj
)
predicate_x
=
predicate_proj
;
}
}
...
...
@@ -277,8 +291,20 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
// Make the true/false arms
Node
*
iff_c_t
=
phase
->
transform
(
new
(
igvn
->
C
,
1
)
IfTrueNode
(
iff_c
));
Node
*
iff_c_f
=
phase
->
transform
(
new
(
igvn
->
C
,
1
)
IfFalseNode
(
iff_c
));
if
(
predicate_c
!=
NULL
)
{
assert
(
predicate_x
==
NULL
,
"only one predicate entry expected"
);
// Clone loop predicates to each path
iff_c_t
=
igvn
->
clone_loop_predicates
(
predicate_c
,
iff_c_t
);
iff_c_f
=
igvn
->
clone_loop_predicates
(
predicate_c
,
iff_c_f
);
}
Node
*
iff_x_t
=
phase
->
transform
(
new
(
igvn
->
C
,
1
)
IfTrueNode
(
iff_x
));
Node
*
iff_x_f
=
phase
->
transform
(
new
(
igvn
->
C
,
1
)
IfFalseNode
(
iff_x
));
if
(
predicate_x
!=
NULL
)
{
assert
(
predicate_c
==
NULL
,
"only one predicate entry expected"
);
// Clone loop predicates to each path
iff_x_t
=
igvn
->
clone_loop_predicates
(
predicate_x
,
iff_x_t
);
iff_x_f
=
igvn
->
clone_loop_predicates
(
predicate_x
,
iff_x_f
);
}
// Merge the TRUE paths
Node
*
region_s
=
new
(
igvn
->
C
,
3
)
RegionNode
(
3
);
...
...
src/share/vm/opto/loopPredicate.cpp
0 → 100644
浏览文件 @
ac8ab5ce
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "opto/loopnode.hpp"
#include "opto/addnode.hpp"
#include "opto/callnode.hpp"
#include "opto/connode.hpp"
#include "opto/loopnode.hpp"
#include "opto/mulnode.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
/*
* The general idea of Loop Predication is to insert a predicate on the entry
* path to a loop, and raise a uncommon trap if the check of the condition fails.
* The condition checks are promoted from inside the loop body, and thus
* the checks inside the loop could be eliminated. Currently, loop predication
* optimization has been applied to remove array range check and loop invariant
* checks (such as null checks).
*/
//-------------------------------is_uncommon_trap_proj----------------------------
// Return true if proj is the form of "proj->[region->..]call_uct"
bool
PhaseIdealLoop
::
is_uncommon_trap_proj
(
ProjNode
*
proj
,
Deoptimization
::
DeoptReason
reason
)
{
int
path_limit
=
10
;
assert
(
proj
,
"invalid argument"
);
Node
*
out
=
proj
;
for
(
int
ct
=
0
;
ct
<
path_limit
;
ct
++
)
{
out
=
out
->
unique_ctrl_out
();
if
(
out
==
NULL
)
return
false
;
if
(
out
->
is_CallStaticJava
())
{
int
req
=
out
->
as_CallStaticJava
()
->
uncommon_trap_request
();
if
(
req
!=
0
)
{
Deoptimization
::
DeoptReason
trap_reason
=
Deoptimization
::
trap_request_reason
(
req
);
if
(
trap_reason
==
reason
||
reason
==
Deoptimization
::
Reason_none
)
{
return
true
;
}
}
return
false
;
// don't do further after call
}
if
(
out
->
Opcode
()
!=
Op_Region
)
return
false
;
}
return
false
;
}
//-------------------------------is_uncommon_trap_if_pattern-------------------------
// Return true for "if(test)-> proj -> ...
// |
// V
// other_proj->[region->..]call_uct"
//
// "must_reason_predicate" means the uct reason must be Reason_predicate
bool
PhaseIdealLoop
::
is_uncommon_trap_if_pattern
(
ProjNode
*
proj
,
Deoptimization
::
DeoptReason
reason
)
{
Node
*
in0
=
proj
->
in
(
0
);
if
(
!
in0
->
is_If
())
return
false
;
// Variation of a dead If node.
if
(
in0
->
outcnt
()
<
2
)
return
false
;
IfNode
*
iff
=
in0
->
as_If
();
// we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
if
(
reason
!=
Deoptimization
::
Reason_none
)
{
if
(
iff
->
in
(
1
)
->
Opcode
()
!=
Op_Conv2B
||
iff
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
!=
Op_Opaque1
)
{
return
false
;
}
}
ProjNode
*
other_proj
=
iff
->
proj_out
(
1
-
proj
->
_con
)
->
as_Proj
();
if
(
is_uncommon_trap_proj
(
other_proj
,
reason
))
{
assert
(
reason
==
Deoptimization
::
Reason_none
||
Compile
::
current
()
->
is_predicate_opaq
(
iff
->
in
(
1
)
->
in
(
1
)),
"should be on the list"
);
return
true
;
}
return
false
;
}
//-------------------------------register_control-------------------------
void
PhaseIdealLoop
::
register_control
(
Node
*
n
,
IdealLoopTree
*
loop
,
Node
*
pred
)
{
assert
(
n
->
is_CFG
(),
"must be control node"
);
_igvn
.
register_new_node_with_optimizer
(
n
);
loop
->
_body
.
push
(
n
);
set_loop
(
n
,
loop
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
set_idom
(
n
,
pred
,
dom_depth
(
pred
));
}
}
//------------------------------create_new_if_for_predicate------------------------
// create a new if above the uct_if_pattern for the predicate to be promoted.
//
// before after
// ---------- ----------
// ctrl ctrl
// | |
// | |
// v v
// iff new_iff
// / \ / \
// / \ / \
// v v v v
// uncommon_proj cont_proj if_uct if_cont
// \ | | | |
// \ | | | |
// v v v | v
// rgn loop | iff
// | | / \
// | | / \
// v | v v
// uncommon_trap | uncommon_proj cont_proj
// \ \ | |
// \ \ | |
// v v v v
// rgn loop
// |
// |
// v
// uncommon_trap
//
//
// We will create a region to guard the uct call if there is no one there.
// The true projecttion (if_cont) of the new_iff is returned.
// This code is also used to clone predicates to clonned loops.
ProjNode
*
PhaseIdealLoop
::
create_new_if_for_predicate
(
ProjNode
*
cont_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
)
{
assert
(
is_uncommon_trap_if_pattern
(
cont_proj
,
reason
),
"must be a uct if pattern!"
);
IfNode
*
iff
=
cont_proj
->
in
(
0
)
->
as_If
();
ProjNode
*
uncommon_proj
=
iff
->
proj_out
(
1
-
cont_proj
->
_con
);
Node
*
rgn
=
uncommon_proj
->
unique_ctrl_out
();
assert
(
rgn
->
is_Region
()
||
rgn
->
is_Call
(),
"must be a region or call uct"
);
uint
proj_index
=
1
;
// region's edge corresponding to uncommon_proj
if
(
!
rgn
->
is_Region
())
{
// create a region to guard the call
assert
(
rgn
->
is_Call
(),
"must be call uct"
);
CallNode
*
call
=
rgn
->
as_Call
();
IdealLoopTree
*
loop
=
get_loop
(
call
);
rgn
=
new
(
C
,
1
)
RegionNode
(
1
);
rgn
->
add_req
(
uncommon_proj
);
register_control
(
rgn
,
loop
,
uncommon_proj
);
_igvn
.
hash_delete
(
call
);
call
->
set_req
(
0
,
rgn
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
set_idom
(
call
,
rgn
,
dom_depth
(
rgn
));
}
}
else
{
// Find region's edge corresponding to uncommon_proj
for
(;
proj_index
<
rgn
->
req
();
proj_index
++
)
if
(
rgn
->
in
(
proj_index
)
==
uncommon_proj
)
break
;
assert
(
proj_index
<
rgn
->
req
(),
"sanity"
);
}
Node
*
entry
=
iff
->
in
(
0
);
if
(
new_entry
!=
NULL
)
{
// Clonning the predicate to new location.
entry
=
new_entry
;
}
// Create new_iff
IdealLoopTree
*
lp
=
get_loop
(
entry
);
IfNode
*
new_iff
=
iff
->
clone
()
->
as_If
();
new_iff
->
set_req
(
0
,
entry
);
register_control
(
new_iff
,
lp
,
entry
);
Node
*
if_cont
=
new
(
C
,
1
)
IfTrueNode
(
new_iff
);
Node
*
if_uct
=
new
(
C
,
1
)
IfFalseNode
(
new_iff
);
if
(
cont_proj
->
is_IfFalse
())
{
// Swap
Node
*
tmp
=
if_uct
;
if_uct
=
if_cont
;
if_cont
=
tmp
;
}
register_control
(
if_cont
,
lp
,
new_iff
);
register_control
(
if_uct
,
get_loop
(
rgn
),
new_iff
);
// if_uct to rgn
_igvn
.
hash_delete
(
rgn
);
rgn
->
add_req
(
if_uct
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
Node
*
ridom
=
idom
(
rgn
);
Node
*
nrdom
=
dom_lca
(
ridom
,
new_iff
);
set_idom
(
rgn
,
nrdom
,
dom_depth
(
rgn
));
}
// If rgn has phis add new edges which has the same
// value as on original uncommon_proj pass.
assert
(
rgn
->
in
(
rgn
->
req
()
-
1
)
==
if_uct
,
"new edge should be last"
);
bool
has_phi
=
false
;
for
(
DUIterator_Fast
imax
,
i
=
rgn
->
fast_outs
(
imax
);
i
<
imax
;
i
++
)
{
Node
*
use
=
rgn
->
fast_out
(
i
);
if
(
use
->
is_Phi
()
&&
use
->
outcnt
()
>
0
)
{
assert
(
use
->
in
(
0
)
==
rgn
,
""
);
_igvn
.
hash_delete
(
use
);
use
->
add_req
(
use
->
in
(
proj_index
));
_igvn
.
_worklist
.
push
(
use
);
has_phi
=
true
;
}
}
assert
(
!
has_phi
||
rgn
->
req
()
>
3
,
"no phis when region is created"
);
if
(
new_entry
==
NULL
)
{
// Attach if_cont to iff
_igvn
.
hash_delete
(
iff
);
iff
->
set_req
(
0
,
if_cont
);
if
(
_idom
!=
NULL
)
{
set_idom
(
iff
,
if_cont
,
dom_depth
(
iff
));
}
}
return
if_cont
->
as_Proj
();
}
//------------------------------create_new_if_for_predicate------------------------
// Create a new if below new_entry for the predicate to be cloned (IGVN optimization)
ProjNode
*
PhaseIterGVN
::
create_new_if_for_predicate
(
ProjNode
*
cont_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
)
{
assert
(
new_entry
!=
0
,
"only used for clone predicate"
);
assert
(
PhaseIdealLoop
::
is_uncommon_trap_if_pattern
(
cont_proj
,
reason
),
"must be a uct if pattern!"
);
IfNode
*
iff
=
cont_proj
->
in
(
0
)
->
as_If
();
ProjNode
*
uncommon_proj
=
iff
->
proj_out
(
1
-
cont_proj
->
_con
);
Node
*
rgn
=
uncommon_proj
->
unique_ctrl_out
();
assert
(
rgn
->
is_Region
()
||
rgn
->
is_Call
(),
"must be a region or call uct"
);
uint
proj_index
=
1
;
// region's edge corresponding to uncommon_proj
if
(
!
rgn
->
is_Region
())
{
// create a region to guard the call
assert
(
rgn
->
is_Call
(),
"must be call uct"
);
CallNode
*
call
=
rgn
->
as_Call
();
rgn
=
new
(
C
,
1
)
RegionNode
(
1
);
register_new_node_with_optimizer
(
rgn
);
rgn
->
add_req
(
uncommon_proj
);
hash_delete
(
call
);
call
->
set_req
(
0
,
rgn
);
}
else
{
// Find region's edge corresponding to uncommon_proj
for
(;
proj_index
<
rgn
->
req
();
proj_index
++
)
if
(
rgn
->
in
(
proj_index
)
==
uncommon_proj
)
break
;
assert
(
proj_index
<
rgn
->
req
(),
"sanity"
);
}
// Create new_iff in new location.
IfNode
*
new_iff
=
iff
->
clone
()
->
as_If
();
new_iff
->
set_req
(
0
,
new_entry
);
register_new_node_with_optimizer
(
new_iff
);
Node
*
if_cont
=
new
(
C
,
1
)
IfTrueNode
(
new_iff
);
Node
*
if_uct
=
new
(
C
,
1
)
IfFalseNode
(
new_iff
);
if
(
cont_proj
->
is_IfFalse
())
{
// Swap
Node
*
tmp
=
if_uct
;
if_uct
=
if_cont
;
if_cont
=
tmp
;
}
register_new_node_with_optimizer
(
if_cont
);
register_new_node_with_optimizer
(
if_uct
);
// if_uct to rgn
hash_delete
(
rgn
);
rgn
->
add_req
(
if_uct
);
// If rgn has phis add corresponding new edges which has the same
// value as on original uncommon_proj pass.
assert
(
rgn
->
in
(
rgn
->
req
()
-
1
)
==
if_uct
,
"new edge should be last"
);
bool
has_phi
=
false
;
for
(
DUIterator_Fast
imax
,
i
=
rgn
->
fast_outs
(
imax
);
i
<
imax
;
i
++
)
{
Node
*
use
=
rgn
->
fast_out
(
i
);
if
(
use
->
is_Phi
()
&&
use
->
outcnt
()
>
0
)
{
hash_delete
(
use
);
use
->
add_req
(
use
->
in
(
proj_index
));
_worklist
.
push
(
use
);
has_phi
=
true
;
}
}
assert
(
!
has_phi
||
rgn
->
req
()
>
3
,
"no phis when region is created"
);
return
if_cont
->
as_Proj
();
}
//--------------------------clone_predicate-----------------------
ProjNode
*
PhaseIdealLoop
::
clone_predicate
(
ProjNode
*
predicate_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
)
{
ProjNode
*
new_predicate_proj
;
if
(
loop_phase
!=
NULL
)
{
new_predicate_proj
=
loop_phase
->
create_new_if_for_predicate
(
predicate_proj
,
new_entry
,
reason
);
}
else
{
new_predicate_proj
=
igvn
->
create_new_if_for_predicate
(
predicate_proj
,
new_entry
,
reason
);
}
IfNode
*
iff
=
new_predicate_proj
->
in
(
0
)
->
as_If
();
Node
*
ctrl
=
iff
->
in
(
0
);
// Match original condition since predicate's projections could be swapped.
assert
(
predicate_proj
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
Node
*
opq
=
new
(
igvn
->
C
,
2
)
Opaque1Node
(
igvn
->
C
,
predicate_proj
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
in
(
1
));
igvn
->
C
->
add_predicate_opaq
(
opq
);
Node
*
bol
=
new
(
igvn
->
C
,
2
)
Conv2BNode
(
opq
);
if
(
loop_phase
!=
NULL
)
{
loop_phase
->
register_new_node
(
opq
,
ctrl
);
loop_phase
->
register_new_node
(
bol
,
ctrl
);
}
else
{
igvn
->
register_new_node_with_optimizer
(
opq
);
igvn
->
register_new_node_with_optimizer
(
bol
);
}
igvn
->
hash_delete
(
iff
);
iff
->
set_req
(
1
,
bol
);
return
new_predicate_proj
;
}
//--------------------------move_predicate-----------------------
// Cut predicate from old place and move it to new.
ProjNode
*
PhaseIdealLoop
::
move_predicate
(
ProjNode
*
predicate_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
)
{
assert
(
new_entry
!=
NULL
,
"must be"
);
assert
(
predicate_proj
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
IfNode
*
iff
=
predicate_proj
->
in
(
0
)
->
as_If
();
Node
*
old_entry
=
iff
->
in
(
0
);
// Cut predicate from old place.
Node
*
old
=
predicate_proj
;
igvn
->
_worklist
.
push
(
old
);
for
(
DUIterator_Last
imin
,
i
=
old
->
last_outs
(
imin
);
i
>=
imin
;
)
{
Node
*
use
=
old
->
last_out
(
i
);
// for each use...
igvn
->
hash_delete
(
use
);
igvn
->
_worklist
.
push
(
use
);
// Update use-def info
uint
uses_found
=
0
;
for
(
uint
j
=
0
;
j
<
use
->
req
();
j
++
)
{
if
(
use
->
in
(
j
)
==
old
)
{
use
->
set_req
(
j
,
old_entry
);
uses_found
++
;
if
(
loop_phase
!=
NULL
)
{
if
(
use
->
is_CFG
())
{
// When called from beautify_loops() idom is not constructed yet.
if
(
loop_phase
->
_idom
!=
NULL
)
loop_phase
->
set_idom
(
use
,
old_entry
,
loop_phase
->
dom_depth
(
use
));
}
else
{
loop_phase
->
set_ctrl
(
use
,
old_entry
);
}
}
}
}
i
-=
uses_found
;
// we deleted 1 or more copies of this edge
}
// Move predicate.
igvn
->
hash_delete
(
iff
);
iff
->
set_req
(
0
,
new_entry
);
igvn
->
_worklist
.
push
(
iff
);
if
(
loop_phase
!=
NULL
)
{
// Fix up idom and ctrl.
loop_phase
->
set_ctrl
(
iff
->
in
(
1
),
new_entry
);
loop_phase
->
set_ctrl
(
iff
->
in
(
1
)
->
in
(
1
),
new_entry
);
// When called from beautify_loops() idom is not constructed yet.
if
(
loop_phase
->
_idom
!=
NULL
)
loop_phase
->
set_idom
(
iff
,
new_entry
,
loop_phase
->
dom_depth
(
iff
));
}
return
predicate_proj
;
}
//--------------------------clone_loop_predicates-----------------------
// Interface from IGVN
Node
*
PhaseIterGVN
::
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
)
{
return
PhaseIdealLoop
::
clone_loop_predicates
(
old_entry
,
new_entry
,
false
,
NULL
,
this
);
}
Node
*
PhaseIterGVN
::
move_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
)
{
return
PhaseIdealLoop
::
clone_loop_predicates
(
old_entry
,
new_entry
,
true
,
NULL
,
this
);
}
// Interface from PhaseIdealLoop
Node
*
PhaseIdealLoop
::
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
)
{
return
clone_loop_predicates
(
old_entry
,
new_entry
,
false
,
this
,
&
this
->
_igvn
);
}
Node
*
PhaseIdealLoop
::
move_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
)
{
return
clone_loop_predicates
(
old_entry
,
new_entry
,
true
,
this
,
&
this
->
_igvn
);
}
// Clone loop predicates to cloned loops (peeled, unswitched, split_if).
Node
*
PhaseIdealLoop
::
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
,
bool
move_predicates
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
)
{
#ifdef ASSERT
if
(
new_entry
==
NULL
||
!
(
new_entry
->
is_Proj
()
||
new_entry
->
is_Region
()
||
new_entry
->
is_SafePoint
()))
{
if
(
new_entry
!=
NULL
)
new_entry
->
dump
();
assert
(
false
,
"not IfTrue, IfFalse, Region or SafePoint"
);
}
#endif
// Search original predicates
Node
*
entry
=
old_entry
;
if
(
UseLoopPredicate
)
{
ProjNode
*
predicate_proj
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
predicate_proj
!=
NULL
)
{
// right pattern that can be used by loop predication
assert
(
entry
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
if
(
move_predicates
)
{
new_entry
=
move_predicate
(
predicate_proj
,
new_entry
,
Deoptimization
::
Reason_predicate
,
loop_phase
,
igvn
);
assert
(
new_entry
==
predicate_proj
,
"old predicate fall through projection"
);
}
else
{
// clone predicate
new_entry
=
clone_predicate
(
predicate_proj
,
new_entry
,
Deoptimization
::
Reason_predicate
,
loop_phase
,
igvn
);
assert
(
new_entry
!=
NULL
&&
new_entry
->
is_Proj
(),
"IfTrue or IfFalse after clone predicate"
);
}
if
(
TraceLoopPredicate
)
{
tty
->
print_cr
(
"Loop Predicate %s: "
,
move_predicates
?
"moved"
:
"cloned"
);
debug_only
(
new_entry
->
in
(
0
)
->
dump
();
)
}
}
}
return
new_entry
;
}
//--------------------------eliminate_loop_predicates-----------------------
void
PhaseIdealLoop
::
eliminate_loop_predicates
(
Node
*
entry
)
{
if
(
UseLoopPredicate
)
{
ProjNode
*
predicate_proj
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
predicate_proj
!=
NULL
)
{
// right pattern that can be used by loop predication
Node
*
n
=
entry
->
in
(
0
)
->
in
(
1
)
->
in
(
1
);
assert
(
n
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
// Remove Opaque1 node from predicates list.
// IGVN will remove this predicate check.
_igvn
.
replace_node
(
n
,
n
->
in
(
1
));
}
}
}
//--------------------------skip_loop_predicates------------------------------
// Skip related predicates.
Node
*
PhaseIdealLoop
::
skip_loop_predicates
(
Node
*
entry
)
{
Node
*
predicate
=
NULL
;
if
(
UseLoopPredicate
)
{
predicate
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
predicate
!=
NULL
)
{
// right pattern that can be used by loop predication
assert
(
entry
->
is_Proj
()
&&
entry
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
IfNode
*
iff
=
entry
->
in
(
0
)
->
as_If
();
ProjNode
*
uncommon_proj
=
iff
->
proj_out
(
1
-
entry
->
as_Proj
()
->
_con
);
Node
*
rgn
=
uncommon_proj
->
unique_ctrl_out
();
assert
(
rgn
->
is_Region
()
||
rgn
->
is_Call
(),
"must be a region or call uct"
);
entry
=
entry
->
in
(
0
)
->
in
(
0
);
while
(
entry
!=
NULL
&&
entry
->
is_Proj
()
&&
entry
->
in
(
0
)
->
is_If
())
{
uncommon_proj
=
entry
->
in
(
0
)
->
as_If
()
->
proj_out
(
1
-
entry
->
as_Proj
()
->
_con
);
if
(
uncommon_proj
->
unique_ctrl_out
()
!=
rgn
)
break
;
entry
=
entry
->
in
(
0
)
->
in
(
0
);
}
}
}
return
entry
;
}
//--------------------------find_predicate_insertion_point-------------------
// Find a good location to insert a predicate
ProjNode
*
PhaseIdealLoop
::
find_predicate_insertion_point
(
Node
*
start_c
,
Deoptimization
::
DeoptReason
reason
)
{
if
(
start_c
==
NULL
||
!
start_c
->
is_Proj
())
return
NULL
;
if
(
is_uncommon_trap_if_pattern
(
start_c
->
as_Proj
(),
reason
))
{
return
start_c
->
as_Proj
();
}
return
NULL
;
}
//--------------------------find_predicate------------------------------------
// Find a predicate
Node
*
PhaseIdealLoop
::
find_predicate
(
Node
*
entry
)
{
Node
*
predicate
=
NULL
;
if
(
UseLoopPredicate
)
{
predicate
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
predicate
!=
NULL
)
{
// right pattern that can be used by loop predication
assert
(
entry
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
return
entry
;
}
}
return
NULL
;
}
//------------------------------Invariance-----------------------------------
// Helper class for loop_predication_impl to compute invariance on the fly and
// clone invariants.
class
Invariance
:
public
StackObj
{
VectorSet
_visited
,
_invariant
;
Node_Stack
_stack
;
VectorSet
_clone_visited
;
Node_List
_old_new
;
// map of old to new (clone)
IdealLoopTree
*
_lpt
;
PhaseIdealLoop
*
_phase
;
// Helper function to set up the invariance for invariance computation
// If n is a known invariant, set up directly. Otherwise, look up the
// the possibility to push n onto the stack for further processing.
void
visit
(
Node
*
use
,
Node
*
n
)
{
if
(
_lpt
->
is_invariant
(
n
))
{
// known invariant
_invariant
.
set
(
n
->
_idx
);
}
else
if
(
!
n
->
is_CFG
())
{
Node
*
n_ctrl
=
_phase
->
ctrl_or_self
(
n
);
Node
*
u_ctrl
=
_phase
->
ctrl_or_self
(
use
);
// self if use is a CFG
if
(
_phase
->
is_dominator
(
n_ctrl
,
u_ctrl
))
{
_stack
.
push
(
n
,
n
->
in
(
0
)
==
NULL
?
1
:
0
);
}
}
}
// Compute invariance for "the_node" and (possibly) all its inputs recursively
// on the fly
void
compute_invariance
(
Node
*
n
)
{
assert
(
_visited
.
test
(
n
->
_idx
),
"must be"
);
visit
(
n
,
n
);
while
(
_stack
.
is_nonempty
())
{
Node
*
n
=
_stack
.
node
();
uint
idx
=
_stack
.
index
();
if
(
idx
==
n
->
req
())
{
// all inputs are processed
_stack
.
pop
();
// n is invariant if it's inputs are all invariant
bool
all_inputs_invariant
=
true
;
for
(
uint
i
=
0
;
i
<
n
->
req
();
i
++
)
{
Node
*
in
=
n
->
in
(
i
);
if
(
in
==
NULL
)
continue
;
assert
(
_visited
.
test
(
in
->
_idx
),
"must have visited input"
);
if
(
!
_invariant
.
test
(
in
->
_idx
))
{
// bad guy
all_inputs_invariant
=
false
;
break
;
}
}
if
(
all_inputs_invariant
)
{
_invariant
.
set
(
n
->
_idx
);
// I am a invariant too
}
}
else
{
// process next input
_stack
.
set_index
(
idx
+
1
);
Node
*
m
=
n
->
in
(
idx
);
if
(
m
!=
NULL
&&
!
_visited
.
test_set
(
m
->
_idx
))
{
visit
(
n
,
m
);
}
}
}
}
// Helper function to set up _old_new map for clone_nodes.
// If n is a known invariant, set up directly ("clone" of n == n).
// Otherwise, push n onto the stack for real cloning.
void
clone_visit
(
Node
*
n
)
{
assert
(
_invariant
.
test
(
n
->
_idx
),
"must be invariant"
);
if
(
_lpt
->
is_invariant
(
n
))
{
// known invariant
_old_new
.
map
(
n
->
_idx
,
n
);
}
else
{
// to be cloned
assert
(
!
n
->
is_CFG
(),
"should not see CFG here"
);
_stack
.
push
(
n
,
n
->
in
(
0
)
==
NULL
?
1
:
0
);
}
}
// Clone "n" and (possibly) all its inputs recursively
void
clone_nodes
(
Node
*
n
,
Node
*
ctrl
)
{
clone_visit
(
n
);
while
(
_stack
.
is_nonempty
())
{
Node
*
n
=
_stack
.
node
();
uint
idx
=
_stack
.
index
();
if
(
idx
==
n
->
req
())
{
// all inputs processed, clone n!
_stack
.
pop
();
// clone invariant node
Node
*
n_cl
=
n
->
clone
();
_old_new
.
map
(
n
->
_idx
,
n_cl
);
_phase
->
register_new_node
(
n_cl
,
ctrl
);
for
(
uint
i
=
0
;
i
<
n
->
req
();
i
++
)
{
Node
*
in
=
n_cl
->
in
(
i
);
if
(
in
==
NULL
)
continue
;
n_cl
->
set_req
(
i
,
_old_new
[
in
->
_idx
]);
}
}
else
{
// process next input
_stack
.
set_index
(
idx
+
1
);
Node
*
m
=
n
->
in
(
idx
);
if
(
m
!=
NULL
&&
!
_clone_visited
.
test_set
(
m
->
_idx
))
{
clone_visit
(
m
);
// visit the input
}
}
}
}
public:
Invariance
(
Arena
*
area
,
IdealLoopTree
*
lpt
)
:
_lpt
(
lpt
),
_phase
(
lpt
->
_phase
),
_visited
(
area
),
_invariant
(
area
),
_stack
(
area
,
10
/* guess */
),
_clone_visited
(
area
),
_old_new
(
area
)
{}
// Map old to n for invariance computation and clone
void
map_ctrl
(
Node
*
old
,
Node
*
n
)
{
assert
(
old
->
is_CFG
()
&&
n
->
is_CFG
(),
"must be"
);
_old_new
.
map
(
old
->
_idx
,
n
);
// "clone" of old is n
_invariant
.
set
(
old
->
_idx
);
// old is invariant
_clone_visited
.
set
(
old
->
_idx
);
}
// Driver function to compute invariance
bool
is_invariant
(
Node
*
n
)
{
if
(
!
_visited
.
test_set
(
n
->
_idx
))
compute_invariance
(
n
);
return
(
_invariant
.
test
(
n
->
_idx
)
!=
0
);
}
// Driver function to clone invariant
Node
*
clone
(
Node
*
n
,
Node
*
ctrl
)
{
assert
(
ctrl
->
is_CFG
(),
"must be"
);
assert
(
_invariant
.
test
(
n
->
_idx
),
"must be an invariant"
);
if
(
!
_clone_visited
.
test
(
n
->
_idx
))
clone_nodes
(
n
,
ctrl
);
return
_old_new
[
n
->
_idx
];
}
};
//------------------------------is_range_check_if -----------------------------------
// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
// Note: this function is particularly designed for loop predication. We require load_range
// and offset to be loop invariant computed on the fly by "invar"
bool
IdealLoopTree
::
is_range_check_if
(
IfNode
*
iff
,
PhaseIdealLoop
*
phase
,
Invariance
&
invar
)
const
{
if
(
!
is_loop_exit
(
iff
))
{
return
false
;
}
if
(
!
iff
->
in
(
1
)
->
is_Bool
())
{
return
false
;
}
const
BoolNode
*
bol
=
iff
->
in
(
1
)
->
as_Bool
();
if
(
bol
->
_test
.
_test
!=
BoolTest
::
lt
)
{
return
false
;
}
if
(
!
bol
->
in
(
1
)
->
is_Cmp
())
{
return
false
;
}
const
CmpNode
*
cmp
=
bol
->
in
(
1
)
->
as_Cmp
();
if
(
cmp
->
Opcode
()
!=
Op_CmpU
)
{
return
false
;
}
Node
*
range
=
cmp
->
in
(
2
);
if
(
range
->
Opcode
()
!=
Op_LoadRange
)
{
const
TypeInt
*
tint
=
phase
->
_igvn
.
type
(
range
)
->
isa_int
();
if
(
!
OptimizeFill
||
tint
==
NULL
||
tint
->
empty
()
||
tint
->
_lo
<
0
)
{
// Allow predication on positive values that aren't LoadRanges.
// This allows optimization of loops where the length of the
// array is a known value and doesn't need to be loaded back
// from the array.
return
false
;
}
}
if
(
!
invar
.
is_invariant
(
range
))
{
return
false
;
}
Node
*
iv
=
_head
->
as_CountedLoop
()
->
phi
();
int
scale
=
0
;
Node
*
offset
=
NULL
;
if
(
!
phase
->
is_scaled_iv_plus_offset
(
cmp
->
in
(
1
),
iv
,
&
scale
,
&
offset
))
{
return
false
;
}
if
(
offset
&&
!
invar
.
is_invariant
(
offset
))
{
// offset must be invariant
return
false
;
}
return
true
;
}
//------------------------------rc_predicate-----------------------------------
// Create a range check predicate
//
// for (i = init; i < limit; i += stride) {
// a[scale*i+offset]
// }
//
// Compute max(scale*i + offset) for init <= i < limit and build the predicate
// as "max(scale*i + offset) u< a.length".
//
// There are two cases for max(scale*i + offset):
// (1) stride*scale > 0
// max(scale*i + offset) = scale*(limit-stride) + offset
// (2) stride*scale < 0
// max(scale*i + offset) = scale*init + offset
BoolNode
*
PhaseIdealLoop
::
rc_predicate
(
Node
*
ctrl
,
int
scale
,
Node
*
offset
,
Node
*
init
,
Node
*
limit
,
Node
*
stride
,
Node
*
range
,
bool
upper
)
{
DEBUG_ONLY
(
ttyLocker
ttyl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"rc_predicate "
);
Node
*
max_idx_expr
=
init
;
int
stride_con
=
stride
->
get_int
();
if
((
stride_con
>
0
)
==
(
scale
>
0
)
==
upper
)
{
max_idx_expr
=
new
(
C
,
3
)
SubINode
(
limit
,
stride
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"(limit - stride) "
);
}
else
{
if
(
TraceLoopPredicate
)
tty
->
print
(
"init "
);
}
if
(
scale
!=
1
)
{
ConNode
*
con_scale
=
_igvn
.
intcon
(
scale
);
max_idx_expr
=
new
(
C
,
3
)
MulINode
(
max_idx_expr
,
con_scale
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"* %d "
,
scale
);
}
if
(
offset
&&
(
!
offset
->
is_Con
()
||
offset
->
get_int
()
!=
0
)){
max_idx_expr
=
new
(
C
,
3
)
AddINode
(
max_idx_expr
,
offset
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
if
(
offset
->
is_Con
())
tty
->
print
(
"+ %d "
,
offset
->
get_int
());
else
tty
->
print
(
"+ offset "
);
}
CmpUNode
*
cmp
=
new
(
C
,
3
)
CmpUNode
(
max_idx_expr
,
range
);
register_new_node
(
cmp
,
ctrl
);
BoolNode
*
bol
=
new
(
C
,
2
)
BoolNode
(
cmp
,
BoolTest
::
lt
);
register_new_node
(
bol
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"<u range"
);
return
bol
;
}
//------------------------------ loop_predication_impl--------------------------
// Insert loop predicates for null checks and range checks
bool
PhaseIdealLoop
::
loop_predication_impl
(
IdealLoopTree
*
loop
)
{
if
(
!
UseLoopPredicate
)
return
false
;
if
(
!
loop
->
_head
->
is_Loop
())
{
// Could be a simple region when irreducible loops are present.
return
false
;
}
if
(
loop
->
_head
->
unique_ctrl_out
()
->
Opcode
()
==
Op_NeverBranch
)
{
// do nothing for infinite loops
return
false
;
}
CountedLoopNode
*
cl
=
NULL
;
if
(
loop
->
_head
->
is_CountedLoop
())
{
cl
=
loop
->
_head
->
as_CountedLoop
();
// do nothing for iteration-splitted loops
if
(
!
cl
->
is_normal_loop
())
return
false
;
}
LoopNode
*
lpn
=
loop
->
_head
->
as_Loop
();
Node
*
entry
=
lpn
->
in
(
LoopNode
::
EntryControl
);
ProjNode
*
predicate_proj
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
!
predicate_proj
)
{
#ifndef PRODUCT
if
(
TraceLoopPredicate
)
{
tty
->
print
(
"missing predicate:"
);
loop
->
dump_head
();
lpn
->
dump
(
1
);
}
#endif
return
false
;
}
ConNode
*
zero
=
_igvn
.
intcon
(
0
);
set_ctrl
(
zero
,
C
->
root
());
ResourceArea
*
area
=
Thread
::
current
()
->
resource_area
();
Invariance
invar
(
area
,
loop
);
// Create list of if-projs such that a newer proj dominates all older
// projs in the list, and they all dominate loop->tail()
Node_List
if_proj_list
(
area
);
LoopNode
*
head
=
loop
->
_head
->
as_Loop
();
Node
*
current_proj
=
loop
->
tail
();
//start from tail
while
(
current_proj
!=
head
)
{
if
(
loop
==
get_loop
(
current_proj
)
&&
// still in the loop ?
current_proj
->
is_Proj
()
&&
// is a projection ?
current_proj
->
in
(
0
)
->
Opcode
()
==
Op_If
)
{
// is a if projection ?
if_proj_list
.
push
(
current_proj
);
}
current_proj
=
idom
(
current_proj
);
}
bool
hoisted
=
false
;
// true if at least one proj is promoted
while
(
if_proj_list
.
size
()
>
0
)
{
// Following are changed to nonnull when a predicate can be hoisted
ProjNode
*
new_predicate_proj
=
NULL
;
ProjNode
*
proj
=
if_proj_list
.
pop
()
->
as_Proj
();
IfNode
*
iff
=
proj
->
in
(
0
)
->
as_If
();
if
(
!
is_uncommon_trap_if_pattern
(
proj
,
Deoptimization
::
Reason_none
))
{
if
(
loop
->
is_loop_exit
(
iff
))
{
// stop processing the remaining projs in the list because the execution of them
// depends on the condition of "iff" (iff->in(1)).
break
;
}
else
{
// Both arms are inside the loop. There are two cases:
// (1) there is one backward branch. In this case, any remaining proj
// in the if_proj list post-dominates "iff". So, the condition of "iff"
// does not determine the execution the remining projs directly, and we
// can safely continue.
// (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj"
// does not dominate loop->tail(), so it can not be in the if_proj list.
continue
;
}
}
Node
*
test
=
iff
->
in
(
1
);
if
(
!
test
->
is_Bool
()){
//Conv2B, ...
continue
;
}
BoolNode
*
bol
=
test
->
as_Bool
();
if
(
invar
.
is_invariant
(
bol
))
{
// Invariant test
new_predicate_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
Node
*
ctrl
=
new_predicate_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
);
BoolNode
*
new_predicate_bol
=
invar
.
clone
(
bol
,
ctrl
)
->
as_Bool
();
// Negate test if necessary
bool
negated
=
false
;
if
(
proj
->
_con
!=
predicate_proj
->
_con
)
{
new_predicate_bol
=
new
(
C
,
2
)
BoolNode
(
new_predicate_bol
->
in
(
1
),
new_predicate_bol
->
_test
.
negate
());
register_new_node
(
new_predicate_bol
,
ctrl
);
negated
=
true
;
}
IfNode
*
new_predicate_iff
=
new_predicate_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
new_predicate_iff
);
new_predicate_iff
->
set_req
(
1
,
new_predicate_bol
);
#ifndef PRODUCT
if
(
TraceLoopPredicate
)
{
tty
->
print
(
"Predicate invariant if%s: %d "
,
negated
?
" negated"
:
""
,
new_predicate_iff
->
_idx
);
loop
->
dump_head
();
}
else
if
(
TraceLoopOpts
)
{
tty
->
print
(
"Predicate IC "
);
loop
->
dump_head
();
}
#endif
}
else
if
(
cl
!=
NULL
&&
loop
->
is_range_check_if
(
iff
,
this
,
invar
))
{
assert
(
proj
->
_con
==
predicate_proj
->
_con
,
"must match"
);
// Range check for counted loops
const
Node
*
cmp
=
bol
->
in
(
1
)
->
as_Cmp
();
Node
*
idx
=
cmp
->
in
(
1
);
assert
(
!
invar
.
is_invariant
(
idx
),
"index is variant"
);
assert
(
cmp
->
in
(
2
)
->
Opcode
()
==
Op_LoadRange
||
OptimizeFill
,
"must be"
);
Node
*
rng
=
cmp
->
in
(
2
);
assert
(
invar
.
is_invariant
(
rng
),
"range must be invariant"
);
int
scale
=
1
;
Node
*
offset
=
zero
;
bool
ok
=
is_scaled_iv_plus_offset
(
idx
,
cl
->
phi
(),
&
scale
,
&
offset
);
assert
(
ok
,
"must be index expression"
);
Node
*
init
=
cl
->
init_trip
();
Node
*
limit
=
cl
->
limit
();
Node
*
stride
=
cl
->
stride
();
// Build if's for the upper and lower bound tests. The
// lower_bound test will dominate the upper bound test and all
// cloned or created nodes will use the lower bound test as
// their declared control.
ProjNode
*
lower_bound_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
ProjNode
*
upper_bound_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
assert
(
upper_bound_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
)
==
lower_bound_proj
,
"should dominate"
);
Node
*
ctrl
=
lower_bound_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
);
// Perform cloning to keep Invariance state correct since the
// late schedule will place invariant things in the loop.
rng
=
invar
.
clone
(
rng
,
ctrl
);
if
(
offset
&&
offset
!=
zero
)
{
assert
(
invar
.
is_invariant
(
offset
),
"offset must be loop invariant"
);
offset
=
invar
.
clone
(
offset
,
ctrl
);
}
// Test the lower bound
Node
*
lower_bound_bol
=
rc_predicate
(
ctrl
,
scale
,
offset
,
init
,
limit
,
stride
,
rng
,
false
);
IfNode
*
lower_bound_iff
=
lower_bound_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
lower_bound_iff
);
lower_bound_iff
->
set_req
(
1
,
lower_bound_bol
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"lower bound check if: %d"
,
lower_bound_iff
->
_idx
);
// Test the upper bound
Node
*
upper_bound_bol
=
rc_predicate
(
ctrl
,
scale
,
offset
,
init
,
limit
,
stride
,
rng
,
true
);
IfNode
*
upper_bound_iff
=
upper_bound_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
upper_bound_iff
);
upper_bound_iff
->
set_req
(
1
,
upper_bound_bol
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"upper bound check if: %d"
,
lower_bound_iff
->
_idx
);
// Fall through into rest of the clean up code which will move
// any dependent nodes onto the upper bound test.
new_predicate_proj
=
upper_bound_proj
;
#ifndef PRODUCT
if
(
TraceLoopOpts
&&
!
TraceLoopPredicate
)
{
tty
->
print
(
"Predicate RC "
);
loop
->
dump_head
();
}
#endif
}
else
{
// Loop variant check (for example, range check in non-counted loop)
// with uncommon trap.
continue
;
}
assert
(
new_predicate_proj
!=
NULL
,
"sanity"
);
// Success - attach condition (new_predicate_bol) to predicate if
invar
.
map_ctrl
(
proj
,
new_predicate_proj
);
// so that invariance test can be appropriate
// Eliminate the old If in the loop body
dominated_by
(
new_predicate_proj
,
iff
,
proj
->
_con
!=
new_predicate_proj
->
_con
);
hoisted
=
true
;
C
->
set_major_progress
();
}
// end while
#ifndef PRODUCT
// report that the loop predication has been actually performed
// for this loop
if
(
TraceLoopPredicate
&&
hoisted
)
{
tty
->
print
(
"Loop Predication Performed:"
);
loop
->
dump_head
();
}
#endif
return
hoisted
;
}
//------------------------------loop_predication--------------------------------
// driver routine for loop predication optimization
bool
IdealLoopTree
::
loop_predication
(
PhaseIdealLoop
*
phase
)
{
bool
hoisted
=
false
;
// Recursively promote predicates
if
(
_child
)
{
hoisted
=
_child
->
loop_predication
(
phase
);
}
// self
if
(
!
_irreducible
&&
!
tail
()
->
is_top
())
{
hoisted
|=
phase
->
loop_predication_impl
(
this
);
}
if
(
_next
)
{
//sibling
hoisted
|=
_next
->
loop_predication
(
phase
);
}
return
hoisted
;
}
src/share/vm/opto/loopTransform.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -301,6 +301,132 @@ void PhaseIdealLoop::peeled_dom_test_elim( IdealLoopTree *loop, Node_List &old_n
// peeled-loop backedge has 2 users.
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
//
// orig
//
// stmt1
// |
// v
// loop predicate
// |
// v
// loop<----+
// | |
// stmt2 |
// | |
// v |
// if ^
// / \ |
// / \ |
// v v |
// false true |
// / \ |
// / ----+
// |
// v
// exit
//
//
// after clone loop
//
// stmt1
// |
// v
// loop predicate
// / \
// clone / \ orig
// / \
// / \
// v v
// +---->loop clone loop<----+
// | | | |
// | stmt2 clone stmt2 |
// | | | |
// | v v |
// ^ if clone If ^
// | / \ / \ |
// | / \ / \ |
// | v v v v |
// | true false false true |
// | / \ / \ |
// +---- \ / ----+
// \ /
// 1v v2
// region
// |
// v
// exit
//
//
// after peel and predicate move
//
// stmt1
// /
// /
// clone / orig
// /
// / +----------+
// / | |
// / loop predicate |
// / | |
// v v |
// TOP-->loop clone loop<----+ |
// | | | |
// stmt2 clone stmt2 | |
// | | | ^
// v v | |
// if clone If ^ |
// / \ / \ | |
// / \ / \ | |
// v v v v | |
// true false false true | |
// | \ / \ | |
// | \ / ----+ ^
// | \ / |
// | 1v v2 |
// v region |
// | | |
// | v |
// | exit |
// | |
// +--------------->-----------------+
//
//
// final graph
//
// stmt1
// |
// v
// stmt2 clone
// |
// v
// if clone
// / |
// / |
// v v
// false true
// | |
// | v
// | loop predicate
// | |
// | v
// | loop<----+
// | | |
// | stmt2 |
// | | |
// | v |
// v if ^
// | / \ |
// | / \ |
// | v v |
// | false true |
// | | \ |
// v v --+
// region
// |
// v
// exit
//
void
PhaseIdealLoop
::
do_peeling
(
IdealLoopTree
*
loop
,
Node_List
&
old_new
)
{
C
->
set_major_progress
();
...
...
@@ -315,9 +441,10 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
loop
->
dump_head
();
}
#endif
Node
*
h
=
loop
->
_head
;
if
(
h
->
is_CountedLoop
())
{
CountedLoopNode
*
cl
=
h
->
as_CountedLoop
();
Node
*
head
=
loop
->
_head
;
bool
counted_loop
=
head
->
is_CountedLoop
();
if
(
counted_loop
)
{
CountedLoopNode
*
cl
=
head
->
as_CountedLoop
();
assert
(
cl
->
trip_count
()
>
0
,
"peeling a fully unrolled loop"
);
cl
->
set_trip_count
(
cl
->
trip_count
()
-
1
);
if
(
cl
->
is_main_loop
())
{
...
...
@@ -330,11 +457,11 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
#endif
}
}
Node
*
entry
=
head
->
in
(
LoopNode
::
EntryControl
);
// Step 1: Clone the loop body. The clone becomes the peeled iteration.
// The pre-loop illegally has 2 control users (old & new loops).
clone_loop
(
loop
,
old_new
,
dom_depth
(
loop
->
_head
)
);
clone_loop
(
loop
,
old_new
,
dom_depth
(
head
)
);
// Step 2: Make the old-loop fall-in edges point to the peeled iteration.
// Do this by making the old-loop fall-in edges act as if they came
...
...
@@ -342,12 +469,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// backedges) and then map to the new peeled iteration. This leaves
// the pre-loop with only 1 user (the new peeled iteration), but the
// peeled-loop backedge has 2 users.
for
(
DUIterator_Fast
jmax
,
j
=
loop
->
_head
->
fast_outs
(
jmax
);
j
<
jmax
;
j
++
)
{
Node
*
old
=
loop
->
_head
->
fast_out
(
j
);
if
(
old
->
in
(
0
)
==
loop
->
_head
&&
old
->
req
()
==
3
&&
(
old
->
is_Loop
()
||
old
->
is_Phi
())
)
{
Node
*
new_exit_value
=
old_new
[
old
->
in
(
LoopNode
::
LoopBackControl
)
->
_idx
];
if
(
!
new_exit_value
)
// Backedge value is ALSO loop invariant?
Node
*
new_exit_value
=
old_new
[
head
->
in
(
LoopNode
::
LoopBackControl
)
->
_idx
];
new_exit_value
=
move_loop_predicates
(
entry
,
new_exit_value
);
_igvn
.
hash_delete
(
head
);
head
->
set_req
(
LoopNode
::
EntryControl
,
new_exit_value
);
for
(
DUIterator_Fast
jmax
,
j
=
head
->
fast_outs
(
jmax
);
j
<
jmax
;
j
++
)
{
Node
*
old
=
head
->
fast_out
(
j
);
if
(
old
->
in
(
0
)
==
loop
->
_head
&&
old
->
req
()
==
3
&&
old
->
is_Phi
())
{
new_exit_value
=
old_new
[
old
->
in
(
LoopNode
::
LoopBackControl
)
->
_idx
];
if
(
!
new_exit_value
)
// Backedge value is ALSO loop invariant?
// Then loop body backedge value remains the same.
new_exit_value
=
old
->
in
(
LoopNode
::
LoopBackControl
);
_igvn
.
hash_delete
(
old
);
...
...
@@ -358,12 +488,12 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
Node
*
nnn
=
old_new
[
loop
->
_
head
->
_idx
];
_igvn
.
hash_delete
(
n
nn
);
n
nn
->
set_req
(
LoopNode
::
LoopBackControl
,
C
->
top
());
for
(
DUIterator_Fast
j2max
,
j2
=
n
nn
->
fast_outs
(
j2max
);
j2
<
j2max
;
j2
++
)
{
Node
*
use
=
n
nn
->
fast_out
(
j2
);
if
(
use
->
in
(
0
)
==
nnn
&&
use
->
req
()
==
3
&&
use
->
is_Phi
()
)
{
Node
*
new_head
=
old_new
[
head
->
_idx
];
_igvn
.
hash_delete
(
n
ew_head
);
n
ew_head
->
set_req
(
LoopNode
::
LoopBackControl
,
C
->
top
());
for
(
DUIterator_Fast
j2max
,
j2
=
n
ew_head
->
fast_outs
(
j2max
);
j2
<
j2max
;
j2
++
)
{
Node
*
use
=
n
ew_head
->
fast_out
(
j2
);
if
(
use
->
in
(
0
)
==
new_head
&&
use
->
req
()
==
3
&&
use
->
is_Phi
()
)
{
_igvn
.
hash_delete
(
use
);
use
->
set_req
(
LoopNode
::
LoopBackControl
,
C
->
top
());
}
...
...
@@ -371,15 +501,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 4: Correct dom-depth info. Set to loop-head depth.
int
dd
=
dom_depth
(
loop
->
_
head
);
set_idom
(
loop
->
_head
,
loop
->
_
head
->
in
(
1
),
dd
);
int
dd
=
dom_depth
(
head
);
set_idom
(
head
,
head
->
in
(
1
),
dd
);
for
(
uint
j3
=
0
;
j3
<
loop
->
_body
.
size
();
j3
++
)
{
Node
*
old
=
loop
->
_body
.
at
(
j3
);
Node
*
nnn
=
old_new
[
old
->
_idx
];
if
(
!
has_ctrl
(
nnn
))
set_idom
(
nnn
,
idom
(
nnn
),
dd
-
1
);
// While we're at it, remove any SafePoints from the peeled code
if
(
old
->
Opcode
()
==
Op_SafePoint
)
{
if
(
old
->
Opcode
()
==
Op_SafePoint
)
{
Node
*
nnn
=
old_new
[
old
->
_idx
];
lazy_replace
(
nnn
,
nnn
->
in
(
TypeFunc
::
Control
));
}
...
...
@@ -1659,7 +1789,7 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
bool
needs_guard
=
!
cl
->
is_main_loop
()
&&
!
cl
->
is_post_loop
();
if
(
needs_guard
)
{
// Check for an obvious zero trip guard.
Node
*
inctrl
=
cl
->
in
(
LoopNode
::
EntryControl
);
Node
*
inctrl
=
PhaseIdealLoop
::
skip_loop_predicates
(
cl
->
in
(
LoopNode
::
EntryControl
)
);
if
(
inctrl
->
Opcode
()
==
Op_IfTrue
)
{
// The test should look like just the backedge of a CountedLoop
Node
*
iff
=
inctrl
->
in
(
0
);
...
...
@@ -1861,651 +1991,8 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new )
return
true
;
}
//-------------------------------is_uncommon_trap_proj----------------------------
// Return true if proj is the form of "proj->[region->..]call_uct"
bool
PhaseIdealLoop
::
is_uncommon_trap_proj
(
ProjNode
*
proj
,
Deoptimization
::
DeoptReason
reason
)
{
int
path_limit
=
10
;
assert
(
proj
,
"invalid argument"
);
Node
*
out
=
proj
;
for
(
int
ct
=
0
;
ct
<
path_limit
;
ct
++
)
{
out
=
out
->
unique_ctrl_out
();
if
(
out
==
NULL
||
out
->
is_Root
()
||
out
->
is_Start
())
return
false
;
if
(
out
->
is_CallStaticJava
())
{
int
req
=
out
->
as_CallStaticJava
()
->
uncommon_trap_request
();
if
(
req
!=
0
)
{
Deoptimization
::
DeoptReason
trap_reason
=
Deoptimization
::
trap_request_reason
(
req
);
if
(
trap_reason
==
reason
||
reason
==
Deoptimization
::
Reason_none
)
{
return
true
;
}
}
return
false
;
// don't do further after call
}
}
return
false
;
}
//-------------------------------is_uncommon_trap_if_pattern-------------------------
// Return true for "if(test)-> proj -> ...
// |
// V
// other_proj->[region->..]call_uct"
//
// "must_reason_predicate" means the uct reason must be Reason_predicate
bool
PhaseIdealLoop
::
is_uncommon_trap_if_pattern
(
ProjNode
*
proj
,
Deoptimization
::
DeoptReason
reason
)
{
Node
*
in0
=
proj
->
in
(
0
);
if
(
!
in0
->
is_If
())
return
false
;
// Variation of a dead If node.
if
(
in0
->
outcnt
()
<
2
)
return
false
;
IfNode
*
iff
=
in0
->
as_If
();
// we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
if
(
reason
!=
Deoptimization
::
Reason_none
)
{
if
(
iff
->
in
(
1
)
->
Opcode
()
!=
Op_Conv2B
||
iff
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
!=
Op_Opaque1
)
{
return
false
;
}
}
ProjNode
*
other_proj
=
iff
->
proj_out
(
1
-
proj
->
_con
)
->
as_Proj
();
return
is_uncommon_trap_proj
(
other_proj
,
reason
);
}
//-------------------------------register_control-------------------------
void
PhaseIdealLoop
::
register_control
(
Node
*
n
,
IdealLoopTree
*
loop
,
Node
*
pred
)
{
assert
(
n
->
is_CFG
(),
"must be control node"
);
_igvn
.
register_new_node_with_optimizer
(
n
);
loop
->
_body
.
push
(
n
);
set_loop
(
n
,
loop
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
set_idom
(
n
,
pred
,
dom_depth
(
pred
));
}
}
//------------------------------create_new_if_for_predicate------------------------
// create a new if above the uct_if_pattern for the predicate to be promoted.
//
// before after
// ---------- ----------
// ctrl ctrl
// | |
// | |
// v v
// iff new_iff
// / \ / \
// / \ / \
// v v v v
// uncommon_proj cont_proj if_uct if_cont
// \ | | | |
// \ | | | |
// v v v | v
// rgn loop | iff
// | | / \
// | | / \
// v | v v
// uncommon_trap | uncommon_proj cont_proj
// \ \ | |
// \ \ | |
// v v v v
// rgn loop
// |
// |
// v
// uncommon_trap
//
//
// We will create a region to guard the uct call if there is no one there.
// The true projecttion (if_cont) of the new_iff is returned.
// This code is also used to clone predicates to clonned loops.
ProjNode
*
PhaseIdealLoop
::
create_new_if_for_predicate
(
ProjNode
*
cont_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
)
{
assert
(
is_uncommon_trap_if_pattern
(
cont_proj
,
reason
),
"must be a uct if pattern!"
);
IfNode
*
iff
=
cont_proj
->
in
(
0
)
->
as_If
();
ProjNode
*
uncommon_proj
=
iff
->
proj_out
(
1
-
cont_proj
->
_con
);
Node
*
rgn
=
uncommon_proj
->
unique_ctrl_out
();
assert
(
rgn
->
is_Region
()
||
rgn
->
is_Call
(),
"must be a region or call uct"
);
if
(
!
rgn
->
is_Region
())
{
// create a region to guard the call
assert
(
rgn
->
is_Call
(),
"must be call uct"
);
CallNode
*
call
=
rgn
->
as_Call
();
IdealLoopTree
*
loop
=
get_loop
(
call
);
rgn
=
new
(
C
,
1
)
RegionNode
(
1
);
rgn
->
add_req
(
uncommon_proj
);
register_control
(
rgn
,
loop
,
uncommon_proj
);
_igvn
.
hash_delete
(
call
);
call
->
set_req
(
0
,
rgn
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
set_idom
(
call
,
rgn
,
dom_depth
(
rgn
));
}
}
Node
*
entry
=
iff
->
in
(
0
);
if
(
new_entry
!=
NULL
)
{
// Clonning the predicate to new location.
entry
=
new_entry
;
}
// Create new_iff
IdealLoopTree
*
lp
=
get_loop
(
entry
);
IfNode
*
new_iff
=
new
(
C
,
2
)
IfNode
(
entry
,
NULL
,
iff
->
_prob
,
iff
->
_fcnt
);
register_control
(
new_iff
,
lp
,
entry
);
Node
*
if_cont
=
new
(
C
,
1
)
IfTrueNode
(
new_iff
);
Node
*
if_uct
=
new
(
C
,
1
)
IfFalseNode
(
new_iff
);
if
(
cont_proj
->
is_IfFalse
())
{
// Swap
Node
*
tmp
=
if_uct
;
if_uct
=
if_cont
;
if_cont
=
tmp
;
}
register_control
(
if_cont
,
lp
,
new_iff
);
register_control
(
if_uct
,
get_loop
(
rgn
),
new_iff
);
// if_uct to rgn
_igvn
.
hash_delete
(
rgn
);
rgn
->
add_req
(
if_uct
);
// When called from beautify_loops() idom is not constructed yet.
if
(
_idom
!=
NULL
)
{
Node
*
ridom
=
idom
(
rgn
);
Node
*
nrdom
=
dom_lca
(
ridom
,
new_iff
);
set_idom
(
rgn
,
nrdom
,
dom_depth
(
rgn
));
}
// rgn must have no phis
assert
(
!
rgn
->
as_Region
()
->
has_phi
(),
"region must have no phis"
);
if
(
new_entry
==
NULL
)
{
// Attach if_cont to iff
_igvn
.
hash_delete
(
iff
);
iff
->
set_req
(
0
,
if_cont
);
if
(
_idom
!=
NULL
)
{
set_idom
(
iff
,
if_cont
,
dom_depth
(
iff
));
}
}
return
if_cont
->
as_Proj
();
}
//--------------------------find_predicate_insertion_point-------------------
// Find a good location to insert a predicate
ProjNode
*
PhaseIdealLoop
::
find_predicate_insertion_point
(
Node
*
start_c
,
Deoptimization
::
DeoptReason
reason
)
{
if
(
start_c
==
NULL
||
!
start_c
->
is_Proj
())
return
NULL
;
if
(
is_uncommon_trap_if_pattern
(
start_c
->
as_Proj
(),
reason
))
{
return
start_c
->
as_Proj
();
}
return
NULL
;
}
//--------------------------find_predicate------------------------------------
// Find a predicate
Node
*
PhaseIdealLoop
::
find_predicate
(
Node
*
entry
)
{
Node
*
predicate
=
NULL
;
if
(
UseLoopPredicate
)
{
predicate
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
predicate
!=
NULL
)
{
// right pattern that can be used by loop predication
assert
(
entry
->
in
(
0
)
->
in
(
1
)
->
in
(
1
)
->
Opcode
()
==
Op_Opaque1
,
"must be"
);
return
entry
;
}
}
return
NULL
;
}
//------------------------------Invariance-----------------------------------
// Helper class for loop_predication_impl to compute invariance on the fly and
// clone invariants.
class
Invariance
:
public
StackObj
{
VectorSet
_visited
,
_invariant
;
Node_Stack
_stack
;
VectorSet
_clone_visited
;
Node_List
_old_new
;
// map of old to new (clone)
IdealLoopTree
*
_lpt
;
PhaseIdealLoop
*
_phase
;
// Helper function to set up the invariance for invariance computation
// If n is a known invariant, set up directly. Otherwise, look up the
// the possibility to push n onto the stack for further processing.
void
visit
(
Node
*
use
,
Node
*
n
)
{
if
(
_lpt
->
is_invariant
(
n
))
{
// known invariant
_invariant
.
set
(
n
->
_idx
);
}
else
if
(
!
n
->
is_CFG
())
{
Node
*
n_ctrl
=
_phase
->
ctrl_or_self
(
n
);
Node
*
u_ctrl
=
_phase
->
ctrl_or_self
(
use
);
// self if use is a CFG
if
(
_phase
->
is_dominator
(
n_ctrl
,
u_ctrl
))
{
_stack
.
push
(
n
,
n
->
in
(
0
)
==
NULL
?
1
:
0
);
}
}
}
// Compute invariance for "the_node" and (possibly) all its inputs recursively
// on the fly
void
compute_invariance
(
Node
*
n
)
{
assert
(
_visited
.
test
(
n
->
_idx
),
"must be"
);
visit
(
n
,
n
);
while
(
_stack
.
is_nonempty
())
{
Node
*
n
=
_stack
.
node
();
uint
idx
=
_stack
.
index
();
if
(
idx
==
n
->
req
())
{
// all inputs are processed
_stack
.
pop
();
// n is invariant if it's inputs are all invariant
bool
all_inputs_invariant
=
true
;
for
(
uint
i
=
0
;
i
<
n
->
req
();
i
++
)
{
Node
*
in
=
n
->
in
(
i
);
if
(
in
==
NULL
)
continue
;
assert
(
_visited
.
test
(
in
->
_idx
),
"must have visited input"
);
if
(
!
_invariant
.
test
(
in
->
_idx
))
{
// bad guy
all_inputs_invariant
=
false
;
break
;
}
}
if
(
all_inputs_invariant
)
{
_invariant
.
set
(
n
->
_idx
);
// I am a invariant too
}
}
else
{
// process next input
_stack
.
set_index
(
idx
+
1
);
Node
*
m
=
n
->
in
(
idx
);
if
(
m
!=
NULL
&&
!
_visited
.
test_set
(
m
->
_idx
))
{
visit
(
n
,
m
);
}
}
}
}
// Helper function to set up _old_new map for clone_nodes.
// If n is a known invariant, set up directly ("clone" of n == n).
// Otherwise, push n onto the stack for real cloning.
void
clone_visit
(
Node
*
n
)
{
assert
(
_invariant
.
test
(
n
->
_idx
),
"must be invariant"
);
if
(
_lpt
->
is_invariant
(
n
))
{
// known invariant
_old_new
.
map
(
n
->
_idx
,
n
);
}
else
{
// to be cloned
assert
(
!
n
->
is_CFG
(),
"should not see CFG here"
);
_stack
.
push
(
n
,
n
->
in
(
0
)
==
NULL
?
1
:
0
);
}
}
// Clone "n" and (possibly) all its inputs recursively
void
clone_nodes
(
Node
*
n
,
Node
*
ctrl
)
{
clone_visit
(
n
);
while
(
_stack
.
is_nonempty
())
{
Node
*
n
=
_stack
.
node
();
uint
idx
=
_stack
.
index
();
if
(
idx
==
n
->
req
())
{
// all inputs processed, clone n!
_stack
.
pop
();
// clone invariant node
Node
*
n_cl
=
n
->
clone
();
_old_new
.
map
(
n
->
_idx
,
n_cl
);
_phase
->
register_new_node
(
n_cl
,
ctrl
);
for
(
uint
i
=
0
;
i
<
n
->
req
();
i
++
)
{
Node
*
in
=
n_cl
->
in
(
i
);
if
(
in
==
NULL
)
continue
;
n_cl
->
set_req
(
i
,
_old_new
[
in
->
_idx
]);
}
}
else
{
// process next input
_stack
.
set_index
(
idx
+
1
);
Node
*
m
=
n
->
in
(
idx
);
if
(
m
!=
NULL
&&
!
_clone_visited
.
test_set
(
m
->
_idx
))
{
clone_visit
(
m
);
// visit the input
}
}
}
}
public:
Invariance
(
Arena
*
area
,
IdealLoopTree
*
lpt
)
:
_lpt
(
lpt
),
_phase
(
lpt
->
_phase
),
_visited
(
area
),
_invariant
(
area
),
_stack
(
area
,
10
/* guess */
),
_clone_visited
(
area
),
_old_new
(
area
)
{}
// Map old to n for invariance computation and clone
void
map_ctrl
(
Node
*
old
,
Node
*
n
)
{
assert
(
old
->
is_CFG
()
&&
n
->
is_CFG
(),
"must be"
);
_old_new
.
map
(
old
->
_idx
,
n
);
// "clone" of old is n
_invariant
.
set
(
old
->
_idx
);
// old is invariant
_clone_visited
.
set
(
old
->
_idx
);
}
// Driver function to compute invariance
bool
is_invariant
(
Node
*
n
)
{
if
(
!
_visited
.
test_set
(
n
->
_idx
))
compute_invariance
(
n
);
return
(
_invariant
.
test
(
n
->
_idx
)
!=
0
);
}
// Driver function to clone invariant
Node
*
clone
(
Node
*
n
,
Node
*
ctrl
)
{
assert
(
ctrl
->
is_CFG
(),
"must be"
);
assert
(
_invariant
.
test
(
n
->
_idx
),
"must be an invariant"
);
if
(
!
_clone_visited
.
test
(
n
->
_idx
))
clone_nodes
(
n
,
ctrl
);
return
_old_new
[
n
->
_idx
];
}
};
//------------------------------is_range_check_if -----------------------------------
// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
// Note: this function is particularly designed for loop predication. We require load_range
// and offset to be loop invariant computed on the fly by "invar"
bool
IdealLoopTree
::
is_range_check_if
(
IfNode
*
iff
,
PhaseIdealLoop
*
phase
,
Invariance
&
invar
)
const
{
if
(
!
is_loop_exit
(
iff
))
{
return
false
;
}
if
(
!
iff
->
in
(
1
)
->
is_Bool
())
{
return
false
;
}
const
BoolNode
*
bol
=
iff
->
in
(
1
)
->
as_Bool
();
if
(
bol
->
_test
.
_test
!=
BoolTest
::
lt
)
{
return
false
;
}
if
(
!
bol
->
in
(
1
)
->
is_Cmp
())
{
return
false
;
}
const
CmpNode
*
cmp
=
bol
->
in
(
1
)
->
as_Cmp
();
if
(
cmp
->
Opcode
()
!=
Op_CmpU
)
{
return
false
;
}
Node
*
range
=
cmp
->
in
(
2
);
if
(
range
->
Opcode
()
!=
Op_LoadRange
)
{
const
TypeInt
*
tint
=
phase
->
_igvn
.
type
(
range
)
->
isa_int
();
if
(
!
OptimizeFill
||
tint
==
NULL
||
tint
->
empty
()
||
tint
->
_lo
<
0
)
{
// Allow predication on positive values that aren't LoadRanges.
// This allows optimization of loops where the length of the
// array is a known value and doesn't need to be loaded back
// from the array.
return
false
;
}
}
if
(
!
invar
.
is_invariant
(
range
))
{
return
false
;
}
Node
*
iv
=
_head
->
as_CountedLoop
()
->
phi
();
int
scale
=
0
;
Node
*
offset
=
NULL
;
if
(
!
phase
->
is_scaled_iv_plus_offset
(
cmp
->
in
(
1
),
iv
,
&
scale
,
&
offset
))
{
return
false
;
}
if
(
offset
&&
!
invar
.
is_invariant
(
offset
))
{
// offset must be invariant
return
false
;
}
return
true
;
}
//------------------------------rc_predicate-----------------------------------
// Create a range check predicate
//
// for (i = init; i < limit; i += stride) {
// a[scale*i+offset]
// }
//
// Compute max(scale*i + offset) for init <= i < limit and build the predicate
// as "max(scale*i + offset) u< a.length".
//
// There are two cases for max(scale*i + offset):
// (1) stride*scale > 0
// max(scale*i + offset) = scale*(limit-stride) + offset
// (2) stride*scale < 0
// max(scale*i + offset) = scale*init + offset
BoolNode
*
PhaseIdealLoop
::
rc_predicate
(
Node
*
ctrl
,
int
scale
,
Node
*
offset
,
Node
*
init
,
Node
*
limit
,
Node
*
stride
,
Node
*
range
,
bool
upper
)
{
DEBUG_ONLY
(
ttyLocker
ttyl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"rc_predicate "
);
Node
*
max_idx_expr
=
init
;
int
stride_con
=
stride
->
get_int
();
if
((
stride_con
>
0
)
==
(
scale
>
0
)
==
upper
)
{
max_idx_expr
=
new
(
C
,
3
)
SubINode
(
limit
,
stride
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"(limit - stride) "
);
}
else
{
if
(
TraceLoopPredicate
)
tty
->
print
(
"init "
);
}
if
(
scale
!=
1
)
{
ConNode
*
con_scale
=
_igvn
.
intcon
(
scale
);
max_idx_expr
=
new
(
C
,
3
)
MulINode
(
max_idx_expr
,
con_scale
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print
(
"* %d "
,
scale
);
}
if
(
offset
&&
(
!
offset
->
is_Con
()
||
offset
->
get_int
()
!=
0
)){
max_idx_expr
=
new
(
C
,
3
)
AddINode
(
max_idx_expr
,
offset
);
register_new_node
(
max_idx_expr
,
ctrl
);
if
(
TraceLoopPredicate
)
if
(
offset
->
is_Con
())
tty
->
print
(
"+ %d "
,
offset
->
get_int
());
else
tty
->
print
(
"+ offset "
);
}
CmpUNode
*
cmp
=
new
(
C
,
3
)
CmpUNode
(
max_idx_expr
,
range
);
register_new_node
(
cmp
,
ctrl
);
BoolNode
*
bol
=
new
(
C
,
2
)
BoolNode
(
cmp
,
BoolTest
::
lt
);
register_new_node
(
bol
,
ctrl
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"<u range"
);
return
bol
;
}
//------------------------------ loop_predication_impl--------------------------
// Insert loop predicates for null checks and range checks
bool
PhaseIdealLoop
::
loop_predication_impl
(
IdealLoopTree
*
loop
)
{
if
(
!
UseLoopPredicate
)
return
false
;
if
(
!
loop
->
_head
->
is_Loop
())
{
// Could be a simple region when irreducible loops are present.
return
false
;
}
if
(
loop
->
_head
->
unique_ctrl_out
()
->
Opcode
()
==
Op_NeverBranch
)
{
// do nothing for infinite loops
return
false
;
}
CountedLoopNode
*
cl
=
NULL
;
if
(
loop
->
_head
->
is_CountedLoop
())
{
cl
=
loop
->
_head
->
as_CountedLoop
();
// do nothing for iteration-splitted loops
if
(
!
cl
->
is_normal_loop
())
return
false
;
}
LoopNode
*
lpn
=
loop
->
_head
->
as_Loop
();
Node
*
entry
=
lpn
->
in
(
LoopNode
::
EntryControl
);
ProjNode
*
predicate_proj
=
find_predicate_insertion_point
(
entry
,
Deoptimization
::
Reason_predicate
);
if
(
!
predicate_proj
)
{
#ifndef PRODUCT
if
(
TraceLoopPredicate
)
{
tty
->
print
(
"missing predicate:"
);
loop
->
dump_head
();
lpn
->
dump
(
1
);
}
#endif
return
false
;
}
ConNode
*
zero
=
_igvn
.
intcon
(
0
);
set_ctrl
(
zero
,
C
->
root
());
ResourceArea
*
area
=
Thread
::
current
()
->
resource_area
();
Invariance
invar
(
area
,
loop
);
// Create list of if-projs such that a newer proj dominates all older
// projs in the list, and they all dominate loop->tail()
Node_List
if_proj_list
(
area
);
LoopNode
*
head
=
loop
->
_head
->
as_Loop
();
Node
*
current_proj
=
loop
->
tail
();
//start from tail
while
(
current_proj
!=
head
)
{
if
(
loop
==
get_loop
(
current_proj
)
&&
// still in the loop ?
current_proj
->
is_Proj
()
&&
// is a projection ?
current_proj
->
in
(
0
)
->
Opcode
()
==
Op_If
)
{
// is a if projection ?
if_proj_list
.
push
(
current_proj
);
}
current_proj
=
idom
(
current_proj
);
}
bool
hoisted
=
false
;
// true if at least one proj is promoted
while
(
if_proj_list
.
size
()
>
0
)
{
// Following are changed to nonnull when a predicate can be hoisted
ProjNode
*
new_predicate_proj
=
NULL
;
ProjNode
*
proj
=
if_proj_list
.
pop
()
->
as_Proj
();
IfNode
*
iff
=
proj
->
in
(
0
)
->
as_If
();
if
(
!
is_uncommon_trap_if_pattern
(
proj
,
Deoptimization
::
Reason_none
))
{
if
(
loop
->
is_loop_exit
(
iff
))
{
// stop processing the remaining projs in the list because the execution of them
// depends on the condition of "iff" (iff->in(1)).
break
;
}
else
{
// Both arms are inside the loop. There are two cases:
// (1) there is one backward branch. In this case, any remaining proj
// in the if_proj list post-dominates "iff". So, the condition of "iff"
// does not determine the execution the remining projs directly, and we
// can safely continue.
// (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj"
// does not dominate loop->tail(), so it can not be in the if_proj list.
continue
;
}
}
Node
*
test
=
iff
->
in
(
1
);
if
(
!
test
->
is_Bool
()){
//Conv2B, ...
continue
;
}
BoolNode
*
bol
=
test
->
as_Bool
();
if
(
invar
.
is_invariant
(
bol
))
{
// Invariant test
new_predicate_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
Node
*
ctrl
=
new_predicate_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
);
BoolNode
*
new_predicate_bol
=
invar
.
clone
(
bol
,
ctrl
)
->
as_Bool
();
// Negate test if necessary
bool
negated
=
false
;
if
(
proj
->
_con
!=
predicate_proj
->
_con
)
{
new_predicate_bol
=
new
(
C
,
2
)
BoolNode
(
new_predicate_bol
->
in
(
1
),
new_predicate_bol
->
_test
.
negate
());
register_new_node
(
new_predicate_bol
,
ctrl
);
negated
=
true
;
}
IfNode
*
new_predicate_iff
=
new_predicate_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
new_predicate_iff
);
new_predicate_iff
->
set_req
(
1
,
new_predicate_bol
);
#ifndef PRODUCT
if
(
TraceLoopPredicate
)
{
tty
->
print
(
"Predicate invariant if%s: %d "
,
negated
?
" negated"
:
""
,
new_predicate_iff
->
_idx
);
loop
->
dump_head
();
}
else
if
(
TraceLoopOpts
)
{
tty
->
print
(
"Predicate IC "
);
loop
->
dump_head
();
}
#endif
}
else
if
(
cl
!=
NULL
&&
loop
->
is_range_check_if
(
iff
,
this
,
invar
))
{
assert
(
proj
->
_con
==
predicate_proj
->
_con
,
"must match"
);
// Range check for counted loops
const
Node
*
cmp
=
bol
->
in
(
1
)
->
as_Cmp
();
Node
*
idx
=
cmp
->
in
(
1
);
assert
(
!
invar
.
is_invariant
(
idx
),
"index is variant"
);
assert
(
cmp
->
in
(
2
)
->
Opcode
()
==
Op_LoadRange
||
OptimizeFill
,
"must be"
);
Node
*
rng
=
cmp
->
in
(
2
);
assert
(
invar
.
is_invariant
(
rng
),
"range must be invariant"
);
int
scale
=
1
;
Node
*
offset
=
zero
;
bool
ok
=
is_scaled_iv_plus_offset
(
idx
,
cl
->
phi
(),
&
scale
,
&
offset
);
assert
(
ok
,
"must be index expression"
);
Node
*
init
=
cl
->
init_trip
();
Node
*
limit
=
cl
->
limit
();
Node
*
stride
=
cl
->
stride
();
// Build if's for the upper and lower bound tests. The
// lower_bound test will dominate the upper bound test and all
// cloned or created nodes will use the lower bound test as
// their declared control.
ProjNode
*
lower_bound_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
ProjNode
*
upper_bound_proj
=
create_new_if_for_predicate
(
predicate_proj
,
NULL
,
Deoptimization
::
Reason_predicate
);
assert
(
upper_bound_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
)
==
lower_bound_proj
,
"should dominate"
);
Node
*
ctrl
=
lower_bound_proj
->
in
(
0
)
->
as_If
()
->
in
(
0
);
// Perform cloning to keep Invariance state correct since the
// late schedule will place invariant things in the loop.
rng
=
invar
.
clone
(
rng
,
ctrl
);
if
(
offset
&&
offset
!=
zero
)
{
assert
(
invar
.
is_invariant
(
offset
),
"offset must be loop invariant"
);
offset
=
invar
.
clone
(
offset
,
ctrl
);
}
// Test the lower bound
Node
*
lower_bound_bol
=
rc_predicate
(
ctrl
,
scale
,
offset
,
init
,
limit
,
stride
,
rng
,
false
);
IfNode
*
lower_bound_iff
=
lower_bound_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
lower_bound_iff
);
lower_bound_iff
->
set_req
(
1
,
lower_bound_bol
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"lower bound check if: %d"
,
lower_bound_iff
->
_idx
);
// Test the upper bound
Node
*
upper_bound_bol
=
rc_predicate
(
ctrl
,
scale
,
offset
,
init
,
limit
,
stride
,
rng
,
true
);
IfNode
*
upper_bound_iff
=
upper_bound_proj
->
in
(
0
)
->
as_If
();
_igvn
.
hash_delete
(
upper_bound_iff
);
upper_bound_iff
->
set_req
(
1
,
upper_bound_bol
);
if
(
TraceLoopPredicate
)
tty
->
print_cr
(
"upper bound check if: %d"
,
lower_bound_iff
->
_idx
);
// Fall through into rest of the clean up code which will move
// any dependent nodes onto the upper bound test.
new_predicate_proj
=
upper_bound_proj
;
#ifndef PRODUCT
if
(
TraceLoopOpts
&&
!
TraceLoopPredicate
)
{
tty
->
print
(
"Predicate RC "
);
loop
->
dump_head
();
}
#endif
}
else
{
// Loop variant check (for example, range check in non-counted loop)
// with uncommon trap.
continue
;
}
assert
(
new_predicate_proj
!=
NULL
,
"sanity"
);
// Success - attach condition (new_predicate_bol) to predicate if
invar
.
map_ctrl
(
proj
,
new_predicate_proj
);
// so that invariance test can be appropriate
// Eliminate the old If in the loop body
dominated_by
(
new_predicate_proj
,
iff
,
proj
->
_con
!=
new_predicate_proj
->
_con
);
hoisted
=
true
;
C
->
set_major_progress
();
}
// end while
#ifndef PRODUCT
// report that the loop predication has been actually performed
// for this loop
if
(
TraceLoopPredicate
&&
hoisted
)
{
tty
->
print
(
"Loop Predication Performed:"
);
loop
->
dump_head
();
}
#endif
return
hoisted
;
}
//------------------------------loop_predication--------------------------------
// driver routine for loop predication optimization
bool
IdealLoopTree
::
loop_predication
(
PhaseIdealLoop
*
phase
)
{
bool
hoisted
=
false
;
// Recursively promote predicates
if
(
_child
)
{
hoisted
=
_child
->
loop_predication
(
phase
);
}
// self
if
(
!
_irreducible
&&
!
tail
()
->
is_top
())
{
hoisted
|=
phase
->
loop_predication_impl
(
this
);
}
if
(
_next
)
{
//sibling
hoisted
|=
_next
->
loop_predication
(
phase
);
}
return
hoisted
;
}
//=============================================================================
// Process all the loops in the loop tree and replace any fill
// patterns with an intrisc version.
bool
PhaseIdealLoop
::
do_intrinsify_fill
()
{
...
...
@@ -2762,6 +2249,13 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
return
false
;
}
#ifndef PRODUCT
if
(
TraceLoopOpts
)
{
tty
->
print
(
"ArrayFill "
);
lpt
->
dump_head
();
}
#endif
// Now replace the whole loop body by a call to a fill routine that
// covers the same region as the loop.
Node
*
base
=
store
->
in
(
MemNode
::
Address
)
->
as_AddP
()
->
in
(
AddPNode
::
Base
);
...
...
src/share/vm/opto/loopUnswitch.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -32,15 +32,17 @@
//
// orig: transformed:
// if (invariant-test) then
// predicate predicate
// loop loop
// stmt1 stmt1
// if (invariant-test) then stmt2
// stmt2 stmt4
// else endloop
// stmt3 else
// endif loop [clone]
// stmt4 stmt1 [clone]
// endloop stmt3
// endif predicate [clone]
// stmt4 loop [clone]
// endloop stmt1 [clone]
// stmt3
// stmt4 [clone]
// endloop
// endif
...
...
@@ -124,8 +126,15 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
ProjNode
*
proj_true
=
create_slow_version_of_loop
(
loop
,
old_new
);
assert
(
proj_true
->
is_IfTrue
()
&&
proj_true
->
unique_ctrl_out
()
==
head
,
"by construction"
);
#ifdef ASSERT
Node
*
uniqc
=
proj_true
->
unique_ctrl_out
();
Node
*
entry
=
head
->
in
(
LoopNode
::
EntryControl
);
Node
*
predicate
=
find_predicate
(
entry
);
if
(
predicate
!=
NULL
)
predicate
=
predicate
->
in
(
0
);
assert
(
proj_true
->
is_IfTrue
()
&&
(
predicate
==
NULL
&&
uniqc
==
head
||
predicate
!=
NULL
&&
uniqc
==
predicate
),
"by construction"
);
#endif
// Increment unswitch count
LoopNode
*
head_clone
=
old_new
[
head
->
_idx
]
->
as_Loop
();
int
nct
=
head
->
unswitch_count
()
+
1
;
...
...
@@ -227,21 +236,24 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop,
register_node
(
ifslow
,
outer_loop
,
iff
,
dom_depth
(
iff
));
// Clone the loop body. The clone becomes the fast loop. The
// original pre-header will (illegally) have 2 control users (old & new loops).
// original pre-header will (illegally) have 3 control users
// (old & new loops & new if).
clone_loop
(
loop
,
old_new
,
dom_depth
(
head
),
iff
);
assert
(
old_new
[
head
->
_idx
]
->
is_Loop
(),
""
);
// Fast (true) control
Node
*
iffast_pred
=
clone_loop_predicates
(
entry
,
iffast
);
_igvn
.
hash_delete
(
head
);
head
->
set_req
(
LoopNode
::
EntryControl
,
iffast
);
set_idom
(
head
,
iffast
,
dom_depth
(
head
));
head
->
set_req
(
LoopNode
::
EntryControl
,
iffast
_pred
);
set_idom
(
head
,
iffast
_pred
,
dom_depth
(
head
));
_igvn
.
_worklist
.
push
(
head
);
// Slow (false) control
Node
*
ifslow_pred
=
move_loop_predicates
(
entry
,
ifslow
);
LoopNode
*
slow_head
=
old_new
[
head
->
_idx
]
->
as_Loop
();
_igvn
.
hash_delete
(
slow_head
);
slow_head
->
set_req
(
LoopNode
::
EntryControl
,
ifslow
);
set_idom
(
slow_head
,
ifslow
,
dom_depth
(
slow_head
));
slow_head
->
set_req
(
LoopNode
::
EntryControl
,
ifslow
_pred
);
set_idom
(
slow_head
,
ifslow
_pred
,
dom_depth
(
slow_head
));
_igvn
.
_worklist
.
push
(
slow_head
);
recompute_dom_depth
();
...
...
src/share/vm/opto/loopnode.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -341,7 +341,12 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
//
assert
(
x
->
Opcode
()
==
Op_Loop
,
"regular loops only"
);
C
->
print_method
(
"Before CountedLoop"
,
3
);
#ifndef PRODUCT
if
(
TraceLoopOpts
)
{
tty
->
print
(
"Counted "
);
loop
->
dump_head
();
}
#endif
// If compare points to incr, we are ok. Otherwise the compare
// can directly point to the phi; in this case adjust the compare so that
// it points to the incr by adjusting the limit.
...
...
@@ -864,8 +869,10 @@ void IdealLoopTree::split_outer_loop( PhaseIdealLoop *phase ) {
Node
*
outer
=
new
(
phase
->
C
,
3
)
LoopNode
(
ctl
,
_head
->
in
(
outer_idx
)
);
outer
=
igvn
.
register_new_node_with_optimizer
(
outer
,
_head
);
phase
->
set_created_loop_node
();
Node
*
pred
=
phase
->
clone_loop_predicates
(
ctl
,
outer
);
// Outermost loop falls into '_head' loop
_head
->
set_req
(
LoopNode
::
EntryControl
,
outer
);
_head
->
set_req
(
LoopNode
::
EntryControl
,
pred
);
_head
->
del_req
(
outer_idx
);
// Split all the Phis up between '_head' loop and 'outer' loop.
for
(
DUIterator_Fast
jmax
,
j
=
_head
->
fast_outs
(
jmax
);
j
<
jmax
;
j
++
)
{
...
...
@@ -1103,12 +1110,13 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
// backedges into a private merge point and use the merge point as
// the one true backedge.
if
(
_head
->
req
()
>
3
)
{
// Merge the many backedges into a single backedge.
// Merge the many backedges into a single backedge but leave
// the hottest backedge as separate edge for the following peel.
merge_many_backedges
(
phase
);
result
=
true
;
}
// If I
am a shared header (multiple backedges)
, peel off myself loop.
// If I
have one hot backedge
, peel off myself loop.
// I better be the outermost loop.
if
(
_head
->
req
()
>
3
)
{
split_outer_loop
(
phase
);
...
...
@@ -1433,9 +1441,9 @@ void IdealLoopTree::dump_head( ) const {
tty
->
print
(
"Loop: N%d/N%d "
,
_head
->
_idx
,
_tail
->
_idx
);
if
(
_irreducible
)
tty
->
print
(
" IRREDUCIBLE"
);
if
(
UseLoopPredicate
)
{
Node
*
entry
=
_head
->
in
(
LoopNode
::
EntryControl
);
if
(
entry
!=
NULL
&&
entry
->
is_Proj
()
&&
PhaseIdealLoop
::
is_uncommon_trap_if_pattern
(
entry
->
as_Proj
(),
Deoptimization
::
Reason_predicate
)
)
{
Node
*
entry
=
PhaseIdealLoop
::
find_predicate_insertion_point
(
_head
->
in
(
LoopNode
::
EntryControl
),
Deoptimization
::
Reason_predicate
);
if
(
entry
!=
NULL
)
{
tty
->
print
(
" predicated"
);
}
}
...
...
@@ -1541,7 +1549,7 @@ void PhaseIdealLoop::eliminate_useless_predicates() {
//----------------------------build_and_optimize-------------------------------
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
void
PhaseIdealLoop
::
build_and_optimize
(
bool
do_split_ifs
,
bool
do_loop_pred
)
{
void
PhaseIdealLoop
::
build_and_optimize
(
bool
do_split_ifs
)
{
ResourceMark
rm
;
int
old_progress
=
C
->
major_progress
();
...
...
@@ -1573,6 +1581,13 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
// Do not need a safepoint at the top level
_ltree_root
->
_has_sfpt
=
1
;
// Initialize Dominators.
// Checked in clone_loop_predicate() during beautify_loops().
_idom_size
=
0
;
_idom
=
NULL
;
_dom_depth
=
NULL
;
_dom_stk
=
NULL
;
// Empty pre-order array
allocate_preorders
();
...
...
@@ -1698,8 +1713,9 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
return
;
}
// some parser-inserted loop predicates could never be used by loop
// predication. Eliminate them before loop optimization
// Some parser-inserted loop predicates could never be used by loop
// predication or they were moved away from loop during some optimizations.
// For example, peeling. Eliminate them before next loop optimizations.
if
(
UseLoopPredicate
)
{
eliminate_useless_predicates
();
}
...
...
@@ -1750,7 +1766,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
}
// Perform loop predication before iteration splitting
if
(
do_loop_pred
&&
C
->
has_loops
()
&&
!
C
->
major_progress
(
))
{
if
(
C
->
has_loops
()
&&
!
C
->
major_progress
()
&&
(
C
->
predicate_count
()
>
0
))
{
_ltree_root
->
_child
->
loop_predication
(
this
);
}
...
...
@@ -1793,8 +1809,20 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
C
->
set_major_progress
();
}
// Convert scalar to superword operations
// Keep loop predicates and perform optimizations with them
// until no more loop optimizations could be done.
// After that switch predicates off and do more loop optimizations.
if
(
!
C
->
major_progress
()
&&
(
C
->
predicate_count
()
>
0
))
{
C
->
cleanup_loop_predicates
(
_igvn
);
#ifndef PRODUCT
if
(
TraceLoopOpts
)
{
tty
->
print_cr
(
"PredicatesOff"
);
}
#endif
C
->
set_major_progress
();
}
// Convert scalar to superword operations at the end of all loop opts.
if
(
UseSuperWord
&&
C
->
has_loops
()
&&
!
C
->
major_progress
())
{
// SuperWord transform
SuperWord
sw
(
this
);
...
...
src/share/vm/opto/loopnode.hpp
浏览文件 @
ac8ab5ce
...
...
@@ -706,11 +706,11 @@ private:
_dom_lca_tags
(
arena
()),
// Thread::resource_area
_verify_me
(
NULL
),
_verify_only
(
true
)
{
build_and_optimize
(
false
,
false
);
build_and_optimize
(
false
);
}
// build the loop tree and perform any requested optimizations
void
build_and_optimize
(
bool
do_split_if
,
bool
do_loop_pred
);
void
build_and_optimize
(
bool
do_split_if
);
public:
// Dominators for the sea of nodes
...
...
@@ -721,13 +721,13 @@ public:
Node
*
dom_lca_internal
(
Node
*
n1
,
Node
*
n2
)
const
;
// Compute the Ideal Node to Loop mapping
PhaseIdealLoop
(
PhaseIterGVN
&
igvn
,
bool
do_split_ifs
,
bool
do_loop_pred
)
:
PhaseIdealLoop
(
PhaseIterGVN
&
igvn
,
bool
do_split_ifs
)
:
PhaseTransform
(
Ideal_Loop
),
_igvn
(
igvn
),
_dom_lca_tags
(
arena
()),
// Thread::resource_area
_verify_me
(
NULL
),
_verify_only
(
false
)
{
build_and_optimize
(
do_split_ifs
,
do_loop_pred
);
build_and_optimize
(
do_split_ifs
);
}
// Verify that verify_me made the same decisions as a fresh run.
...
...
@@ -737,7 +737,7 @@ public:
_dom_lca_tags
(
arena
()),
// Thread::resource_area
_verify_me
(
verify_me
),
_verify_only
(
false
)
{
build_and_optimize
(
false
,
false
);
build_and_optimize
(
false
);
}
// Build and verify the loop tree without modifying the graph. This
...
...
@@ -830,7 +830,26 @@ public:
Deoptimization
::
DeoptReason
reason
);
void
register_control
(
Node
*
n
,
IdealLoopTree
*
loop
,
Node
*
pred
);
// Find a good location to insert a predicate
// Clone loop predicates to cloned loops (peeled, unswitched)
static
ProjNode
*
clone_predicate
(
ProjNode
*
predicate_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
);
static
ProjNode
*
move_predicate
(
ProjNode
*
predicate_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
);
static
Node
*
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
,
bool
move_predicates
,
PhaseIdealLoop
*
loop_phase
,
PhaseIterGVN
*
igvn
);
Node
*
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
);
Node
*
move_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
);
void
eliminate_loop_predicates
(
Node
*
entry
);
static
Node
*
skip_loop_predicates
(
Node
*
entry
);
// Find a good location to insert a predicate
static
ProjNode
*
find_predicate_insertion_point
(
Node
*
start_c
,
Deoptimization
::
DeoptReason
reason
);
// Find a predicate
static
Node
*
find_predicate
(
Node
*
entry
);
...
...
src/share/vm/opto/loopopts.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -2139,9 +2139,12 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
// orig
//
// stmt1
// |
// v
// stmt1
// |
// v
// loop predicate
// |
// v
// loop<----+
// | |
// stmt2 |
...
...
@@ -2172,6 +2175,9 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after clone loop
//
// stmt1
// |
// v
// loop predicate
// / \
// clone / \ orig
// / \
...
...
@@ -2210,12 +2216,15 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after partial peel
//
// stmt1
// |
// v
// loop predicate
// /
// clone / orig
// / TOP
// / \
// v v
// TOP->
region region
----+
// TOP->
loop loop
----+
// | | |
// stmt2 stmt2 |
// | | |
...
...
@@ -2253,13 +2262,17 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// stmt1
// |
// v
// stmt2 clone
// |
// v
// ........> ifA clone
// : / |
// dom / |
// : v v
// : false true
// : | |
// : | stmt2 clone
// : | v
// : | loop predicate
// : | |
// : | v
// : | newloop<-----+
...
...
@@ -2289,6 +2302,7 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
bool
PhaseIdealLoop
::
partial_peel
(
IdealLoopTree
*
loop
,
Node_List
&
old_new
)
{
assert
(
!
loop
->
_head
->
is_CountedLoop
(),
"Non-counted loop only"
);
if
(
!
loop
->
_head
->
is_Loop
())
{
return
false
;
}
...
...
@@ -2316,6 +2330,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
}
}
Node
*
entry
=
head
->
in
(
LoopNode
::
EntryControl
);
int
dd
=
dom_depth
(
head
);
// Step 1: find cut point
...
...
@@ -2612,6 +2627,8 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
// Backedge of the surviving new_head (the clone) is original last_peel
_igvn
.
hash_delete
(
new_head_clone
);
Node
*
new_entry
=
move_loop_predicates
(
entry
,
new_head_clone
->
in
(
LoopNode
::
EntryControl
));
new_head_clone
->
set_req
(
LoopNode
::
EntryControl
,
new_entry
);
new_head_clone
->
set_req
(
LoopNode
::
LoopBackControl
,
last_peel
);
_igvn
.
_worklist
.
push
(
new_head_clone
);
...
...
src/share/vm/opto/phaseX.hpp
浏览文件 @
ac8ab5ce
...
...
@@ -471,6 +471,13 @@ public:
_delay_transform
=
delay
;
}
// Clone loop predicates. Defined in loopTransform.cpp.
Node
*
clone_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
);
Node
*
move_loop_predicates
(
Node
*
old_entry
,
Node
*
new_entry
);
// Create a new if below new_entry for the predicate to be cloned
ProjNode
*
create_new_if_for_predicate
(
ProjNode
*
cont_proj
,
Node
*
new_entry
,
Deoptimization
::
DeoptReason
reason
);
#ifndef PRODUCT
protected:
// Sub-quadratic implementation of VerifyIterativeGVN.
...
...
src/share/vm/opto/split_if.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -399,6 +399,9 @@ void PhaseIdealLoop::do_split_if( Node *iff ) {
#ifndef PRODUCT
if
(
PrintOpto
&&
VerifyLoopOptimizations
)
tty
->
print_cr
(
"Split-if"
);
if
(
TraceLoopOpts
)
{
tty
->
print_cr
(
"SplitIf"
);
}
#endif
C
->
set_major_progress
();
Node
*
region
=
iff
->
in
(
0
);
...
...
src/share/vm/opto/superword.cpp
浏览文件 @
ac8ab5ce
...
...
@@ -1132,6 +1132,13 @@ void SuperWord::co_locate_pack(Node_List* pk) {
void
SuperWord
::
output
()
{
if
(
_packset
.
length
()
==
0
)
return
;
#ifndef PRODUCT
if
(
TraceLoopOpts
)
{
tty
->
print
(
"SuperWord "
);
lpt
()
->
dump_head
();
}
#endif
// MUST ENSURE main loop's initial value is properly aligned:
// (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
...
...
src/share/vm/opto/vectornode.hpp
浏览文件 @
ac8ab5ce
...
...
@@ -32,6 +32,7 @@
//------------------------------VectorNode--------------------------------------
// Vector Operation
class
VectorNode
:
public
Node
{
virtual
uint
size_of
()
const
{
return
sizeof
(
*
this
);
}
protected:
uint
_length
;
// vector length
virtual
BasicType
elt_basic_type
()
const
=
0
;
// Vector element basic type
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录