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 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]
......
This diff is collapsed.
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