Commit b45a5aed authored by Taddeus Kroes's avatar Taddeus Kroes

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

parent 7e680e4a
#!/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):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment