-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathllvmcfg.py
executable file
·91 lines (80 loc) · 2.93 KB
/
llvmcfg.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
#!/usr/bin/env python3
import re
import sys
def func_begin(out, name):
out.write(f"\n<h2>{name}</h2>\n")
out.write("<svg class=\"graphdrawing resizeToBBox\">\n")
out.write("<g class=\"layout\">\n")
def func_end(out, nodes, edges, branches):
for n in nodes:
branch_insn = branches.get(n)
out.write(f" <text id=\"{n}\">\n")
out.write(f" <tspan x=\"0\" dy=\".6em\" class=\"label\">{n}:</tspan>\n")
if branch_insn is not None:
out.write(f" <tspan x=\"0\" dy=\"1.2em\" class=\"terminator\"> {branch_insn}</span>\n")
out.write(f" </text>\n")
out.write("\n")
for e in edges:
out.write(f" <path class=\"edge\" src=\"{e[0]}\" dst=\"{e[1]}\"/>\n")
out.write("</g>\n")
out.write("</svg>\n")
def translate(out, fp):
DEFINE_FUNC = re.compile(r"^define .*@(?P<funcname>[^(]+)\(")
BLOCK_BEGIN = re.compile(r"^(?P<blockname>[a-zA-Z0-9_.]+):")
BRANCH = re.compile(r"^\s+(?P<insn>br|invoke) (?P<branchops>.*)")
INVOKE_CONT = re.compile(r"^\s+to label.*unwind.*")
LABEL = re.compile(r"label %(?P<label>[a-zA-Z0-9_.]+)")
TERMINATOR = re.compile(f"^\s+(?P<insn>ret|unreachable)")
current_func = None
current_block = None
nodes = set()
edges = []
branches = dict()
for line in fp:
m = DEFINE_FUNC.match(line)
if m:
if current_func is not None:
func_end(out, nodes, edges, branches)
nodes.clear()
edges.clear()
current_func = m.group("funcname")
current_block = "0"
func_begin(out, current_func)
continue
m = BLOCK_BEGIN.match(line)
if m:
current_block = m.group("blockname")
nodes.add(current_block)
continue
m = BRANCH.match(line)
m2 = INVOKE_CONT.match(line)
if m or m2:
if current_block is None:
sys.stderr.write("Branch appears to be outside basic block?")
continue
if m:
branches[current_block] = m.group("insn")
elif m2:
branches[current_block] = "invoke"
for m in LABEL.finditer(line):
target = m.group("label")
nodes.add(target)
edges.append((current_block, target))
m = TERMINATOR.match(line)
if m:
branches[current_block] = m.group("insn")
# TODO:
# - Does not work for unnamed/numbered blocks
# - No support for switch
# - No support for indirectbr / computed goto etc.
if current_func is not None:
func_end(out, nodes, edges, branches)
def main():
filename = sys.argv[1]
out = sys.stdout
out.write(open("llvmcfg.header.snippet", "r").read())
with open(filename) as fp:
translate(out, fp)
out.write(open("llvmcfg.footer.snippet", "r").read())
if __name__ == "__main__":
main()