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
ef3125ad
Commit
ef3125ad
authored
Dec 22, 2011
by
Taddeus Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved util functions to separate files.
parent
5de90da4
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
190 additions
and
91 deletions
+190
-91
src/dataflow.py
src/dataflow.py
+141
-0
src/optimize.py
src/optimize.py
+21
-15
src/statement.py
src/statement.py
+1
-60
tests/test_dataflow.py
tests/test_dataflow.py
+25
-0
tests/test_statement.py
tests/test_statement.py
+2
-16
No files found.
src/dataflow.py
0 → 100644
View file @
ef3125ad
from
copy
import
copy
from
utils
import
Block
class
BasicBlock
(
Block
):
edges_to
=
[]
edges_from
=
[]
dominates
=
[]
dominated_by
=
[]
def
add_edge_to
(
self
,
block
):
self
.
edges_to
.
append
(
block
)
block
.
edges_from
.
append
(
self
)
def
set_dominates
(
self
,
block
):
self
.
dominates
.
append
(
block
)
block
.
dominated_by
.
append
(
self
)
def
get_gen
(
self
):
pass
def
get_kill
(
self
):
pass
def
get_in
(
self
):
pass
def
get_out
(
self
):
pass
def
find_leaders
(
statements
):
"""Determine the leaders, which are:
1. The first statement.
2. Any statement that is the target of a jump.
3. Any statement that follows directly follows a jump."""
leaders
=
[
0
]
jump_target_labels
=
[]
# Append statements following jumps and save jump target labels
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
if
statement
.
is_jump
():
leaders
.
append
(
i
+
2
)
jump_target_labels
.
append
(
statement
[
-
1
])
# Append jump targets
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
if
i
+
1
not
in
leaders
\
and
statement
.
is_label
()
\
and
statement
.
name
in
jump_target_labels
:
leaders
.
append
(
i
+
1
)
leaders
.
sort
()
return
leaders
def
find_basic_blocks
(
statements
):
"""Divide a statement list into basic blocks. Returns a list of basic
blocks, which are also statement lists."""
leaders
=
find_leaders
(
statements
)
blocks
=
[]
for
i
in
range
(
len
(
leaders
)
-
1
):
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
i
]:
leaders
[
i
+
1
]]))
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
-
1
]:]))
return
blocks
def
generate_flow_graph
(
blocks
):
"""Add flow graph edge administration of an ordered sequence of basic
blocks."""
for
b
in
blocks
:
last_statement
=
b
[
-
1
]
if
last_statement
.
is_jump
():
target
=
last_statement
.
jump_target
()
# Compare the target to all leading labels, add an edge if the
# label matches the jump target
for
other
in
blocks
:
if
other
[
0
].
is_label
(
target
):
b
.
add_edge_to
(
other
)
def
generate_dominator_tree
(
nodes
):
"""Add dominator administration to the given flow graph nodes."""
# Dominator of the start node is the start itself
nodes
[
0
].
dom
=
set
([
nodes
[
0
]])
# For all other nodes, set all nodes as the dominators
for
n
in
nodes
[
1
:]:
n
.
dom
=
set
(
copy
(
nodes
))
def
pred
(
n
,
known
=
[]):
"""Recursively find all predecessors of a node."""
direct
=
filter
(
lambda
x
:
x
not
in
known
,
n
.
edges_from
)
p
=
copy
(
direct
)
for
ancestor
in
direct
:
p
+=
pred
(
ancestor
,
direct
)
return
p
# Iteratively eliminate nodes that are not dominators
changed
=
True
while
changed
:
changed
=
False
for
n
in
nodes
[
1
:]:
old_dom
=
n
.
dom
intersection
=
lambda
p1
,
p2
:
p1
.
dom
&
p2
.
dom
n
.
dom
=
set
([
n
])
|
reduce
(
intersection
,
pred
(
n
),
set
([]))
if
n
.
dom
!=
old_dom
:
changed
=
True
def
idom
(
d
,
n
):
"""Check if d immediately dominates n."""
for
b
in
n
.
dom
:
if
b
!=
d
and
b
!=
n
and
b
in
n
.
dom
:
return
False
return
True
# Build tree using immediate dominators
for
n
in
nodes
:
for
d
in
n
.
dom
:
if
idom
(
d
,
n
):
d
.
set_dominates
(
n
)
break
# statements = parse_file(...)
# b = find_basic_blocks(statements)
# generate_flow_graph(b) # nodes now have edges
# generate_dominator_tree(b) # nodes now have dominators
src/optimize.py
View file @
ef3125ad
from
utils
import
find_basic_blocks
from
dataflow
import
find_basic_blocks
def
optimize_global
(
statements
):
"""Optimize statement sequences
in
on a global level."""
"""Optimize statement sequences on a global level."""
old_len
=
-
1
while
old_len
!=
len
(
statements
):
...
...
@@ -11,12 +11,12 @@ def optimize_global(statements):
while
not
statements
.
end
():
s
=
statements
.
read
()
# mov $regA,
$regB
-> --- remove it
# mov $regA,
$regA
-> --- remove it
if
s
.
is_command
(
'move'
)
and
s
[
0
]
==
s
[
1
]:
statements
.
replace
(
1
,
[])
continue
# mov $regA,
$regB
-> instr $regA, $regB, ...
# mov $regA,
$regB
-> instr $regA, $regB, ...
# instr $regA, $regA, ...
if
s
.
is_command
(
'move'
):
ins
=
statements
.
peek
()
...
...
@@ -35,8 +35,8 @@ def optimize_global(statements):
if
len
(
following
)
==
2
:
mov
,
jal
=
following
if
mov
.
name
==
'move'
and
mov
[
1
]
==
s
[
0
]
\
and
jal
.
name
==
'jal'
:
if
mov
.
is_command
(
'move'
)
and
mov
[
1
]
==
s
[
0
]
\
and
jal
.
is_command
(
'jal'
)
:
s
[
0
]
=
mov
[
0
]
statements
.
replace
(
1
,
[],
start
=
statements
.
pointer
+
1
)
continue
...
...
@@ -78,8 +78,6 @@ def optimize_global(statements):
s
[
2
]
=
label
.
name
statements
.
replace
(
3
,
[
s
,
label
])
return
statements
def
optimize_blocks
(
blocks
):
"""Call the optimizer for each basic block. Do this several times until
...
...
@@ -115,21 +113,29 @@ def optimize_block(statements):
return
changed
,
output_statements
def
optimize
(
original
,
verbose
=
0
):
def
optimize
(
statements
,
verbose
=
0
):
"""optimization wrapper function, calls global and basic-block level
optimization functions."""
# Optimize on a global level
opt_global
=
optimize_global
(
original
)
o
=
len
(
statements
)
optimize_global
(
statements
)
g
=
len
(
statements
)
# Optimize basic blocks
basic_blocks
=
find_basic_blocks
(
opt_global
)
basic_blocks
=
find_basic_blocks
(
statements
)
blocks
=
optimize_blocks
(
basic_blocks
)
opt_blocks
=
reduce
(
lambda
a
,
b
:
a
.
statements
+
b
.
statements
,
blocks
)
block_statements
=
map
(
lambda
b
:
b
.
statements
,
blocks
)
opt_blocks
=
reduce
(
lambda
a
,
b
:
a
+
b
,
block_statements
)
b
=
len
(
opt_blocks
)
# - Common subexpression elimination
# - Constant folding
# - Copy propagation
# - Dead-code elimination
# - Temporary variable renaming
# - Interchange of independent statements
if
verbose
:
o
=
len
(
original
)
g
=
len
(
opt_global
)
b
=
len
(
opt_blocks
)
print
'Original statements: %d'
%
o
print
'After global optimization: %d'
%
g
print
'After basic blocks optimization: %d'
%
b
...
...
src/
utils
.py
→
src/
statement
.py
View file @
ef3125ad
import
re
class
Statement
:
def
__init__
(
self
,
stype
,
name
,
*
args
,
**
kwargs
):
self
.
stype
=
stype
...
...
@@ -71,26 +72,6 @@ class Statement:
return self[-1]
def get_def(self):
"""Get the def[S] of this statement."""
if not self.is_command():
return []
if self.is_load() or self.is_arith():
return [self[0]]
def get_use(self):
"""Get the use[S] of this statement."""
return []
def defines(self, var):
"""Check if a variable is defined by this statement."""
return var in self.get_def()
def uses(self, var):
"""Check if a variable is used by this statement."""
return var in self.get_use()
class Block:
def __init__(self, statements=[]):
...
...
@@ -137,43 +118,3 @@ class Block:
"""Apply a filter to the statement list. If the callback returns True,
the statement will remain in the list.."""
self.statements = filter(callback, self.statements)
def find_leaders(statements):
"""Determine the leaders, which are:
1. The first statement.
2. Any statement that is the target of a jump.
3. Any statement that follows directly follows a jump."""
leaders = [0]
jump_target_labels = []
# Append statements following jumps and save jump target labels
for i, statement in enumerate(statements[1:]):
if statement.is_jump():
leaders.append(i + 2)
jump_target_labels.append(statement[-1])
# Append jump targets
for i, statement in enumerate(statements[1:]):
if i + 1 not in leaders
\
and statement.is_label()
\
and statement.name in jump_target_labels:
leaders.append(i + 1)
leaders.sort()
return leaders
def find_basic_blocks(statements):
"""Divide a statement list into basic blocks. Returns a list of basic
blocks, which are also statement lists."""
leaders = find_leaders(statements)
blocks = []
for i in range(len(leaders) - 1):
blocks.append(Block(statements[leaders[i]:leaders[i + 1]]))
blocks.append(Block(statements[leaders[-1]:]))
return blocks
tests/test_dataflow.py
0 → 100644
View file @
ef3125ad
import
unittest
from
src.statement
import
Statement
as
S
,
Block
as
B
from
src.dataflow
import
find_leaders
,
find_basic_blocks
class
TestDataflow
(
unittest
.
TestCase
):
def
setUp
(
self
):
add
=
S
(
'command'
,
'add'
,
'$1'
,
'$2'
,
'$3'
)
self
.
statements
=
[
add
,
S
(
'command'
,
'j'
,
'foo'
),
add
,
add
,
\
S
(
'label'
,
'foo'
)]
def
tearDown
(
self
):
del
self
.
statements
def
test_find_leaders
(
self
):
self
.
assertEqual
(
find_leaders
(
self
.
statements
),
[
0
,
2
,
4
])
def
test_find_basic_blocks
(
self
):
s
=
self
.
statements
self
.
assertEqual
(
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)),
\
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
\
B
(
s
[
4
:]).
statements
])
tests/test_
utils
.py
→
tests/test_
statement
.py
View file @
ef3125ad
import
unittest
from
src.utils
import
Statement
as
S
,
Block
as
B
,
find_leaders
,
\
find_basic_blocks
from
src.statement
import
Statement
as
S
,
Block
as
B
class
Test
Utils
(
unittest
.
TestCase
):
class
Test
Statement
(
unittest
.
TestCase
):
def
setUp
(
self
):
add
=
S
(
'command'
,
'add'
,
'$1'
,
'$2'
,
'$3'
)
self
.
statements
=
[
add
,
S
(
'command'
,
'j'
,
'foo'
),
add
,
add
,
\
S
(
'label'
,
'foo'
)]
self
.
block
=
B
([
S
(
'command'
,
'foo'
),
\
S
(
'comment'
,
'bar'
),
S
(
'command'
,
'baz'
)])
def
tearDown
(
self
):
del
self
.
statements
del
self
.
block
def
test_find_leaders
(
self
):
self
.
assertEqual
(
find_leaders
(
self
.
statements
),
[
0
,
2
,
4
])
def
test_find_basic_blocks
(
self
):
s
=
self
.
statements
self
.
assertEqual
(
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)),
\
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
\
B
(
s
[
4
:]).
statements
])
def
test_eq
(
self
):
self
.
assertTrue
(
S
(
'command'
,
'foo'
)
==
S
(
'command'
,
'foo'
))
self
.
assertFalse
(
S
(
'command'
,
'foo'
)
==
S
(
'command'
,
'bar'
))
...
...
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