-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathllvmUtil.py
153 lines (144 loc) · 4.53 KB
/
llvmUtil.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
This compiler interface was implemented for Clang version 3.8.0.
The cleanup stage (part of the process method) might not work properly for other versions of Clang.
"""
import os
import re
import ConfigParser
from compilerUtil import create_source_file
from regex import match
llvm_config = ConfigParser.ConfigParser()
llvm_config.read('configs/llvm.config')
llvm_separator = ' ; '
def compiler(s, check_success=False):
src_file = create_source_file(s)
tgt_file = 'tmp' + str(os.getpid()) + '.ll'
optimization_level = ' -O0' if llvm_config.getboolean('Compile', 'Optimized') else ''
os.system('clang -S -emit-llvm' + optimization_level + ' -o '+tgt_file+' '+src_file+' > /dev/null 2>&1')
if check_success:
if not os.path.exists(tgt_file):
return None
with open(tgt_file, 'r') as f:
lines = [l.strip() for l in f.readlines()]
splitlines = []
for l in lines:
splitlines += l.split(' ; ')
lines = splitlines
start = min(filter(lambda i: lines[i].startswith('define') and 'main()' in lines[i], range(len(lines))))
lines = lines[start+1:]
end = min(filter(lambda i: lines[i] == '}', range(len(lines))))
lines = lines[:end-1]
lllines = []
for line in lines:
line = line.strip().replace(',', ' ,')
line = re.sub('[ \t]+', ' ', line)
if line.startswith(';'):
line = line[1:].strip()
if len(line) > 0:
lllines += [line.strip()]
try:
os.remove(src_file)
os.remove(tgt_file)
except OSError:
pass
return process(lllines)
def process(lines):
res = ''
labels = {}
for line in lines:
if line.startswith('<label>:'):
num = line[8:]
if ' ' in num:
num = num[:num.find(' ')]
labels[num] = str(len(labels.keys()))
for line in lines:
line = line.strip()
if len(line) == 0:
continue
if llvm_config.getboolean('Process', 'RemovePreds'):
if line.startswith('preds '):
continue
if llvm_config.getboolean('Compile', 'Optimized'):
if '!' in line:
line = line[:line.find('!')].strip()[:-1].strip()
if llvm_config.getboolean('Process', 'RemoveAlign4'):
line = re.sub(', align 4', ' ', line)
if llvm_config.getboolean('Process', 'RemoveI32'):
line = re.sub('i32\*? ', '', line)
line = re.sub('i1 ', '', line)
if llvm_config.getboolean('Process', 'RemoveNSW'):
line = re.sub('nsw ', '', line)
if llvm_config.getboolean('Process', 'ReplaceLabels'):
for label in labels.keys():
line = re.sub('<label>:'+label+'$', '<label>'+labels[label]+' :', line)
line = re.sub('label %'+label+'$', '<label>'+labels[label], line)
line = re.sub('label %'+label+' ', '<label>'+labels[label]+' ', line)
res += line+' ; '
res = re.sub('[ \t]+', ' ', res)
return res.strip()
def is_number(n):
return match("^[0-9]+$", n)
def get_number(n):
return n
equivalent_ops = []
class Instruction:
def __init__(self, code, i):
self.code = code
self.op = ''
self.is_jump = False
self.is_label = False
self.targets = []
self.defines = []
self.is_branch = False
self.is_condition = False
self.uses = []
self.is_symmetric = False
self.labels = []
self.can_be_reduced = False
self.parse_instruction(code, i)
def parse_instruction(self, code, i):
if code in ['__entry__', '__exit__']:
self.op = code
return
if re.match('^<label>[0-9]+ :$', code):
self.is_label = True
self.labels.append(code)
return
if code.startswith('br '):
self.is_jump = True
self.op = 'br'
code = code[3:]
if ',' in self.code:
self.is_branch = True
parts = map(lambda x: x.strip(), code.split(','))
labels = parts[1:]
self.uses.append(parts[0])
else:
labels = [code]
self.targets = ['<label>'+x[7:]+' :' for x in labels]
elif code.startswith('store'):
code = code[6:]
parts = map(lambda x: x.strip(), code.split(','))
self.op = 'store'
self.defines = [parts[1][1:]]
self.uses.append(parts[0])
elif ' = ' in self.code:
self.defines = [self.code.split(' = ')[0].strip()]
code = code[code.index('=')+1:].strip()
self.op = code[:code.index(' ')]
if code.startswith('load'):
self.uses.append(code.split(',')[1].strip()[1:])
else:
code = code[len(self.op)+1:].strip()
if self.op == 'icmp':
self.is_condition = True
self.relation = code[:code.index(' ')]
code = code[len(self.relation)+1:].strip()
self.uses += map(lambda x: x.strip(), code.split(','))
# normalize conditions
if self.is_condition:
if self.relation in ['sgt', 'sge']:
self.relation = 'sl' + self.relation[2]
self.uses.reverse()
if self.op in ['add', 'mul'] or (self.is_condition and self.relation in ['eq', 'ne']):
self.is_symmetric = True