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

Merge branch 'master' of github.com:taddeus/peephole

parents 292754aa 2c24b0b7
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,45 @@ def optimize_global(statements): ...@@ -7,6 +7,45 @@ def optimize_global(statements):
"""Optimize statement sequences on a global level.""" """Optimize statement sequences on a global level."""
old_len = -1 old_len = -1
while old_len != len(statements):
old_len = len(statements)
while not statements.end():
s = statements.read()
# beq/bne ..., $Lx -> bne/beq ..., $Ly
# j $Ly $Lx:
# $Lx:
if s.is_command('beq') or s.is_command('bne'):
following = statements.peek(2)
if len(following) == 2:
j, label = following
if j.is_command('j') and label.is_label(s[2]):
if s.is_command('beq'):
s.name = 'bne'
else:
s.name = 'beq'
s[2] = j[0]
statements.replace(3, [s, label])
def optimize_blocks(blocks):
"""Call the optimizer for each basic block. Do this several times until
no more optimizations are achieved."""
optimized = []
for block in blocks:
optimize_block(block)
return blocks
def optimize_block(statements):
"""Optimize a basic block."""
old_len = -1
while old_len != len(statements): while old_len != len(statements):
old_len = len(statements) old_len = len(statements)
...@@ -67,57 +106,15 @@ def optimize_global(statements): ...@@ -67,57 +106,15 @@ def optimize_global(statements):
lw[-1] = str(s[2]) + lw[-1][1:] lw[-1] = str(s[2]) + lw[-1][1:]
statements.replace(2, [lw]) statements.replace(2, [lw])
continue continue
# move $RegA, $RegB -> move $RegA, $RegB
# move $RegB, $RegA
if s.is_command('move'):
move = statements.peek()
# beq/bne ..., $Lx -> bne/beq ..., $Ly if move.is_command('move') and move[0] == s[1] and \
# j $Ly $Lx: move[1] == s[0]:
# $Lx: statements.replace(2, [s])
if s.is_command('beq') or s.is_command('bne'):
following = statements.peek(2)
if len(following) == 2:
j, label = following
if j.is_command('j') and label.is_label(s[2]):
if s.is_command('beq'):
s.name = 'bne'
else:
s.name = 'beq'
s[2] = j[0]
statements.replace(3, [s, label])
def optimize_blocks(blocks):
"""Call the optimizer for each basic block. Do this several times until
no more optimizations are achieved."""
changed = True
while changed:
changed = False
optimized = []
for block in blocks:
block_changed, b = optimize_block(block)
optimized.append(b)
if block_changed:
changed = True
blocks = optimized
return reduce(lambda a, b: a + b, blocks, [])
def optimize_block(statements):
"""Optimize a basic block."""
changed = False
output_statements = []
for statement in statements:
new_statement = statement
output_statements.append(new_statement)
return changed, output_statements
def optimize(statements, verbose=0): def optimize(statements, verbose=0):
...@@ -130,8 +127,7 @@ def optimize(statements, verbose=0): ...@@ -130,8 +127,7 @@ def optimize(statements, verbose=0):
# Optimize basic blocks # Optimize basic blocks
basic_blocks = find_basic_blocks(statements) basic_blocks = find_basic_blocks(statements)
# blocks = optimize_blocks(basic_blocks) blocks = optimize_blocks(basic_blocks)
blocks = basic_blocks
block_statements = map(lambda b: b.statements, blocks) block_statements = map(lambda b: b.statements, blocks)
opt_blocks = reduce(lambda a, b: a + b, block_statements) opt_blocks = reduce(lambda a, b: a + b, block_statements)
b = len(opt_blocks) b = len(opt_blocks)
...@@ -147,7 +143,7 @@ def optimize(statements, verbose=0): ...@@ -147,7 +143,7 @@ def optimize(statements, verbose=0):
print 'Original statements: %d' % o print 'Original statements: %d' % o
print 'After global optimization: %d' % g print 'After global optimization: %d' % g
print 'After basic blocks optimization: %d' % b print 'After basic blocks optimization: %d' % b
print 'Speedup: %d (%d%%)' \ print 'Optimization: %d (%d%%)' \
% (b - o, int((b - o) / o * 100)) % (b - o, int((b - o) / float(o) * 100))
return opt_blocks return opt_blocks
...@@ -118,7 +118,10 @@ class Block: ...@@ -118,7 +118,10 @@ class Block:
def peek(self, count=1): def peek(self, count=1):
"""Read the statements until an offset from the current pointer """Read the statements until an offset from the current pointer
position.""" position."""
if self.end():
return Statement('empty', '') if count == 1 else []
return self.statements[self.pointer] if count == 1 \ return self.statements[self.pointer] if count == 1 \
else self.statements[self.pointer:self.pointer + count] else self.statements[self.pointer:self.pointer + count]
......
import unittest import unittest
from src.optimize import optimize_global from src.optimize import optimize_global, optimize_block, optimize_blocks
from src.statement import Statement as S, Block as B from src.statement import Statement as S, Block as B
...@@ -9,26 +9,26 @@ class TestOptimize(unittest.TestCase): ...@@ -9,26 +9,26 @@ class TestOptimize(unittest.TestCase):
def setUp(self): def setUp(self):
pass pass
def test_optimize_global_movaa(self): def test_optimize_block_movaa(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
block = B([foo, block = B([foo,
S('command', 'move', '$regA', '$regA'), S('command', 'move', '$regA', '$regA'),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, bar]) self.assertEquals(block.statements, [foo, bar])
def test_optimize_global_movab(self): def test_optimize_block_movab(self):
foo = S('command', 'foo') foo = S('command', 'foo')
move = S('command', 'move', '$regA', '$regB') move = S('command', 'move', '$regA', '$regB')
bar = S('command', 'bar') bar = S('command', 'bar')
block = B([foo, block = B([foo,
move, move,
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, move, bar]) self.assertEquals(block.statements, [foo, move, bar])
def test_optimize_global_movinst_true(self): def test_optimize_block_movinst_true(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -36,12 +36,12 @@ class TestOptimize(unittest.TestCase): ...@@ -36,12 +36,12 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regA', '$regB'), S('command', 'move', '$regA', '$regB'),
S('command', 'addu', '$regA', '$regA', 2), S('command', 'addu', '$regA', '$regA', 2),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'addu', '$regA', '$regB', 2), S('command', 'addu', '$regA', '$regB', 2),
bar]) bar])
def test_optimize_global_movinst_false(self): def test_optimize_block_movinst_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
statements = [foo, \ statements = [foo, \
...@@ -50,10 +50,10 @@ class TestOptimize(unittest.TestCase): ...@@ -50,10 +50,10 @@ class TestOptimize(unittest.TestCase):
bar] bar]
block = B(statements) block = B(statements)
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, statements) self.assertEquals(block.statements, statements)
def test_optimize_global_instr_mov_jal_true(self): def test_optimize_block_instr_mov_jal_true(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -62,14 +62,14 @@ class TestOptimize(unittest.TestCase): ...@@ -62,14 +62,14 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$4', '$regA'), S('command', 'move', '$4', '$regA'),
S('command', 'jal', 'L1'), S('command', 'jal', 'L1'),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'addu', '$4', '$regC', 2), S('command', 'addu', '$4', '$regC', 2),
S('command', 'jal', 'L1'), S('command', 'jal', 'L1'),
bar]) bar])
def test_optimize_global_instr_mov_jal_false(self): def test_optimize_block_instr_mov_jal_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -79,11 +79,11 @@ class TestOptimize(unittest.TestCase): ...@@ -79,11 +79,11 @@ class TestOptimize(unittest.TestCase):
S('command', 'jal', 'L1'), \ S('command', 'jal', 'L1'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_global_sw_ld_true(self): def test_optimize_block_sw_ld_true(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -91,13 +91,13 @@ class TestOptimize(unittest.TestCase): ...@@ -91,13 +91,13 @@ class TestOptimize(unittest.TestCase):
S('command', 'sw', '$regA', '$regB'), S('command', 'sw', '$regA', '$regB'),
S('command', 'ld', '$regA', '$regC'), S('command', 'ld', '$regA', '$regC'),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'sw', '$regA', '$regB'), S('command', 'sw', '$regA', '$regB'),
bar]) bar])
def test_optimize_global_sw_ld_false(self): def test_optimize_block_sw_ld_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -106,23 +106,23 @@ class TestOptimize(unittest.TestCase): ...@@ -106,23 +106,23 @@ class TestOptimize(unittest.TestCase):
S('command', 'ld', '$regD', '$regC'), \ S('command', 'ld', '$regD', '$regC'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_global_shift_true(self): def test_optimize_block_shift_true(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
block = B([foo, block = B([foo,
S('command', 'sll', '$regA', '$regA', 0), S('command', 'sll', '$regA', '$regA', 0),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
bar]) bar])
def test_optimize_global_shift_false(self): def test_optimize_block_shift_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -130,7 +130,7 @@ class TestOptimize(unittest.TestCase): ...@@ -130,7 +130,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'sll', '$regA', '$regB', 0), \ S('command', 'sll', '$regA', '$regB', 0), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
...@@ -138,11 +138,11 @@ class TestOptimize(unittest.TestCase): ...@@ -138,11 +138,11 @@ class TestOptimize(unittest.TestCase):
S('command', 'sll', '$regA', '$regA', 1), \ S('command', 'sll', '$regA', '$regA', 1), \
bar] bar]
block2 = B(arguments2) block2 = B(arguments2)
optimize_global(block2) optimize_block(block2)
self.assertEquals(block2.statements, arguments2) self.assertEquals(block2.statements, arguments2)
def test_optimize_global_add_lw_true(self): def test_optimize_block_add_lw_true(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -150,13 +150,13 @@ class TestOptimize(unittest.TestCase): ...@@ -150,13 +150,13 @@ class TestOptimize(unittest.TestCase):
S('command', 'add', '$regA', '$regA', 10), S('command', 'add', '$regA', '$regA', 10),
S('command', 'lw', '$regB', '0($regA)'), S('command', 'lw', '$regB', '0($regA)'),
bar]) bar])
optimize_global(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'lw', '$regB', '10($regA)'), S('command', 'lw', '$regB', '10($regA)'),
bar]) bar])
def test_optimize_global_add_lw_false(self): def test_optimize_block_add_lw_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
...@@ -165,7 +165,7 @@ class TestOptimize(unittest.TestCase): ...@@ -165,7 +165,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'lw', '$regB', '0($regC)'), \ S('command', 'lw', '$regB', '0($regC)'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_block(block)
arguments2 = [foo, \ arguments2 = [foo, \
S('command', 'add', '$regA', '$regB', 10), \ S('command', 'add', '$regA', '$regB', 10), \
...@@ -178,7 +178,7 @@ class TestOptimize(unittest.TestCase): ...@@ -178,7 +178,7 @@ class TestOptimize(unittest.TestCase):
S('command', 'lw', '$regB', '1($regA)'), \ S('command', 'lw', '$regB', '1($regA)'), \
bar] bar]
block3 = B(arguments3) block3 = B(arguments3)
optimize_global(block3) optimize_block(block3)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
self.assertEquals(block2.statements, arguments2) self.assertEquals(block2.statements, arguments2)
...@@ -243,3 +243,42 @@ class TestOptimize(unittest.TestCase): ...@@ -243,3 +243,42 @@ class TestOptimize(unittest.TestCase):
optimize_global(block) optimize_global(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_block_move_move_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'move', '$regA', '$regB'),
S('command', 'move', '$regB', '$regA'),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
S('command', 'move', '$regA', '$regB'),
bar])
def test_optimize_block_mov_mov_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'move', '$regA', '$regB'), \
S('command', 'move', '$regB', '$regC'), \
bar]
block = B(arguments)
optimize_block(block)
self.assertEquals(block.statements, arguments)
def test_optimize_blocks(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block1 = B([foo, bar])
block2 = B([bar, foo])
blocks_in = [block1, block2];
blocks_out = optimize_blocks(blocks_in)
self.assertEquals(blocks_in, blocks_out)
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