-
Notifications
You must be signed in to change notification settings - Fork 0
/
df.py
executable file
·127 lines (112 loc) · 3.64 KB
/
df.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import argparse
import json
import sys
from cfg import cfg
from briltxt import instr_to_string
class Dataflow :
def __init__(self, init, direction, meet, transfer):
self.init = init
self.direction = direction
self.meet = meet
self.transfer = transfer
if printer != "default":
self.printer = printer
def df(self, func_cfg):
analysis = {} # label -> (in, out)
if self.direction == "FORWARD":
preds = func_cfg['lbl2pred']
succs = func_cfg['lbl2succ']
if self.direction == "BACKWARD":
preds = func_cfg['lbl2succ']
succs = func_cfg['lbl2pred']
# initialize variables
worklist = set(func_cfg['lbl2block'].keys())
analysis = {} # label -> (in, out)
for lbl in worklist:
analysis[lbl] = (None, self.init)
# perform analysis
while worklist:
lbl = worklist.pop()
if len(preds[lbl]) == 0:
# print("no preds")
inb = self.init
else:
# print("has preds")
inb = analysis[preds[lbl][0]][1]
# print("partial in: ", inb)
for i in range(1, len(preds[lbl])):
pred = preds[lbl][i]
inb = self.meet(inb, analysis[pred][1])
# print("partial in: ", inb)
outb = self.transfer(func_cfg['lbl2block'][lbl], inb)
if outb != analysis[lbl][1]:
worklist.update(succs[lbl])
analysis[lbl] = (inb.copy(), outb.copy())
# if this is a backwards pass, reverse the input and output
if self.direction == "BACKWARD":
for lbl, output in analysis.items():
analysis[lbl] = (output[1], output[0])
return analysis
def printer(blocks, analysis):
lbls = [block[0]['label'] for block in blocks]
for lbl in lbls:
data = analysis[lbl]
print(" ", lbl)
print(" in: ", data[0])
print(" out: ", data[1])
def reaching_defs(cfg):
def meet(reachable1, reachable2):
reachable = {}
for dest, instrs in reachable1.items():
reachable[dest] = instrs.copy()
for dest, instrs in reachable2.items():
reachable[dest] = reachable.get(dest, [])
non_duplicates = [instr for instr in instrs if instr not in reachable[dest]]
reachable[dest].extend(non_duplicates)
return reachable
def transfer(block, inb):
outb = inb.copy()
kill = False
for instr in block:
if 'dest' in instr:
outb[instr['dest']] = [instr]
kill = True
return outb if kill else inb
def printer(blocks, analysis):
lbls = [block[0]['label'] for block in blocks]
for lbl in lbls:
in_, out_ = analysis[lbl]
print(" block:", lbl)
inb = [instr for instrs in in_.values() for instr in instrs]
print(" in: ")
for instr in inb:
print(' {}'.format(instr_to_string(instr)))
outb = [instr for instrs in out_.values() for instr in instrs]
print(" out: ")
for instr in outb:
print(' {}'.format(instr_to_string(instr)))
solver = Dataflow(dict(), "FORWARD", meet, transfer)
defs = solver.df(cfg)
printer(cfg['blocks'], defs)
def live_vars(cfg):
def meet(live1, live2): return live1.union(live2)
def transfer(block, outb):
inb = outb.copy()
for instr in reversed(block):
if 'dest' in instr:
inb.discard(instr['dest'])
for arg in instr.get('args', []):
inb.add(arg)
return inb
solver = Dataflow(set(), "BACKWARD", meet, transfer)
return solver.df(cfg)
if __name__ == "__main__":
analysis = sys.argv[1]
prog = json.load(sys.stdin)
if analysis == "reaching":
for func in prog['functions']:
print(func['name'], ":")
func_cfg = cfg(func['instrs'])
reaching_defs(func_cfg)
else:
print("Not a valid argument")