Académique Documents
Professionnel Documents
Culture Documents
A THESIS
Submitted by
AKHILA C M
In partial fulfilment for the award of the degree of
MASTER OF TECHNOLOGY
IN
COMPUTER SCIENCE AND ENGINEERING
Under the guidance of
Dr. SALEENA N
ACKNOWLEDGEMENTS
First and foremost, I thank God Almighty for allowing me to complete the
project successfully, and for all the blessings he showered on me during the course
of the project.
introducing me to the topic and for the motivation and support she has given me
allowing me to use all the facilities of the Department, which I required for this
project.
I would like to thank the members of my evaluation panel, Dr. Vineeth Pa-
leri, Ms. Nadia T T, Ms. Sreeja M, and Mr. Aswin Jacob for the thoughts and
advices given to me, that helped me improve the outcome of the project.
Last but not the least I would also like to thank all, especially my family
and my friends, without whose support, moral and intellectual, this work would
Akhila C M
DECLARATION
“I hereby declare that this submission is my own work and that, to the best of my
knowledge and belief, it contains no material previously published or written by
another person nor material which has been accepted for the award of any other
degree or diploma of the university or other institute of higher learning, except
where due acknowledgment has been made in the text”.
Place: Signature :
Date: Name :
Reg.No:
CERTIFICATE
Place:
Date:
Office Seal
Contents
Chapter
1 Problem Definition 1
2 Introduction 2
3 Literature Survey 8
5 Implementation 14
5.1 LLVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5.4 Confluence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6 Results 23
7 Conclusions 25
Bibliography 26
vi
Abstract
in a program. This project aims to detect the equivalent expressions in the SSA
form of a program using global value numbering. For this, we extend the Simple
Algorithm for Global Value Numbering[Saleena and Paleri, 2014 ] to SSA form.
We make use of the φ-functions present at the join points to compute the confluence
We measured the number of redundancies detected by the algorithm for the SPEC
CPU2006 benchmark programs and compared it with the number of lexical redun-
Table
Figure
Problem Definition
Static Single Assignment(SSA) form and implement the algorithm using LLVM.
program has only one definition. SSA makes data flow analysis and optimizations
more simpler and effective[6]. So, most of the compilers are representing the in-
to GVN algorithm by Saleena and Paleri[7], it will miss some of the redundancies.
Hence, we aim to extend the algorithm to SSA form so that it could detect those
missing redundancies.
Chapter 2
Introduction
determine that both the expressions will have the same value during execution”[7].
If we can identify that two expressions are equivalent in a program, then we can
replace the second expression by the value of the first expression. GVN can be
used to eliminate the redundant code, even the ones which cannot be eliminated
The value numbering for a block, which is also known as Local Value Num-
bering is done by assigning a value number to every expressions in the basic block
and this number will be same for the expressions that are equivalent. Global Value
Numbering is the idea of extending this concept to the whole program. In GVN
are value numbers[7]. For each expression of the form x op y, we can obtain a
expression pool. Each class in the expression pool contains the expressions that
3
are equivalent. By this method, we have a compact representation of a set of ex-
EIN : φ
x=1
(1)
y=2
EIN :{[v1 , x, 1], [v2 , y, 2]} EIN :{[v1 , x, 1], [v2 , y, 2]}
x=3
(2) (3) z = x+y
z = x+y
EOUT :{[v1 , 1], [v2 , y, 2], EOUT :{[v1 , x, 1], [v2 , y, 2],
[v3 , x, 3], [v4 , z, v3 + v2 ]} [v5 , z, v1 + v2 ]}
Figure 2.1: Expression pool computed by GVN algorithm for non-SSA code
“The points at which multiple control flow paths join are called confluence
points”[7]. At the confluence points in the program, suppose the value expression
from the left branch is vi1 + vi2 and that from the right branch is vj1 + vj2 . Then
checked whether there is any common element corresponding to vi1 and vj1 , and
vi2 and vj2 . If there are common elements, then a new value expression will be
4
generated representing the common expression reaching the confluence point.
Figure 2.1 shows the expression pool computed by the GVN algorithm at
input and output point of each basic block in a sample non-SSA code. The expres-
sion x+y at node (4) can be identified as redundant. This is because, the value
node.
each variable has only one definition in the program text”[6]. In other words, ev-
ery definition of a variable dominates its use. “In translating to SSA form, the
branch. If the variables xi and xj are reaching at the join point from two different
Figure 2.2 shows the control flow graph(CFG) of a sample non-SSA code.
The corresponding SSA code is shown in Figure 2.3. In the non-SSA code, we can
observe that there are more than one definitions for the variables x and z. While
converting the code into SSA form, when the first definition of x is seen, we replace
it by the variable x1 and we replace all uses of x by x1 until the next definition of
for z. At the join point of node (2) and node (3) in Figure 2.3, definition of the
x=1
(1)
y=2
x=3
(2) (3) z = x+y
z = x+y
(4) p = x+y
x1 = 1
(1)
y1 = 2
x2 = 3
(2) (3) z2 = x1 + y1
z1 = x2 + y1
x3 = φ(x2 , x1 )
z3 = φ(z1 , z2 )
(4) p1 = x3 + y1
If SSA code is given as input to the GVN algorithm by Saleena and Paleri[7],
it fails to detect some of the redundancies that were detected by the algorithm when
non-SSA code is given as input. This is because, the algorithm does not deal with
EIN : φ
x1 = 1
(1)
y1 = 2
EIN :{[v1 , x1 , 1], [v2 , y1 , 2]} EIN :{[v1 , x1 , 1], [v2 , y1 , 2]}
x2 = 3
(2) (3) z2 = x1 + y1
z1 = x2 + y1
EOUT :{[v1 , x1 , 1], [v2 , y1 , 2], EOUT :{[v1 , x1 , 1], [v2 , y1 , 2],
[v3 , x2 , 3], [v4 , z1 , v3 + v2 ]} [v5 , z2 , v1 + v2 ]}
x3 = φ(x2 , x1 )
z3 = φ(z1 , z2 )
(4) p 1 = x3 + y 1
Figure 2.4: Expression pool computed by GVN algorithm for SSA code
Figure 2.4 shows the expression pool computed by the GVN algorithm at
7
input and output point of each basic block in the SSA form of the code given
this redundancy is not detected by the GVN algorithm. In Figure 2.1, we have
seen that the expression x+y in node (4) can be identified as redundant by the
GVN algorithm when non-SSA code is given as input. But, when SSA code is
given as input, GVN algorithm fails to detect the redundancy of the corresponding
expression in node (4). This project aims to extend the GVN algorithm by Saleena
and Paleri[7] to work with SSA form, so that it could detect all the redundancies
in SSA code that are detected by the GVN algorithm when the corresponding
non-SSA code is given as input. For this, we make use of the φ-functions present
Literature Survey
and Aho[5]. Data flow analysis refers to a body of techniques that derive infor-
mation about the flow of data along program execution paths. Foundations of
data flow analysis and the iterative solution to general data flow framework are
explained in [5].
Global Value Numbering is given by Saleena and Paleri[7]. The basic idea of the
The details about SSA and the concept of φ-functions are clearly explained
in [4]. The SSA conversion algorithms are given by Muchnick[6] and Appel[4].
Appel use the concept of dominance frontiers to calculate the minimum set of φ
functions. “The dominance frontier of a node x is the set of all nodes w such that x
graph that represents the symbolic execution of the program. “This approach is
miss some of the redundancies, when SSA code is given as input. Hence, we have
modified the algorithm to work with SSA code. The algorithm is modified in the
points in a program.
of the algorithm.
Algorithm 2: Computing Ci u Cj
*/
Ck = Ci ∩ Cj ;
add var1 to Ck ;
end
end
/* let vi1 + vi2 and vj1 + vj2 be the value expressions in Ci and
Cj respectively */
end
end
end
return Ck ;
12
Algorithm 2 is the modified algorithm for computing Ci u Cj . This algorithm
will compute the expressions that are equivalent in both Ci and Cj with the help
tion about the φ-functions at a confluence point are available while computing the
xr . Otherwise, it will return NULL. This modified algorithm for computing Ci uCj
has an additional step apart from the steps in the GVN algorithm for computing
Ci u Cj [7]. That is, apart from adding the common expressions in Ci and Cj to
x3 = φ(x1 , x2 )
y3 = φ(y1 , y2 )
In Figure 4.1, the expression pool from left is E1 and that from right is E2 .
and a value number v7 is assigned to it. The resulting class is then added to the
since C1 u C4 and C2 u C5 are not NULL and the value numbers of their result-
ing classes are v7 and v8 respectively, we add v7 + v8 to another class with a new
value number v9 (Cn is a class with value number vn ). Then, C9 is also added to E3 .
Chapter 5
Implementation
only the integer arithmetic instructions are considered. The IR code in SSA form
is given as the input to the program and it will compute the expression pool at the
input and output point of each instruction. The number of redundancies in each
5.1 LLVM
SSA form, mem2reg pass is used. This pass promotes memory references to regis-
ter references. This is just the standard SSA construction algorithm to construct
pruned SSA form[2]. Using the command line option –time-passes, we can get the
For each instruction, two instances of this map, namely EIN and EOUT
is created to store the expression pool at input and output point of an in-
x1 → v1
5 → v1
y1 → v2
b → v2
v1 + v2 → v3
In this example, since y1 and b have same value number, they can be
• map<Instruction*, ExPool>
this map is created. First one is used to map each instruction pointer to
the corresponding EIN. This map will contain expression pool at the in-
put point of each instruction. Second one is used to map each instruction
At the input and output point of each basic block, a map which maps
point of a basic block. This map is created for the convenience in comput-
ing confluence. The expression pool {[v1 , x1 , 5], [v2 , y1 , b], [v3 , v1 + v2 ]} will
v1 → {x1 , 5}
v2 → {y1 , b}
v3 → {v1 + v2 }
• map<BasicBlock*, BB ExPool>
This will map a basic block pointer to the expression pool of a basic block.
Two instances of this map is created. One is for storing the expression pool
at the input pool of each basic block. Other is for storing the expression
pool at the output point of each basic block. These two instances together
It is a data structure that is used for storing the information about the φ-
first iteration of the program, this map is created to store the φ-functions
at each basic block. Suppose there are two φ-functions, say x3 = φ(x1 , x2 )
PHIMAP as
17
x1 → x3
x2 → x3
y1 → y3
y2 → y3
• map<BasicBlock*, PHIMAP>
This will map a basic block pointer to the PHIMAP of the basic block.
This map will contain the details about φ-functions in each basic block. It
Using the above said data structures, the Transfer Function of the modified
y, where op is an arithmetic operator is seen. Then the Transfer Function will take
EIN as input and returns EOUT. EIN and EOUT are string to string maps which
maps expression to its corresponding value number. EIN represents the expression
First of all, Transfer Function will initialize EOUT with EIN and check if x
is already present in EOUT using the inbuilt function find(x). If x is not present,
x will be inserted to EOUT with a new value number. This new value number
will be the same as the value number of x in the previous iteration. If it is the first
iteration, then a new value number is given. Similarly for y. The expression pool
invoked. It will return the value expression of x op y as a string. Then, it will check
18
whether the value expression of x op y is present in EOUT. If it is present, z will
be inserted into EOUT with same value number as that of the value expression of
with a new value number. This value number is also assigned in the same manner
as that of x. z is also inserted to EOUT with the same value number. Finally,
At every function call, the expression pool is set to NULL. For any instruc-
tion other than arithmetic expression and Call instruction, Transfer Function will
return EIN itself as EOUT 1 . After calling the Transfer Function, the instruction
pointer is mapped to EIN in one map and is mapped to EOUT in another map. In
LLVM, some optimizations are done when IR is converted into SSA code. Hence,
representation of variables in SSA code are in such a way that we cannot identify
Example
• EIN :φ
EOUT : { 2 → v1 , 1 → v2 , add → v3 , v1 + v2 → v3 }
• EIN : { 2 → v1 , 1 → v2 , add → v3 , v1 + v2 → v3 }
1
In the converted SSA code, we have observed that there are no load and store instructions.
19
• EIN : { 2 → v1 , 1 → v2 , add → v3 , v1 +v2 → v3 , v3 ∗v3 → v4 , mul → v4 }
add1 → v3 }
add1 → v3 }
add1 → v3 , mul2 → v4 }
5.4 Confluence
Confluence point is the program point at which two or more control flow
paths join. i.e, if there are more than one predecessor to a basic block, then
the input point of the basic block is a confluence point. In order to compute
the EIN at the confluence point, the Confluence() function is called with out-
put expression pools from its predecessors as argument. The expression pools are
two arguments. If there are more than two predecessors, then the output of the
fluence() function with the output expression pool of the third predecessor and so
on. i.e, If there are n predecessors for a basic block, then the Confluence() function
is called n − 1 times.
the basic block with more than one predecessors. So, the information about φ-
functions of a basic block are stored in the data structure PHIMAP. In the first
20
iteration of the program, for each basic block, the basic block pointer and its cor-
responding PHIMAP is stored in a map. From the second iteration onwards, the
stored information is used for computing EIN. The φ-functions of a basic block
are present at the beginning of the basic block. When a P HI instruction of the
pools that are passed as the arguments to the function is done. The expression
pools are stored in the data structure BB ExPool. For each pair of classes in the
the two classes is given as input to the function and it will return the value num-
ber of the resultant class. If the resultant class is empty, it will return NULL.
Intersect() function will initially check whether it is already invoked for the same
pair of value numbers. If it is, then the value number of the resultant class is re-
turned. Otherwise, it will take the sets corresponding to the value numbers in its
input from BB ExPool. Then, it takes the intersection of these two sets and insert
the result of intersection into a new set, say S. After that, each pair of distinct
expressions in the sets are taken and PhiMap() function is called. Suppose one of
the sets contains xp and other contains xq . When PhiMap(xp ) and PhiMap(xq )
in the basic block. So, if the variable returned by PhiMap(xp ) and PhiMap(xq )
are same, then it is added to the set S. In this case, xr is added to S. Then, it
checks for the value expression of the form vi op vj in the sets. If both the sets
contain such value expression, it checks if operator of both the value expressions
are same. If they are same, then Intersect() function is called recursively. Suppose
21
v1 op v2 is present in one set and v3 op v4 in the other, then Intersect(v1 , v3 ) and
added to the set S. And if any of them returns NULL, it means that no expression
is common in the two sets. So, nothing will be added to S. After that, a value
number will be assigned to the set S. If the value numbers passed as arguments
to Intersect() function are same, then the same value number will be assigned to
the newly created set S. If the value numbers are different and if it is not the first
iteration, it will check if any of the elements in the set were present in the input
expression pool of the basic block in previous iteration. If it is present, the same
value number will be assigned to the set S. Otherwise, a new value number will be
assigned. Finally, the set S along with its value number is inserted into the input
v1 → {x1 , 5} v4 → {x2 , p}
E1 : v2 → {y1 , b} E2 : v5 → {y2 , q}
v3 → {v1 + v2 } v6 → {v4 + v5 }
x3 = φ(x1 , x2 )
y3 = φ(y1 , y2 )
v7 → {x3 }
E3 : v8 → {y3 }
v9 → {v7 + v8 }
output expression pool of the previous iteration. i.e, when EOUT of two consec-
utive iterations are same, the iteration is terminated. So, it takes a minimum of
22
two iterations for the pass to terminate. Computation of confluence in Figure 4.1
Results
The extended GVN algorithm for SSA form is implemented in LLVM. SPEC
CPU2006[1] benchmarks are executed and the number of redundancies are com-
puted. Since the benchmarks are in non-SSA form, they are converted into SSA
form by running the mem2reg pass and are given as the input to our GVN pass.
When the test cases are executed, it is observed that most of the straight line
programs terminate after two iterations and those with loops terminate after three
iterations.
have written a pass that uses a lexical based algorithm to compute the number
SSA version of GVN algorithm and the number of lexical redundancies is shown
in table 6.1. The GVN algorithm will compute value based equivalence apart from
lexical equivalence. So, GVN algorithm will detect more number of redundancies
The mem2reg pass does many optimizations like constant propagation and
SPECint 2006 GVN Lexical 24
astar 22 22
bzip2 44 38
gcc 69 64
gromacs 260 215
h264ref 1287 971
hmmer 360 348
lbm 794 340
mcf 35 29
povray 191 169
sjeng 139 139
soplex 13 10
sphinx 27 25
copy propagation, while converting the IR into SSA form. So, many of the expres-
sions in the IR becomes lexically equivalent. That is the reason why two folders in
Table 6.1 are detecting same number of redundancies. For all other folders in Ta-
ble 6.1, GVN algorithm is detecting more number of redundancies than the lexical
redundancies.
Chapter 7
Conclusions
The GVN algorithm is modified for SSA code. We make use of the φ-function
at the join points to compute the confluence operations. The modified algorithm
executed and the number of redundancies are measured. The result obtained is
then compared with the number of lexical redundancies for the same input pro-
grams. It is observed that the SSA version of the GVN algorithm is detecting more
[3] Bowen Alpern, Mark N Wegman, and F Kenneth Zadeck. Detecting equality
of variables in programs. In Proceedings of the 15th ACM SIGPLAN-
SIGACT symposium on Principles of programming languages, pages
1–11. ACM, 1988.
[4] Andrew W Appel and P Jens. Modern compiler implementation in java, 2002.
[5] Monica Lam, Ravi Sethi, JD Ullman, and AV Aho. Compilers: Principles,
techniques and tools, 2006.
[7] Nabizath Saleena and Vineeth Paleri. Global value numbering for redundancy
detection: a simple and efficient algorithm. In Proceedings of the 29th
Annual ACM Symposium on Applied Computing, pages 1609–1611.
ACM, 2014.