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):
...
@@ -23,55 +23,59 @@ class BasicBlock(Block):
block
.
dominated_by
.
append
(
self
)
block
.
dominated_by
.
append
(
self
)
def
find_leaders
(
statements
):
def
find_leaders
(
statements
,
return_jump_targets
=
False
):
"""Determine the leaders, which are:
"""
1. The first statement.
- Determine the leaders, which are:
2. Any statement that is the target of a jump.
1. The first statement.
3. Any statement that follows directly follows a jump."""
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
]
leaders
=
[
0
]
jump_target
_label
s
=
[]
jump_targets
=
[]
# Append statements following jumps and save jump target labels
# Append statements following jumps and save jump target labels
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
if
statement
.
is_jump
():
if
statement
.
is_jump
():
leaders
.
append
(
i
+
2
)
leaders
.
append
(
i
+
2
)
jump_target
_label
s
.
append
(
statement
[
-
1
])
jump_targets
.
append
(
statement
[
-
1
])
# Append jump targets
# Append jump targets
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
for
i
,
statement
in
enumerate
(
statements
[
1
:]):
if
i
+
1
not
in
leaders
\
if
i
+
1
not
in
leaders
\
and
statement
.
is_label
()
\
and
statement
.
is_label
()
\
and
statement
.
name
in
jump_target
_label
s
:
and
statement
.
name
in
jump_targets
:
leaders
.
append
(
i
+
1
)
leaders
.
append
(
i
+
1
)
leaders
.
sort
()
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
"""Divide a statement list into basic blocks. Returns a list of basic
blocks, which are also statement lists."""
blocks, which are also statement lists."""
leaders
=
find_leaders
(
statements
)
leaders
,
jump_targets
=
find_leaders
(
statements
,
True
)
blocks
=
[]
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
[
i
]:
leaders
[
i
+
1
]]))
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
-
1
]:]))
blocks
.
append
(
BasicBlock
(
statements
[
leaders
[
-
1
]:]))
# Add a target block for unknown jump targets
# 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
):
def
generate_flow_graph
(
blocks
):
"""Add flow graph edge administration of an ordered sequence of basic
"""Add flow graph edge administration of an ordered sequence of basic
blocks."""
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
]
last_statement
=
b
[
-
1
]
if
last_statement
.
is_jump
():
if
last_statement
.
is_jump
():
...
@@ -81,15 +85,15 @@ def generate_flow_graph(blocks):
...
@@ -81,15 +85,15 @@ def generate_flow_graph(blocks):
# label matches the jump target
# label matches the jump target
target_found
=
False
target_found
=
False
for
other
in
blocks
[:
-
1
]
:
for
other
in
blocks
:
if
other
[
0
].
is_label
(
target
):
if
other
[
0
].
is_label
(
target
):
b
.
add_edge_to
(
other
)
b
.
add_edge_to
(
other
)
target_found
=
True
target_found
=
True
# If the jump target is outside the program, add an edge to the
# If the jump target is outside the program, add an edge to the
# dummy block
# dummy block
if
not
target_found
:
#
if not target_found:
b
.
add_edge_to
(
dummy_block
)
#
b.add_edge_to(dummy_block)
# A branch and jump-and-line instruction also creates an edge to
# A branch and jump-and-line instruction also creates an edge to
# the next block
# the next block
...
...
src/liveness.py
View file @
7018b528
...
@@ -2,13 +2,22 @@ from copy import copy
...
@@ -2,13 +2,22 @@ from copy import copy
RESERVED_REGISTERS
=
[
'$fp'
,
'$sp'
,
'$31'
]
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."""
"""Check if a register is dead after a certain point in a basic block."""
if
reg
in
RESERVED_REGISTERS
:
if
reg
in
RESERVED_REGISTERS
:
return
False
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
:
if
index
<
len
(
block
)
-
1
:
for
s
in
block
[
index
+
1
:]:
for
s
in
block
[
index
+
1
:]:
# If used, the previous definition is live
# If used, the previous definition is live
...
@@ -25,16 +34,15 @@ def is_reg_dead_after(reg, block, index):
...
@@ -25,16 +34,15 @@ def is_reg_dead_after(reg, block, index):
def
create_use_def
(
block
):
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
()
used
=
set
()
defined
=
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
.
use_set
=
set
()
block
.
def_set
=
set
()
block
.
def_set
=
set
()
...
...
src/optimize/__init__.py
View file @
7018b528
...
@@ -15,14 +15,11 @@ def optimize(program, verbose=0):
...
@@ -15,14 +15,11 @@ def optimize(program, verbose=0):
iterations
=
0
iterations
=
0
while
changed
:
while
changed
:
<<<<<<<
HEAD
iterations
+=
1
iterations
+=
1
if
verbose
>
1
:
if
verbose
>
1
:
print
'main iteration %d'
,
iterations
print
'main iteration %d'
,
iterations
=======
>>>>>>>
98
c43ff02c474a62e42ac89ba9fe20be98f9eccd
changed
=
False
changed
=
False
# Optimize on a global level
# Optimize on a global level
...
...
src/optimize/advanced.py
View file @
7018b528
...
@@ -4,31 +4,32 @@ from src.statement import Statement as S
...
@@ -4,31 +4,32 @@ from src.statement import Statement as S
from
src.liveness
import
is_reg_dead_after
from
src.liveness
import
is_reg_dead_after
def
reg_can_be_used_in
(
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
#
"""Check if a register addres safely be used in a block section using local
dataflow analysis."""
#
dataflow analysis."""
# Check if the register used or defined in the block section
#
# Check if the register used or defined in the block section
for
s
in
block
[
start
:
end
]:
#
for s in block[start:end]:
if
s
.
uses
(
reg
)
or
s
.
defines
(
reg
):
#
if s.uses(reg) or s.defines(reg):
return
False
#
return False
#
# Check if the register is used inside the block after the specified
#
# Check if the register is used inside the block after the specified
# section, without having been re-assigned first
#
# section, without having been re-assigned first
for
s
in
block
[
end
:]:
#
for s in block[end:]:
if
s
.
uses
(
reg
):
#
if s.uses(reg):
return
False
#
return False
elif
s
.
defines
(
reg
):
#
elif s.defines(reg):
return
True
#
return True
#
return
reg
not
in
block
.
live_out
#
return reg not in block.live_out
def
find_free_reg
(
block
,
start
,
end
):
def
find_free_reg
(
block
,
start
):
"""Find a temporary register that is free in a given list of statements."""
"""Find a temporary register that is free in a given list of statements."""
for
i
in
xrange
(
8
,
16
):
for
i
in
xrange
(
8
,
16
):
tmp
=
'$%d'
%
i
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
return
tmp
raise
Exception
(
'No temporary register is available.'
)
raise
Exception
(
'No temporary register is available.'
)
...
@@ -78,7 +79,7 @@ def eliminate_common_subexpressions(block):
...
@@ -78,7 +79,7 @@ def eliminate_common_subexpressions(block):
occurrences
.
append
(
block
.
pointer
-
1
)
occurrences
.
append
(
block
.
pointer
-
1
)
if
len
(
occurrences
)
>
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
# Replace all occurrences with a move statement
message
=
'Common subexpression reference: %s %s'
\
message
=
'Common subexpression reference: %s %s'
\
...
@@ -341,49 +342,6 @@ def copy_propagation(block):
...
@@ -341,49 +342,6 @@ def copy_propagation(block):
return
changed
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
):
def
eliminate_dead_code
(
block
):
"""
"""
Dead code elimination:
Dead code elimination:
...
...
src/program.py
View file @
7018b528
...
@@ -92,7 +92,6 @@ class Program(Block):
...
@@ -92,7 +92,6 @@ class Program(Block):
for
b
in
self
.
blocks
:
for
b
in
self
.
blocks
:
b
.
verbose
=
self
.
verbose
b
.
verbose
=
self
.
verbose
# Remove the old statement list, since it will probably change
del
self
.
statements
del
self
.
statements
def
perform_dataflow_analysis
(
self
):
def
perform_dataflow_analysis
(
self
):
...
...
src/statement.py
View file @
7018b528
...
@@ -207,7 +207,7 @@ class Statement:
...
@@ -207,7 +207,7 @@ class Statement:
if m:
if m:
use.add(m.group(1))
use.add(m.group(1))
el
se
:
el
if not re.match('
^
\
$
LC
\
d
+
$
', self[1])
:
use.add(self[1])
use.add(self[1])
# Case arg2
# Case arg2
...
...
tests/test_dataflow.py
View file @
7018b528
import
unittest
import
unittest
from
src.statement
import
Statement
as
S
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
,
\
from
src.dataflow
import
BasicBlock
as
B
,
find_leaders
,
find_basic_blocks
,
\
generate_flow_graph
generate_flow_graph
...
@@ -20,11 +21,8 @@ class TestDataflow(unittest.TestCase):
...
@@ -20,11 +21,8 @@ class TestDataflow(unittest.TestCase):
def
test_find_basic_blocks
(
self
):
def
test_find_basic_blocks
(
self
):
s
=
self
.
statements
s
=
self
.
statements
self
.
assertEqual
(
statements
=
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
))
map
(
lambda
b
:
b
.
statements
,
find_basic_blocks
(
s
)[:
-
1
]),
self
.
assertEqual
(
statements
,
[
s
[:
2
],
s
[
2
:
4
],
s
[
4
:]])
[
B
(
s
[:
2
]).
statements
,
B
(
s
[
2
:
4
]).
statements
,
B
(
s
[
4
:]).
statements
]
)
def
test_generate_flow_graph_simple
(
self
):
def
test_generate_flow_graph_simple
(
self
):
b1
=
B
([
S
(
'command'
,
'foo'
),
S
(
'command'
,
'j'
,
'b2'
)])
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