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
7018b528
Commit
7018b528
authored
Dec 30, 2011
by
Taddeus Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed liveness analysis.
parent
770cbc9f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
66 additions
and
102 deletions
+66
-102
src/dataflow.py
src/dataflow.py
+23
-19
src/liveness.py
src/liveness.py
+16
-8
src/optimize/__init__.py
src/optimize/__init__.py
+0
-3
src/optimize/advanced.py
src/optimize/advanced.py
+23
-65
src/program.py
src/program.py
+0
-1
src/statement.py
src/statement.py
+1
-1
tests/test_dataflow.py
tests/test_dataflow.py
+3
-5
No files found.
src/dataflow.py
View file @
7018b528
...
...
@@ -23,55 +23,59 @@ class BasicBlock(Block):
block
.
dominated_by
.
append
(
self
)
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."""
def
find_leaders
(
statements
,
return_jump_targets
=
False
):
"""
- 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.
- To determine the leaders, a list of known jump targets is created. This
list can also be returned for later use.
"""
leaders
=
[
0
]
jump_target
_label
s
=
[]
jump_targets
=
[]
# 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
_label
s
.
append
(
statement
[
-
1
])
jump_targets
.
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
_label
s
:
and
statement
.
name
in
jump_targets
:
leaders
.
append
(
i
+
1
)
leaders
.
sort
()
return
leaders
return
(
leaders
,
jump_targets
)
if
return_jump_targets
else
leaders
def
find_basic_blocks
(
statements
):
def
find_basic_blocks
(
statements
,
return_jump_targets
=
False
):
"""Divide a statement list into basic blocks. Returns a list of basic
blocks, which are also statement lists."""
leaders
=
find_leaders
(
statements
)
leaders
,
jump_targets
=
find_leaders
(
statements
,
True
)
blocks
=
[]
for
i
in
range
(
len
(
leaders
)
-
1
):
for
i
in
x
range
(
len
(
leaders
)
-
1
):
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
i
]:
leaders
[
i
+
1
]]))
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
-
1
]:]))
# Add a target block for unknown jump targets
blocks
.
append
(
BasicBlock
([],
dummy
=
True
))
#
blocks.append(BasicBlock([], dummy=True))
return
blocks
return
(
blocks
,
jump_targets
)
if
return_jump_targets
else
blocks
def
generate_flow_graph
(
blocks
):
"""Add flow graph edge administration of an ordered sequence of basic
blocks."""
dummy_block
=
blocks
[
-
1
]
#
dummy_block = blocks[-1]
for
i
,
b
in
enumerate
(
blocks
[:
-
1
]
):
for
i
,
b
in
enumerate
(
blocks
):
last_statement
=
b
[
-
1
]
if
last_statement
.
is_jump
():
...
...
@@ -81,15 +85,15 @@ def generate_flow_graph(blocks):
# label matches the jump target
target_found
=
False
for
other
in
blocks
[:
-
1
]
:
for
other
in
blocks
:
if
other
[
0
].
is_label
(
target
):
b
.
add_edge_to
(
other
)
target_found
=
True
# If the jump target is outside the program, add an edge to the
# dummy block
if
not
target_found
:
b
.
add_edge_to
(
dummy_block
)
#
if not target_found:
#
b.add_edge_to(dummy_block)
# A branch and jump-and-line instruction also creates an edge to
# the next block
...
...
src/liveness.py
View file @
7018b528
...
...
@@ -2,13 +2,22 @@ from copy import copy
RESERVED_REGISTERS
=
[
'$fp'
,
'$sp'
,
'$31'
]
RESERVED_USE
=
[
'$%d'
%
i
for
i
in
range
(
2
,
8
)]
\
+
[
'$f%d'
%
i
for
i
in
range
(
32
)]
RESERVED_DEF
=
[
'$2'
,
'$3'
]
def
is_reg_dead_after
(
reg
,
block
,
index
):
def
is_reg_dead_after
(
reg
,
block
,
index
,
known_jump_targets
=
[]
):
"""Check if a register is dead after a certain point in a basic block."""
if
reg
in
RESERVED_REGISTERS
:
return
False
# If the block jumps to an unknown jump target, make sure that definitions
# of reserved argument registers are not removed
if
reg
in
RESERVED_USE
and
block
[
-
1
].
is_command
(
'jal'
)
\
and
block
[
-
1
][
0
]
not
in
known_jump_targets
:
return
False
if
index
<
len
(
block
)
-
1
:
for
s
in
block
[
index
+
1
:]:
# If used, the previous definition is live
...
...
@@ -25,16 +34,15 @@ def is_reg_dead_after(reg, block, index):
def
create_use_def
(
block
):
#if block.dummy:
# block.use_set = set(RESERVED_USE)
# block.def_set = set(RESERVED_DEF)
# return
# Get the last of each definition series and put in in the `def' set
used
=
set
()
defined
=
set
()
if
block
.
dummy
:
block
.
use_set
=
set
([
'$4'
,
'$5'
,
'$6'
,
'$7'
,
\
'$f0'
,
'$f3'
,
'$f4'
,
'$f12'
,
'$2'
])
block
.
def_set
=
set
([
'$2'
,
'$3'
])
return
# Get the last of each definition series and put in in the `def' set
block
.
use_set
=
set
()
block
.
def_set
=
set
()
...
...
src/optimize/__init__.py
View file @
7018b528
...
...
@@ -15,14 +15,11 @@ def optimize(program, verbose=0):
iterations
=
0
while
changed
:
<<<<<<<
HEAD
iterations
+=
1
if
verbose
>
1
:
print
'main iteration %d'
,
iterations
=======
>>>>>>>
98
c43ff02c474a62e42ac89ba9fe20be98f9eccd
changed
=
False
# Optimize on a global level
...
...
src/optimize/advanced.py
View file @
7018b528
...
...
@@ -4,31 +4,32 @@ from src.statement import Statement as S
from
src.liveness
import
is_reg_dead_after
def
reg_can_be_used_in
(
reg
,
block
,
start
,
end
):
"""Check if a register addres safely be used in a block section using local
dataflow analysis."""
# Check if the register used or defined in the block section
for
s
in
block
[
start
:
end
]:
if
s
.
uses
(
reg
)
or
s
.
defines
(
reg
):
return
False
# Check if the register is used inside the block after the specified
# section, without having been re-assigned first
for
s
in
block
[
end
:]:
if
s
.
uses
(
reg
):
return
False
elif
s
.
defines
(
reg
):
return
True
return
reg
not
in
block
.
live_out
def
find_free_reg
(
block
,
start
,
end
):
#
def reg_can_be_used_in(reg, block, start, end):
#
"""Check if a register addres safely be used in a block section using local
#
dataflow analysis."""
#
# Check if the register used or defined in the block section
#
for s in block[start:end]:
#
if s.uses(reg) or s.defines(reg):
#
return False
#
#
# Check if the register is used inside the block after the specified
#
# section, without having been re-assigned first
#
for s in block[end:]:
#
if s.uses(reg):
#
return False
#
elif s.defines(reg):
#
return True
#
#
return reg not in block.live_out
def
find_free_reg
(
block
,
start
):
"""Find a temporary register that is free in a given list of statements."""
for
i
in
xrange
(
8
,
16
):
tmp
=
'$%d'
%
i
if
reg_can_be_used_in
(
tmp
,
block
,
start
,
end
):
#if reg_can_be_used_in(tmp, block, start, end):
if
is_reg_dead_after
(
tmp
,
block
,
start
):
return
tmp
raise
Exception
(
'No temporary register is available.'
)
...
...
@@ -78,7 +79,7 @@ def eliminate_common_subexpressions(block):
occurrences
.
append
(
block
.
pointer
-
1
)
if
len
(
occurrences
)
>
1
:
new_reg
=
find_free_reg
(
block
,
occurrences
[
0
]
,
occurrences
[
-
1
]
)
new_reg
=
find_free_reg
(
block
,
occurrences
[
0
])
# Replace all occurrences with a move statement
message
=
'Common subexpression reference: %s %s'
\
...
...
@@ -341,49 +342,6 @@ def copy_propagation(block):
return
changed
def
algebraic_transformations
(
block
):
"""
Change ineffective or useless algebraic expressions. Handled are:
- x = y + 0 -> x = y
- x = y - 0 -> x = y
- x = y * 1 -> x = y
- x = y * 0 -> x = 0
- x = y * 2 -> x = x << 1
"""
changed
=
False
block
.
reset
()
while
not
block
.
end
():
s
=
block
.
read
()
if
(
s
.
is_command
(
'addu'
)
or
s
.
is_command
(
'subu'
))
and
s
[
2
]
==
0
:
block
.
replace
(
1
,
[
S
(
'command'
,
'move'
,
s
[
0
],
s
[
1
])])
changed
=
True
elif
s
.
is_command
(
'mult'
):
mflo
=
block
.
peek
()
if
mflo
.
is_command
(
'mflo'
):
if
s
[
1
]
==
1
:
block
.
replace
(
2
,
[
S
(
'command'
,
'move'
,
mflo
[
0
],
s
[
0
])])
changed
=
True
continue
elif
s
[
1
]
==
0
:
block
.
replace
(
2
,
[
S
(
'command'
,
'li'
,
'$1'
,
to_hex
(
0
))])
changed
=
True
continue
shift_amount
=
log
(
s
[
1
],
2
)
if
shift_amount
.
is_integer
():
new_command
=
S
(
'command'
,
'sll'
,
\
mflo
[
0
],
s
[
0
],
\
int
(
shift_amount
))
block
.
replace
(
2
,
[
new_command
])
changed
=
True
return
changed
def
eliminate_dead_code
(
block
):
"""
Dead code elimination:
...
...
src/program.py
View file @
7018b528
...
...
@@ -92,7 +92,6 @@ class Program(Block):
for
b
in
self
.
blocks
:
b
.
verbose
=
self
.
verbose
# Remove the old statement list, since it will probably change
del
self
.
statements
def
perform_dataflow_analysis
(
self
):
...
...
src/statement.py
View file @
7018b528
...
...
@@ -207,7 +207,7 @@ class Statement:
if m:
use.add(m.group(1))
el
se
:
el
if not re.match('
^
\
$
LC
\
d
+
$
', self[1])
:
use.add(self[1])
# Case arg2
...
...
tests/test_dataflow.py
View file @
7018b528
import
unittest
from
src.statement
import
Statement
as
S
from
src.program
import
Program
as
P
from
src.dataflow
import
BasicBlock
as
B
,
find_leaders
,
find_basic_blocks
,
\
generate_flow_graph
...
...
@@ -20,11 +21,8 @@ class TestDataflow(unittest.TestCase):
def
test_find_basic_blocks
(
self
):
s
=
self
.
statements
self
.
assertEqual
(
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)[:
-
1
]),
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
B
(
s
[
4
:]).
statements
]
)
statements
=
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
))
self
.
assertEqual
(
statements
,
[
s
[:
2
],
s
[
2
:
4
],
s
[
4
:]])
def
test_generate_flow_graph_simple
(
self
):
b1
=
B
([
S
(
'command'
,
'foo'
),
S
(
'command'
,
'j'
,
'b2'
)])
...
...
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