Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
peephole
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Taddeüs Kroes
peephole
Commits
405dc7a5
Commit
405dc7a5
authored
Dec 29, 2011
by
Richard Torenvliet
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:taddeus/peephole
parents
41528750
58c6acb7
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
405 additions
and
8505 deletions
+405
-8505
benchmarks/optimized/clinpack.s
benchmarks/optimized/clinpack.s
+0
-3740
benchmarks/optimized/slalom.s
benchmarks/optimized/slalom.s
+0
-4630
report/report.tex
report/report.tex
+34
-10
src/dataflow.py
src/dataflow.py
+80
-35
src/optimize/__init__.py
src/optimize/__init__.py
+4
-3
src/optimize/advanced.py
src/optimize/advanced.py
+118
-57
src/statement.py
src/statement.py
+91
-11
tests/test_dataflow.py
tests/test_dataflow.py
+49
-9
tests/test_optimize_advanced.py
tests/test_optimize_advanced.py
+27
-8
tests/test_statement.py
tests/test_statement.py
+2
-2
No files found.
benchmarks/optimized/clinpack.s
deleted
100644 → 0
View file @
41528750
This diff is collapsed.
Click to expand it.
benchmarks/optimized/slalom.s
deleted
100644 → 0
View file @
41528750
This diff is collapsed.
Click to expand it.
report/report.tex
View file @
405dc7a5
...
@@ -120,13 +120,27 @@ We now add the instruction above the first use, and write the result in a new
...
@@ -120,13 +120,27 @@ We now add the instruction above the first use, and write the result in a new
variable. Then all occurrences of this expression can be replaced by a move of
variable. Then all occurrences of this expression can be replaced by a move of
from new variable into the original destination variable of the instruction.
from new variable into the original destination variable of the instruction.
This is a less efficient method then the
dag
, but because the basic blocks are
This is a less efficient method then the
DAG
, but because the basic blocks are
in general not very large and the execution time of the optimizer is not a
in general not very large and the execution time of the optimizer is not a
primary concern, this is not a big problem.
primary concern, this is not a big problem.
\subsubsection
*
{
Fold constants
}
\subsubsection
*
{
Constant folding
}
Another optimization is to do constant folding. Constant folding is replacing
a expensive step like addition with a more simple step like loading a constant.
Of course, this is not always possible. It is possible in cases where you apply
an operation on two constants, or a constant and a variable of which you know
for sure that it always has a certain value at that point. For example:
\begin
{
verbatim
}
li
$
regA, 1 li
$
regA,
1
addu
$
regB,
$
regA,
2
-
> li
$
regB, 3
\end{verbatim}
Of course, if
\texttt
{
\$
regA
}
is not used after this, it can be removed, which
will be done by the dead code elimination.
One problem we encountered with this is that the use of a
\texttt
{
li
}
is that
the program often also stores this in the memory, so we had to check whether
this was necessary here as well.
\subsubsection*
{
Copy propagation
}
\subsubsection*
{
Copy propagation
}
...
@@ -153,12 +167,11 @@ of the move operation.
...
@@ -153,12 +167,11 @@ of the move operation.
An example would be the following:
An example would be the following:
\begin{verbatim}
\begin{verbatim}
move
$
regA,
$
regB move
$
regA,
$
regB
move
$
regA,
$
regB move
$
regA,
$
regB
... ...
... ...
Code not writing
$
regA, -> ...
Code not writing
$
regA,
$
regB -> ...
$
regB ...
... ...
... ...
addu
$
regC,
$
regA, ... addu
$
regC,
$
regB, ...
addu
$
regC,
$
regA, ... addu
$
regC,
$
regB, ...
\end{verbatim}
\end{verbatim}
This code shows that
\texttt
{
\$
regA
}
is replaced with
\texttt
{
\$
regB
}
. This
This code shows that
\texttt
{
\$
regA
}
is replaced with
\texttt
{
\$
regB
}
. This
way, the move instruction might have become useless, and it will then be
way, the move instruction might have become useless, and it will then be
...
@@ -166,7 +179,18 @@ removed by the dead code elimination.
...
@@ -166,7 +179,18 @@ removed by the dead code elimination.
\subsubsection*
{
Algebraic transformations
}
\subsubsection*
{
Algebraic transformations
}
Some expression can easily be replaced with more simple once if you look at
what they are saying algebraically. An example is the statement
$
x
=
y
+
0
$
, or
in Assembly
\texttt
{
addu
\$
1,
\$
2, 0
}
. This can easily be changed into
$
x
=
y
$
or
\texttt
{
move
\$
1,
\$
2
}
.
Another case is the multiplication with a power of two. This can be done way
more efficiently by shifting left a number of times. An example:
\texttt
{
mult
\$
regA,
\$
regB, 4 -> sll
\$
regA,
\$
regB, 2
}
. We perform this
optimization for any multiplication with a power of two.
There are a number of such cases, all of which are once again stated in
appendix
\ref
{
opt
}
.
\section
{
Implementation
}
\section
{
Implementation
}
...
@@ -203,7 +227,7 @@ The optimizations are done in two different steps. First the global
...
@@ -203,7 +227,7 @@ The optimizations are done in two different steps. First the global
optimizations are performed, which are only the optimizations on branch-jump
optimizations are performed, which are only the optimizations on branch-jump
constructions. This is done repeatedly until there are no more changes.
constructions. This is done repeatedly until there are no more changes.
After all possible global optimizations are done, the program is sep
e
rated into
After all possible global optimizations are done, the program is sep
a
rated into
basic blocks. The algorithm to do this is described earlier, and means all
basic blocks. The algorithm to do this is described earlier, and means all
jump and branch instructions are called leaders, as are their targets. A basic
jump and branch instructions are called leaders, as are their targets. A basic
block then goes from leader to leader.
block then goes from leader to leader.
...
@@ -215,7 +239,7 @@ steps can be done to optimize something.
...
@@ -215,7 +239,7 @@ steps can be done to optimize something.
\subsection
{
Writing
}
\subsection
{
Writing
}
Once all the optimizations have been done, the IR needs to be rewritten into
Once all the optimizations have been done, the IR needs to be rewritten into
Assembly code, so the xgcc crosscompiler can make binary code out of it.
Assembly code, so the xgcc cross
compiler can make binary code out of it.
The writer expects a list of statements, so first the blocks have to be
The writer expects a list of statements, so first the blocks have to be
concatenated again into a list. After this is done, the list is passed on to
concatenated again into a list. After this is done, the list is passed on to
...
...
src/dataflow.py
View file @
405dc7a5
#
from copy import copy
from
copy
import
copy
from
statement
import
Block
from
statement
import
Block
...
@@ -25,40 +25,85 @@ class BasicBlock(Block):
...
@@ -25,40 +25,85 @@ class BasicBlock(Block):
if
block
not
in
self
.
dominates
:
if
block
not
in
self
.
dominates
:
self
.
dominates
.
append
(
block
)
self
.
dominates
.
append
(
block
)
block
.
dominated_by
.
append
(
self
)
block
.
dominated_by
.
append
(
self
)
def
create_gen_kill
(
self
,
defs
):
# def get_gen(self):
used
=
set
()
# for s in self.statements:
self_defs
=
{}
# if s.is_arith():
# self.gen_set.add(s[0])
# Get the last of each definition series and put in in the `def' set
# print 'added: ', s[0]
self
.
gen_set
=
set
()
#
# return self.gen_set
for
s
in
reversed
(
self
):
#
for
reg
in
s
.
get_def
():
# def get_kill(self):
if
reg
not
in
self_defs
:
## if self.edges_from != []:
print
'Found def:'
,
s
#
self_defs
[
reg
]
=
s
.
sid
# for backw in self.edges_from:
self
.
gen_set
.
add
(
s
.
sid
)
# self.kill_set = self.gen_set & backw.kill_set
#
# Generate kill set
# self.kill_set = self.kill_set - self.get_gen()
self
.
kill_set
=
set
()
# print 'get_kill_set', self.kill_set
# return self.kill_set
for
reg
,
statement_ids
in
defs
.
iteritems
():
if
reg
in
self_defs
:
# def get_in(self):
add
=
statement_ids
-
set
([
self_defs
[
reg
]])
# for backw in self.edges_from:
else
:
# self.in_set = self.in_set | backw.out_set
add
=
statement_ids
# print 'in_set', self.in_set
# return self.in_set
self
.
kill_set
|=
add
# def get_out(self):
# print 'gen_set', self.gen_set
def
defs
(
blocks
):
# print 'get_in', self.get_in()
# Collect definitions of all registers
# print 'get_kill', self.get_kill()
defs
=
{}
# self.out_set = self.gen_set | (self.get_in() - self.get_kill())
for
b
in
blocks
:
for
s
in
b
:
for
reg
in
s
.
get_def
():
if
reg
not
in
defs
:
defs
[
reg
]
=
set
([
s
.
sid
])
else
:
defs
[
reg
].
add
(
s
.
sid
)
return
defs
def
reaching_definitions
(
blocks
):
"""Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the slides."""
defs
=
defs
(
blocks
)
for
b
in
blocks
:
b
.
create_gen_kill
(
defs
)
b
.
out_set
=
b
.
gen_set
change
=
True
while
change
:
change
=
False
for
b
in
blocks
:
b
.
in_set
=
set
()
for
pred
in
b
.
edges_from
:
b
.
in_set
|=
pred
.
out_set
oldout
=
copy
(
p
.
out_set
)
p
.
out_set
=
b
.
gen_set
|
(
b
.
in_set
-
b
.
kill_set
)
if
b
.
out_set
!=
oldout
:
change
=
True
def
pred
(
n
,
known
=
[]):
"""Recursively find all predecessors of a node."""
direct
=
filter
(
lambda
b
:
b
not
in
known
,
n
.
edges_from
)
p
=
copy
(
direct
)
for
ancestor
in
direct
:
p
+=
pred
(
ancestor
,
direct
)
return
p
def
find_leaders
(
statements
):
def
find_leaders
(
statements
):
"""Determine the leaders, which are:
"""Determine the leaders, which are:
...
...
src/optimize/__init__.py
View file @
405dc7a5
...
@@ -3,7 +3,7 @@ from src.dataflow import find_basic_blocks
...
@@ -3,7 +3,7 @@ from src.dataflow import find_basic_blocks
from
redundancies
import
remove_redundant_jumps
,
move_1
,
move_2
,
move_3
,
\
from
redundancies
import
remove_redundant_jumps
,
move_1
,
move_2
,
move_3
,
\
move_4
,
load
,
shift
,
add
move_4
,
load
,
shift
,
add
from
advanced
import
eliminate_common_subexpressions
,
fold_constants
,
\
from
advanced
import
eliminate_common_subexpressions
,
fold_constants
,
\
copy_propagation
,
algebraic_transformations
copy_propagation
,
algebraic_transformations
,
eliminate_dead_code
def
remove_redundancies
(
block
):
def
remove_redundancies
(
block
):
...
@@ -32,7 +32,8 @@ def optimize_block(block):
...
@@ -32,7 +32,8 @@ def optimize_block(block):
|
eliminate_common_subexpressions
(
block
)
\
|
eliminate_common_subexpressions
(
block
)
\
|
fold_constants
(
block
)
\
|
fold_constants
(
block
)
\
|
copy_propagation
(
block
)
\
|
copy_propagation
(
block
)
\
|
algebraic_transformations
(
block
):
|
algebraic_transformations
(
block
)
\
|
eliminate_dead_code
(
block
):
pass
pass
...
@@ -63,6 +64,6 @@ def optimize(statements, verbose=0):
...
@@ -63,6 +64,6 @@ def optimize(statements, verbose=0):
print
'After global optimization: %d'
%
g
print
'After global optimization: %d'
%
g
print
'After basic blocks optimization: %d'
%
b
print
'After basic blocks optimization: %d'
%
b
print
'Optimization: %d (%d%%)'
\
print
'Optimization: %d (%d%%)'
\
%
(
b
-
o
,
int
((
b
-
o
)
/
float
(
o
)
*
100
))
%
(
o
-
b
,
int
((
o
-
b
)
/
float
(
b
)
*
100
))
return
opt_blocks
return
opt_blocks
src/optimize/advanced.py
View file @
405dc7a5
This diff is collapsed.
Click to expand it.
src/statement.py
View file @
405dc7a5
...
@@ -2,12 +2,18 @@ import re
...
@@ -2,12 +2,18 @@ import re
class
Statement
:
class
Statement
:
sid
=
1
def
__init__
(
self
,
stype
,
name
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
stype
,
name
,
*
args
,
**
kwargs
):
self
.
stype
=
stype
self
.
stype
=
stype
self
.
name
=
name
self
.
name
=
name
self
.
args
=
list
(
args
)
self
.
args
=
list
(
args
)
self
.
options
=
kwargs
self
.
options
=
kwargs
# Assign a unique ID to each satement
self
.
sid
=
Statement
.
sid
Statement
.
sid
+=
1
def
__getitem__
(
self
,
n
):
def
__getitem__
(
self
,
n
):
"""Get an argument."""
"""Get an argument."""
return
self
.
args
[
n
]
return
self
.
args
[
n
]
...
@@ -26,8 +32,8 @@ class Statement:
...
@@ -26,8 +32,8 @@ class Statement:
return
len
(
self
.
args
)
return
len
(
self
.
args
)
def
__str__
(
self
):
# pragma: nocover
def
__str__
(
self
):
# pragma: nocover
return
'<Statement type=%s name=%s args=%s>'
\
return
'<Statement
sid=%d
type=%s name=%s args=%s>'
\
%
(
self
.
stype
,
self
.
name
,
self
.
args
)
%
(
self
.
s
id
,
self
.
s
type
,
self
.
name
,
self
.
args
)
def
__repr__
(
self
):
# pragma: nocover
def
__repr__
(
self
):
# pragma: nocover
return
str
(
self
)
return
str
(
self
)
...
@@ -62,16 +68,21 @@ class Statement:
...
@@ -62,16 +68,21 @@ class Statement:
def
is_shift
(
self
):
def
is_shift
(
self
):
"""Check if the statement is a shift operation."""
"""Check if the statement is a shift operation."""
return
self
.
is_command
()
and
re
.
match
(
'^s(ll|
la|
rl|ra)$'
,
self
.
name
)
return
self
.
is_command
()
and
re
.
match
(
'^s(ll|rl|ra)$'
,
self
.
name
)
def
is_load
(
self
):
def
is_load
(
self
):
"""Check if the statement is a load instruction."""
"""Check if the statement is a load instruction."""
return
self
.
is_command
()
and
self
.
name
in
[
'lw'
,
'dlw'
,
'l.s'
,
'l.d'
]
return
self
.
is_command
()
and
self
.
name
in
[
'lw'
,
'li'
,
'dlw'
,
'l.s'
,
\
'l.d'
]
def
is_arith
(
self
):
def
is_arith
(
self
):
"""Check if the statement is an arithmetic operation."""
"""Check if the statement is an arithmetic operation."""
return
self
.
is_command
()
\
return
self
.
is_command
()
\
and
re
.
match
(
'^(add|sub|mult|div|abs|neg)(u|
\
.d)?$
'
, self.name)
and
re
.
match
(
'^s(ll|rl|ra)'
+
'|(mfhi|mflo|abs|neg|and|[xn]?or)'
+
'|(add|sub|slt)u?'
+
'|(add|sub|mult|div|abs|neg|sqrt|c)
\
.[sd]$
'
,
\
self.name)
def is_monop(self):
def is_monop(self):
"""Check if the statement is an unary operation."""
"""Check if the statement is an unary operation."""
...
@@ -80,23 +91,92 @@ class Statement:
...
@@ -80,23 +91,92 @@ class Statement:
def is_binop(self):
def is_binop(self):
"""Check if the statement is an binary operation."""
"""Check if the statement is an binary operation."""
return self.is_command() and len(self) == 3 and not self.is_jump()
return self.is_command() and len(self) == 3 and not self.is_jump()
def is_load_non_immediate(self):
"""Check if the statement is a load statement."""
return self.is_command()
\
and re.match('
^
l
(
w
|
a
|
b
|
bu
|
\
.
d
|
\
.
s
)
|
dlw
$
',
\
self.name)
def is_logical(self):
"""Check if the statement is a logical operator."""
return self.is_command() and re.match('
^
(
xor
|
or
|
and
)
i
?$
', self.name)
def is_double_aritmethic(self):
"""Check if the statement is a arithmetic .d operator."""
return self.is_command() and
\
re.match('
^
(
add
|
sub
|
div
|
mul
)
\
.
d
$
', self.name)
def is_double_unary(self):
"""Check if the statement is a unary .d operator."""
return self.is_command() and
\
re.match('
^
(
abs
|
neg
|
mov
)
\
.
d
$
', self.name)
def is_move_from_spec(self):
"""Check if the statement is a move from the result register."""
return self.is_command() and self.name in ['
mflo
', '
mthi
']
def is_set_if_less(self):
"""Check if the statement is a shift if less then."""
return self.is_command() and self.name in ['
slt
', '
sltu
']
def is_convert(self):
"""Check if the statement is a convert operator."""
return self.is_command() and re.match('
^
cvt
\
.[
a
-
z
\
.]
*
$
', self.name)
def is_truncate(self):
"""Check if the statement is a convert operator."""
return self.is_command() and re.match('
^
trunc
\
.[
a
-
z
\
.]
*
$
', self.name)
def jump_target(self):
def jump_target(self):
"""Get the jump target of this statement."""
"""Get the jump target of this statement."""
if not self.is_jump():
if not self.is_jump():
raise Exception('
Command
"%s"
has
no
jump
target
' % self.name)
raise Exception('
Command
"%s"
has
no
jump
target
' % self.name)
return self[-1]
return self[-1]
def get_def(self):
"""Get the variable that this statement defines, if any."""
instr = ['
move
', '
addu
', '
subu
', '
li
', '
mtc1
', '
dmfc1
']
if self.is_load_non_immediate() or self.is_arith()
\
or self.is_logical() or self.is_double_arithmetic()
\
or self.is_move_from_spec() or self.is_double_unary()
\
or self.is_set_if_less() or self.is_convert()
\
or self.is_truncate() or self.is_load()
\
or (self.is_command and self.name in instr):
return self[0]
return []
def get_use(self):
# TODO: Finish with ALL the available commands!
use = []
if self.is_binop():
use += self[1:]
elif self.is_command('
move
'):
use.append(self[1])
elif self.is_command('
lw
', '
sb
', '
sw
', '
dsw
', '
s
.
s
', '
s
.
d
'):
m = re.match('
^
\
d
+
\
(([
^
)]
+
)
\
)
$
', self[1])
if m:
use.append(m.group(1))
# '
sw
' also uses its first argument
if self.name in ['
sw
', '
dsw
']:
use.append(self[0])
elif len(self) == 2: # FIXME: temporary fix, manually add all commands
use.append(self[1])
return use
def defines(self, reg):
def defines(self, reg):
"""Check if this statement defines the given register."""
"""Check if this statement defines the given register."""
# TODO: Finish
return reg in self.get_def()
return (self.is_load() or self.is_arith()) and self[0] == reg
def uses(self, reg):
def uses(self, reg):
"""Check if this statement uses the given register."""
"""Check if this statement uses the given register."""
# TODO: Finish
return reg in self.get_use()
return (self.is_load() or self.is_arith()) and reg in self[1:]
class Block:
class Block:
...
...
tests/test_dataflow.py
View file @
405dc7a5
...
@@ -2,7 +2,7 @@ import unittest
...
@@ -2,7 +2,7 @@ import unittest
from
src.statement
import
Statement
as
S
from
src.statement
import
Statement
as
S
from
src.dataflow
import
BasicBlock
as
B
,
find_leaders
,
find_basic_blocks
,
\
from
src.dataflow
import
BasicBlock
as
B
,
find_leaders
,
find_basic_blocks
,
\
generate_flow_graph
,
Dag
,
DagNode
,
DagLeaf
generate_flow_graph
,
Dag
,
DagNode
,
DagLeaf
,
defs
,
reaching_definitions
class
TestDataflow
(
unittest
.
TestCase
):
class
TestDataflow
(
unittest
.
TestCase
):
...
@@ -23,12 +23,12 @@ class TestDataflow(unittest.TestCase):
...
@@ -23,12 +23,12 @@ class TestDataflow(unittest.TestCase):
self
.
assertEqual
(
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)),
\
self
.
assertEqual
(
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)),
\
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
\
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
\
B
(
s
[
4
:]).
statements
])
B
(
s
[
4
:]).
statements
])
# def test_get_gen(self):
# def test_get_gen(self):
# b1 = B([S('command', 'add', '$1', '$2', '$3'), \
# b1 = B([S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$1', '$4', '$5')])
# S('command', 'add', '$1', '$4', '$5')])
#
#
# self.assertEqual(b1.get_gen(), ['$1', '$2'])
# self.assertEqual(b1.get_gen(), ['$1', '$2'])
# def test_get_out(self):
# def test_get_out(self):
...
@@ -36,18 +36,18 @@ class TestDataflow(unittest.TestCase):
...
@@ -36,18 +36,18 @@ class TestDataflow(unittest.TestCase):
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$2', '$3', '$4'), \
# S('command', 'add', '$1', '$4', '$5'), \
# S('command', 'add', '$1', '$4', '$5'), \
# S('command', 'j', 'b2')])
# S('command', 'j', 'b2')])
#
#
# b2 = B([S('command', 'add', '$3', '$5', '$6'), \
# b2 = B([S('command', 'add', '$3', '$5', '$6'), \
# S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$1', '$2', '$3'), \
# S('command', 'add', '$6', '$4', '$5')])
# S('command', 'add', '$6', '$4', '$5')])
#
#
# blocks = [b1, b2]
# blocks = [b1, b2]
#
#
# # initialize out[B] = gen[B] for every block
# # initialize out[B] = gen[B] for every block
# for block in blocks:
# for block in blocks:
# block.out_set = block.get_gen()
# block.out_set = block.get_gen()
# print 'block.out_set', block.out_set
# print 'block.out_set', block.out_set
#
#
# generate_flow_graph(blocks)
# generate_flow_graph(blocks)
# change = True
# change = True
...
@@ -112,6 +112,46 @@ class TestDataflow(unittest.TestCase):
...
@@ -112,6 +112,46 @@ class TestDataflow(unittest.TestCase):
#
#
# self.assertEqualDag(dag, expect)
# self.assertEqualDag(dag, expect)
def
test_defs
(
self
):
s1
=
S
(
'command'
,
'addu'
,
'$3'
,
'$1'
,
'$2'
)
s2
=
S
(
'command'
,
'addu'
,
'$1'
,
'$3'
,
10
)
s3
=
S
(
'command'
,
'subu'
,
'$3'
,
'$1'
,
5
)
s4
=
S
(
'command'
,
'li'
,
'$4'
,
'0x00000001'
)
block
=
B
([
s1
,
s2
,
s3
,
s4
])
self
.
assertEqual
(
defs
([
block
]),
{
'$3'
:
set
([
s1
.
sid
,
s3
.
sid
]),
'$1'
:
set
([
s2
.
sid
]),
'$4'
:
set
([
s4
.
sid
])
})
#def test_defs(self):
# s1 = S('command', 'add', '$3', '$1', '$2')
# s2 = S('command', 'move', '$1', '$3')
# s3 = S('command', 'move', '$3', '$2')
# s4 = S('command', 'li', '$4', '0x00000001')
# block = B([s1, s2, s3, s4])
# self.assertEqual(defs([block]), {
# '$3': set([s1.sid, s3.sid]),
# '$1': set([s2.sid]),
# '$4': set([s4.sid])
# })
def
test_create_gen_kill_gen
(
self
):
s1
=
S
(
'command'
,
'addu'
,
'$3'
,
'$1'
,
'$2'
)
s2
=
S
(
'command'
,
'addu'
,
'$1'
,
'$3'
,
10
)
s3
=
S
(
'command'
,
'subu'
,
'$3'
,
'$1'
,
5
)
s4
=
S
(
'command'
,
'li'
,
'$4'
,
'0x00000001'
)
block
=
B
([
s1
,
s2
,
s3
,
s4
])
block
.
create_gen_kill
(
defs
([
block
]))
self
.
assertEqual
(
block
.
gen_set
,
set
([
s2
.
sid
,
s3
.
sid
,
s4
.
sid
]))
#def test_get_kill_used(self):
# block = B([S('command', 'move', '$1', '$3'),
# S('command', 'add', '$3', '$1', '$2'),
# S('command', 'move', '$1', '$3'),
# S('command', 'move', '$2', '$3')])
# self.assertEqual(block.get_kill(), set())
def
assertEqualDag
(
self
,
dag1
,
dag2
):
def
assertEqualDag
(
self
,
dag1
,
dag2
):
self
.
assertEqual
(
len
(
dag1
.
nodes
),
len
(
dag2
.
nodes
))
self
.
assertEqual
(
len
(
dag1
.
nodes
),
len
(
dag2
.
nodes
))
...
...
tests/test_optimize_advanced.py
View file @
405dc7a5
...
@@ -19,9 +19,9 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -19,9 +19,9 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_eliminate_common_subexpressions_simple
(
self
):
def
test_eliminate_common_subexpressions_simple
(
self
):
b
=
B
([
S
(
'command'
,
'addu'
,
'$regC'
,
'$regA'
,
'$regB'
),
b
=
B
([
S
(
'command'
,
'addu'
,
'$regC'
,
'$regA'
,
'$regB'
),
S
(
'command'
,
'addu'
,
'$regD'
,
'$regA'
,
'$regB'
)])
S
(
'command'
,
'addu'
,
'$regD'
,
'$regA'
,
'$regB'
)])
e
=
[
S
(
'command'
,
'addu'
,
'$
t0
'
,
'$regA'
,
'$regB'
),
\
e
=
[
S
(
'command'
,
'addu'
,
'$
8
'
,
'$regA'
,
'$regB'
),
\
S
(
'command'
,
'move'
,
'$regC'
,
'$
t0
'
),
\
S
(
'command'
,
'move'
,
'$regC'
,
'$
8
'
),
\
S
(
'command'
,
'move'
,
'$regD'
,
'$
t0
'
)]
S
(
'command'
,
'move'
,
'$regD'
,
'$
8
'
)]
eliminate_common_subexpressions
(
b
)
eliminate_common_subexpressions
(
b
)
self
.
assertEqual
(
b
.
statements
,
e
)
self
.
assertEqual
(
b
.
statements
,
e
)
...
@@ -49,6 +49,20 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -49,6 +49,20 @@ class TestOptimizeAdvanced(unittest.TestCase):
self
.
foo
,
self
.
foo
,
S
(
'command'
,
'addu'
,
'$3'
,
'$2'
,
'$4'
),
S
(
'command'
,
'addu'
,
'$3'
,
'$2'
,
'$4'
),
self
.
bar
])
self
.
bar
])
def
test_copy_propagation_other_arg
(
self
):
block
=
B
([
self
.
foo
,
S
(
'command'
,
'move'
,
'$1'
,
'$2'
),
self
.
foo
,
S
(
'command'
,
'addu'
,
'$3'
,
'$4'
,
'$1'
),
self
.
bar
])
self
.
assertTrue
(
copy_propagation
(
block
))
self
.
assertEqual
(
block
.
statements
,
[
self
.
foo
,
S
(
'command'
,
'move'
,
'$1'
,
'$2'
),
self
.
foo
,
S
(
'command'
,
'addu'
,
'$3'
,
'$4'
,
'$2'
),
self
.
bar
])
def
test_copy_propagation_overwrite
(
self
):
def
test_copy_propagation_overwrite
(
self
):
block
=
B
([
self
.
foo
,
\
block
=
B
([
self
.
foo
,
\
...
@@ -125,7 +139,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -125,7 +139,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_algebraic_transforms_mult0
(
self
):
def
test_algebraic_transforms_mult0
(
self
):
block
=
B
([
self
.
foo
,
block
=
B
([
self
.
foo
,
S
(
'command'
,
'mult'
,
'$1'
,
'$2'
,
0
),
S
(
'command'
,
'mult'
,
'$2'
,
0
),
S
(
'command'
,
'mflo'
,
'$1'
),
self
.
bar
])
self
.
bar
])
self
.
assertTrue
(
algebraic_transformations
(
block
))
self
.
assertTrue
(
algebraic_transformations
(
block
))
...
@@ -135,7 +150,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -135,7 +150,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_algebraic_transforms_mult1
(
self
):
def
test_algebraic_transforms_mult1
(
self
):
block
=
B
([
self
.
foo
,
block
=
B
([
self
.
foo
,
S
(
'command'
,
'mult'
,
'$1'
,
'$2'
,
1
),
S
(
'command'
,
'mult'
,
'$2'
,
1
),
S
(
'command'
,
'mflo'
,
'$1'
),
self
.
bar
])
self
.
bar
])
self
.
assertTrue
(
algebraic_transformations
(
block
))
self
.
assertTrue
(
algebraic_transformations
(
block
))
...
@@ -145,7 +161,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -145,7 +161,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_algebraic_transforms_mult2
(
self
):
def
test_algebraic_transforms_mult2
(
self
):
block
=
B
([
self
.
foo
,
block
=
B
([
self
.
foo
,
S
(
'command'
,
'mult'
,
'$1'
,
'$2'
,
2
),
S
(
'command'
,
'mult'
,
'$2'
,
2
),
S
(
'command'
,
'mflo'
,
'$1'
),
self
.
bar
])
self
.
bar
])
self
.
assertTrue
(
algebraic_transformations
(
block
))
self
.
assertTrue
(
algebraic_transformations
(
block
))
...
@@ -155,7 +172,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -155,7 +172,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_algebraic_transforms_mult16
(
self
):
def
test_algebraic_transforms_mult16
(
self
):
block
=
B
([
self
.
foo
,
block
=
B
([
self
.
foo
,
S
(
'command'
,
'mult'
,
'$1'
,
'$2'
,
16
),
S
(
'command'
,
'mult'
,
'$2'
,
16
),
S
(
'command'
,
'mflo'
,
'$1'
),
self
.
bar
])
self
.
bar
])
self
.
assertTrue
(
algebraic_transformations
(
block
))
self
.
assertTrue
(
algebraic_transformations
(
block
))
...
@@ -165,7 +183,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
...
@@ -165,7 +183,8 @@ class TestOptimizeAdvanced(unittest.TestCase):
def
test_algebraic_transforms_mult3
(
self
):
def
test_algebraic_transforms_mult3
(
self
):
arguments
=
[
self
.
foo
,
arguments
=
[
self
.
foo
,
S
(
'command'
,
'mult'
,
'$1'
,
'$2'
,
3
),
S
(
'command'
,
'mult'
,
'$2'
,
3
),
S
(
'command'
,
'mflo'
,
'$1'
),
self
.
bar
]
self
.
bar
]
block
=
B
(
arguments
)
block
=
B
(
arguments
)
...
...
tests/test_statement.py
View file @
405dc7a5
...
@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase):
...
@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase):
self
.
assertFalse
(
S
(
'label'
,
'lw'
).
is_load
())
self
.
assertFalse
(
S
(
'label'
,
'lw'
).
is_load
())
def
test_is_arith
(
self
):
def
test_is_arith
(
self
):
self
.
assertTrue
(
S
(
'command'
,
'add'
,
'$1'
,
'$2'
,
'$3'
).
is_arith
())
self
.
assertTrue
(
S
(
'command'
,
'add
u
'
,
'$1'
,
'$2'
,
'$3'
).
is_arith
())
self
.
assertFalse
(
S
(
'command'
,
'foo'
).
is_arith
())
self
.
assertFalse
(
S
(
'command'
,
'foo'
).
is_arith
())
self
.
assertFalse
(
S
(
'label'
,
'add'
).
is_arith
())
self
.
assertFalse
(
S
(
'label'
,
'add
u
'
).
is_arith
())
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment