Skip to content
Snippets Groups Projects
Commit 6924b53c authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Separated liveness, reaching definitions and dominator tree from dataflow.py.

parent 053da966
No related branches found
No related tags found
No related merge requests found
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):
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
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
def create_gen_kill(block):
# Get the last of each definition series and put in in the `def' set
block.live_gen = set()
block.live_kill = set()
print 'block:', block
for s in block:
# If a register is used without having been defined in this block,
# yet, put it in the `gen' set
for reg in s.get_use():
if reg not in block.live_kill:
print ' add:', reg
block.live_gen.add(reg)
for reg in s.get_def():
block.live_kill.add(reg)
def create_in_out(blocks):
pass
from dataflow import BasicBlock as B, generate_flow_graph
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.reach_gen = 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)
# Generate kill set
block.reach_kill = set()
for reg, statement_ids in global_defs.iteritems():
if reg in block_defs:
block.reach_kill |= 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)
print 'defs:', defs
for b in blocks:
create_gen_kill(b, defs)
b.reach_out = b.reach_gen
change = True
while change:
change = False
for b in blocks:
print 'block:', b
b.reach_in = set()
for pred in b.edges_from:
print 'pred: ', pred
b.reach_in |= pred.reach_out
print 'b.reach_in: ', b.reach_in
print 'b.reach_out: ', b.reach_out
new_out = b.reach_gen | (b.reach_in - b.reach_kill)
print 'new_out: ', new_out
if new_out != b.reach_out:
print 'changed'
b.reach_out = new_out
change = True
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
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)
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
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_gen_kill(block)
self.assertEqual(block.live_gen, set(['$1', '$2']))
self.assertEqual(block.live_kill, set(['$3', '$1', '$1']))
#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', '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])
# create_in_out([b1, b2, b3])
# self.assertEqual(b1.live_gen, set([s11.sid, s12.sid, s13.sid, s14.sid]))
# self.assertEqual(b1.live_kill, set([s22.sid]))
# self.assertEqual(b2.live_gen, set([s21.sid, s22.sid]))
# self.assertEqual(b2.live_kill, set([s13.sid, s32.sid]))
# self.assertEqual(b3.live_gen, set([s32.sid, s34.sid, s35.sid]))
# self.assertEqual(b3.live_kill, set([s21.sid]))
# 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())
import unittest
from src.statement import Statement as S
from src.dataflow import BasicBlock as B
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_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])
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]))
#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])
# create_gen_kill(b1, defs)
# create_gen_kill(b2, defs)
# create_gen_kill(b3, defs)
# self.assertEqual(b1.reach_gen, 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]))
#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', '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])
# create_in_out([b1, b2, b3])
# self.assertEqual(b1.reach_in, set())
# self.assertEqual(b1.reach_out, set([s11.sid, s12.sid, s13.sid]))
# self.assertEqual(b2.reach_in, set([s11.sid, s12.sid]))
# self.assertEqual(b2.reach_out, set([s12.sid, s22.sid]))
# self.assertEqual(b3.reach_in, set([s12.sid, s22.sid]))
# self.assertEqual(b3.reach_out, set())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment