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
from src.parser import parse_file
from src.optimize import optimize
from src.writer import write_statements
if __name__ == '__main__':
from sys import argv, exit
......@@ -11,21 +10,15 @@ if __name__ == '__main__':
% argv[0]
exit(1)
# Parse File
original = parse_file(argv[1])
# Parse file
program = parse_file(argv[1])
if len(argv) > 3:
# Save input assembly in new file for easy comparison
out = write_statements(original)
f = open(argv[3], 'w+')
f.write(out)
f.close()
program.save(argv[3])
optimized = optimize(original, verbose=1)
optimize(program, verbose=1)
if len(argv) > 2:
# Save output assembly
out = write_statements(optimized)
f = open(argv[2], 'w+')
f.write(out)
f.close()
program.save(argv[2])
from src.dataflow import find_basic_blocks, generate_flow_graph
import src.liveness as liveness
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 redundancies import remove_redundancies
from advanced import eliminate_common_subexpressions, fold_constants, \
copy_propagation, eliminate_dead_code
import src.liveness as liveness
import src.reaching_definitions as reaching_definitions
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):
def optimize(program, verbose=0):
"""Optimization wrapper function, calls global and basic-block level
optimization functions."""
# Optimize on a global level
# TODO: only count instructions (no directives)
o = len(statements)
remove_redundant_jumps(statements)
g = len(statements)
# Remember original number of statements
o = program.count_instructions()
# Divide into basic blocks
blocks = find_basic_blocks(statements)
# Optimize on a global level
program.optimize_global()
g = program.count_instructions()
# Perform dataflow analysis
generate_flow_graph(blocks)
liveness.create_in_out(blocks)
reaching_definitions.create_in_out(blocks)
program.perform_dataflow_analysis()
# Optimize basic blocks
map(optimize_block, blocks)
program.optimize_blocks()
# Concatenate optimized blocks to obtain
block_statements = map(lambda b: b.statements, blocks)
opt_blocks = reduce(lambda a, b: a + b, block_statements)
b = len(opt_blocks)
b = program.count_instructions()
# Print results
if verbose:
......@@ -85,5 +31,3 @@ def optimize(statements, verbose=0):
print 'After basic block optimization: %d (%d removed)' % (b, g - b)
print 'Statements removed: %d (%d%%)' \
% (o - b, int((o - b) / float(b) * 100))
return opt_blocks
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):
"""
mov $regA, $regA -> --- remove it
......@@ -124,3 +146,5 @@ def remove_redundant_jumps(statements):
s.name = 'bne' if s.is_command('beq') else 'beq'
s[2] = j[0]
statements.replace(3, [s, label])
statements.reset()
import ply.lex as lex
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
......@@ -126,4 +127,4 @@ def parse_file(filename):
except IOError:
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
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
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):
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