Java Reference
In-Depth Information
Of course, a redundant Phi function will not be changed. If the
w
is never modified in the
loop body, the Phi function instruction takes the form
w
2
= [
w
1
w
2
]
and can be removed as it is apparent that
w
has not been changed.
Phi functions are tightly bound to state vectors. When a block is processed:
If the block has just a single predecessor, then it may inherit the state vector of that
predecessor; the states are simply copied.
If the block has more than one predecessor, then those states in the vectors that differ
must be merged using Phi functions.
For loop headers we conservatively create Phi functions for all variables, and then
later remove redundant Phi functions.
In block B2 in the code for
Factorial
(Figure 6.7),
I3
and
I4
identify the instructions
I3:[I0I8]
I4:[I2I9]
These are Phi function instructions capturing the local variable
n
and
result
respectively.
I3
is a Phi function with operands
I0
and
I8
;
I4
is a Phi function with operands
I2
and
I9
.
Control-Flow Graph Construction
The best place to look at the translation process is the constructor
NEmitter()
in class
NEmitter
. For each method, the control-flow graph of HIR is constructed in several steps:
1. The
NControlFlowGraph
constructor is invoked on the method. This produces the
control-flow graph
cfg
. In this first step, the JVM code is translated to sequences of
tuples:
(a) Objects of type
NBasicBlock
represent the basic blocks in the control-flow graph.
The control flow is captured by the links
successors
in each block. There are
also the links
predecessors
for analysis.
(b) The JVM code is first translated to a list of tuples, corresponding to the JVM
instructions. Each block stores its sequence of tuples in an
ArrayList
,
tuples
.
For example, the blocks of tuples for our
Factorial
example,
computeIter()
are as follows:
B0
B1
0:iconst_1
1:istore_1
B2
2:iload_0
3:iconst_0
4:if_icmple 0 13
B3
7:iload_1
8:iload_0
9:iinc 0 255
12:imul
Search WWH ::
Custom Search