Commit f438cef1 authored by Taddeus Kroes's avatar Taddeus Kroes

Moved optimization implementations to module 'optimize'.

parent af811f6e
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)
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