llvmlite 0.46.0b1__cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of llvmlite might be problematic. Click here for more details.
- llvmlite/__init__.py +11 -0
- llvmlite/_version.py +11 -0
- llvmlite/binding/__init__.py +18 -0
- llvmlite/binding/analysis.py +69 -0
- llvmlite/binding/common.py +34 -0
- llvmlite/binding/config.py +143 -0
- llvmlite/binding/context.py +31 -0
- llvmlite/binding/dylib.py +45 -0
- llvmlite/binding/executionengine.py +330 -0
- llvmlite/binding/ffi.py +395 -0
- llvmlite/binding/initfini.py +85 -0
- llvmlite/binding/libllvmlite.so +0 -0
- llvmlite/binding/linker.py +20 -0
- llvmlite/binding/module.py +349 -0
- llvmlite/binding/newpassmanagers.py +1049 -0
- llvmlite/binding/object_file.py +82 -0
- llvmlite/binding/options.py +17 -0
- llvmlite/binding/orcjit.py +342 -0
- llvmlite/binding/targets.py +462 -0
- llvmlite/binding/typeref.py +267 -0
- llvmlite/binding/value.py +632 -0
- llvmlite/ir/__init__.py +11 -0
- llvmlite/ir/_utils.py +80 -0
- llvmlite/ir/builder.py +1120 -0
- llvmlite/ir/context.py +20 -0
- llvmlite/ir/instructions.py +920 -0
- llvmlite/ir/module.py +256 -0
- llvmlite/ir/transforms.py +64 -0
- llvmlite/ir/types.py +730 -0
- llvmlite/ir/values.py +1217 -0
- llvmlite/tests/__init__.py +57 -0
- llvmlite/tests/__main__.py +3 -0
- llvmlite/tests/customize.py +407 -0
- llvmlite/tests/refprune_proto.py +330 -0
- llvmlite/tests/test_binding.py +3155 -0
- llvmlite/tests/test_ir.py +3095 -0
- llvmlite/tests/test_refprune.py +574 -0
- llvmlite/tests/test_valuerepr.py +60 -0
- llvmlite/utils.py +29 -0
- llvmlite-0.46.0b1.dist-info/METADATA +145 -0
- llvmlite-0.46.0b1.dist-info/RECORD +45 -0
- llvmlite-0.46.0b1.dist-info/WHEEL +6 -0
- llvmlite-0.46.0b1.dist-info/licenses/LICENSE +24 -0
- llvmlite-0.46.0b1.dist-info/licenses/LICENSE.thirdparty +225 -0
- llvmlite-0.46.0b1.dist-info/top_level.txt +1 -0
llvmlite/ir/values.py
ADDED
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Classes that are LLVM values: Value, Constant...
|
|
3
|
+
Instructions are in the instructions module.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import functools
|
|
7
|
+
import string
|
|
8
|
+
import re
|
|
9
|
+
from types import MappingProxyType
|
|
10
|
+
|
|
11
|
+
from llvmlite.ir import values, types, _utils
|
|
12
|
+
from llvmlite.ir._utils import (_StrCaching, _StringReferenceCaching,
|
|
13
|
+
_HasMetadata)
|
|
14
|
+
|
|
15
|
+
_VALID_CHARS = (frozenset(map(ord, string.ascii_letters)) |
|
|
16
|
+
frozenset(map(ord, string.digits)) |
|
|
17
|
+
frozenset(map(ord, ' !#$%&\'()*+,-./:;<=>?@[]^_`{|}~')))
|
|
18
|
+
|
|
19
|
+
_SIMPLE_IDENTIFIER_RE = re.compile(r"[-a-zA-Z$._][-a-zA-Z$._0-9]*$")
|
|
20
|
+
|
|
21
|
+
_CMP_MAP = {
|
|
22
|
+
'>': 'gt',
|
|
23
|
+
'<': 'lt',
|
|
24
|
+
'==': 'eq',
|
|
25
|
+
'!=': 'ne',
|
|
26
|
+
'>=': 'ge',
|
|
27
|
+
'<=': 'le',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _escape_string(text, _map={}):
|
|
32
|
+
"""
|
|
33
|
+
Escape the given bytestring for safe use as a LLVM array constant.
|
|
34
|
+
Any unicode string input is first encoded with utf8 into bytes.
|
|
35
|
+
"""
|
|
36
|
+
if isinstance(text, str):
|
|
37
|
+
text = text.encode()
|
|
38
|
+
assert isinstance(text, (bytes, bytearray))
|
|
39
|
+
|
|
40
|
+
if not _map:
|
|
41
|
+
for ch in range(256):
|
|
42
|
+
if ch in _VALID_CHARS:
|
|
43
|
+
_map[ch] = chr(ch)
|
|
44
|
+
else:
|
|
45
|
+
_map[ch] = '\\%02x' % ch
|
|
46
|
+
|
|
47
|
+
buf = [_map[ch] for ch in text]
|
|
48
|
+
return ''.join(buf)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _binop(opname):
|
|
52
|
+
def wrap(fn):
|
|
53
|
+
@functools.wraps(fn)
|
|
54
|
+
def wrapped(lhs, rhs):
|
|
55
|
+
if lhs.type != rhs.type:
|
|
56
|
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
|
57
|
+
% (lhs.type, rhs.type))
|
|
58
|
+
|
|
59
|
+
fmt = "{0} ({1} {2}, {3} {4})".format(opname,
|
|
60
|
+
lhs.type, lhs.get_reference(),
|
|
61
|
+
rhs.type, rhs.get_reference())
|
|
62
|
+
return FormattedConstant(lhs.type, fmt)
|
|
63
|
+
|
|
64
|
+
return wrapped
|
|
65
|
+
return wrap
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _castop(opname):
|
|
69
|
+
def wrap(fn):
|
|
70
|
+
@functools.wraps(fn)
|
|
71
|
+
def wrapped(self, typ):
|
|
72
|
+
fn(self, typ)
|
|
73
|
+
if typ == self.type:
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
op = "{0} ({1} {2} to {3})".format(opname, self.type,
|
|
77
|
+
self.get_reference(), typ)
|
|
78
|
+
return FormattedConstant(typ, op)
|
|
79
|
+
|
|
80
|
+
return wrapped
|
|
81
|
+
return wrap
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class _ConstOpMixin(object):
|
|
85
|
+
"""
|
|
86
|
+
A mixin defining constant operations, for use in constant-like classes.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Arithmetic APIs
|
|
91
|
+
#
|
|
92
|
+
|
|
93
|
+
@_binop('shl')
|
|
94
|
+
def shl(self, other):
|
|
95
|
+
"""
|
|
96
|
+
Left integer shift:
|
|
97
|
+
lhs << rhs
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
@_binop('lshr')
|
|
101
|
+
def lshr(self, other):
|
|
102
|
+
"""
|
|
103
|
+
Logical (unsigned) right integer shift:
|
|
104
|
+
lhs >> rhs
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
@_binop('ashr')
|
|
108
|
+
def ashr(self, other):
|
|
109
|
+
"""
|
|
110
|
+
Arithmetic (signed) right integer shift:
|
|
111
|
+
lhs >> rhs
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
@_binop('add')
|
|
115
|
+
def add(self, other):
|
|
116
|
+
"""
|
|
117
|
+
Integer addition:
|
|
118
|
+
lhs + rhs
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
@_binop('fadd')
|
|
122
|
+
def fadd(self, other):
|
|
123
|
+
"""
|
|
124
|
+
Floating-point addition:
|
|
125
|
+
lhs + rhs
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
@_binop('sub')
|
|
129
|
+
def sub(self, other):
|
|
130
|
+
"""
|
|
131
|
+
Integer subtraction:
|
|
132
|
+
lhs - rhs
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
@_binop('fsub')
|
|
136
|
+
def fsub(self, other):
|
|
137
|
+
"""
|
|
138
|
+
Floating-point subtraction:
|
|
139
|
+
lhs - rhs
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
@_binop('mul')
|
|
143
|
+
def mul(self, other):
|
|
144
|
+
"""
|
|
145
|
+
Integer multiplication:
|
|
146
|
+
lhs * rhs
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
@_binop('fmul')
|
|
150
|
+
def fmul(self, other):
|
|
151
|
+
"""
|
|
152
|
+
Floating-point multiplication:
|
|
153
|
+
lhs * rhs
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
@_binop('udiv')
|
|
157
|
+
def udiv(self, other):
|
|
158
|
+
"""
|
|
159
|
+
Unsigned integer division:
|
|
160
|
+
lhs / rhs
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
@_binop('sdiv')
|
|
164
|
+
def sdiv(self, other):
|
|
165
|
+
"""
|
|
166
|
+
Signed integer division:
|
|
167
|
+
lhs / rhs
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
@_binop('fdiv')
|
|
171
|
+
def fdiv(self, other):
|
|
172
|
+
"""
|
|
173
|
+
Floating-point division:
|
|
174
|
+
lhs / rhs
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
@_binop('urem')
|
|
178
|
+
def urem(self, other):
|
|
179
|
+
"""
|
|
180
|
+
Unsigned integer remainder:
|
|
181
|
+
lhs % rhs
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
@_binop('srem')
|
|
185
|
+
def srem(self, other):
|
|
186
|
+
"""
|
|
187
|
+
Signed integer remainder:
|
|
188
|
+
lhs % rhs
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
@_binop('frem')
|
|
192
|
+
def frem(self, other):
|
|
193
|
+
"""
|
|
194
|
+
Floating-point remainder:
|
|
195
|
+
lhs % rhs
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
@_binop('or')
|
|
199
|
+
def or_(self, other):
|
|
200
|
+
"""
|
|
201
|
+
Bitwise integer OR:
|
|
202
|
+
lhs | rhs
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
@_binop('and')
|
|
206
|
+
def and_(self, other):
|
|
207
|
+
"""
|
|
208
|
+
Bitwise integer AND:
|
|
209
|
+
lhs & rhs
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
@_binop('xor')
|
|
213
|
+
def xor(self, other):
|
|
214
|
+
"""
|
|
215
|
+
Bitwise integer XOR:
|
|
216
|
+
lhs ^ rhs
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
def _cmp(self, prefix, sign, cmpop, other):
|
|
220
|
+
ins = prefix + 'cmp'
|
|
221
|
+
try:
|
|
222
|
+
op = _CMP_MAP[cmpop]
|
|
223
|
+
except KeyError:
|
|
224
|
+
raise ValueError("invalid comparison %r for %s" % (cmpop, ins))
|
|
225
|
+
|
|
226
|
+
if not (prefix == 'i' and cmpop in ('==', '!=')):
|
|
227
|
+
op = sign + op
|
|
228
|
+
|
|
229
|
+
if self.type != other.type:
|
|
230
|
+
raise ValueError("Operands must be the same type, got (%s, %s)"
|
|
231
|
+
% (self.type, other.type))
|
|
232
|
+
|
|
233
|
+
fmt = "{0} {1} ({2} {3}, {4} {5})".format(
|
|
234
|
+
ins, op,
|
|
235
|
+
self.type, self.get_reference(),
|
|
236
|
+
other.type, other.get_reference())
|
|
237
|
+
|
|
238
|
+
return FormattedConstant(types.IntType(1), fmt)
|
|
239
|
+
|
|
240
|
+
def icmp_signed(self, cmpop, other):
|
|
241
|
+
"""
|
|
242
|
+
Signed integer comparison:
|
|
243
|
+
lhs <cmpop> rhs
|
|
244
|
+
|
|
245
|
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
|
246
|
+
"""
|
|
247
|
+
return self._cmp('i', 's', cmpop, other)
|
|
248
|
+
|
|
249
|
+
def icmp_unsigned(self, cmpop, other):
|
|
250
|
+
"""
|
|
251
|
+
Unsigned integer (or pointer) comparison:
|
|
252
|
+
lhs <cmpop> rhs
|
|
253
|
+
|
|
254
|
+
where cmpop can be '==', '!=', '<', '<=', '>', '>='
|
|
255
|
+
"""
|
|
256
|
+
return self._cmp('i', 'u', cmpop, other)
|
|
257
|
+
|
|
258
|
+
def fcmp_ordered(self, cmpop, other):
|
|
259
|
+
"""
|
|
260
|
+
Floating-point ordered comparison:
|
|
261
|
+
lhs <cmpop> rhs
|
|
262
|
+
|
|
263
|
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
|
264
|
+
"""
|
|
265
|
+
return self._cmp('f', 'o', cmpop, other)
|
|
266
|
+
|
|
267
|
+
def fcmp_unordered(self, cmpop, other):
|
|
268
|
+
"""
|
|
269
|
+
Floating-point unordered comparison:
|
|
270
|
+
lhs <cmpop> rhs
|
|
271
|
+
|
|
272
|
+
where cmpop can be '==', '!=', '<', '<=', '>', '>=', 'ord', 'uno'
|
|
273
|
+
"""
|
|
274
|
+
return self._cmp('f', 'u', cmpop, other)
|
|
275
|
+
|
|
276
|
+
#
|
|
277
|
+
# Unary APIs
|
|
278
|
+
#
|
|
279
|
+
|
|
280
|
+
def not_(self):
|
|
281
|
+
"""
|
|
282
|
+
Bitwise integer complement:
|
|
283
|
+
~value
|
|
284
|
+
"""
|
|
285
|
+
if isinstance(self.type, types.VectorType):
|
|
286
|
+
rhs = values.Constant(self.type, (-1,) * self.type.count)
|
|
287
|
+
else:
|
|
288
|
+
rhs = values.Constant(self.type, -1)
|
|
289
|
+
|
|
290
|
+
return self.xor(rhs)
|
|
291
|
+
|
|
292
|
+
def neg(self):
|
|
293
|
+
"""
|
|
294
|
+
Integer negative:
|
|
295
|
+
-value
|
|
296
|
+
"""
|
|
297
|
+
zero = values.Constant(self.type, 0)
|
|
298
|
+
return zero.sub(self)
|
|
299
|
+
|
|
300
|
+
def fneg(self):
|
|
301
|
+
"""
|
|
302
|
+
Floating-point negative:
|
|
303
|
+
-value
|
|
304
|
+
"""
|
|
305
|
+
fmt = "fneg ({0} {1})".format(self.type, self.get_reference())
|
|
306
|
+
return FormattedConstant(self.type, fmt)
|
|
307
|
+
|
|
308
|
+
#
|
|
309
|
+
# Cast APIs
|
|
310
|
+
#
|
|
311
|
+
|
|
312
|
+
@_castop('trunc')
|
|
313
|
+
def trunc(self, typ):
|
|
314
|
+
"""
|
|
315
|
+
Truncating integer downcast to a smaller type.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
@_castop('zext')
|
|
319
|
+
def zext(self, typ):
|
|
320
|
+
"""
|
|
321
|
+
Zero-extending integer upcast to a larger type
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
@_castop('sext')
|
|
325
|
+
def sext(self, typ):
|
|
326
|
+
"""
|
|
327
|
+
Sign-extending integer upcast to a larger type.
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
@_castop('fptrunc')
|
|
331
|
+
def fptrunc(self, typ):
|
|
332
|
+
"""
|
|
333
|
+
Floating-point downcast to a less precise type.
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
@_castop('fpext')
|
|
337
|
+
def fpext(self, typ):
|
|
338
|
+
"""
|
|
339
|
+
Floating-point upcast to a more precise type.
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
@_castop('bitcast')
|
|
343
|
+
def bitcast(self, typ):
|
|
344
|
+
"""
|
|
345
|
+
Pointer cast to a different pointer type.
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
@_castop('fptoui')
|
|
349
|
+
def fptoui(self, typ):
|
|
350
|
+
"""
|
|
351
|
+
Convert floating-point to unsigned integer.
|
|
352
|
+
"""
|
|
353
|
+
|
|
354
|
+
@_castop('uitofp')
|
|
355
|
+
def uitofp(self, typ):
|
|
356
|
+
"""
|
|
357
|
+
Convert unsigned integer to floating-point.
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
@_castop('fptosi')
|
|
361
|
+
def fptosi(self, typ):
|
|
362
|
+
"""
|
|
363
|
+
Convert floating-point to signed integer.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
@_castop('sitofp')
|
|
367
|
+
def sitofp(self, typ):
|
|
368
|
+
"""
|
|
369
|
+
Convert signed integer to floating-point.
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
@_castop('ptrtoint')
|
|
373
|
+
def ptrtoint(self, typ):
|
|
374
|
+
"""
|
|
375
|
+
Cast pointer to integer.
|
|
376
|
+
"""
|
|
377
|
+
if not isinstance(self.type, types.PointerType):
|
|
378
|
+
msg = "can only call ptrtoint() on pointer type, not '%s'"
|
|
379
|
+
raise TypeError(msg % (self.type,))
|
|
380
|
+
if not isinstance(typ, types.IntType):
|
|
381
|
+
raise TypeError("can only ptrtoint() to integer type, not '%s'"
|
|
382
|
+
% (typ,))
|
|
383
|
+
|
|
384
|
+
@_castop('inttoptr')
|
|
385
|
+
def inttoptr(self, typ):
|
|
386
|
+
"""
|
|
387
|
+
Cast integer to pointer.
|
|
388
|
+
"""
|
|
389
|
+
if not isinstance(self.type, types.IntType):
|
|
390
|
+
msg = "can only call inttoptr() on integer constants, not '%s'"
|
|
391
|
+
raise TypeError(msg % (self.type,))
|
|
392
|
+
if not isinstance(typ, types.PointerType):
|
|
393
|
+
raise TypeError("can only inttoptr() to pointer type, not '%s'"
|
|
394
|
+
% (typ,))
|
|
395
|
+
|
|
396
|
+
def gep(self, indices):
|
|
397
|
+
"""
|
|
398
|
+
Call getelementptr on this pointer constant.
|
|
399
|
+
"""
|
|
400
|
+
if not isinstance(self.type, types.PointerType):
|
|
401
|
+
raise TypeError("can only call gep() on pointer constants, not '%s'"
|
|
402
|
+
% (self.type,))
|
|
403
|
+
|
|
404
|
+
outtype = self.type
|
|
405
|
+
for i in indices:
|
|
406
|
+
outtype = outtype.gep(i)
|
|
407
|
+
|
|
408
|
+
strindices = ["{0} {1}".format(idx.type, idx.get_reference())
|
|
409
|
+
for idx in indices]
|
|
410
|
+
|
|
411
|
+
op = "getelementptr ({0}, {1} {2}, {3})".format(
|
|
412
|
+
self.type.pointee, self.type,
|
|
413
|
+
self.get_reference(), ', '.join(strindices))
|
|
414
|
+
return FormattedConstant(outtype.as_pointer(self.addrspace), op)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class Value(object):
|
|
418
|
+
"""
|
|
419
|
+
The base class for all values.
|
|
420
|
+
"""
|
|
421
|
+
|
|
422
|
+
def __repr__(self):
|
|
423
|
+
return "<ir.%s type='%s' ...>" % (self.__class__.__name__, self.type,)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
class _Undefined(object):
|
|
427
|
+
"""
|
|
428
|
+
'undef': a value for undefined values.
|
|
429
|
+
"""
|
|
430
|
+
def __new__(cls):
|
|
431
|
+
try:
|
|
432
|
+
return Undefined
|
|
433
|
+
except NameError:
|
|
434
|
+
return object.__new__(_Undefined)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
Undefined = _Undefined()
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
class Constant(_StrCaching, _StringReferenceCaching, _ConstOpMixin, Value):
|
|
441
|
+
"""
|
|
442
|
+
A constant LLVM value.
|
|
443
|
+
"""
|
|
444
|
+
|
|
445
|
+
def __init__(self, typ, constant):
|
|
446
|
+
assert isinstance(typ, types.Type)
|
|
447
|
+
assert not isinstance(typ, types.VoidType)
|
|
448
|
+
self.type = typ
|
|
449
|
+
constant = typ.wrap_constant_value(constant)
|
|
450
|
+
self.constant = constant
|
|
451
|
+
|
|
452
|
+
def _to_string(self):
|
|
453
|
+
return '{0} {1}'.format(self.type, self.get_reference())
|
|
454
|
+
|
|
455
|
+
def _get_reference(self):
|
|
456
|
+
if self.constant is None:
|
|
457
|
+
val = self.type.null
|
|
458
|
+
|
|
459
|
+
elif self.constant is Undefined:
|
|
460
|
+
val = "undef"
|
|
461
|
+
|
|
462
|
+
elif isinstance(self.constant, bytearray):
|
|
463
|
+
val = 'c"{0}"'.format(_escape_string(self.constant))
|
|
464
|
+
|
|
465
|
+
else:
|
|
466
|
+
val = self.type.format_constant(self.constant)
|
|
467
|
+
|
|
468
|
+
return val
|
|
469
|
+
|
|
470
|
+
@classmethod
|
|
471
|
+
def literal_array(cls, elems):
|
|
472
|
+
"""
|
|
473
|
+
Construct a literal array constant made of the given members.
|
|
474
|
+
"""
|
|
475
|
+
tys = [el.type for el in elems]
|
|
476
|
+
if len(tys) == 0:
|
|
477
|
+
raise ValueError("need at least one element")
|
|
478
|
+
ty = tys[0]
|
|
479
|
+
for other in tys:
|
|
480
|
+
if ty != other:
|
|
481
|
+
raise TypeError("all elements must have the same type")
|
|
482
|
+
return cls(types.ArrayType(ty, len(elems)), elems)
|
|
483
|
+
|
|
484
|
+
@classmethod
|
|
485
|
+
def literal_struct(cls, elems, packed=False):
|
|
486
|
+
"""
|
|
487
|
+
Construct a literal structure constant made of the given members.
|
|
488
|
+
"""
|
|
489
|
+
tys = [el.type for el in elems]
|
|
490
|
+
return cls(types.LiteralStructType(tys, packed), elems)
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def addrspace(self):
|
|
494
|
+
if not isinstance(self.type, types.PointerType):
|
|
495
|
+
raise TypeError("Only pointer constant have address spaces")
|
|
496
|
+
return self.type.addrspace
|
|
497
|
+
|
|
498
|
+
def __eq__(self, other):
|
|
499
|
+
if isinstance(other, Constant):
|
|
500
|
+
return str(self) == str(other)
|
|
501
|
+
else:
|
|
502
|
+
return False
|
|
503
|
+
|
|
504
|
+
def __ne__(self, other):
|
|
505
|
+
return not self.__eq__(other)
|
|
506
|
+
|
|
507
|
+
def __hash__(self):
|
|
508
|
+
return hash(str(self))
|
|
509
|
+
|
|
510
|
+
def __repr__(self):
|
|
511
|
+
return "<ir.Constant type='%s' value=%r>" % (self.type, self.constant)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
class FormattedConstant(Constant):
|
|
515
|
+
"""
|
|
516
|
+
A constant with an already formatted IR representation.
|
|
517
|
+
"""
|
|
518
|
+
|
|
519
|
+
def __init__(self, typ, constant):
|
|
520
|
+
assert isinstance(constant, str)
|
|
521
|
+
Constant.__init__(self, typ, constant)
|
|
522
|
+
|
|
523
|
+
def _to_string(self):
|
|
524
|
+
return self.constant
|
|
525
|
+
|
|
526
|
+
def _get_reference(self):
|
|
527
|
+
return self.constant
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
class NamedValue(_StrCaching, _StringReferenceCaching, Value):
|
|
531
|
+
"""
|
|
532
|
+
The base class for named values.
|
|
533
|
+
"""
|
|
534
|
+
name_prefix = '%'
|
|
535
|
+
deduplicate_name = True
|
|
536
|
+
|
|
537
|
+
def __init__(self, parent, type, name):
|
|
538
|
+
assert parent is not None
|
|
539
|
+
assert isinstance(type, types.Type)
|
|
540
|
+
self.parent = parent
|
|
541
|
+
self.type = type
|
|
542
|
+
self._set_name(name)
|
|
543
|
+
|
|
544
|
+
def _to_string(self):
|
|
545
|
+
buf = []
|
|
546
|
+
if not isinstance(self.type, types.VoidType):
|
|
547
|
+
buf.append("{0} = ".format(self.get_reference()))
|
|
548
|
+
self.descr(buf)
|
|
549
|
+
return "".join(buf).rstrip()
|
|
550
|
+
|
|
551
|
+
def descr(self, buf):
|
|
552
|
+
raise NotImplementedError
|
|
553
|
+
|
|
554
|
+
def _get_name(self):
|
|
555
|
+
return self._name
|
|
556
|
+
|
|
557
|
+
def _set_name(self, name):
|
|
558
|
+
name = self.parent.scope.register(name,
|
|
559
|
+
deduplicate=self.deduplicate_name)
|
|
560
|
+
self._name = name
|
|
561
|
+
|
|
562
|
+
name = property(_get_name, _set_name)
|
|
563
|
+
|
|
564
|
+
def _get_reference(self):
|
|
565
|
+
name = self.name
|
|
566
|
+
# Quote and escape value name
|
|
567
|
+
if '\\' in name or '"' in name:
|
|
568
|
+
name = name.replace('\\', '\\5c').replace('"', '\\22')
|
|
569
|
+
return '{0}"{1}"'.format(self.name_prefix, name)
|
|
570
|
+
|
|
571
|
+
def __repr__(self):
|
|
572
|
+
return "<ir.%s %r of type '%s'>" % (
|
|
573
|
+
self.__class__.__name__, self.name, self.type)
|
|
574
|
+
|
|
575
|
+
@property
|
|
576
|
+
def function_type(self):
|
|
577
|
+
ty = self.type
|
|
578
|
+
if isinstance(ty, types.PointerType):
|
|
579
|
+
ty = self.type.pointee
|
|
580
|
+
if isinstance(ty, types.FunctionType):
|
|
581
|
+
return ty
|
|
582
|
+
else:
|
|
583
|
+
raise TypeError("Not a function: {0}".format(self.type))
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class MetaDataString(NamedValue):
|
|
587
|
+
"""
|
|
588
|
+
A metadata string, i.e. a constant string used as a value in a metadata
|
|
589
|
+
node.
|
|
590
|
+
"""
|
|
591
|
+
|
|
592
|
+
def __init__(self, parent, string):
|
|
593
|
+
super(MetaDataString, self).__init__(parent,
|
|
594
|
+
types.MetaDataType(),
|
|
595
|
+
name="")
|
|
596
|
+
self.string = string
|
|
597
|
+
|
|
598
|
+
def descr(self, buf):
|
|
599
|
+
buf += (self.get_reference(), "\n")
|
|
600
|
+
|
|
601
|
+
def _get_reference(self):
|
|
602
|
+
return '!"{0}"'.format(_escape_string(self.string))
|
|
603
|
+
|
|
604
|
+
_to_string = _get_reference
|
|
605
|
+
|
|
606
|
+
def __eq__(self, other):
|
|
607
|
+
if isinstance(other, MetaDataString):
|
|
608
|
+
return self.string == other.string
|
|
609
|
+
else:
|
|
610
|
+
return False
|
|
611
|
+
|
|
612
|
+
def __ne__(self, other):
|
|
613
|
+
return not self.__eq__(other)
|
|
614
|
+
|
|
615
|
+
def __hash__(self):
|
|
616
|
+
return hash(self.string)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class MetaDataArgument(_StrCaching, _StringReferenceCaching, Value):
|
|
620
|
+
"""
|
|
621
|
+
An argument value to a function taking metadata arguments.
|
|
622
|
+
This can wrap any other kind of LLVM value.
|
|
623
|
+
|
|
624
|
+
Do not instantiate directly, Builder.call() will create these
|
|
625
|
+
automatically.
|
|
626
|
+
"""
|
|
627
|
+
|
|
628
|
+
def __init__(self, value):
|
|
629
|
+
assert isinstance(value, Value)
|
|
630
|
+
assert not isinstance(value.type, types.MetaDataType)
|
|
631
|
+
self.type = types.MetaDataType()
|
|
632
|
+
self.wrapped_value = value
|
|
633
|
+
|
|
634
|
+
def _get_reference(self):
|
|
635
|
+
# e.g. "i32* %2"
|
|
636
|
+
return "{0} {1}".format(self.wrapped_value.type,
|
|
637
|
+
self.wrapped_value.get_reference())
|
|
638
|
+
|
|
639
|
+
_to_string = _get_reference
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
class NamedMetaData(object):
|
|
643
|
+
"""
|
|
644
|
+
A named metadata node.
|
|
645
|
+
|
|
646
|
+
Do not instantiate directly, use Module.add_named_metadata() instead.
|
|
647
|
+
"""
|
|
648
|
+
|
|
649
|
+
def __init__(self, parent):
|
|
650
|
+
self.parent = parent
|
|
651
|
+
self.operands = []
|
|
652
|
+
|
|
653
|
+
def add(self, md):
|
|
654
|
+
self.operands.append(md)
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
class MDValue(NamedValue):
|
|
658
|
+
"""
|
|
659
|
+
A metadata node's value, consisting of a sequence of elements ("operands").
|
|
660
|
+
|
|
661
|
+
Do not instantiate directly, use Module.add_metadata() instead.
|
|
662
|
+
"""
|
|
663
|
+
name_prefix = '!'
|
|
664
|
+
|
|
665
|
+
def __init__(self, parent, values, name):
|
|
666
|
+
super(MDValue, self).__init__(parent,
|
|
667
|
+
types.MetaDataType(),
|
|
668
|
+
name=name)
|
|
669
|
+
self.operands = tuple(values)
|
|
670
|
+
parent.metadata.append(self)
|
|
671
|
+
|
|
672
|
+
def descr(self, buf):
|
|
673
|
+
operands = []
|
|
674
|
+
for op in self.operands:
|
|
675
|
+
if isinstance(op.type, types.MetaDataType):
|
|
676
|
+
if isinstance(op, Constant) and op.constant is None:
|
|
677
|
+
operands.append("null")
|
|
678
|
+
else:
|
|
679
|
+
operands.append(op.get_reference())
|
|
680
|
+
else:
|
|
681
|
+
operands.append("{0} {1}".format(op.type, op.get_reference()))
|
|
682
|
+
operands = ', '.join(operands)
|
|
683
|
+
buf += ("!{{ {0} }}".format(operands), "\n")
|
|
684
|
+
|
|
685
|
+
def _get_reference(self):
|
|
686
|
+
return self.name_prefix + str(self.name)
|
|
687
|
+
|
|
688
|
+
def __eq__(self, other):
|
|
689
|
+
if isinstance(other, MDValue):
|
|
690
|
+
return self.operands == other.operands
|
|
691
|
+
else:
|
|
692
|
+
return False
|
|
693
|
+
|
|
694
|
+
def __ne__(self, other):
|
|
695
|
+
return not self.__eq__(other)
|
|
696
|
+
|
|
697
|
+
def __hash__(self):
|
|
698
|
+
return hash(self.operands)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
class DIToken:
|
|
702
|
+
"""
|
|
703
|
+
A debug information enumeration value that should appear bare in
|
|
704
|
+
the emitted metadata.
|
|
705
|
+
|
|
706
|
+
Use this to wrap known constants, e.g. the DW_* enumerations.
|
|
707
|
+
"""
|
|
708
|
+
|
|
709
|
+
def __init__(self, value):
|
|
710
|
+
self.value = value
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
class DIValue(NamedValue):
|
|
714
|
+
"""
|
|
715
|
+
A debug information descriptor, containing key-value pairs.
|
|
716
|
+
|
|
717
|
+
Do not instantiate directly, use Module.add_debug_info() instead.
|
|
718
|
+
"""
|
|
719
|
+
name_prefix = '!'
|
|
720
|
+
|
|
721
|
+
def __init__(self, parent, is_distinct, kind, operands, name):
|
|
722
|
+
super(DIValue, self).__init__(parent,
|
|
723
|
+
types.MetaDataType(),
|
|
724
|
+
name=name)
|
|
725
|
+
self.is_distinct = is_distinct
|
|
726
|
+
self.kind = kind
|
|
727
|
+
self.operands = tuple(operands)
|
|
728
|
+
parent.metadata.append(self)
|
|
729
|
+
|
|
730
|
+
def descr(self, buf):
|
|
731
|
+
if self.is_distinct:
|
|
732
|
+
buf += ("distinct ",)
|
|
733
|
+
operands = []
|
|
734
|
+
for key, value in self.operands:
|
|
735
|
+
if value is None:
|
|
736
|
+
strvalue = "null"
|
|
737
|
+
elif value is True:
|
|
738
|
+
strvalue = "true"
|
|
739
|
+
elif value is False:
|
|
740
|
+
strvalue = "false"
|
|
741
|
+
elif isinstance(value, DIToken):
|
|
742
|
+
strvalue = value.value
|
|
743
|
+
elif isinstance(value, str):
|
|
744
|
+
strvalue = '"{}"'.format(_escape_string(value))
|
|
745
|
+
elif isinstance(value, int):
|
|
746
|
+
strvalue = str(value)
|
|
747
|
+
elif isinstance(value, NamedValue):
|
|
748
|
+
strvalue = value.get_reference()
|
|
749
|
+
else:
|
|
750
|
+
raise TypeError("invalid operand type for debug info: %r"
|
|
751
|
+
% (value,))
|
|
752
|
+
operands.append("{0}: {1}".format(key, strvalue))
|
|
753
|
+
operands = ', '.join(operands)
|
|
754
|
+
buf += ("!", self.kind, "(", operands, ")\n")
|
|
755
|
+
|
|
756
|
+
def _get_reference(self):
|
|
757
|
+
return self.name_prefix + str(self.name)
|
|
758
|
+
|
|
759
|
+
def __eq__(self, other):
|
|
760
|
+
if isinstance(other, DIValue):
|
|
761
|
+
return self.is_distinct == other.is_distinct and \
|
|
762
|
+
self.kind == other.kind and \
|
|
763
|
+
self.operands == other.operands
|
|
764
|
+
else:
|
|
765
|
+
return False
|
|
766
|
+
|
|
767
|
+
def __ne__(self, other):
|
|
768
|
+
return not self.__eq__(other)
|
|
769
|
+
|
|
770
|
+
def __hash__(self):
|
|
771
|
+
return hash((self.is_distinct, self.kind, self.operands))
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
class GlobalValue(NamedValue, _ConstOpMixin, _HasMetadata):
|
|
775
|
+
"""
|
|
776
|
+
A global value.
|
|
777
|
+
"""
|
|
778
|
+
name_prefix = '@'
|
|
779
|
+
deduplicate_name = False
|
|
780
|
+
|
|
781
|
+
def __init__(self, *args, **kwargs):
|
|
782
|
+
super(GlobalValue, self).__init__(*args, **kwargs)
|
|
783
|
+
self.linkage = ''
|
|
784
|
+
self.storage_class = ''
|
|
785
|
+
self.section = ''
|
|
786
|
+
self.metadata = {}
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
class GlobalVariable(GlobalValue):
|
|
790
|
+
"""
|
|
791
|
+
A global variable.
|
|
792
|
+
"""
|
|
793
|
+
|
|
794
|
+
def __init__(self, module, typ, name, addrspace=0):
|
|
795
|
+
assert isinstance(typ, types.Type)
|
|
796
|
+
super(GlobalVariable, self).__init__(module, typ.as_pointer(addrspace),
|
|
797
|
+
name=name)
|
|
798
|
+
self.value_type = typ
|
|
799
|
+
self.initializer = None
|
|
800
|
+
self.unnamed_addr = False
|
|
801
|
+
self.global_constant = False
|
|
802
|
+
self.addrspace = addrspace
|
|
803
|
+
self.align = None
|
|
804
|
+
self.parent.add_global(self)
|
|
805
|
+
|
|
806
|
+
def descr(self, buf):
|
|
807
|
+
if self.global_constant:
|
|
808
|
+
kind = 'constant'
|
|
809
|
+
else:
|
|
810
|
+
kind = 'global'
|
|
811
|
+
|
|
812
|
+
if not self.linkage:
|
|
813
|
+
# Default to external linkage
|
|
814
|
+
linkage = 'external' if self.initializer is None else ''
|
|
815
|
+
else:
|
|
816
|
+
linkage = self.linkage
|
|
817
|
+
|
|
818
|
+
if linkage:
|
|
819
|
+
buf.append(linkage + " ")
|
|
820
|
+
if self.storage_class:
|
|
821
|
+
buf.append(self.storage_class + " ")
|
|
822
|
+
if self.unnamed_addr:
|
|
823
|
+
buf.append("unnamed_addr ")
|
|
824
|
+
if self.addrspace != 0:
|
|
825
|
+
buf.append('addrspace({0:d}) '.format(self.addrspace))
|
|
826
|
+
|
|
827
|
+
buf.append("{kind} {type}" .format(kind=kind, type=self.value_type))
|
|
828
|
+
|
|
829
|
+
if self.initializer is not None:
|
|
830
|
+
if self.initializer.type != self.value_type:
|
|
831
|
+
raise TypeError("got initializer of type %s "
|
|
832
|
+
"for global value type %s"
|
|
833
|
+
% (self.initializer.type, self.value_type))
|
|
834
|
+
buf.append(" " + self.initializer.get_reference())
|
|
835
|
+
elif linkage not in ('external', 'extern_weak'):
|
|
836
|
+
# emit 'undef' for non-external linkage GV
|
|
837
|
+
buf.append(" " + self.value_type(Undefined).get_reference())
|
|
838
|
+
|
|
839
|
+
if self.section:
|
|
840
|
+
buf.append(", section \"%s\"" % (self.section,))
|
|
841
|
+
|
|
842
|
+
if self.align is not None:
|
|
843
|
+
buf.append(", align %d" % (self.align,))
|
|
844
|
+
|
|
845
|
+
if self.metadata:
|
|
846
|
+
buf.append(self._stringify_metadata(leading_comma=True))
|
|
847
|
+
|
|
848
|
+
buf.append("\n")
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
class AttributeSet(set):
|
|
852
|
+
"""A set of string attribute.
|
|
853
|
+
Only accept items listed in *_known*.
|
|
854
|
+
|
|
855
|
+
Properties:
|
|
856
|
+
* Iterate in sorted order
|
|
857
|
+
"""
|
|
858
|
+
_known = ()
|
|
859
|
+
|
|
860
|
+
def __init__(self, args=()):
|
|
861
|
+
super().__init__()
|
|
862
|
+
if isinstance(args, str):
|
|
863
|
+
args = [args]
|
|
864
|
+
for name in args:
|
|
865
|
+
self.add(name)
|
|
866
|
+
|
|
867
|
+
def _expand(self, name, typ):
|
|
868
|
+
return name
|
|
869
|
+
|
|
870
|
+
def add(self, name):
|
|
871
|
+
if name not in self._known:
|
|
872
|
+
raise ValueError('unknown attr {!r} for {}'.format(name, self))
|
|
873
|
+
return super(AttributeSet, self).add(name)
|
|
874
|
+
|
|
875
|
+
def _to_list(self, typ):
|
|
876
|
+
return [self._expand(i, typ) for i in sorted(self)]
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
class FunctionAttributes(AttributeSet):
|
|
880
|
+
_known = frozenset([
|
|
881
|
+
'argmemonly', 'alwaysinline', 'builtin', 'cold', 'convergent',
|
|
882
|
+
'inaccessiblememonly', 'inaccessiblemem_or_argmemonly', 'inlinehint',
|
|
883
|
+
'jumptable', 'minsize', 'naked', 'nobuiltin', 'noduplicate',
|
|
884
|
+
'noimplicitfloat', 'noinline', 'nonlazybind', 'norecurse',
|
|
885
|
+
'noredzone', 'noreturn', 'nounwind', 'optnone', 'optsize',
|
|
886
|
+
'readnone', 'readonly', 'returns_twice', 'sanitize_address',
|
|
887
|
+
'sanitize_memory', 'sanitize_thread', 'ssp',
|
|
888
|
+
'sspreg', 'sspstrong', 'uwtable'])
|
|
889
|
+
|
|
890
|
+
def __init__(self, args=()):
|
|
891
|
+
self._alignstack = 0
|
|
892
|
+
self._personality = None
|
|
893
|
+
super(FunctionAttributes, self).__init__(args)
|
|
894
|
+
|
|
895
|
+
def add(self, name):
|
|
896
|
+
if ((name == 'alwaysinline' and 'noinline' in self) or
|
|
897
|
+
(name == 'noinline' and 'alwaysinline' in self)):
|
|
898
|
+
raise ValueError("Can't have alwaysinline and noinline")
|
|
899
|
+
|
|
900
|
+
super().add(name)
|
|
901
|
+
|
|
902
|
+
@property
|
|
903
|
+
def alignstack(self):
|
|
904
|
+
return self._alignstack
|
|
905
|
+
|
|
906
|
+
@alignstack.setter
|
|
907
|
+
def alignstack(self, val):
|
|
908
|
+
assert val >= 0
|
|
909
|
+
self._alignstack = val
|
|
910
|
+
|
|
911
|
+
@property
|
|
912
|
+
def personality(self):
|
|
913
|
+
return self._personality
|
|
914
|
+
|
|
915
|
+
@personality.setter
|
|
916
|
+
def personality(self, val):
|
|
917
|
+
assert val is None or isinstance(val, GlobalValue)
|
|
918
|
+
self._personality = val
|
|
919
|
+
|
|
920
|
+
def _to_list(self, ret_type):
|
|
921
|
+
attrs = super()._to_list(ret_type)
|
|
922
|
+
if self.alignstack:
|
|
923
|
+
attrs.append('alignstack({0:d})'.format(self.alignstack))
|
|
924
|
+
if self.personality:
|
|
925
|
+
attrs.append('personality {persty} {persfn}'.format(
|
|
926
|
+
persty=self.personality.type,
|
|
927
|
+
persfn=self.personality.get_reference()))
|
|
928
|
+
return attrs
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
class Function(GlobalValue):
|
|
932
|
+
"""Represent a LLVM Function but does uses a Module as parent.
|
|
933
|
+
Global Values are stored as a set of dependencies (attribute `depends`).
|
|
934
|
+
"""
|
|
935
|
+
|
|
936
|
+
def __init__(self, module, ftype, name):
|
|
937
|
+
assert isinstance(ftype, types.Type)
|
|
938
|
+
super(Function, self).__init__(module, ftype.as_pointer(), name=name)
|
|
939
|
+
self.ftype = ftype
|
|
940
|
+
self.scope = _utils.NameScope()
|
|
941
|
+
self.blocks = []
|
|
942
|
+
self.attributes = FunctionAttributes()
|
|
943
|
+
self.args = tuple([Argument(self, t)
|
|
944
|
+
for t in ftype.args])
|
|
945
|
+
self.return_value = ReturnValue(self, ftype.return_type)
|
|
946
|
+
self.parent.add_global(self)
|
|
947
|
+
self.calling_convention = ''
|
|
948
|
+
|
|
949
|
+
@property
|
|
950
|
+
def module(self):
|
|
951
|
+
return self.parent
|
|
952
|
+
|
|
953
|
+
@property
|
|
954
|
+
def entry_basic_block(self):
|
|
955
|
+
return self.blocks[0]
|
|
956
|
+
|
|
957
|
+
@property
|
|
958
|
+
def basic_blocks(self):
|
|
959
|
+
return self.blocks
|
|
960
|
+
|
|
961
|
+
def append_basic_block(self, name=''):
|
|
962
|
+
blk = Block(parent=self, name=name)
|
|
963
|
+
self.blocks.append(blk)
|
|
964
|
+
return blk
|
|
965
|
+
|
|
966
|
+
def insert_basic_block(self, before, name=''):
|
|
967
|
+
"""Insert block before
|
|
968
|
+
"""
|
|
969
|
+
blk = Block(parent=self, name=name)
|
|
970
|
+
self.blocks.insert(before, blk)
|
|
971
|
+
return blk
|
|
972
|
+
|
|
973
|
+
def descr_prototype(self, buf):
|
|
974
|
+
"""
|
|
975
|
+
Describe the prototype ("head") of the function.
|
|
976
|
+
"""
|
|
977
|
+
state = "define" if self.blocks else "declare"
|
|
978
|
+
ret = self.return_value
|
|
979
|
+
args = ", ".join(str(a) for a in self.args)
|
|
980
|
+
name = self.get_reference()
|
|
981
|
+
attrs = ' ' + ' '.join(self.attributes._to_list(
|
|
982
|
+
self.ftype.return_type)) if self.attributes else ''
|
|
983
|
+
if any(self.args):
|
|
984
|
+
vararg = ', ...' if self.ftype.var_arg else ''
|
|
985
|
+
else:
|
|
986
|
+
vararg = '...' if self.ftype.var_arg else ''
|
|
987
|
+
linkage = self.linkage
|
|
988
|
+
cconv = self.calling_convention
|
|
989
|
+
prefix = " ".join(str(x) for x in [state, linkage, cconv, ret] if x)
|
|
990
|
+
metadata = self._stringify_metadata()
|
|
991
|
+
metadata = ' {}'.format(metadata) if metadata else ''
|
|
992
|
+
section = ' section "{}"'.format(self.section) if self.section else ''
|
|
993
|
+
pt_str = "{prefix} {name}({args}{vararg}){attrs}{section}{metadata}\n"
|
|
994
|
+
prototype = pt_str.format(prefix=prefix, name=name, args=args,
|
|
995
|
+
vararg=vararg, attrs=attrs, section=section,
|
|
996
|
+
metadata=metadata)
|
|
997
|
+
buf.append(prototype)
|
|
998
|
+
|
|
999
|
+
def descr_body(self, buf):
|
|
1000
|
+
"""
|
|
1001
|
+
Describe of the body of the function.
|
|
1002
|
+
"""
|
|
1003
|
+
for blk in self.blocks:
|
|
1004
|
+
blk.descr(buf)
|
|
1005
|
+
|
|
1006
|
+
def descr(self, buf):
|
|
1007
|
+
self.descr_prototype(buf)
|
|
1008
|
+
if self.blocks:
|
|
1009
|
+
buf.append("{\n")
|
|
1010
|
+
self.descr_body(buf)
|
|
1011
|
+
buf.append("}\n")
|
|
1012
|
+
|
|
1013
|
+
def __str__(self):
|
|
1014
|
+
buf = []
|
|
1015
|
+
self.descr(buf)
|
|
1016
|
+
return "".join(buf)
|
|
1017
|
+
|
|
1018
|
+
@property
|
|
1019
|
+
def is_declaration(self):
|
|
1020
|
+
return len(self.blocks) == 0
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
class ArgumentAttributes(AttributeSet):
|
|
1024
|
+
# List from
|
|
1025
|
+
# https://releases.llvm.org/14.0.0/docs/LangRef.html#parameter-attributes
|
|
1026
|
+
_known = MappingProxyType({
|
|
1027
|
+
# True (emit type),
|
|
1028
|
+
# False (emit name only)
|
|
1029
|
+
'byref': True,
|
|
1030
|
+
'byval': True,
|
|
1031
|
+
'elementtype': True,
|
|
1032
|
+
'immarg': False,
|
|
1033
|
+
'inalloca': True,
|
|
1034
|
+
'inreg': False,
|
|
1035
|
+
'nest': False,
|
|
1036
|
+
'noalias': False,
|
|
1037
|
+
'nocapture': False,
|
|
1038
|
+
'nofree': False,
|
|
1039
|
+
'nonnull': False,
|
|
1040
|
+
'noundef': False,
|
|
1041
|
+
'preallocated': True,
|
|
1042
|
+
'returned': False,
|
|
1043
|
+
'signext': False,
|
|
1044
|
+
'sret': True,
|
|
1045
|
+
'swiftasync': False,
|
|
1046
|
+
'swifterror': False,
|
|
1047
|
+
'swiftself': False,
|
|
1048
|
+
'zeroext': False,
|
|
1049
|
+
})
|
|
1050
|
+
|
|
1051
|
+
def __init__(self, args=()):
|
|
1052
|
+
self._align = 0
|
|
1053
|
+
self._dereferenceable = 0
|
|
1054
|
+
self._dereferenceable_or_null = 0
|
|
1055
|
+
super(ArgumentAttributes, self).__init__(args)
|
|
1056
|
+
|
|
1057
|
+
def _expand(self, name, typ):
|
|
1058
|
+
requires_type = self._known.get(name)
|
|
1059
|
+
if requires_type:
|
|
1060
|
+
return f"{name}({typ.pointee})"
|
|
1061
|
+
else:
|
|
1062
|
+
return name
|
|
1063
|
+
|
|
1064
|
+
@property
|
|
1065
|
+
def align(self):
|
|
1066
|
+
return self._align
|
|
1067
|
+
|
|
1068
|
+
@align.setter
|
|
1069
|
+
def align(self, val):
|
|
1070
|
+
assert isinstance(val, int) and val >= 0
|
|
1071
|
+
self._align = val
|
|
1072
|
+
|
|
1073
|
+
@property
|
|
1074
|
+
def dereferenceable(self):
|
|
1075
|
+
return self._dereferenceable
|
|
1076
|
+
|
|
1077
|
+
@dereferenceable.setter
|
|
1078
|
+
def dereferenceable(self, val):
|
|
1079
|
+
assert isinstance(val, int) and val >= 0
|
|
1080
|
+
self._dereferenceable = val
|
|
1081
|
+
|
|
1082
|
+
@property
|
|
1083
|
+
def dereferenceable_or_null(self):
|
|
1084
|
+
return self._dereferenceable_or_null
|
|
1085
|
+
|
|
1086
|
+
@dereferenceable_or_null.setter
|
|
1087
|
+
def dereferenceable_or_null(self, val):
|
|
1088
|
+
assert isinstance(val, int) and val >= 0
|
|
1089
|
+
self._dereferenceable_or_null = val
|
|
1090
|
+
|
|
1091
|
+
def _to_list(self, typ):
|
|
1092
|
+
attrs = super()._to_list(typ)
|
|
1093
|
+
if self.align:
|
|
1094
|
+
attrs.append('align {0:d}'.format(self.align))
|
|
1095
|
+
if self.dereferenceable:
|
|
1096
|
+
attrs.append('dereferenceable({0:d})'.format(self.dereferenceable))
|
|
1097
|
+
if self.dereferenceable_or_null:
|
|
1098
|
+
dref = 'dereferenceable_or_null({0:d})'
|
|
1099
|
+
attrs.append(dref.format(self.dereferenceable_or_null))
|
|
1100
|
+
return attrs
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
class _BaseArgument(NamedValue):
|
|
1104
|
+
def __init__(self, parent, typ, name=''):
|
|
1105
|
+
assert isinstance(typ, types.Type)
|
|
1106
|
+
super(_BaseArgument, self).__init__(parent, typ, name=name)
|
|
1107
|
+
self.parent = parent
|
|
1108
|
+
self.attributes = ArgumentAttributes()
|
|
1109
|
+
|
|
1110
|
+
def __repr__(self):
|
|
1111
|
+
return "<ir.%s %r of type %s>" % (self.__class__.__name__, self.name,
|
|
1112
|
+
self.type)
|
|
1113
|
+
|
|
1114
|
+
def add_attribute(self, attr):
|
|
1115
|
+
self.attributes.add(attr)
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
class Argument(_BaseArgument):
|
|
1119
|
+
"""
|
|
1120
|
+
The specification of a function argument.
|
|
1121
|
+
"""
|
|
1122
|
+
|
|
1123
|
+
def __str__(self):
|
|
1124
|
+
attrs = self.attributes._to_list(self.type)
|
|
1125
|
+
if attrs:
|
|
1126
|
+
return "{0} {1} {2}".format(self.type, ' '.join(attrs),
|
|
1127
|
+
self.get_reference())
|
|
1128
|
+
else:
|
|
1129
|
+
return "{0} {1}".format(self.type, self.get_reference())
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
class ReturnValue(_BaseArgument):
|
|
1133
|
+
"""
|
|
1134
|
+
The specification of a function's return value.
|
|
1135
|
+
"""
|
|
1136
|
+
|
|
1137
|
+
def __str__(self):
|
|
1138
|
+
attrs = self.attributes._to_list(self.type)
|
|
1139
|
+
if attrs:
|
|
1140
|
+
return "{0} {1}".format(' '.join(attrs), self.type)
|
|
1141
|
+
else:
|
|
1142
|
+
return str(self.type)
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
class Block(NamedValue):
|
|
1146
|
+
"""
|
|
1147
|
+
A LLVM IR basic block. A basic block is a sequence of
|
|
1148
|
+
instructions whose execution always goes from start to end. That
|
|
1149
|
+
is, a control flow instruction (branch) can only appear as the
|
|
1150
|
+
last instruction, and incoming branches can only jump to the first
|
|
1151
|
+
instruction.
|
|
1152
|
+
"""
|
|
1153
|
+
|
|
1154
|
+
def __init__(self, parent, name=''):
|
|
1155
|
+
super(Block, self).__init__(parent, types.LabelType(), name=name)
|
|
1156
|
+
self.scope = parent.scope
|
|
1157
|
+
self.instructions = []
|
|
1158
|
+
self.terminator = None
|
|
1159
|
+
|
|
1160
|
+
@property
|
|
1161
|
+
def is_terminated(self):
|
|
1162
|
+
return self.terminator is not None
|
|
1163
|
+
|
|
1164
|
+
@property
|
|
1165
|
+
def function(self):
|
|
1166
|
+
return self.parent
|
|
1167
|
+
|
|
1168
|
+
@property
|
|
1169
|
+
def module(self):
|
|
1170
|
+
return self.parent.module
|
|
1171
|
+
|
|
1172
|
+
def descr(self, buf):
|
|
1173
|
+
buf.append("{0}:\n".format(self._format_name()))
|
|
1174
|
+
buf += [" {0}\n".format(instr) for instr in self.instructions]
|
|
1175
|
+
|
|
1176
|
+
def replace(self, old, new):
|
|
1177
|
+
"""Replace an instruction"""
|
|
1178
|
+
if old.type != new.type:
|
|
1179
|
+
raise TypeError("new instruction has a different type")
|
|
1180
|
+
pos = self.instructions.index(old)
|
|
1181
|
+
self.instructions.remove(old)
|
|
1182
|
+
self.instructions.insert(pos, new)
|
|
1183
|
+
|
|
1184
|
+
for bb in self.parent.basic_blocks:
|
|
1185
|
+
for instr in bb.instructions:
|
|
1186
|
+
instr.replace_usage(old, new)
|
|
1187
|
+
|
|
1188
|
+
def _format_name(self):
|
|
1189
|
+
# Per the LLVM Language Ref on identifiers, names matching the following
|
|
1190
|
+
# regex do not need to be quoted: [%@][-a-zA-Z$._][-a-zA-Z$._0-9]*
|
|
1191
|
+
# Otherwise, the identifier must be quoted and escaped.
|
|
1192
|
+
name = self.name
|
|
1193
|
+
if not _SIMPLE_IDENTIFIER_RE.match(name):
|
|
1194
|
+
name = name.replace('\\', '\\5c').replace('"', '\\22')
|
|
1195
|
+
name = '"{0}"'.format(name)
|
|
1196
|
+
return name
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
class BlockAddress(Value):
|
|
1200
|
+
"""
|
|
1201
|
+
The address of a basic block.
|
|
1202
|
+
"""
|
|
1203
|
+
|
|
1204
|
+
def __init__(self, function, basic_block):
|
|
1205
|
+
assert isinstance(function, Function)
|
|
1206
|
+
assert isinstance(basic_block, Block)
|
|
1207
|
+
self.type = types.IntType(8).as_pointer()
|
|
1208
|
+
self.function = function
|
|
1209
|
+
self.basic_block = basic_block
|
|
1210
|
+
|
|
1211
|
+
def __str__(self):
|
|
1212
|
+
return '{0} {1}'.format(self.type, self.get_reference())
|
|
1213
|
+
|
|
1214
|
+
def get_reference(self):
|
|
1215
|
+
return "blockaddress({0}, {1})".format(
|
|
1216
|
+
self.function.get_reference(),
|
|
1217
|
+
self.basic_block.get_reference())
|