Commit 0c7d903d authored by Jayke Meijer's avatar Jayke Meijer

Fixed merge conflict.

parents fdd0ba24 a24a3b0e
BUILD=build/ BUILD=build/
CLEAN=src/*.pyc src/optimize/*.pyc CLEAN=*.pyc src/*.pyc src/optimize/*.pycrm -f parser.out parsetab.py
# Fix pdflatex search path # Fix pdflatex search path
TGT_DIR := TGT_DIR :=
......
...@@ -7,11 +7,20 @@ if __name__ == '__main__': ...@@ -7,11 +7,20 @@ if __name__ == '__main__':
from sys import argv, exit from sys import argv, exit
if len(argv) < 2: if len(argv) < 2:
print 'Usage: python %s FILE' % argv[0] print 'Usage: python %s SOURCE_FILE [ OUT_FILE [ SOURCE_OUT_FILE ] ]' \
% argv[0]
exit(1) exit(1)
# Parse File # Parse File
original = parse_file(argv[1]) original = parse_file(argv[1])
if len(argv) > 3:
# Save input assembly in new file for easy comparison
out = write_statements(original)
f = open(argv[3], 'w+')
f.write(out)
f.close()
optimized = optimize(original, verbose=1) optimized = optimize(original, verbose=1)
if len(argv) > 2: if len(argv) > 2:
......
...@@ -109,14 +109,13 @@ addu $5,$4,$3 mov = $4, $t1 ...@@ -109,14 +109,13 @@ addu $5,$4,$3 mov = $4, $t1
\end{verbatim} \end{verbatim}
A standard method for doing this is the creation of a DAG or Directed Acyclic A standard method for doing this is the creation of a DAG or Directed Acyclic
Graph. However, this requires a fairly advanced implementation. Our Graph. However, this requires a fairly advanced implementation. Our
implementation is a slightly less fancy, but easier to implement. implementation is a slightly less fancy, but easier to implement.
We search from the end of the block up for instructions that are eligible for We search from the end of the block up for instructions that are eligible for
CSE. If we find one, we check further up in the code for the same instruction, CSE. If we find one, we check further up in the code for the same instruction,
and add that to a temporary storage list. This is done until the beginning of and add that to a temporary storage list. This is done until the beginning of
the block or until one of the arguments of this expression is assigned. the block or until one of the arguments of this expression is assigned. The temporty storage is
We now add the instruction above the first use, and write the result in a new We now add the instruction above the first use, and write the result in a new
variable. Then all occurrences of this expression can be replaced by a move of variable. Then all occurrences of this expression can be replaced by a move of
...@@ -127,6 +126,7 @@ in general not very large and the execution time of the optimizer is not a ...@@ -127,6 +126,7 @@ in general not very large and the execution time of the optimizer is not a
primary concern, this is not a big problem. primary concern, this is not a big problem.
\subsubsection*{Fold constants} \subsubsection*{Fold constants}
Constant folding is an optimization where the outcome of arithmetics are calculated at compile time. If a value x is assigned to a certain value, let's say 10, than all next occurences of \texttt{x} are replaced by 10 until a redefinition of x. Arithmetics in Assembly are always preformed between two constants, if this is not the case the calculation is not possible. See the example for a more clear explanation of constant folding(will come). In other words until the current definition of \texttt{x} becomes dead. Therefore reaching definitions analysis is needed.
......
class Dag:
def __init__(self, block):
"""Create the Directed Acyclic Graph of all binary operations in a
basic block."""
self.nodes = []
for s in block:
if s.is_command('move') or s.is_monop():
rd, rs = s
y = self.find_reg_node(rs)
self.find_op_node(s.name, rd, y)
elif s.is_binop():
rd, rs, rt = s
y = self.find_reg_node(rs)
z = self.find_reg_node(rt)
self.find_op_node(s.name, rd, y, z)
def find_reg_node(self, reg):
for n in self.nodes:
if reg in n.reg:
return n
node = DagLeaf(reg)
self.nodes.append(node)
return node
def find_op_node(self, op, rd, *args):
for n in self.nodes:
if not isinstance(n, DagLeaf) and n.op == op and n.nodes == args:
n.labels.append(rd)
return n
node = DagNode(op, rd, *args)
self.nodes.append(node)
return node
class DagNode:
def __init__(self, op, label, *args):
self.op = op
self.labels = [label]
self.nodes = args
class DagLeaf:
def __init__(self, reg):
self.reg = reg
...@@ -9,10 +9,6 @@ class BasicBlock(Block): ...@@ -9,10 +9,6 @@ class BasicBlock(Block):
self.dominates = [] self.dominates = []
self.dominated_by = [] self.dominated_by = []
self.in_set = set([])
self.out_set = set([])
self.gen_set = set([])
self.kill_set = set([])
def add_edge_to(self, block): def add_edge_to(self, block):
if block not in self.edges_to: if block not in self.edges_to:
...@@ -24,90 +20,6 @@ class BasicBlock(Block): ...@@ -24,90 +20,6 @@ class BasicBlock(Block):
self.dominates.append(block) self.dominates.append(block)
block.dominated_by.append(self) block.dominated_by.append(self)
def create_gen_kill(self, defs):
used = set()
self_defs = {}
# Get the last of each definition series and put in in the `def' set
self.gen_set = set()
for s in reversed(self):
for reg in s.get_def():
if reg not in self_defs:
self_defs[reg] = s.sid
self.gen_set.add(s.sid)
# Generate kill set
self.kill_set = set()
for reg, statement_ids in defs.iteritems():
if reg in self_defs:
self.kill_set |= statement_ids - set([self_defs[reg]])
def get_defs(blocks):
# Collect definitions of all registers
defs = {}
for b in blocks:
for s in b:
for reg in s.get_def():
if reg not in defs:
defs[reg] = set([s.sid])
else:
defs[reg].add(s.sid)
return defs
def reaching_definitions(blocks):
"""Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the lecture slides."""
# Generate flow graph
generate_flow_graph(blocks)
# Create gen/kill sets
defs = get_defs(blocks)
print 'defs:', defs
for b in blocks:
b.create_gen_kill(defs)
b.out_set = b.gen_set
change = True
while change:
change = False
for b in blocks:
print 'block:', b
b.in_set = set()
for pred in b.edges_from:
print 'pred: ', pred
b.in_set |= pred.out_set
print 'b.in_set: ', b.in_set
print 'b.out_set: ', b.out_set
new_out = b.gen_set | (b.in_set - b.kill_set)
print 'new_out: ', new_out
if new_out != b.out_set:
print 'changed'
b.out_set = new_out
change = True
def pred(n, known=[]):
"""Recursively find all predecessors of a node."""
direct = filter(lambda b: b not in known, n.edges_from)
p = copy(direct)
for ancestor in direct:
p += pred(ancestor, direct)
return p
def find_leaders(statements): def find_leaders(statements):
"""Determine the leaders, which are: """Determine the leaders, which are:
...@@ -169,104 +81,3 @@ def generate_flow_graph(blocks): ...@@ -169,104 +81,3 @@ def generate_flow_graph(blocks):
b.add_edge_to(blocks[i + 1]) b.add_edge_to(blocks[i + 1])
elif i < len(blocks) - 1: elif i < len(blocks) - 1:
b.add_edge_to(blocks[i + 1]) b.add_edge_to(blocks[i + 1])
#def generate_dominator_tree(nodes):
# """Add dominator administration to the given flow graph nodes."""
# # Dominator of the start node is the start itself
# nodes[0].dom = set([nodes[0]])
#
# # For all other nodes, set all nodes as the dominators
# for n in nodes[1:]:
# n.dom = set(copy(nodes))
#
# def pred(n, known=[]):
# """Recursively find all predecessors of a node."""
# direct = filter(lambda x: x not in known, n.edges_from)
# p = copy(direct)
#
# for ancestor in direct:
# p += pred(ancestor, direct)
#
# return p
#
# # Iteratively eliminate nodes that are not dominators
# changed = True
#
# while changed:
# changed = False
#
# for n in nodes[1:]:
# old_dom = n.dom
# intersection = lambda p1, p2: p1.dom & p2.dom
# n.dom = set([n]) | reduce(intersection, pred(n), set([]))
#
# if n.dom != old_dom:
# changed = True
#
# def idom(d, n):
# """Check if d immediately dominates n."""
# for b in n.dom:
# if b != d and b != n and b in n.dom:
# return False
#
# return True
#
# # Build tree using immediate dominators
# for n in nodes:
# for d in n.dom:
# if idom(d, n):
# d.set_dominates(n)
# break
class Dag:
def __init__(self, block):
"""Create the Directed Acyclic Graph of all binary operations in a
basic block."""
self.nodes = []
for s in block:
if s.is_command('move') or s.is_monop():
rd, rs = s
y = self.find_reg_node(rs)
self.find_op_node(s.name, rd, y)
elif s.is_binop():
rd, rs, rt = s
y = self.find_reg_node(rs)
z = self.find_reg_node(rt)
self.find_op_node(s.name, rd, y, z)
def find_reg_node(self, reg):
for n in self.nodes:
if reg in n.reg:
return n
node = DagLeaf(reg)
self.nodes.append(node)
return node
def find_op_node(self, op, rd, *args):
for n in self.nodes:
if not isinstance(n, DagLeaf) and n.op == op and n.nodes == args:
n.labels.append(rd)
return n
node = DagNode(op, rd, *args)
self.nodes.append(node)
return node
class DagNode:
def __init__(self, op, label, *args):
self.op = op
self.labels = [label]
self.nodes = args
class DagLeaf:
def __init__(self, reg):
self.reg = reg
from copy import copy
def generate_dominator_tree(nodes):
"""Add dominator administration to the given flow graph nodes."""
# Dominator of the start node is the start itself
nodes[0].dom = set([nodes[0]])
# For all other nodes, set all nodes as the dominators
for n in nodes[1:]:
n.dom = set(copy(nodes))
def pred(n, known=[]):
"""Recursively find all predecessors of a node."""
direct = filter(lambda x: x not in known, n.edges_from)
p = copy(direct)
for ancestor in direct:
p += pred(ancestor, direct)
return p
# Iteratively eliminate nodes that are not dominators
changed = True
while changed:
changed = False
for n in nodes[1:]:
old_dom = n.dom
intersection = lambda p1, p2: p1.dom & p2.dom
n.dom = set([n]) | reduce(intersection, pred(n), set([]))
if n.dom != old_dom:
changed = True
def idom(d, n):
"""Check if d immediately dominates n."""
for b in n.dom:
if b != d and b != n and b in n.dom:
return False
return True
# Build tree using immediate dominators
for n in nodes:
for d in n.dom:
if idom(d, n):
d.set_dominates(n)
break
from copy import copy
def create_use_def(block):
used = set()
defined = set()
# Get the last of each definition series and put in in the `def' set
block.use_set = set()
block.def_set = set()
for s in block:
# use[B] is the set of variables whose values may be used in B prior to
# any definition of the variable
for reg in s.get_use():
used.add(reg)
if reg not in defined:
block.use_set.add(reg)
# def[B] is the set of variables assigned values in B prior to any use
# of that variable in B
for reg in s.get_def():
defined.add(reg)
if reg not in used:
block.def_set.add(reg)
def succ(block, known=[]):
"""Recursively find all successors of a node."""
direct = filter(lambda b: b != block and b not in known, block.edges_to)
s = copy(direct)
for successor in direct:
s += succ(successor, known + direct)
return s
return s
def create_in_out(blocks):
for b in blocks:
create_use_def(b)
b.live_in = b.use_set
b.live_out = set()
change = True
while change:
change = False
for b in blocks:
# in[B] = use[B] | (out[B] - def[B])
new_in = b.use_set | (b.live_out - b.def_set)
# out[B] = union of in[S] for S in succ(B)
new_out = set()
for s in succ(b):
new_out |= s.live_in
# Check if either `in' or `out' changed
if new_in != b.live_in:
b.live_in = new_in
change = True
if new_out != b.live_out:
b.live_out = new_out
change = True
from src.dataflow import find_basic_blocks, reaching_definitions from src.dataflow import find_basic_blocks, generate_flow_graph
import src.liveness as liveness
import src.reaching_definitions as reaching_definitions
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, eliminate_dead_code copy_propagation, eliminate_dead_code
def remove_redundancies(block): def remove_redundancies(block):
...@@ -41,6 +43,7 @@ def optimize(statements, verbose=0): ...@@ -41,6 +43,7 @@ def optimize(statements, verbose=0):
"""Optimization wrapper function, calls global and basic-block level """Optimization wrapper function, calls global and basic-block level
optimization functions.""" optimization functions."""
# Optimize on a global level # Optimize on a global level
# TODO: only count instructions (no directives)
o = len(statements) o = len(statements)
remove_redundant_jumps(statements) remove_redundant_jumps(statements)
g = len(statements) g = len(statements)
...@@ -48,8 +51,10 @@ def optimize(statements, verbose=0): ...@@ -48,8 +51,10 @@ def optimize(statements, verbose=0):
# Divide into basic blocks # Divide into basic blocks
blocks = find_basic_blocks(statements) blocks = find_basic_blocks(statements)
# Find reaching definitions # Perform dataflow analysis
reaching_definitions(blocks) generate_flow_graph(blocks)
liveness.create_in_out(blocks)
reaching_definitions.create_in_out(blocks)
# Optimize basic blocks # Optimize basic blocks
map(optimize_block, blocks) map(optimize_block, blocks)
......
...@@ -18,7 +18,7 @@ def reg_can_be_used_in(reg, block, start, end): ...@@ -18,7 +18,7 @@ def reg_can_be_used_in(reg, block, start, end):
elif s.defines(reg): elif s.defines(reg):
return True return True
return reg not in block.out_set return reg not in block.live_out
def find_free_reg(block, start, end): def find_free_reg(block, start, end):
......
from dataflow import BasicBlock as B
def get_defs(blocks):
"""Collect definitions of all registers."""
defs = {}
for b in blocks:
for s in b:
for reg in s.get_def():
if reg not in defs:
defs[reg] = set([s.sid])
else:
defs[reg].add(s.sid)
return defs
def create_gen_kill(block, global_defs):
block_defs = {}
# Get the last of each definition series and put in in the `def' set
block.gen_set = set()
for s in reversed(block):
for reg in s.get_def():
if reg not in block_defs:
block_defs[reg] = s.sid
block.gen_set.add(s.sid)
# Generate kill set
block.kill_set = set()
for reg, statement_ids in global_defs.iteritems():
if reg in block_defs:
block.kill_set |= statement_ids - set([block_defs[reg]])
def create_in_out(blocks):
"""Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the lecture slides."""
# Create gen/kill sets
defs = get_defs(blocks)
for b in blocks:
create_gen_kill(b, defs)
b.reach_out = b.gen_set
change = True
while change:
change = False
for b in blocks:
b.reach_in = set()
for pred in b.edges_from:
b.reach_in |= pred.reach_out
new_out = b.gen_set | (b.reach_in - b.kill_set)
if new_out != b.reach_out:
b.reach_out = new_out
change = True
...@@ -107,6 +107,7 @@ class Statement: ...@@ -107,6 +107,7 @@ class Statement:
return self.is_command() \ return self.is_command() \
and re.match('^l(w|a|b|bu|\.d|\.s)|dlw$', \ and re.match('^l(w|a|b|bu|\.d|\.s)|dlw$', \
self.name) self.name)
def is_logical(self): def is_logical(self):
"""Check if the statement is a logical operator.""" """Check if the statement is a logical operator."""
return self.is_command() and re.match('^(xor|or|and)i?$', self.name) return self.is_command() and re.match('^(xor|or|and)i?$', self.name)
...@@ -160,7 +161,7 @@ class Statement: ...@@ -160,7 +161,7 @@ class Statement:
or self.is_set_if_less() or self.is_convert() \ or self.is_set_if_less() or self.is_convert() \
or self.is_truncate() or self.is_load() \ or self.is_truncate() or self.is_load() \
or self.is_command(*instr): or self.is_command(*instr):
return [self[0]] return self[:1]
return [] return []
...@@ -175,7 +176,9 @@ class Statement: ...@@ -175,7 +176,9 @@ class Statement:
or self.is_command(*['mult', 'div', 'dsz', 'mtc1']): or self.is_command(*['mult', 'div', 'dsz', 'mtc1']):
if self.name == 'dsz': if self.name == 'dsz':
m = re.match('^\d+\(([^)]+)\)$', self[0]) m = re.match('^\d+\(([^)]+)\)$', self[0])
use.append(m)
if m:
use.append(m.group(1))
else: else:
use.append(self[0]) use.append(self[0])
# Case arg1 direct adressing # Case arg1 direct adressing
...@@ -188,15 +191,16 @@ class Statement: ...@@ -188,15 +191,16 @@ class Statement:
# Case arg1 relative adressing # Case arg1 relative adressing
if self.is_load_non_immediate() or self.is_store(): if self.is_load_non_immediate() or self.is_store():
m = re.match('^\d+\(([^)]+)\)$', self[1]) m = re.match('^\d+\(([^)]+)\)$', self[1])
if m: if m:
use.append(m) use.append(m.group(1))
else: else:
use.append(self[1]) use.append(self[1])
# Case arg2 # Case arg2
if self.is_double_arithmetic() or self.is_set_if_less() \ if self.is_double_arithmetic() or self.is_set_if_less() \
or self.is_logical() \ or self.is_logical() \
or self.is_command(*['addu', 'subu']): or self.is_command(*['addu', 'subu']):
if not isinstance(self[2] , int): if not isinstance(self[2], int):
use.append(self[2]) use.append(self[2])
return use return use
...@@ -246,7 +250,7 @@ class Block: ...@@ -246,7 +250,7 @@ class Block:
def end(self): def end(self):
"""Check if the pointer is at the end of the statement list.""" """Check if the pointer is at the end of the statement list."""
return self.pointer == len(self) return self.pointer >= len(self)
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
......
#!/usr/bin/python
from testrunner import main from testrunner import main
import sys import sys
main(sys.argv[1:]) main(sys.argv[1:])
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B
from src.dag import Dag, DagNode, DagLeaf
class TestDag(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_dag_unary(self):
dag = Dag(B([S('command', 'neg.d', '$rd', '$rs')]))
expect = Dag([])
expect.nodes = [DagLeaf('$rs'), DagNode('neg.d', '$rd', \
DagLeaf('$rs'))]
self.assertEqualDag(dag, expect)
def test_dag_binary(self):
dag = Dag(B([S('command', 'addu', '$rd', '$r1', '$r2')]))
expect = Dag([])
expect.nodes = [DagLeaf('$r1'),
DagLeaf('$r2'),
DagNode('addu', '$rd', DagLeaf('$r1'), DagLeaf('$r2'))]
self.assertEqualDag(dag, expect)
# def test_dag_combinednode(self):
# dag = Dag(B([S('command', 'mult', '$rd1', '$r1', '$r2'),
# S('command', 'mult', '$rd2', '$r1', '$r2')]))
# expect = Dag([])
# multnode = DagNode('mult',
# DagLeaf('$r1'),
# DagLeaf('$r2'))
# multnode.labels = ['$rd1', '$rd2']
# expect.nodes = [DagLeaf('$r1'),
# DagLeaf('$r2'),
# multnode]
#
# self.assertEqualDag(dag, expect)
def assertEqualDag(self, dag1, dag2):
self.assertEqual(len(dag1.nodes), len(dag2.nodes))
for node1, node2 in zip(dag1.nodes, dag2.nodes):
self.assertEqualNodes(node1, node2)
def assertEqualNodes(self, node1, node2):
if isinstance(node1, DagLeaf):
self.assertIsInstance(node2, DagLeaf)
self.assertEqual(node1.reg, node2.reg)
elif isinstance(node2, DagLeaf):
raise AssertionError
else:
self.assertEqual(node1.op, node2.op)
self.assertEqual(node1.labels, node2.labels)
self.assertEqual(len(node1.nodes), len(node2.nodes))
for child1, child2 in zip(node1.nodes, node2.nodes):
self.assertEqualNodes(child1, child2)
...@@ -2,8 +2,7 @@ import unittest ...@@ -2,8 +2,7 @@ import unittest
from src.statement import Statement as S from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_leaders, find_basic_blocks, \ from src.dataflow import BasicBlock as B, find_leaders, find_basic_blocks, \
generate_flow_graph, Dag, DagNode, DagLeaf, get_defs, \ generate_flow_graph
reaching_definitions
class TestDataflow(unittest.TestCase): class TestDataflow(unittest.TestCase):
...@@ -25,90 +24,6 @@ class TestDataflow(unittest.TestCase): ...@@ -25,90 +24,6 @@ class TestDataflow(unittest.TestCase):
[B(s[:2]).statements, B(s[2:4]).statements, \ [B(s[:2]).statements, B(s[2:4]).statements, \
B(s[4:]).statements]) B(s[4:]).statements])
def test_get_defs(self):
s1 = S('command', 'add', '$3', '$1', '$2')
s2 = S('command', 'move', '$1', '$3')
s3 = S('command', 'move', '$3', '$2')
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
self.assertEqual(get_defs([block]), {
'$3': set([s1.sid, s3.sid]),
'$1': set([s2.sid]),
'$4': set([s4.sid])
})
def test_create_gen_kill_simple(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
block.create_gen_kill(get_defs([block]))
self.assertEqual(block.gen_set, set([s2.sid, s3.sid, s4.sid]))
self.assertEqual(block.kill_set, set([s1.sid]))
def test_create_gen_kill_between_blocks(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'blt', 'a', 'b', 'L1')
b1 = B([s11, s12, s13, s14, s15])
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
b2 = B([s21, s22])
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b3 = B([s31, s32, s33, s34, s35])
defs = get_defs([b1, b2, b3])
b1.create_gen_kill(defs)
b2.create_gen_kill(defs)
b3.create_gen_kill(defs)
self.assertEqual(b1.gen_set, set([s11.sid, s12.sid, s13.sid, s14.sid]))
self.assertEqual(b1.kill_set, set([s22.sid]))
self.assertEqual(b2.gen_set, set([s21.sid, s22.sid]))
self.assertEqual(b2.kill_set, set([s13.sid, s32.sid]))
self.assertEqual(b3.gen_set, set([s32.sid, s34.sid, s35.sid]))
self.assertEqual(b3.kill_set, set([s21.sid]))
def test_reaching_definitions(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'blt', 'a', 'b', 'L1')
b1 = B([s11, s12, s13, s14, s15])
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
b2 = B([s21, s22])
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b3 = B([s31, s32, s33, s34, s35])
reaching_definitions([b1, b2, b3])
self.assertEqual(b1.in_set, set())
self.assertEqual(b1.out_set, set([s11.sid, s12.sid, s13.sid]))
self.assertEqual(b2.in_set, set([s11.sid, s12.sid]))
self.assertEqual(b2.out_set, set([s12.sid, s22.sid]))
self.assertEqual(b3.in_set, set([s12.sid, s22.sid]))
self.assertEqual(b3.out_set, set())
def test_generate_flow_graph_simple(self): def test_generate_flow_graph_simple(self):
b1 = B([S('command', 'foo'), S('command', 'j', 'b2')]) b1 = B([S('command', 'foo'), S('command', 'j', 'b2')])
b2 = B([S('label', 'b2'), S('command', 'bar')]) b2 = B([S('label', 'b2'), S('command', 'bar')])
...@@ -129,54 +44,3 @@ class TestDataflow(unittest.TestCase): ...@@ -129,54 +44,3 @@ class TestDataflow(unittest.TestCase):
self.assertEqual(b2.edges_to, [b3]) self.assertEqual(b2.edges_to, [b3])
self.assertIn(b1, b3.edges_from) self.assertIn(b1, b3.edges_from)
self.assertIn(b2, b3.edges_from) self.assertIn(b2, b3.edges_from)
def test_dag_unary(self):
dag = Dag(B([S('command', 'neg.d', '$rd', '$rs')]))
expect = Dag([])
expect.nodes = [DagLeaf('$rs'), DagNode('neg.d', '$rd', \
DagLeaf('$rs'))]
self.assertEqualDag(dag, expect)
def test_dag_binary(self):
dag = Dag(B([S('command', 'addu', '$rd', '$r1', '$r2')]))
expect = Dag([])
expect.nodes = [DagLeaf('$r1'),
DagLeaf('$r2'),
DagNode('addu', '$rd', DagLeaf('$r1'), DagLeaf('$r2'))]
self.assertEqualDag(dag, expect)
# def test_dag_combinednode(self):
# dag = Dag(B([S('command', 'mult', '$rd1', '$r1', '$r2'),
# S('command', 'mult', '$rd2', '$r1', '$r2')]))
# expect = Dag([])
# multnode = DagNode('mult',
# DagLeaf('$r1'),
# DagLeaf('$r2'))
# multnode.labels = ['$rd1', '$rd2']
# expect.nodes = [DagLeaf('$r1'),
# DagLeaf('$r2'),
# multnode]
#
# self.assertEqualDag(dag, expect)
def assertEqualDag(self, dag1, dag2):
self.assertEqual(len(dag1.nodes), len(dag2.nodes))
for node1, node2 in zip(dag1.nodes, dag2.nodes):
self.assertEqualNodes(node1, node2)
def assertEqualNodes(self, node1, node2):
if isinstance(node1, DagLeaf):
self.assertIsInstance(node2, DagLeaf)
self.assertEqual(node1.reg, node2.reg)
elif isinstance(node2, DagLeaf):
raise AssertionError
else:
self.assertEqual(node1.op, node2.op)
self.assertEqual(node1.labels, node2.labels)
self.assertEqual(len(node1.nodes), len(node2.nodes))
for child1, child2 in zip(node1.nodes, node2.nodes):
self.assertEqualNodes(child1, child2)
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_basic_blocks, \
generate_flow_graph
from src.liveness import create_use_def, create_in_out
class TestLiveness(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_create_gen_kill(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
create_use_def(block)
self.assertEqual(block.use_set, set(['$1', '$2']))
self.assertEqual(block.def_set, set(['$3', '$4']))
def test_create_in_out(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'beq', 'a', 'b', 'L1')
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
s31, s32, s33, s34, s35])
generate_flow_graph([b1, b2, b3])
create_in_out([b1, b2, b3])
self.assertEqual(b1.use_set, set())
self.assertEqual(b1.def_set, set(['a', 'b', 'd', 'x']))
self.assertEqual(b2.use_set, set(['a', 'b']))
self.assertEqual(b2.def_set, set(['c', 'd']))
self.assertEqual(b3.use_set, set(['b', 'd']))
self.assertEqual(b3.def_set, set(['c', 'temp', 'return']))
self.assertEqual(b1.live_in, set())
self.assertEqual(b1.live_out, set(['a', 'b', 'd']))
self.assertEqual(b2.live_in, set(['a', 'b']))
self.assertEqual(b2.live_out, set(['b', 'd']))
self.assertEqual(b3.live_in, set(['b', 'd']))
self.assertEqual(b3.live_out, set())
...@@ -3,7 +3,9 @@ from copy import copy ...@@ -3,7 +3,9 @@ from copy import copy
from src.optimize.advanced import eliminate_common_subexpressions, \ from src.optimize.advanced import eliminate_common_subexpressions, \
fold_constants, copy_propagation, algebraic_transformations fold_constants, copy_propagation, algebraic_transformations
from src.statement import Statement as S, Block as B from src.statement import Statement as S
from src.dataflow import BasicBlock as B, generate_flow_graph
import src.liveness as liveness
class TestOptimizeAdvanced(unittest.TestCase): class TestOptimizeAdvanced(unittest.TestCase):
...@@ -22,6 +24,7 @@ class TestOptimizeAdvanced(unittest.TestCase): ...@@ -22,6 +24,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
e = [S('command', 'addu', '$8', '$regA', '$regB'), \ e = [S('command', 'addu', '$8', '$regA', '$regB'), \
S('command', 'move', '$regC', '$8'), \ S('command', 'move', '$regC', '$8'), \
S('command', 'move', '$regD', '$8')] S('command', 'move', '$regD', '$8')]
liveness.create_in_out([b])
eliminate_common_subexpressions(b) eliminate_common_subexpressions(b)
self.assertEqual(b.statements, e) self.assertEqual(b.statements, e)
...@@ -30,6 +33,7 @@ class TestOptimizeAdvanced(unittest.TestCase): ...@@ -30,6 +33,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
S('command', 'li', '$regA', '0x00000001'), S('command', 'li', '$regA', '0x00000001'),
S('command', 'addu', '$regD', '$regA', '$regB')]) S('command', 'addu', '$regD', '$regA', '$regB')])
e = copy(b.statements) e = copy(b.statements)
liveness.create_in_out([b])
eliminate_common_subexpressions(b) eliminate_common_subexpressions(b)
self.assertEqual(b.statements, e) self.assertEqual(b.statements, e)
......
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B, find_basic_blocks, \
generate_flow_graph
from src.reaching_definitions import get_defs, create_gen_kill, create_in_out
class TestReachingDefinitions(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_get_defs(self):
s1 = S('command', 'add', '$3', '$1', '$2')
s2 = S('command', 'move', '$1', '$3')
s3 = S('command', 'move', '$3', '$2')
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
self.assertEqual(get_defs([block]), {
'$3': set([s1.sid, s3.sid]),
'$1': set([s2.sid]),
'$4': set([s4.sid])
})
def test_create_gen_kill(self):
s1 = S('command', 'addu', '$3', '$1', '$2')
s2 = S('command', 'addu', '$1', '$3', 10)
s3 = S('command', 'subu', '$3', '$1', 5)
s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4])
create_gen_kill(block, get_defs([block]))
self.assertEqual(block.gen_set, set([s2.sid, s3.sid, s4.sid]))
self.assertEqual(block.kill_set, set([s1.sid]))
def test_create_in_out(self):
s11 = S('command', 'li', 'a', 3)
s12 = S('command', 'li', 'b', 5)
s13 = S('command', 'li', 'd', 4)
s14 = S('command', 'li', 'x', 100)
s15 = S('command', 'beq', 'a', 'b', 'L1')
s21 = S('command', 'addu', 'c', 'a', 'b')
s22 = S('command', 'li', 'd', 2)
s31 = S('label', 'L1')
s32 = S('command', 'li', 'c', 4)
s33 = S('command', 'mult', 'b', 'd')
s34 = S('command', 'mflo', 'temp')
s35 = S('command', 'addu', 'return', 'temp', 'c')
b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
s31, s32, s33, s34, s35])
generate_flow_graph([b1, b2, b3])
create_in_out([b1, b2, b3])
self.assertEqual(b1.gen_set, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b1.kill_set, set([s22.sid]))
self.assertEqual(b2.gen_set, set([s21.sid, s22.sid]))
self.assertEqual(b2.kill_set, set([s13.sid, s32.sid]))
self.assertEqual(b3.gen_set, set([s32.sid, s34.sid, s35.sid]))
self.assertEqual(b3.kill_set, set([s21.sid]))
self.assertEqual(b1.reach_in, set())
self.assertEqual(b1.reach_out, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b2.reach_in, set([s11.sid, s12.sid, s13.sid,
s14.sid]))
self.assertEqual(b2.reach_out, set([s21.sid, s22.sid, s11.sid, \
s12.sid, s14.sid]))
self.assertEqual(b3.reach_in, set([s21.sid, s22.sid, s11.sid, \
s12.sid, s13.sid, s14.sid]))
self.assertEqual(b3.reach_out, set([s32.sid, s34.sid, s35.sid, \
s22.sid, s11.sid, s12.sid, \
s13.sid, s14.sid]))
...@@ -95,23 +95,19 @@ class TestStatement(unittest.TestCase): ...@@ -95,23 +95,19 @@ class TestStatement(unittest.TestCase):
self.assertFalse(S('label', 'addu').is_arith()) self.assertFalse(S('label', 'addu').is_arith())
def test_get_def(self): def test_get_def(self):
self.assertEqual(S('command', 'move', '$1', '$2').get_def(), ['$1']) a = ['a']
self.assertEqual(S('command', 'subu', '$1', '$2').get_def(), ['$1'])
self.assertEqual(S('command', 'addu','$1','$2','$3').get_def(), ['$1']) self.assertEqual(S('command', 'move', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'sll','$1','$2','$3').get_def(), ['$1']) self.assertEqual(S('command', 'subu', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'srl','$1','$2','$3').get_def(), ['$1']) self.assertEqual(S('command', 'addu', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'la', '$1','16($fp)').get_def(), ['$1']) self.assertEqual(S('command', 'sll', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command', 'li', '$1','16($fp)').get_def(), ['$1']) self.assertEqual(S('command', 'srl', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command','add.d', '$1','$2','$3').get_def(),['$1']) self.assertEqual(S('command', 'la', 'a', '16($fp)').get_def(), a)
self.assertEqual(S('command','neg.d', '$1','$2').get_def(),['$1']) self.assertEqual(S('command', 'li', 'a', '16($fp)').get_def(), a)
self.assertEqual(S('command','sub.d','$1','$2', '$3').get_def(),['$1']) self.assertEqual(S('command', 'add.d', 'a', 'b', 'c').get_def(), a)
self.assertEqual(S('command','slt', '$1','$2').get_def(),['$1']) self.assertEqual(S('command', 'neg.d', 'a', 'b').get_def(), a)
self.assertEqual(S('command','xori', '$1','$2', '0x0000').get_def(), \ self.assertEqual(S('command', 'sub.d', 'a', 'b', 'c').get_def(), a)
['$1']) self.assertEqual(S('command', 'slt', 'a', 'b').get_def(), a)
self.assertEqual(S('command','mov.d', '$1','$2').get_def(), ['$1']) self.assertEqual(S('command', 'xori', 'a', 'b', '0x0000').get_def(), a)
self.assertEqual(S('command','dmfc1', '$1','$f0').get_def(), ['$1']) self.assertEqual(S('command', 'mov.d', 'a', 'b').get_def(), a)
self.assertEqual(S('command', 'dmfc1', 'a', '$f0').get_def(), a)
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