Sfoglia il codice sorgente

Fixed merge conflict.

Jayke Meijer 14 anni fa
parent
commit
0c7d903df5

+ 1 - 1
Makefile

@@ -1,5 +1,5 @@
 BUILD=build/
-CLEAN=src/*.pyc src/optimize/*.pyc
+CLEAN=*.pyc src/*.pyc src/optimize/*.pycrm -f parser.out parsetab.py
 
 # Fix pdflatex search path
 TGT_DIR :=

+ 10 - 1
main.py

@@ -7,11 +7,20 @@ if __name__ == '__main__':
     from sys import argv, exit
 
     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)
 
     # Parse File
     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)
 
     if len(argv) > 2:

+ 3 - 3
report/report.tex

@@ -105,18 +105,17 @@ addu	$2,$4,$3              addu = $t1, $4, $3
 ...                        mov = $2, $t1
 ...                   ->   ...
 ...                        ...
-addu	$5,$4,$3		   mov = $4, $t1
+addu	$5,$4,$3              mov = $4, $t1
 
 \end{verbatim}
 
-
 A standard method for doing this is the creation of a DAG or Directed Acyclic
 Graph. However, this requires a fairly advanced implementation. Our
 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
 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
-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
 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
 primary concern, this is not a big problem.
 
 \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.
 
 
 

+ 50 - 0
src/dag.py

@@ -0,0 +1,50 @@
+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

+ 0 - 189
src/dataflow.py

@@ -9,10 +9,6 @@ class BasicBlock(Block):
 
         self.dominates = []
         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):
         if block not in self.edges_to:
@@ -24,90 +20,6 @@ class BasicBlock(Block):
             self.dominates.append(block)
             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):
     """Determine the leaders, which are:
@@ -169,104 +81,3 @@ def generate_flow_graph(blocks):
                 b.add_edge_to(blocks[i + 1])
         elif i < len(blocks) - 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

+ 50 - 0
src/dominator.py

@@ -0,0 +1,50 @@
+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

+ 71 - 0
src/liveness.py

@@ -0,0 +1,71 @@
+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

+ 9 - 4
src/optimize/__init__.py

@@ -1,9 +1,11 @@
-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, \
         move_4, load, shift, add
 from advanced import eliminate_common_subexpressions, fold_constants, \
-        copy_propagation, algebraic_transformations, eliminate_dead_code
+        copy_propagation, eliminate_dead_code
 
 
 def remove_redundancies(block):
@@ -41,6 +43,7 @@ def optimize(statements, verbose=0):
     """Optimization wrapper function, calls global and basic-block level
     optimization functions."""
     # Optimize on a global level
+    # TODO: only count instructions (no directives)
     o = len(statements)
     remove_redundant_jumps(statements)
     g = len(statements)
@@ -48,8 +51,10 @@ def optimize(statements, verbose=0):
     # Divide into basic blocks
     blocks = find_basic_blocks(statements)
 
-    # Find reaching definitions
-    reaching_definitions(blocks)
+    # Perform dataflow analysis
+    generate_flow_graph(blocks)
+    liveness.create_in_out(blocks)
+    reaching_definitions.create_in_out(blocks)
 
     # Optimize basic blocks
     map(optimize_block, blocks)

+ 2 - 2
src/optimize/advanced.py

@@ -18,7 +18,7 @@ def reg_can_be_used_in(reg, block, start, end):
         elif s.defines(reg):
             return True
 
-    return reg not in block.out_set
+    return reg not in block.live_out
 
 
 def find_free_reg(block, start, end):
@@ -271,7 +271,7 @@ def copy_propagation(block):
             # the list.
             i = 0
 
-            while i  < len(moves_to):
+            while i < len(moves_to):
                 if moves_to[i] == s[0] or moves_to[i] == s[1]:
                     del moves_to[i]
                     del moves_from[i]

+ 64 - 0
src/reaching_definitions.py

@@ -0,0 +1,64 @@
+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

+ 9 - 5
src/statement.py

@@ -107,6 +107,7 @@ class Statement:
         return self.is_command() \
                and re.match('^l(w|a|b|bu|\.d|\.s)|dlw$', \
                             self.name)
+
     def is_logical(self):
         """Check if the statement is a logical operator."""
         return self.is_command() and re.match('^(xor|or|and)i?$', self.name)
@@ -160,7 +161,7 @@ class Statement:
                 or self.is_set_if_less() or self.is_convert() \
                 or self.is_truncate() or self.is_load() \
                 or self.is_command(*instr):
-            return [self[0]]
+            return self[:1]
 
         return []
 
@@ -175,7 +176,9 @@ class Statement:
                 or self.is_command(*['mult', 'div', 'dsz', 'mtc1']):
             if self.name == 'dsz':
                 m = re.match('^\d+\(([^)]+)\)$', self[0])
-                use.append(m)
+
+                if m:
+                    use.append(m.group(1))
             else:
                 use.append(self[0])
         # Case arg1 direct adressing
@@ -188,15 +191,16 @@ class Statement:
         # Case arg1 relative adressing
         if self.is_load_non_immediate() or self.is_store():
             m = re.match('^\d+\(([^)]+)\)$', self[1])
+
             if m:
-                use.append(m)
+                use.append(m.group(1))
             else:
                 use.append(self[1])
         # Case arg2
         if self.is_double_arithmetic() or self.is_set_if_less() \
                 or self.is_logical() \
                 or self.is_command(*['addu', 'subu']):
-            if not isinstance(self[2] , int):
+            if not isinstance(self[2], int):
                     use.append(self[2])
 
         return use
@@ -246,7 +250,7 @@ class Block:
 
     def end(self):
         """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):
         """Read the statements until an offset from the current pointer

+ 2 - 0
test.py

@@ -1,3 +1,5 @@
+#!/usr/bin/python
 from testrunner import main
 import sys
+
 main(sys.argv[1:])

+ 65 - 0
tests/test_dag.py

@@ -0,0 +1,65 @@
+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)

+ 1 - 137
tests/test_dataflow.py

@@ -2,8 +2,7 @@ import unittest
 
 from src.statement import Statement as S
 from src.dataflow import BasicBlock as B, find_leaders, find_basic_blocks, \
-        generate_flow_graph, Dag, DagNode, DagLeaf, get_defs, \
-        reaching_definitions
+        generate_flow_graph
 
 
 class TestDataflow(unittest.TestCase):
@@ -25,90 +24,6 @@ class TestDataflow(unittest.TestCase):
                 [B(s[:2]).statements, B(s[2: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):
         b1 = B([S('command', 'foo'), S('command', 'j', 'b2')])
         b2 = B([S('label', 'b2'), S('command', 'bar')])
@@ -129,54 +44,3 @@ class TestDataflow(unittest.TestCase):
         self.assertEqual(b2.edges_to, [b3])
         self.assertIn(b1, 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)

+ 65 - 0
tests/test_liveness.py

@@ -0,0 +1,65 @@
+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())

+ 6 - 2
tests/test_optimize_advanced.py

@@ -3,7 +3,9 @@ from copy import copy
 
 from src.optimize.advanced import eliminate_common_subexpressions, \
         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):
@@ -22,6 +24,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
         e = [S('command', 'addu', '$8', '$regA', '$regB'), \
              S('command', 'move', '$regC', '$8'), \
              S('command', 'move', '$regD', '$8')]
+        liveness.create_in_out([b])
         eliminate_common_subexpressions(b)
         self.assertEqual(b.statements, e)
 
@@ -30,6 +33,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
                S('command', 'li', '$regA', '0x00000001'),
                S('command', 'addu', '$regD', '$regA', '$regB')])
         e = copy(b.statements)
+        liveness.create_in_out([b])
         eliminate_common_subexpressions(b)
         self.assertEqual(b.statements, e)
 
@@ -49,7 +53,7 @@ class TestOptimizeAdvanced(unittest.TestCase):
                    self.foo,
                    S('command', 'addu', '$3', '$2', '$4'),
                    self.bar])
-                   
+
     def test_copy_propagation_other_arg(self):
         block = B([self.foo,
                    S('command', 'move', '$1', '$2'),

+ 83 - 0
tests/test_reaching_definitions.py

@@ -0,0 +1,83 @@
+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]))

+ 17 - 21
tests/test_statement.py

@@ -93,25 +93,21 @@ class TestStatement(unittest.TestCase):
         self.assertTrue(S('command', 'addu', '$1', '$2', '$3').is_arith())
         self.assertFalse(S('command', 'foo').is_arith())
         self.assertFalse(S('label', 'addu').is_arith())
-        
+
     def test_get_def(self):
-        self.assertEqual(S('command', 'move', '$1', '$2').get_def(), ['$1'])
-        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', 'sll','$1','$2','$3').get_def(), ['$1'])
-        self.assertEqual(S('command', 'srl','$1','$2','$3').get_def(), ['$1'])
-        self.assertEqual(S('command', 'la', '$1','16($fp)').get_def(), ['$1'])
-        self.assertEqual(S('command', 'li', '$1','16($fp)').get_def(), ['$1'])
-        self.assertEqual(S('command','add.d', '$1','$2','$3').get_def(),['$1'])
-        self.assertEqual(S('command','neg.d', '$1','$2').get_def(),['$1'])
-        self.assertEqual(S('command','sub.d','$1','$2', '$3').get_def(),['$1'])
-        self.assertEqual(S('command','slt', '$1','$2').get_def(),['$1'])
-        self.assertEqual(S('command','xori', '$1','$2', '0x0000').get_def(), \
-                                                                     ['$1']) 
-        self.assertEqual(S('command','mov.d', '$1','$2').get_def(), ['$1'])
-        self.assertEqual(S('command','dmfc1', '$1','$f0').get_def(), ['$1'])
-        
-        
-        
-        
-        
+        a = ['a']
+
+        self.assertEqual(S('command', 'move', 'a', 'b').get_def(), a)
+        self.assertEqual(S('command', 'subu', 'a', 'b').get_def(), a)
+        self.assertEqual(S('command', 'addu', 'a', 'b', 'c').get_def(), a)
+        self.assertEqual(S('command', 'sll', 'a', 'b', 'c').get_def(), a)
+        self.assertEqual(S('command', 'srl', 'a', 'b', 'c').get_def(), a)
+        self.assertEqual(S('command', 'la', 'a', '16($fp)').get_def(), a)
+        self.assertEqual(S('command', 'li', 'a', '16($fp)').get_def(), a)
+        self.assertEqual(S('command', 'add.d', 'a', 'b', 'c').get_def(), a)
+        self.assertEqual(S('command', 'neg.d', 'a', 'b').get_def(), a)
+        self.assertEqual(S('command', 'sub.d', 'a', 'b', 'c').get_def(), a)
+        self.assertEqual(S('command', 'slt', 'a', 'b').get_def(), a)
+        self.assertEqual(S('command', 'xori', 'a', 'b', '0x0000').get_def(), a)
+        self.assertEqual(S('command', 'mov.d', 'a', 'b').get_def(), a)
+        self.assertEqual(S('command', 'dmfc1', 'a', '$f0').get_def(), a)