Explorar o código

Implemented variable liveness analysis, renamed the sets for RD.

Taddeus Kroes %!s(int64=14) %!d(string=hai) anos
pai
achega
091fc8d050

+ 59 - 9
src/liveness.py

@@ -1,20 +1,70 @@
-def create_gen_kill(block):
+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.live_gen = set()
-    block.live_kill = set()
+    block.use_set = set()
+    block.def_set = set()
 
     for s in block:
-        # If a register is used without having been defined in this block,
-        # yet, put it in the `gen' set
+        # 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():
-            if reg not in block.live_kill:
-                block.live_gen.add(reg)
+            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():
-            block.live_kill.add(reg)
+            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 not in known, block.edges_to)
+    p = copy(direct)
+
+    for successor in direct:
+        p += succ(successor, direct)
+
+    return p
 
 
 def create_in_out(blocks):
     for b in blocks:
-        b.live_in = set()
+        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

+ 2 - 1
src/optimize/__init__.py

@@ -1,4 +1,4 @@
-from src.dataflow import find_basic_blocks
+from src.dataflow import find_basic_blocks, generate_flow_graph
 import src.liveness as liveness
 import src.reaching_definitions as reaching_definitions
 
@@ -51,6 +51,7 @@ def optimize(statements, verbose=0):
     blocks = find_basic_blocks(statements)
 
     # Perform dataflow analysis
+    generate_flow_graph(blocks)
     liveness.create_in_out(blocks)
     reaching_definitions.create_in_out(blocks)
 

+ 1 - 1
src/optimize/advanced.py

@@ -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]

+ 7 - 10
src/reaching_definitions.py

@@ -1,4 +1,4 @@
-from dataflow import BasicBlock as B, generate_flow_graph
+from dataflow import BasicBlock as B
 
 
 def get_defs(blocks):
@@ -20,34 +20,31 @@ def create_gen_kill(block, global_defs):
     block_defs = {}
 
     # Get the last of each definition series and put in in the `def' set
-    block.reach_gen = 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.reach_gen.add(s.sid)
+                block.gen_set.add(s.sid)
 
     # Generate kill set
-    block.reach_kill = set()
+    block.kill_set = set()
 
     for reg, statement_ids in global_defs.iteritems():
         if reg in block_defs:
-            block.reach_kill |= statement_ids - set([block_defs[reg]])
+            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."""
-    # Generate flow graph
-    generate_flow_graph(blocks)
-
     # Create gen/kill sets
     defs = get_defs(blocks)
 
     for b in blocks:
         create_gen_kill(b, defs)
-        b.reach_out = b.reach_gen
+        b.reach_out = b.gen_set
 
     change = True
 
@@ -60,7 +57,7 @@ def create_in_out(blocks):
             for pred in b.edges_from:
                 b.reach_in |= pred.reach_out
 
-            new_out = b.reach_gen | (b.reach_in - b.reach_kill)
+            new_out = b.gen_set | (b.reach_in - b.kill_set)
 
             if new_out != b.reach_out:
                 b.reach_out = new_out

+ 36 - 34
tests/test_liveness.py

@@ -1,8 +1,9 @@
 import unittest
 
 from src.statement import Statement as S
-from src.dataflow import BasicBlock as B
-from src.liveness import create_gen_kill, create_in_out
+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):
@@ -20,44 +21,45 @@ class TestLiveness(unittest.TestCase):
         s4 = S('command', 'li', '$4', '0x00000001')
         block = B([s1, s2, s3, s4])
 
-        create_gen_kill(block)
+        create_use_def(block)
 
-        self.assertEqual(block.live_gen, set(['$1', '$2']))
-        self.assertEqual(block.live_kill, set(['$3', '$1', '$4']))
+        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')
-    #    b1 = B([s11, s12, s13, s14, s15])
+    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)
-    #    b2 = B([s21, s22])
+        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')
-    #    b3 = B([s31, s32, s33, s34, s35])
+        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')
 
-    #    create_in_out([b1, b2, b3])
+        b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
+                                        s31, s32, s33, s34, s35])
 
-    #    self.assertEqual(b1.live_gen, set([s11.sid, s12.sid, s13.sid, s14.sid]))
-    #    self.assertEqual(b1.live_kill, set([s22.sid]))
+        generate_flow_graph([b1, b2, b3])
+        create_in_out([b1, b2, b3])
 
-    #    self.assertEqual(b2.live_gen, set([s21.sid, s22.sid]))
-    #    self.assertEqual(b2.live_kill, set([s13.sid, s32.sid]))
+        self.assertEqual(b1.use_set, set())
+        self.assertEqual(b1.def_set, set(['a', 'b', 'd', 'x']))
 
-    #    self.assertEqual(b3.live_gen, set([s32.sid, s34.sid, s35.sid]))
-    #    self.assertEqual(b3.live_kill, set([s21.sid]))
+        self.assertEqual(b2.use_set, set(['a', 'b']))
+        self.assertEqual(b2.def_set, set(['c', 'd']))
 
-    #    self.assertEqual(b1.live_in, set())
-    #    self.assertEqual(b1.live_out, set([s11.sid, s12.sid, s13.sid]))
-    #    self.assertEqual(b2.live_in, set([s11.sid, s12.sid]))
-    #    self.assertEqual(b2.live_out, set([s12.sid, s22.sid]))
-    #    self.assertEqual(b3.live_in, set([s12.sid, s22.sid]))
-    #    self.assertEqual(b3.live_out, set())
+        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())

+ 2 - 1
tests/test_optimize_advanced.py

@@ -3,7 +3,8 @@ 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
 
 

+ 11 - 9
tests/test_reaching_definitions.py

@@ -1,7 +1,8 @@
 import unittest
 
 from src.statement import Statement as S
-from src.dataflow import BasicBlock as B, find_basic_blocks
+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
 
 
@@ -35,8 +36,8 @@ class TestReachingDefinitions(unittest.TestCase):
 
         create_gen_kill(block, get_defs([block]))
 
-        self.assertEqual(block.reach_gen, set([s2.sid, s3.sid, s4.sid]))
-        self.assertEqual(block.reach_kill, set([s1.sid]))
+        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)
@@ -57,15 +58,16 @@ class TestReachingDefinitions(unittest.TestCase):
         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.reach_gen, set([s11.sid, s12.sid, s13.sid,
+        self.assertEqual(b1.gen_set, set([s11.sid, s12.sid, s13.sid,
                                             s14.sid]))
-        self.assertEqual(b1.reach_kill, set([s22.sid]))
-        self.assertEqual(b2.reach_gen, set([s21.sid, s22.sid]))
-        self.assertEqual(b2.reach_kill, set([s13.sid, s32.sid]))
-        self.assertEqual(b3.reach_gen, set([s32.sid, s34.sid, s35.sid]))
-        self.assertEqual(b3.reach_kill, set([s21.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,