Commit ccaa52ac authored by Taddeus Kroes's avatar Taddeus Kroes

Started implementing Dead Code elimination.

parent 0ee8729c
...@@ -3,7 +3,7 @@ from src.dataflow import find_basic_blocks ...@@ -3,7 +3,7 @@ from src.dataflow import find_basic_blocks
from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \ from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \
move_4, load, shift, add move_4, load, shift, add
from advanced import eliminate_common_subexpressions, fold_constants, \ from advanced import eliminate_common_subexpressions, fold_constants, \
copy_propagation, algebraic_transformations copy_propagation, algebraic_transformations, eliminate_dead_code
def remove_redundancies(block): def remove_redundancies(block):
...@@ -32,7 +32,8 @@ def optimize_block(block): ...@@ -32,7 +32,8 @@ def optimize_block(block):
| eliminate_common_subexpressions(block) \ | eliminate_common_subexpressions(block) \
| fold_constants(block) \ | fold_constants(block) \
| copy_propagation(block)\ | copy_propagation(block)\
| algebraic_transformations(block): | algebraic_transformations(block) \
| eliminate_dead_code(block):
pass pass
......
...@@ -40,7 +40,7 @@ def eliminate_common_subexpressions(block): ...@@ -40,7 +40,7 @@ def eliminate_common_subexpressions(block):
y = u y = u
The algorithm used is as follows: The algorithm used is as follows:
- Traverse through the statements in reverse order. - Traverse through the statements.
- If the statement can be possibly be eliminated, walk further collecting - If the statement can be possibly be eliminated, walk further collecting
all other occurrences of the expression until one of the arguments is all other occurrences of the expression until one of the arguments is
assigned in a statement, or the start of the block has been reached. assigned in a statement, or the start of the block has been reached.
...@@ -292,3 +292,40 @@ def algebraic_transformations(block): ...@@ -292,3 +292,40 @@ def algebraic_transformations(block):
changed = True changed = True
return changed return changed
def eliminate_dead_code(block):
"""
Dead code elimination:
TODO: example...
The algorithm used is as follows:
- Traverse through the statements in reverse order.
- If the statement definition is dead, remove it. A variable is dead if it
is not used in the rest of the block, and is not in the `out' set of the
block.
"""
# TODO: Finish
changed = False
block.reverse_statements()
unused = set()
while not block.end():
s = block.read()
for reg in s.get_def():
if reg in unused:
# Statement is redefined later, so this statement is useless
s.remove = True
#print 'reg %s is in %s, remove:' % (reg, unused), \
# block.pointer - 1, s
else:
unused.add(reg)
unused -= set(s.get_use())
block.apply_filter(lambda s: not hasattr(s, 'remove'))
block.reverse_statements()
return changed
...@@ -71,8 +71,11 @@ class Statement: ...@@ -71,8 +71,11 @@ class Statement:
def is_arith(self): def is_arith(self):
"""Check if the statement is an arithmetic operation.""" """Check if the statement is an arithmetic operation."""
return self.is_command() \ return self.is_command() \
and re.match('^s(ll|rl|ra)|(add|sub|mflo|abs|neg|slt|sqrt)' \ and re.match('^s(ll|rl|ra)'
+ '(u|\.s|\.d)?$', self.name) + '|(mfhi|mflo|abs|neg|and|[xn]?or)'
+ '|(add|sub|slt)u?'
+ '|(add|sub|mult|div|abs|neg|sqrt|c)\.[sd]$', \
self.name)
def is_monop(self): def is_monop(self):
"""Check if the statement is an unary operation.""" """Check if the statement is an unary operation."""
...@@ -89,31 +92,42 @@ class Statement: ...@@ -89,31 +92,42 @@ class Statement:
return self[-1] return self[-1]
def defines(self, reg): def get_def(self):
"""Check if this statement defines the given register."""
# TODO: Finish # TODO: Finish
return (self.is_load() or self.is_arith()) and self[0] == reg if self.is_load() or self.is_arith():
return self[:1]
def uses(self, reg): return []
"""Check if this statement uses the given register."""
# TODO: Finish
if self.is_arith():
return reg in self[1:]
if self.is_command('move'): def get_use(self):
return self[1] == reg # TODO: Finish with ALL the available commands!
use = []
if self.is_command('lw', 'sb', 'sw', 'dsw'): if self.is_binop():
use += self[1:]
elif self.is_command('move'):
use.append(self[1])
elif self.is_command('lw', 'sb', 'sw', 'dsw', 's.s', 's.d'):
m = re.match('^\d+\(([^)]+)\)$', self[1]) m = re.match('^\d+\(([^)]+)\)$', self[1])
if m: if m:
return m.group(1) == reg use.append(m.group(1))
# 'sw' also uses its first argument # 'sw' also uses its first argument
if self.name in ['sw', 'dsw']: if self.name in ['sw', 'dsw']:
return self[0] == reg use.append(self[0])
elif len(self) == 2: # FIXME: temporary fix, manually add all commands
use.append(self[1])
return False return use
def defines(self, reg):
"""Check if this statement defines the given register."""
return reg in self.get_def()
def uses(self, reg):
"""Check if this statement uses the given register."""
return reg in self.get_use()
class Block: class Block:
......
...@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase): ...@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase):
self.assertFalse(S('label', 'lw').is_load()) self.assertFalse(S('label', 'lw').is_load())
def test_is_arith(self): def test_is_arith(self):
self.assertTrue(S('command', 'add', '$1', '$2', '$3').is_arith()) self.assertTrue(S('command', 'addu', '$1', '$2', '$3').is_arith())
self.assertFalse(S('command', 'foo').is_arith()) self.assertFalse(S('command', 'foo').is_arith())
self.assertFalse(S('label', 'add').is_arith()) self.assertFalse(S('label', 'addu').is_arith())
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