Commit 091fc8d0 authored by Taddeus Kroes's avatar Taddeus Kroes

Implemented variable liveness analysis, renamed the sets for RD.

parent a6dfda54
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 # Get the last of each definition series and put in in the `def' set
block.live_gen = set() block.use_set = set()
block.live_kill = set() block.def_set = set()
for s in block: for s in block:
# If a register is used without having been defined in this block, # use[B] is the set of variables whose values may be used in B prior to
# yet, put it in the `gen' set # any definition of the variable
for reg in s.get_use(): for reg in s.get_use():
if reg not in block.live_kill: used.add(reg)
block.live_gen.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(): 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): def create_in_out(blocks):
for b in blocks: for b in blocks:
b.live_in = set() create_use_def(b)
b.live_in = b.use_set
b.live_out = 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 from src.dataflow import find_basic_blocks, generate_flow_graph
import src.liveness as liveness import src.liveness as liveness
import src.reaching_definitions as reaching_definitions import src.reaching_definitions as reaching_definitions
...@@ -51,6 +51,7 @@ def optimize(statements, verbose=0): ...@@ -51,6 +51,7 @@ def optimize(statements, verbose=0):
blocks = find_basic_blocks(statements) blocks = find_basic_blocks(statements)
# Perform dataflow analysis # Perform dataflow analysis
generate_flow_graph(blocks)
liveness.create_in_out(blocks) liveness.create_in_out(blocks)
reaching_definitions.create_in_out(blocks) reaching_definitions.create_in_out(blocks)
......
...@@ -271,7 +271,7 @@ def copy_propagation(block): ...@@ -271,7 +271,7 @@ def copy_propagation(block):
# the list. # the list.
i = 0 i = 0
while i < len(moves_to): while i < len(moves_to):
if moves_to[i] == s[0] or moves_to[i] == s[1]: if moves_to[i] == s[0] or moves_to[i] == s[1]:
del moves_to[i] del moves_to[i]
del moves_from[i] del moves_from[i]
......
from dataflow import BasicBlock as B, generate_flow_graph from dataflow import BasicBlock as B
def get_defs(blocks): def get_defs(blocks):
...@@ -20,34 +20,31 @@ def create_gen_kill(block, global_defs): ...@@ -20,34 +20,31 @@ def create_gen_kill(block, global_defs):
block_defs = {} block_defs = {}
# Get the last of each definition series and put in in the `def' set # 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 s in reversed(block):
for reg in s.get_def(): for reg in s.get_def():
if reg not in block_defs: if reg not in block_defs:
block_defs[reg] = s.sid block_defs[reg] = s.sid
block.reach_gen.add(s.sid) block.gen_set.add(s.sid)
# Generate kill set # Generate kill set
block.reach_kill = set() block.kill_set = set()
for reg, statement_ids in global_defs.iteritems(): for reg, statement_ids in global_defs.iteritems():
if reg in block_defs: 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): def create_in_out(blocks):
"""Generate the `in' and `out' sets of the given blocks using the iterative """Generate the `in' and `out' sets of the given blocks using the iterative
algorithm from the lecture slides.""" algorithm from the lecture slides."""
# Generate flow graph
generate_flow_graph(blocks)
# Create gen/kill sets # Create gen/kill sets
defs = get_defs(blocks) defs = get_defs(blocks)
for b in blocks: for b in blocks:
create_gen_kill(b, defs) create_gen_kill(b, defs)
b.reach_out = b.reach_gen b.reach_out = b.gen_set
change = True change = True
...@@ -60,7 +57,7 @@ def create_in_out(blocks): ...@@ -60,7 +57,7 @@ def create_in_out(blocks):
for pred in b.edges_from: for pred in b.edges_from:
b.reach_in |= pred.reach_out 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: if new_out != b.reach_out:
b.reach_out = new_out b.reach_out = new_out
......
import unittest import unittest
from src.statement import Statement as S from src.statement import Statement as S
from src.dataflow import BasicBlock as B from src.dataflow import BasicBlock as B, find_basic_blocks, \
from src.liveness import create_gen_kill, create_in_out generate_flow_graph
from src.liveness import create_use_def, create_in_out
class TestLiveness(unittest.TestCase): class TestLiveness(unittest.TestCase):
...@@ -20,44 +21,45 @@ class TestLiveness(unittest.TestCase): ...@@ -20,44 +21,45 @@ class TestLiveness(unittest.TestCase):
s4 = S('command', 'li', '$4', '0x00000001') s4 = S('command', 'li', '$4', '0x00000001')
block = B([s1, s2, s3, s4]) 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.use_set, set(['$1', '$2']))
self.assertEqual(block.live_kill, set(['$3', '$1', '$4'])) self.assertEqual(block.def_set, set(['$3', '$4']))
#def test_create_in_out(self): def test_create_in_out(self):
# s11 = S('command', 'li', 'a', 3) s11 = S('command', 'li', 'a', 3)
# s12 = S('command', 'li', 'b', 5) s12 = S('command', 'li', 'b', 5)
# s13 = S('command', 'li', 'd', 4) s13 = S('command', 'li', 'd', 4)
# s14 = S('command', 'li', 'x', 100) s14 = S('command', 'li', 'x', 100)
# s15 = S('command', 'beq', 'a', 'b', 'L1') s15 = S('command', 'beq', 'a', 'b', 'L1')
# b1 = B([s11, s12, s13, s14, s15])
# s21 = S('command', 'addu', 'c', 'a', 'b') s21 = S('command', 'addu', 'c', 'a', 'b')
# s22 = S('command', 'li', 'd', 2) s22 = S('command', 'li', 'd', 2)
# b2 = B([s21, s22])
# s31 = S('label', 'L1') s31 = S('label', 'L1')
# s32 = S('command', 'li', 'c', 4) s32 = S('command', 'li', 'c', 4)
# s33 = S('command', 'mult', 'b', 'd') s33 = S('command', 'mult', 'b', 'd')
# s34 = S('command', 'mflo', 'temp') s34 = S('command', 'mflo', 'temp')
# s35 = S('command', 'addu', 'return', 'temp', 'c') s35 = S('command', 'addu', 'return', 'temp', 'c')
# b3 = B([s31, s32, s33, s34, s35])
# 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])) generate_flow_graph([b1, b2, b3])
# self.assertEqual(b1.live_kill, set([s22.sid])) create_in_out([b1, b2, b3])
# self.assertEqual(b2.live_gen, set([s21.sid, s22.sid])) self.assertEqual(b1.use_set, set())
# self.assertEqual(b2.live_kill, set([s13.sid, s32.sid])) self.assertEqual(b1.def_set, set(['a', 'b', 'd', 'x']))
# self.assertEqual(b3.live_gen, set([s32.sid, s34.sid, s35.sid])) self.assertEqual(b2.use_set, set(['a', 'b']))
# self.assertEqual(b3.live_kill, set([s21.sid])) self.assertEqual(b2.def_set, set(['c', 'd']))
# self.assertEqual(b1.live_in, set()) self.assertEqual(b3.use_set, set(['b', 'd']))
# self.assertEqual(b1.live_out, set([s11.sid, s12.sid, s13.sid])) self.assertEqual(b3.def_set, set(['c', 'temp', 'return']))
# self.assertEqual(b2.live_in, set([s11.sid, s12.sid]))
# self.assertEqual(b2.live_out, set([s12.sid, s22.sid])) self.assertEqual(b1.live_in, set())
# self.assertEqual(b3.live_in, set([s12.sid, s22.sid])) self.assertEqual(b1.live_out, set(['a', 'b', 'd']))
# self.assertEqual(b3.live_out, set()) 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,8 @@ from copy import copy ...@@ -3,7 +3,8 @@ 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 import src.liveness as liveness
......
import unittest import unittest
from src.statement import Statement as S 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 from src.reaching_definitions import get_defs, create_gen_kill, create_in_out
...@@ -35,8 +36,8 @@ class TestReachingDefinitions(unittest.TestCase): ...@@ -35,8 +36,8 @@ class TestReachingDefinitions(unittest.TestCase):
create_gen_kill(block, get_defs([block])) create_gen_kill(block, get_defs([block]))
self.assertEqual(block.reach_gen, set([s2.sid, s3.sid, s4.sid])) self.assertEqual(block.gen_set, set([s2.sid, s3.sid, s4.sid]))
self.assertEqual(block.reach_kill, set([s1.sid])) self.assertEqual(block.kill_set, set([s1.sid]))
def test_create_in_out(self): def test_create_in_out(self):
s11 = S('command', 'li', 'a', 3) s11 = S('command', 'li', 'a', 3)
...@@ -57,15 +58,16 @@ class TestReachingDefinitions(unittest.TestCase): ...@@ -57,15 +58,16 @@ class TestReachingDefinitions(unittest.TestCase):
b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \ b1, b2, b3 = find_basic_blocks([s11, s12, s13, s14, s15, s21, s22, \
s31, s32, s33, s34, s35]) s31, s32, s33, s34, s35])
generate_flow_graph([b1, b2, b3])
create_in_out([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])) s14.sid]))
self.assertEqual(b1.reach_kill, set([s22.sid])) self.assertEqual(b1.kill_set, set([s22.sid]))
self.assertEqual(b2.reach_gen, set([s21.sid, s22.sid])) self.assertEqual(b2.gen_set, set([s21.sid, s22.sid]))
self.assertEqual(b2.reach_kill, set([s13.sid, s32.sid])) self.assertEqual(b2.kill_set, set([s13.sid, s32.sid]))
self.assertEqual(b3.reach_gen, set([s32.sid, s34.sid, s35.sid])) self.assertEqual(b3.gen_set, set([s32.sid, s34.sid, s35.sid]))
self.assertEqual(b3.reach_kill, set([s21.sid])) self.assertEqual(b3.kill_set, set([s21.sid]))
self.assertEqual(b1.reach_in, set()) self.assertEqual(b1.reach_in, set())
self.assertEqual(b1.reach_out, set([s11.sid, s12.sid, s13.sid, self.assertEqual(b1.reach_out, set([s11.sid, s12.sid, s13.sid,
......
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