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
......
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 dataflow import find_basic_blocks
from src.dataflow import find_basic_blocks
from glob import redundant_move_1, redundant_move_2, \
redundant_move_3, redundant_move_4, redundant_load, \
redundant_shift, redundant_add
def optimize_global(statements):
......@@ -16,34 +17,31 @@ def optimize_global(statements):
# beq/bne ..., $Lx -> bne/beq ..., $Ly
# j $Ly $Lx:
# $Lx:
if s.is_command('beq') or s.is_command('bne'):
if s.is_command('beq', '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.name = 'bne' if s.is_command('beq') else '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_blocks(blocks):
# """Call the optimizer for each basic block. Do this several times until
# no more optimizations are achieved."""
# for block in blocks:
# optimize_block(block)
#
# return blocks
def optimize_block(statements):
"""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
while old_len != len(statements):
......@@ -52,69 +50,17 @@ def optimize_block(statements):
while not statements.end():
s = statements.read()
# mov $regA, $regA -> --- remove it
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()
cont = False
if ins and len(ins) >= 2 and ins[0] == s[0] and ins[1] == s[0]:
ins[1] = s[1]
statements.replace(2, [ins])
continue
for callback in glob:
if callback(s, statements):
cont = True
break
# instr $regA, ... -> instr $4, ...
# 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, [])
if cont:
continue
# add $regA, $regA, X -> lw ..., X($regA)
# 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])
# Other optimizations...
def optimize(statements, verbose=0):
......@@ -126,8 +72,8 @@ def optimize(statements, verbose=0):
g = len(statements)
# Optimize basic blocks
basic_blocks = find_basic_blocks(statements)
blocks = optimize_blocks(basic_blocks)
blocks = find_basic_blocks(statements)
map(optimize_block, blocks)
block_statements = map(lambda b: b.statements, blocks)
opt_blocks = reduce(lambda a, b: a + b, block_statements)
b = len(opt_blocks)
......
......@@ -45,9 +45,8 @@ class Statement:
return self.stype == 'label' if name == None \
else self.stype == 'label' and self.name == name
def is_command(self, name=None):
return self.stype == 'command' if name == None \
else self.stype == 'command' and self.name == name
def is_command(self, *args):
return self.stype == 'command' and (not len(args) or self.name in args)
def is_jump(self):
"""Check if the statement is a jump."""
......@@ -118,10 +117,10 @@ class Block:
def peek(self, count=1):
"""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 \
else self.statements[self.pointer:self.pointer + count]
......
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
......@@ -17,7 +17,7 @@ class TestOptimize(unittest.TestCase):
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo, bar])
def test_optimize_block_movab(self):
foo = S('command', 'foo')
move = S('command', 'move', '$regA', '$regB')
......@@ -27,20 +27,20 @@ class TestOptimize(unittest.TestCase):
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo, move, bar])
def test_optimize_block_movinst_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'move', '$regA', '$regB'),
S('command', 'addu', '$regA', '$regA', 2),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
S('command', 'addu', '$regA', '$regB', 2),
self.assertEquals(block.statements, [foo,
S('command', 'addu', '$regA', '$regB', 2),
bar])
def test_optimize_block_movinst_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
......@@ -48,31 +48,31 @@ class TestOptimize(unittest.TestCase):
S('command', 'move', '$regA', '$regB'), \
S('command', 'addu', '$regA', '$regC', 2), \
bar]
block = B(statements)
optimize_block(block)
self.assertEquals(block.statements, statements)
def test_optimize_block_instr_mov_jal_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'addu', '$regA', '$regC', 2),
S('command', 'move', '$4', '$regA'),
S('command', 'jal', 'L1'),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
self.assertEquals(block.statements, [foo,
S('command', 'addu', '$4', '$regC', 2),
S('command', 'jal', 'L1'),
S('command', 'jal', 'L1'),
bar])
def test_optimize_block_instr_mov_jal_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'addu', '$regA', '$regC', 2), \
S('command', 'move', '$3', '$regA'), \
......@@ -80,130 +80,129 @@ class TestOptimize(unittest.TestCase):
bar]
block = B(arguments)
optimize_block(block)
self.assertEquals(block.statements, arguments)
def test_optimize_block_sw_ld_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'sw', '$regA', '$regB'),
S('command', 'ld', '$regA', '$regC'),
S('command', 'lw', '$regA', '$regB'),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
S('command', 'sw', '$regA', '$regB'),
bar])
def test_optimize_block_sw_ld_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'sw', '$regA', '$regB'), \
S('command', 'ld', '$regD', '$regC'), \
S('command', 'lw', '$regD', '$regC'), \
bar]
block = B(arguments)
optimize_block(block)
self.assertEquals(block.statements, arguments)
def test_optimize_block_shift_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'sll', '$regA', '$regA', 0),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
bar])
self.assertEquals(block.statements, [foo, bar])
def test_optimize_block_shift_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'sll', '$regA', '$regB', 0), \
bar]
block = B(arguments)
optimize_block(block)
self.assertEquals(block.statements, arguments)
arguments2 = [foo, \
S('command', 'sll', '$regA', '$regA', 1), \
bar]
block2 = B(arguments2)
optimize_block(block2)
self.assertEquals(block2.statements, arguments2)
def test_optimize_block_add_lw_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'add', '$regA', '$regA', 10),
S('command', 'addu', '$regA', '$regA', 10),
S('command', 'lw', '$regB', '0($regA)'),
bar])
optimize_block(block)
self.assertEquals(block.statements, [foo,
S('command', 'lw', '$regB', '10($regA)'),
bar])
def test_optimize_block_add_lw_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'add', '$regA', '$regA', 10), \
S('command', 'addu', '$regA', '$regA', 10), \
S('command', 'lw', '$regB', '0($regC)'), \
bar]
block = B(arguments)
optimize_block(block)
arguments2 = [foo, \
S('command', 'add', '$regA', '$regB', 10), \
S('command', 'addu', '$regA', '$regB', 10), \
S('command', 'lw', '$regB', '0($regA)'), \
bar]
block2 = B(arguments2)
arguments3 = [foo, \
S('command', 'add', '$regA', '$regA', 10), \
S('command', 'addu', '$regA', '$regA', 10), \
S('command', 'lw', '$regB', '1($regA)'), \
bar]
block3 = B(arguments3)
optimize_block(block3)
self.assertEquals(block.statements, arguments)
self.assertEquals(block2.statements, arguments2)
self.assertEquals(block3.statements, arguments3)
def test_optimize_global_beq_j_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'beq', '$regA', '$regB', '$Lx'),
S('command', 'j', '$Ly'),
S('label', '$Lx'),
bar])
optimize_global(block)
self.assertEquals(block.statements, [foo,
S('command', 'bne', '$regA', '$regB', '$Ly'),
S('label', '$Lx'),
bar])
def test_optimize_global_beq_j_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'beq', '$regA', '$regB', '$Lz'), \
S('command', 'j', '$Ly'), \
......@@ -211,29 +210,29 @@ class TestOptimize(unittest.TestCase):
bar]
block = B(arguments)
optimize_global(block)
self.assertEquals(block.statements, arguments)
def test_optimize_global_bne_j_true(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
block = B([foo,
S('command', 'bne', '$regA', '$regB', '$Lx'),
S('command', 'j', '$Ly'),
S('label', '$Lx'),
bar])
optimize_global(block)
self.assertEquals(block.statements, [foo,
S('command', 'beq', '$regA', '$regB', '$Ly'),
S('label', '$Lx'),
bar])
def test_optimize_global_bne_j_false(self):
foo = S('command', 'foo')
bar = S('command', 'bar')
arguments = [foo, \
S('command', 'bne', '$regA', '$regB', '$Lz'), \
S('command', 'j', '$Ly'), \
......@@ -241,44 +240,44 @@ class TestOptimize(unittest.TestCase):
bar]
block = B(arguments)
optimize_global(block)
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)
#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