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

Moved optimization implementations to module 'optimize'.

parent af811f6e
No related branches found
No related tags found
No related merge requests found
from copy import copy #from copy import copy
from statement import Block from statement import Block
......
import re
def redundant_move_1(mov, statements):
"""
mov $regA, $regA -> --- remove it
"""
if mov.is_command('move') and mov[0] == mov[1]:
statements.replace(1, [])
return True
def redundant_move_2(mov, statements):
"""
mov $regA, $regB -> instr $regA, $regB, ...
instr $regA, $regA, ...
"""
if mov.is_command('move'):
ins = statements.peek()
if ins and len(ins) >= 2 and ins[0] == mov[0] and ins[1] == mov[0]:
ins[1] = mov[1]
statements.replace(2, [ins])
return True
def redundant_move_3(ins, statements):
"""
instr $regA, ... -> instr $4, ...
mov $4, $regA jal XX
jal XX
"""
if ins.is_command() and len(ins):
following = statements.peek(2)
if len(following) == 2:
mov, jal = following
if mov.is_command('move') and mov[1] == ins[0] \
and re.match('^\$[4-7]$', mov[0]) \
and jal.is_command('jal'):
ins[0] = mov[0]
statements.replace(2, [ins])
return True
def redundant_move_4(mov1, statements):
"""
mov $RegA, $RegB -> move $RegA, $RegB
mov $RegB, $RegA
"""
if mov1.is_command('move'):
mov2 = statements.peek()
if mov2.is_command('move') and mov2[0] == mov1[1] and \
mov2[1] == mov1[0]:
statements.replace(2, [mov1])
return True
def redundant_load(sw, statements):
"""
sw $regA, XX -> sw $regA, XX
ld $regA, XX
"""
if sw.is_command('sw'):
ld = statements.peek()
if ld.is_command('lw') and ld.args == sw.args:
statements.replace(2, [sw])
return True
def redundant_shift(shift, statements):
"""
shift $regA, $regA, 0 -> --- remove it
"""
if shift.is_shift() and shift[0] == shift[1] and shift[2] == 0:
statements.replace(1, [])
return True
def redundant_add(add, statements):
"""
add $regA, $regA, X -> lw ..., X($regA)
lw ..., 0($regA)
"""
if add.is_command('addu') and add[0] == add[1] and isinstance(add[2], int):
lw = statements.peek()
if lw.is_load() and lw[-1] == '0(%s)' % add[0]:
lw[-1] = '%s(%s)' % (add[2], add[0])
statements.replace(2, [lw])
return True
import re from src.dataflow import find_basic_blocks
from glob import redundant_move_1, redundant_move_2, \
from dataflow import find_basic_blocks redundant_move_3, redundant_move_4, redundant_load, \
redundant_shift, redundant_add
def optimize_global(statements): def optimize_global(statements):
...@@ -16,34 +17,31 @@ def optimize_global(statements): ...@@ -16,34 +17,31 @@ def optimize_global(statements):
# beq/bne ..., $Lx -> bne/beq ..., $Ly # beq/bne ..., $Lx -> bne/beq ..., $Ly
# j $Ly $Lx: # j $Ly $Lx:
# $Lx: # $Lx:
if s.is_command('beq') or s.is_command('bne'): if s.is_command('beq', 'bne'):
following = statements.peek(2) following = statements.peek(2)
if len(following) == 2: if len(following) == 2:
j, label = following j, label = following
if j.is_command('j') and label.is_label(s[2]): if j.is_command('j') and label.is_label(s[2]):
if s.is_command('beq'): s.name = 'bne' if s.is_command('beq') else 'beq'
s.name = 'bne'
else:
s.name = 'beq'
s[2] = j[0] s[2] = j[0]
statements.replace(3, [s, label]) statements.replace(3, [s, label])
def optimize_blocks(blocks): #def optimize_blocks(blocks):
"""Call the optimizer for each basic block. Do this several times until # """Call the optimizer for each basic block. Do this several times until
no more optimizations are achieved.""" # no more optimizations are achieved."""
optimized = [] # for block in blocks:
# optimize_block(block)
for block in blocks: #
optimize_block(block) # return blocks
return blocks
def optimize_block(statements): def optimize_block(statements):
"""Optimize a basic block.""" """Optimize a basic block."""
glob = [redundant_move_1, redundant_move_2, redundant_move_3, \
redundant_move_4, redundant_load, redundant_shift, redundant_add]
old_len = -1 old_len = -1
while old_len != len(statements): while old_len != len(statements):
...@@ -52,69 +50,17 @@ def optimize_block(statements): ...@@ -52,69 +50,17 @@ def optimize_block(statements):
while not statements.end(): while not statements.end():
s = statements.read() s = statements.read()
# mov $regA, $regA -> --- remove it cont = False
if s.is_command('move') and s[0] == s[1]:
statements.replace(1, [])
continue
# mov $regA, $regB -> instr $regA, $regB, ...
# instr $regA, $regA, ...
if s.is_command('move'):
ins = statements.peek()
if ins and len(ins) >= 2 and ins[0] == s[0] and ins[1] == s[0]: for callback in glob:
ins[1] = s[1] if callback(s, statements):
statements.replace(2, [ins]) cont = True
continue break
# instr $regA, ... -> instr $4, ... if cont:
# mov $4, $regA jal XX
# jal XX
if s.is_command() and len(s):
following = statements.peek(2)
if len(following) == 2:
mov, jal = following
if mov.is_command('move') and mov[1] == s[0] \
and re.match('^\$[4-7]$', mov[0]) \
and jal.is_command('jal'):
s[0] = mov[0]
statements.replace(2, [s])
continue
# sw $regA, XX -> sw $regA, XX
# ld $regA, XX
if s.is_command('sw'):
ld = statements.peek()
if ld.is_command('ld') and ld[0] == s[0]:
statements.replace(2, [s])
continue
# shift $regA, $regA, 0 -> --- remove it
if s.is_shift() and s[0] == s[1] and s[2] == 0:
statements.replace(1, [])
continue continue
# add $regA, $regA, X -> lw ..., X($regA) # Other optimizations...
# lw ..., 0($regA)
if s.is_command('add') and s[0] == s[1]:
lw = statements.peek()
if lw.is_command('lw') and lw[-1] == '0(%s)' % s[0]:
lw[-1] = str(s[2]) + lw[-1][1:]
statements.replace(2, [lw])
continue
# move $RegA, $RegB -> move $RegA, $RegB
# move $RegB, $RegA
if s.is_command('move'):
move = statements.peek()
if move.is_command('move') and move[0] == s[1] and \
move[1] == s[0]:
statements.replace(2, [s])
def optimize(statements, verbose=0): def optimize(statements, verbose=0):
...@@ -126,8 +72,8 @@ def optimize(statements, verbose=0): ...@@ -126,8 +72,8 @@ def optimize(statements, verbose=0):
g = len(statements) g = len(statements)
# Optimize basic blocks # Optimize basic blocks
basic_blocks = find_basic_blocks(statements) blocks = find_basic_blocks(statements)
blocks = optimize_blocks(basic_blocks) map(optimize_block, 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)
......
...@@ -45,9 +45,8 @@ class Statement: ...@@ -45,9 +45,8 @@ class Statement:
return self.stype == 'label' if name == None \ return self.stype == 'label' if name == None \
else self.stype == 'label' and self.name == name else self.stype == 'label' and self.name == name
def is_command(self, name=None): def is_command(self, *args):
return self.stype == 'command' if name == None \ return self.stype == 'command' and (not len(args) or self.name in args)
else self.stype == 'command' and self.name == name
def is_jump(self): def is_jump(self):
"""Check if the statement is a jump.""" """Check if the statement is a jump."""
...@@ -118,10 +117,10 @@ class Block: ...@@ -118,10 +117,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(): if self.end():
return Statement('empty', '') if count == 1 else [] 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, optimize_block, optimize_blocks from src.optimize.main 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
...@@ -17,7 +17,7 @@ class TestOptimize(unittest.TestCase): ...@@ -17,7 +17,7 @@ class TestOptimize(unittest.TestCase):
bar]) bar])
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, [foo, bar]) self.assertEquals(block.statements, [foo, bar])
def test_optimize_block_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')
...@@ -27,20 +27,20 @@ class TestOptimize(unittest.TestCase): ...@@ -27,20 +27,20 @@ class TestOptimize(unittest.TestCase):
bar]) bar])
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, [foo, move, bar]) self.assertEquals(block.statements, [foo, move, bar])
def test_optimize_block_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')
block = B([foo, block = B([foo,
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_block(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_block_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')
...@@ -48,31 +48,31 @@ class TestOptimize(unittest.TestCase): ...@@ -48,31 +48,31 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regA', '$regB'), \ S('command', 'move', '$regA', '$regB'), \
S('command', 'addu', '$regA', '$regC', 2), \ S('command', 'addu', '$regA', '$regC', 2), \
bar] bar]
block = B(statements) block = B(statements)
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, statements) self.assertEquals(block.statements, statements)
def test_optimize_block_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')
block = B([foo, block = B([foo,
S('command', 'addu', '$regA', '$regC', 2), S('command', 'addu', '$regA', '$regC', 2),
S('command', 'move', '$4', '$regA'), S('command', 'move', '$4', '$regA'),
S('command', 'jal', 'L1'), S('command', 'jal', 'L1'),
bar]) bar])
optimize_block(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_block_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')
arguments = [foo, \ arguments = [foo, \
S('command', 'addu', '$regA', '$regC', 2), \ S('command', 'addu', '$regA', '$regC', 2), \
S('command', 'move', '$3', '$regA'), \ S('command', 'move', '$3', '$regA'), \
...@@ -80,130 +80,129 @@ class TestOptimize(unittest.TestCase): ...@@ -80,130 +80,129 @@ class TestOptimize(unittest.TestCase):
bar] bar]
block = B(arguments) block = B(arguments)
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_block_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')
block = B([foo, block = B([foo,
S('command', 'sw', '$regA', '$regB'), S('command', 'sw', '$regA', '$regB'),
S('command', 'ld', '$regA', '$regC'), S('command', 'lw', '$regA', '$regB'),
bar]) bar])
optimize_block(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_block_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')
arguments = [foo, \ arguments = [foo, \
S('command', 'sw', '$regA', '$regB'), \ S('command', 'sw', '$regA', '$regB'), \
S('command', 'ld', '$regD', '$regC'), \ S('command', 'lw', '$regD', '$regC'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_block_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_block(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo, bar])
bar])
def test_optimize_block_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')
arguments = [foo, \ arguments = [foo, \
S('command', 'sll', '$regA', '$regB', 0), \ S('command', 'sll', '$regA', '$regB', 0), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
arguments2 = [foo, \ arguments2 = [foo, \
S('command', 'sll', '$regA', '$regA', 1), \ S('command', 'sll', '$regA', '$regA', 1), \
bar] bar]
block2 = B(arguments2) block2 = B(arguments2)
optimize_block(block2) optimize_block(block2)
self.assertEquals(block2.statements, arguments2) self.assertEquals(block2.statements, arguments2)
def test_optimize_block_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')
block = B([foo, block = B([foo,
S('command', 'add', '$regA', '$regA', 10), S('command', 'addu', '$regA', '$regA', 10),
S('command', 'lw', '$regB', '0($regA)'), S('command', 'lw', '$regB', '0($regA)'),
bar]) bar])
optimize_block(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_block_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')
arguments = [foo, \ arguments = [foo, \
S('command', 'add', '$regA', '$regA', 10), \ S('command', 'addu', '$regA', '$regA', 10), \
S('command', 'lw', '$regB', '0($regC)'), \ S('command', 'lw', '$regB', '0($regC)'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_block(block) optimize_block(block)
arguments2 = [foo, \ arguments2 = [foo, \
S('command', 'add', '$regA', '$regB', 10), \ S('command', 'addu', '$regA', '$regB', 10), \
S('command', 'lw', '$regB', '0($regA)'), \ S('command', 'lw', '$regB', '0($regA)'), \
bar] bar]
block2 = B(arguments2) block2 = B(arguments2)
arguments3 = [foo, \ arguments3 = [foo, \
S('command', 'add', '$regA', '$regA', 10), \ S('command', 'addu', '$regA', '$regA', 10), \
S('command', 'lw', '$regB', '1($regA)'), \ S('command', 'lw', '$regB', '1($regA)'), \
bar] bar]
block3 = B(arguments3) block3 = B(arguments3)
optimize_block(block3) optimize_block(block3)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
self.assertEquals(block2.statements, arguments2) self.assertEquals(block2.statements, arguments2)
self.assertEquals(block3.statements, arguments3) self.assertEquals(block3.statements, arguments3)
def test_optimize_global_beq_j_true(self): def test_optimize_global_beq_j_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', 'beq', '$regA', '$regB', '$Lx'), S('command', 'beq', '$regA', '$regB', '$Lx'),
S('command', 'j', '$Ly'), S('command', 'j', '$Ly'),
S('label', '$Lx'), S('label', '$Lx'),
bar]) bar])
optimize_global(block) optimize_global(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'bne', '$regA', '$regB', '$Ly'), S('command', 'bne', '$regA', '$regB', '$Ly'),
S('label', '$Lx'), S('label', '$Lx'),
bar]) bar])
def test_optimize_global_beq_j_false(self): def test_optimize_global_beq_j_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
arguments = [foo, \ arguments = [foo, \
S('command', 'beq', '$regA', '$regB', '$Lz'), \ S('command', 'beq', '$regA', '$regB', '$Lz'), \
S('command', 'j', '$Ly'), \ S('command', 'j', '$Ly'), \
...@@ -211,29 +210,29 @@ class TestOptimize(unittest.TestCase): ...@@ -211,29 +210,29 @@ class TestOptimize(unittest.TestCase):
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_global(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_global_bne_j_true(self): def test_optimize_global_bne_j_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', 'bne', '$regA', '$regB', '$Lx'), S('command', 'bne', '$regA', '$regB', '$Lx'),
S('command', 'j', '$Ly'), S('command', 'j', '$Ly'),
S('label', '$Lx'), S('label', '$Lx'),
bar]) bar])
optimize_global(block) optimize_global(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'beq', '$regA', '$regB', '$Ly'), S('command', 'beq', '$regA', '$regB', '$Ly'),
S('label', '$Lx'), S('label', '$Lx'),
bar]) bar])
def test_optimize_global_bne_j_false(self): def test_optimize_global_bne_j_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
arguments = [foo, \ arguments = [foo, \
S('command', 'bne', '$regA', '$regB', '$Lz'), \ S('command', 'bne', '$regA', '$regB', '$Lz'), \
S('command', 'j', '$Ly'), \ S('command', 'j', '$Ly'), \
...@@ -241,44 +240,44 @@ class TestOptimize(unittest.TestCase): ...@@ -241,44 +240,44 @@ class TestOptimize(unittest.TestCase):
bar] bar]
block = B(arguments) block = B(arguments)
optimize_global(block) optimize_global(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_block_move_move_true(self): def test_optimize_block_move_move_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', 'move', '$regA', '$regB'), S('command', 'move', '$regA', '$regB'),
S('command', 'move', '$regB', '$regA'), S('command', 'move', '$regB', '$regA'),
bar]) bar])
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, [foo, self.assertEquals(block.statements, [foo,
S('command', 'move', '$regA', '$regB'), S('command', 'move', '$regA', '$regB'),
bar]) bar])
def test_optimize_block_mov_mov_false(self): def test_optimize_block_mov_mov_false(self):
foo = S('command', 'foo') foo = S('command', 'foo')
bar = S('command', 'bar') bar = S('command', 'bar')
arguments = [foo, \ arguments = [foo, \
S('command', 'move', '$regA', '$regB'), \ S('command', 'move', '$regA', '$regB'), \
S('command', 'move', '$regB', '$regC'), \ S('command', 'move', '$regB', '$regC'), \
bar] bar]
block = B(arguments) block = B(arguments)
optimize_block(block) optimize_block(block)
self.assertEquals(block.statements, arguments) self.assertEquals(block.statements, arguments)
def test_optimize_blocks(self): #def test_optimize_blocks(self):
foo = S('command', 'foo') # foo = S('command', 'foo')
bar = S('command', 'bar') # bar = S('command', 'bar')
block1 = B([foo, bar]) # block1 = B([foo, bar])
block2 = B([bar, foo]) # block2 = B([bar, foo])
blocks_in = [block1, block2]; # blocks_in = [block1, block2];
blocks_out = optimize_blocks(blocks_in) # blocks_out = optimize_blocks(blocks_in)
self.assertEquals(blocks_in, blocks_out) # 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