Skip to content
Snippets Groups Projects
Commit b45a5aed authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Added Program class for easy handling of statement lists (readability is massively increased).

parent 7e680e4a
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/python #!/usr/bin/python
from src.parser import parse_file from src.parser import parse_file
from src.optimize import optimize from src.optimize import optimize
from src.writer import write_statements
if __name__ == '__main__': if __name__ == '__main__':
from sys import argv, exit from sys import argv, exit
...@@ -11,21 +10,15 @@ if __name__ == '__main__': ...@@ -11,21 +10,15 @@ if __name__ == '__main__':
% argv[0] % argv[0]
exit(1) exit(1)
# Parse File # Parse file
original = parse_file(argv[1]) program = parse_file(argv[1])
if len(argv) > 3: if len(argv) > 3:
# Save input assembly in new file for easy comparison # Save input assembly in new file for easy comparison
out = write_statements(original) program.save(argv[3])
f = open(argv[3], 'w+')
f.write(out)
f.close()
optimized = optimize(original, verbose=1) optimize(program, verbose=1)
if len(argv) > 2: if len(argv) > 2:
# Save output assembly # Save output assembly
out = write_statements(optimized) program.save(argv[2])
f = open(argv[2], 'w+')
f.write(out)
f.close()
from src.dataflow import find_basic_blocks, generate_flow_graph from src.dataflow import find_basic_blocks, generate_flow_graph
import src.liveness as liveness from redundancies import remove_redundancies
import src.reaching_definitions as reaching_definitions
from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \
move_4, load, shift, add
from advanced import eliminate_common_subexpressions, fold_constants, \ from advanced import eliminate_common_subexpressions, fold_constants, \
copy_propagation, eliminate_dead_code copy_propagation, eliminate_dead_code
import src.liveness as liveness
import src.reaching_definitions as reaching_definitions
def optimize(program, verbose=0):
def remove_redundancies(block):
"""Execute all functions that remove redundant statements."""
callbacks = [move_1, move_2, move_3, move_4, load, shift, add]
old_len = -1
changed = False
while old_len != len(block):
old_len = len(block)
block.reset()
while not block.end():
s = block.read()
for callback in callbacks:
if callback(s, block):
changed = True
break
return changed
def optimize_block(block):
"""Optimize a basic block."""
#changed = True
#while changed:
# changed = False
# if remove_redundancies(block): changed = True
# if eliminate_common_subexpressions(block): changed = True
# if fold_constants(block): changed = True
# if copy_propagation(block): changed = True
# if eliminate_dead_code(block): changed = True
# print 'iteration'
while remove_redundancies(block) \
| eliminate_common_subexpressions(block) \
| fold_constants(block) \
| copy_propagation(block) \
| eliminate_dead_code(block):
#| algebraic_transformations(block) \
#print 'iteration'
pass
def optimize(statements, verbose=0):
"""Optimization wrapper function, calls global and basic-block level """Optimization wrapper function, calls global and basic-block level
optimization functions.""" optimization functions."""
# Optimize on a global level # Remember original number of statements
# TODO: only count instructions (no directives) o = program.count_instructions()
o = len(statements)
remove_redundant_jumps(statements)
g = len(statements)
# Divide into basic blocks # Optimize on a global level
blocks = find_basic_blocks(statements) program.optimize_global()
g = program.count_instructions()
# Perform dataflow analysis # Perform dataflow analysis
generate_flow_graph(blocks) program.perform_dataflow_analysis()
liveness.create_in_out(blocks)
reaching_definitions.create_in_out(blocks)
# Optimize basic blocks # Optimize basic blocks
map(optimize_block, blocks) program.optimize_blocks()
# Concatenate optimized blocks to obtain # Concatenate optimized blocks to obtain
block_statements = map(lambda b: b.statements, blocks) b = program.count_instructions()
opt_blocks = reduce(lambda a, b: a + b, block_statements)
b = len(opt_blocks)
# Print results # Print results
if verbose: if verbose:
...@@ -85,5 +31,3 @@ def optimize(statements, verbose=0): ...@@ -85,5 +31,3 @@ def optimize(statements, verbose=0):
print 'After basic block optimization: %d (%d removed)' % (b, g - b) print 'After basic block optimization: %d (%d removed)' % (b, g - b)
print 'Statements removed: %d (%d%%)' \ print 'Statements removed: %d (%d%%)' \
% (o - b, int((o - b) / float(b) * 100)) % (o - b, int((o - b) / float(b) * 100))
return opt_blocks
import re import re
def remove_redundancies(block):
"""Execute all functions that remove redundant statements."""
callbacks = [move_1, move_2, move_3, move_4, load, shift, add]
old_len = -1
changed = False
while old_len != len(block):
old_len = len(block)
block.reset()
while not block.end():
s = block.read()
for callback in callbacks:
if callback(s, block):
changed = True
break
return changed
def move_1(mov, statements): def move_1(mov, statements):
""" """
mov $regA, $regA -> --- remove it mov $regA, $regA -> --- remove it
...@@ -124,3 +146,5 @@ def remove_redundant_jumps(statements): ...@@ -124,3 +146,5 @@ def remove_redundant_jumps(statements):
s.name = 'bne' if s.is_command('beq') else 'beq' s.name = 'bne' if s.is_command('beq') else 'beq'
s[2] = j[0] s[2] = j[0]
statements.replace(3, [s, label]) statements.replace(3, [s, label])
statements.reset()
import ply.lex as lex import ply.lex as lex
import ply.yacc as yacc import ply.yacc as yacc
from statement import Statement as S, Block from statement import Statement as S
from program import Program
# Global statements administration # Global statements administration
...@@ -126,4 +127,4 @@ def parse_file(filename): ...@@ -126,4 +127,4 @@ def parse_file(filename):
except IOError: except IOError:
raise Exception('File "%s" could not be opened' % filename) raise Exception('File "%s" could not be opened' % filename)
return Block(statements) return Program(statements)
from statement import Block
from dataflow import find_basic_blocks, generate_flow_graph
from optimize.redundancies import remove_redundant_jumps, remove_redundancies
from optimize.advanced import eliminate_common_subexpressions, \
fold_constants, copy_propagation, eliminate_dead_code
from writer import write_statements
import liveness
import reaching_definitions
class Program(Block):
def __init__(self, statements):
"""Start with a given statement list."""
Block.__init__(self, statements)
def __iter__(self):
return iter(self.blocks)
def __len__(self):
"""Get the number of statements in the program."""
return len(self.statements) if hasattr(self, 'statements') \
else reduce(lambda a, b: len(a) + len(b), self.blocks, 0)
def get_statements(self):
"""Concatenate the statements of all blocks and return the resulting
list."""
if hasattr(self, 'statements'):
return self.statements
else:
return reduce(lambda a, b: a + b,
[b.statements for b in self.blocks])
def count_instructions(self):
"""Count the number of statements that are commands or labels."""
return len(filter(lambda s: s.is_command() or s.is_label(),
self.get_statements()))
def optimize_global(self):
"""Optimize on a global level."""
remove_redundant_jumps(self)
def optimize_blocks(self):
"""Optimize on block level. Keep executing all optimizations until no
more changes occur."""
self.program_iterations = self.block_iterations = 0
program_changed = True
while program_changed:
self.program_iterations += 1
program_changed = False
for block in self.blocks:
self.block_iterations += 1
block_changed = True
while block_changed:
block_changed = False
if remove_redundancies(block):
block_changed = True
if eliminate_common_subexpressions(block):
block_changed = True
if fold_constants(block):
block_changed = True
if copy_propagation(block):
block_changed = True
if eliminate_dead_code(block):
block_changed = True
if block_changed:
program_changed = True
def find_basic_blocks(self):
"""Divide the statement list into basic blocks."""
self.blocks = find_basic_blocks(self.statements)
# Remove the old statment list, since it will probably change
del self.statements
def perform_dataflow_analysis(self):
"""Perform dataflow analysis:
-Divide the statement list into basic blocks
- Generate flow graph
- Create liveness sets: def, use, in, out
- Create reaching definitions sets: gen, kill, in, out"""
self.find_basic_blocks()
generate_flow_graph(self.blocks)
liveness.create_in_out(self.blocks)
reaching_definitions.create_in_out(self.blocks)
def save(self, filename):
"""Save the program in the specified file."""
f = open(filename, 'w+')
f.write(write_statements(self.get_statements()))
f.close()
import unittest import unittest
from src.optimize.redundancies import remove_redundant_jumps from src.optimize.redundancies import remove_redundant_jumps
from src.optimize import optimize_block from src.program import Program
from src.statement import Statement as S, Block as B from src.statement import Statement as S, Block as B
def optimize_block(block):
"""Optimize a basic block using a Program object."""
program = Program([])
program.blocks = [block]
del program.statements
program.optimize_blocks()
return program.blocks
class TestOptimize(unittest.TestCase): class TestOptimize(unittest.TestCase):
def setUp(self): def setUp(self):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment