llvmlite 0.46.0b1__cp312-cp312-macosx_11_0_universal2.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.dylib +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 +5 -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
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Implementation of LLVM IR instructions.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from llvmlite.ir import types
|
|
6
|
+
from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant,
|
|
7
|
+
MetaDataArgument, MetaDataString, AttributeSet,
|
|
8
|
+
Undefined, ArgumentAttributes)
|
|
9
|
+
from llvmlite.ir._utils import _HasMetadata
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Instruction(NamedValue, _HasMetadata):
|
|
13
|
+
def __init__(self, parent, typ, opname, operands, name='', flags=()):
|
|
14
|
+
super(Instruction, self).__init__(parent, typ, name=name)
|
|
15
|
+
assert isinstance(parent, Block)
|
|
16
|
+
assert isinstance(flags, (tuple, list))
|
|
17
|
+
self.opname = opname
|
|
18
|
+
self.operands = operands
|
|
19
|
+
self.flags = list(flags)
|
|
20
|
+
self.metadata = {}
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def function(self):
|
|
24
|
+
return self.parent.function
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def module(self):
|
|
28
|
+
return self.parent.function.module
|
|
29
|
+
|
|
30
|
+
def descr(self, buf):
|
|
31
|
+
opname = self.opname
|
|
32
|
+
if self.flags:
|
|
33
|
+
opname = ' '.join([opname] + self.flags)
|
|
34
|
+
operands = ', '.join([op.get_reference() for op in self.operands])
|
|
35
|
+
typ = self.type
|
|
36
|
+
metadata = self._stringify_metadata(leading_comma=True)
|
|
37
|
+
buf.append("{0} {1} {2}{3}\n"
|
|
38
|
+
.format(opname, typ, operands, metadata))
|
|
39
|
+
|
|
40
|
+
def replace_usage(self, old, new):
|
|
41
|
+
if old in self.operands:
|
|
42
|
+
ops = []
|
|
43
|
+
for op in self.operands:
|
|
44
|
+
ops.append(new if op is old else op)
|
|
45
|
+
self.operands = tuple(ops)
|
|
46
|
+
self._clear_string_cache()
|
|
47
|
+
|
|
48
|
+
def __repr__(self):
|
|
49
|
+
return "<ir.%s %r of type '%s', opname %r, operands %r>" % (
|
|
50
|
+
self.__class__.__name__, self.name, self.type,
|
|
51
|
+
self.opname, self.operands)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class CallInstrAttributes(AttributeSet):
|
|
55
|
+
_known = frozenset(['convergent', 'noreturn', 'nounwind', 'readonly',
|
|
56
|
+
'readnone', 'noinline', 'alwaysinline'])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
TailMarkerOptions = frozenset(['tail', 'musttail', 'notail'])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class FastMathFlags(AttributeSet):
|
|
63
|
+
_known = frozenset(['fast', 'nnan', 'ninf', 'nsz', 'arcp', 'contract',
|
|
64
|
+
'afn', 'reassoc'])
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class CallInstr(Instruction):
|
|
68
|
+
def __init__(self, parent, func, args, name='', cconv=None, tail=None,
|
|
69
|
+
fastmath=(), attrs=(), arg_attrs=None):
|
|
70
|
+
self.cconv = (func.calling_convention
|
|
71
|
+
if cconv is None and isinstance(func, Function)
|
|
72
|
+
else cconv)
|
|
73
|
+
|
|
74
|
+
# For backwards compatibility with previous API of accepting a "truthy"
|
|
75
|
+
# value for a hint to the optimizer to potentially tail optimize.
|
|
76
|
+
if isinstance(tail, str) and tail in TailMarkerOptions:
|
|
77
|
+
pass
|
|
78
|
+
elif tail:
|
|
79
|
+
tail = "tail"
|
|
80
|
+
else:
|
|
81
|
+
tail = ""
|
|
82
|
+
|
|
83
|
+
self.tail = tail
|
|
84
|
+
self.fastmath = FastMathFlags(fastmath)
|
|
85
|
+
self.attributes = CallInstrAttributes(attrs)
|
|
86
|
+
self.arg_attributes = {}
|
|
87
|
+
if arg_attrs:
|
|
88
|
+
for idx, attrs in arg_attrs.items():
|
|
89
|
+
if not (0 <= idx < len(args)):
|
|
90
|
+
raise ValueError("Invalid argument index {}"
|
|
91
|
+
.format(idx))
|
|
92
|
+
self.arg_attributes[idx] = ArgumentAttributes(attrs)
|
|
93
|
+
|
|
94
|
+
# Fix and validate arguments
|
|
95
|
+
args = list(args)
|
|
96
|
+
for i in range(len(func.function_type.args)):
|
|
97
|
+
arg = args[i]
|
|
98
|
+
expected_type = func.function_type.args[i]
|
|
99
|
+
if (isinstance(expected_type, types.MetaDataType) and
|
|
100
|
+
arg.type != expected_type):
|
|
101
|
+
arg = MetaDataArgument(arg)
|
|
102
|
+
if arg.type != expected_type:
|
|
103
|
+
msg = ("Type of #{0} arg mismatch: {1} != {2}"
|
|
104
|
+
.format(1 + i, expected_type, arg.type))
|
|
105
|
+
raise TypeError(msg)
|
|
106
|
+
args[i] = arg
|
|
107
|
+
|
|
108
|
+
super(CallInstr, self).__init__(parent, func.function_type.return_type,
|
|
109
|
+
"call", [func] + list(args), name=name)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def callee(self):
|
|
113
|
+
return self.operands[0]
|
|
114
|
+
|
|
115
|
+
@callee.setter
|
|
116
|
+
def callee(self, newcallee):
|
|
117
|
+
self.operands[0] = newcallee
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def args(self):
|
|
121
|
+
return self.operands[1:]
|
|
122
|
+
|
|
123
|
+
def replace_callee(self, newfunc):
|
|
124
|
+
if newfunc.function_type != self.callee.function_type:
|
|
125
|
+
raise TypeError("New function has incompatible type")
|
|
126
|
+
self.callee = newfunc
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def called_function(self):
|
|
130
|
+
"""The callee function"""
|
|
131
|
+
return self.callee
|
|
132
|
+
|
|
133
|
+
def _descr(self, buf, add_metadata):
|
|
134
|
+
def descr_arg(i, a):
|
|
135
|
+
if i in self.arg_attributes:
|
|
136
|
+
attrs = ' '.join(self.arg_attributes[i]._to_list(a.type)) + ' '
|
|
137
|
+
else:
|
|
138
|
+
attrs = ''
|
|
139
|
+
return '{0} {1}{2}'.format(a.type, attrs, a.get_reference())
|
|
140
|
+
args = ', '.join([descr_arg(i, a) for i, a in enumerate(self.args)])
|
|
141
|
+
|
|
142
|
+
fnty = self.callee.function_type
|
|
143
|
+
# Only print function type if variable-argument
|
|
144
|
+
if fnty.var_arg:
|
|
145
|
+
ty = fnty
|
|
146
|
+
# Otherwise, just print the return type.
|
|
147
|
+
else:
|
|
148
|
+
# Fastmath flag work only in this case
|
|
149
|
+
ty = fnty.return_type
|
|
150
|
+
callee_ref = "{0} {1}".format(ty, self.callee.get_reference())
|
|
151
|
+
if self.cconv:
|
|
152
|
+
callee_ref = "{0} {1}".format(self.cconv, callee_ref)
|
|
153
|
+
|
|
154
|
+
tail_marker = ""
|
|
155
|
+
if self.tail:
|
|
156
|
+
tail_marker = "{0} ".format(self.tail)
|
|
157
|
+
|
|
158
|
+
fn_attrs = ' ' + ' '.join(self.attributes._to_list(fnty.return_type))\
|
|
159
|
+
if self.attributes else ''
|
|
160
|
+
|
|
161
|
+
fm_attrs = ' ' + ' '.join(self.fastmath._to_list(fnty.return_type))\
|
|
162
|
+
if self.fastmath else ''
|
|
163
|
+
|
|
164
|
+
buf.append("{tail}{op}{fastmath} {callee}({args}){attr}{meta}\n".format(
|
|
165
|
+
tail=tail_marker,
|
|
166
|
+
op=self.opname,
|
|
167
|
+
callee=callee_ref,
|
|
168
|
+
fastmath=fm_attrs,
|
|
169
|
+
args=args,
|
|
170
|
+
attr=fn_attrs,
|
|
171
|
+
meta=(self._stringify_metadata(leading_comma=True)
|
|
172
|
+
if add_metadata else ""),
|
|
173
|
+
))
|
|
174
|
+
|
|
175
|
+
def descr(self, buf):
|
|
176
|
+
self._descr(buf, add_metadata=True)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class InvokeInstr(CallInstr):
|
|
180
|
+
def __init__(self, parent, func, args, normal_to, unwind_to, name='',
|
|
181
|
+
cconv=None, fastmath=(), attrs=(), arg_attrs=None):
|
|
182
|
+
assert isinstance(normal_to, Block)
|
|
183
|
+
assert isinstance(unwind_to, Block)
|
|
184
|
+
super(InvokeInstr, self).__init__(parent, func, args, name, cconv,
|
|
185
|
+
tail=False, fastmath=fastmath,
|
|
186
|
+
attrs=attrs, arg_attrs=arg_attrs)
|
|
187
|
+
self.opname = "invoke"
|
|
188
|
+
self.normal_to = normal_to
|
|
189
|
+
self.unwind_to = unwind_to
|
|
190
|
+
|
|
191
|
+
def descr(self, buf):
|
|
192
|
+
super(InvokeInstr, self)._descr(buf, add_metadata=False)
|
|
193
|
+
buf.append(" to label {0} unwind label {1}{metadata}\n".format(
|
|
194
|
+
self.normal_to.get_reference(),
|
|
195
|
+
self.unwind_to.get_reference(),
|
|
196
|
+
metadata=self._stringify_metadata(leading_comma=True),
|
|
197
|
+
))
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Terminator(Instruction):
|
|
201
|
+
def __init__(self, parent, opname, operands):
|
|
202
|
+
super(Terminator, self).__init__(parent, types.VoidType(), opname,
|
|
203
|
+
operands)
|
|
204
|
+
|
|
205
|
+
def descr(self, buf):
|
|
206
|
+
opname = self.opname
|
|
207
|
+
operands = ', '.join(["{0} {1}".format(op.type, op.get_reference())
|
|
208
|
+
for op in self.operands])
|
|
209
|
+
metadata = self._stringify_metadata(leading_comma=True)
|
|
210
|
+
buf.append("{0} {1}{2}".format(opname, operands, metadata))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class PredictableInstr(Instruction):
|
|
214
|
+
|
|
215
|
+
def set_weights(self, weights):
|
|
216
|
+
operands = [MetaDataString(self.module, "branch_weights")]
|
|
217
|
+
for w in weights:
|
|
218
|
+
if w < 0:
|
|
219
|
+
raise ValueError("branch weight must be a positive integer")
|
|
220
|
+
operands.append(Constant(types.IntType(32), w))
|
|
221
|
+
md = self.module.add_metadata(operands)
|
|
222
|
+
self.set_metadata("prof", md)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class Ret(Terminator):
|
|
226
|
+
def __init__(self, parent, opname, return_value=None):
|
|
227
|
+
operands = [return_value] if return_value is not None else []
|
|
228
|
+
super(Ret, self).__init__(parent, opname, operands)
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def return_value(self):
|
|
232
|
+
if self.operands:
|
|
233
|
+
return self.operands[0]
|
|
234
|
+
else:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
def descr(self, buf):
|
|
238
|
+
return_value = self.return_value
|
|
239
|
+
metadata = self._stringify_metadata(leading_comma=True)
|
|
240
|
+
if return_value is not None:
|
|
241
|
+
buf.append("{0} {1} {2}{3}\n"
|
|
242
|
+
.format(self.opname, return_value.type,
|
|
243
|
+
return_value.get_reference(),
|
|
244
|
+
metadata))
|
|
245
|
+
else:
|
|
246
|
+
buf.append("{0}{1}\n".format(self.opname, metadata))
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class Branch(Terminator):
|
|
250
|
+
pass
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class ConditionalBranch(PredictableInstr, Terminator):
|
|
254
|
+
pass
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class IndirectBranch(PredictableInstr, Terminator):
|
|
258
|
+
def __init__(self, parent, opname, addr):
|
|
259
|
+
super(IndirectBranch, self).__init__(parent, opname, [addr])
|
|
260
|
+
self.destinations = []
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def address(self):
|
|
264
|
+
return self.operands[0]
|
|
265
|
+
|
|
266
|
+
def add_destination(self, block):
|
|
267
|
+
assert isinstance(block, Block)
|
|
268
|
+
self.destinations.append(block)
|
|
269
|
+
|
|
270
|
+
def descr(self, buf):
|
|
271
|
+
destinations = ["label {0}".format(blk.get_reference())
|
|
272
|
+
for blk in self.destinations]
|
|
273
|
+
buf.append("indirectbr {0} {1}, [{2}] {3}\n".format(
|
|
274
|
+
self.address.type,
|
|
275
|
+
self.address.get_reference(),
|
|
276
|
+
', '.join(destinations),
|
|
277
|
+
self._stringify_metadata(leading_comma=True),
|
|
278
|
+
))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class SwitchInstr(PredictableInstr, Terminator):
|
|
282
|
+
|
|
283
|
+
def __init__(self, parent, opname, val, default):
|
|
284
|
+
super(SwitchInstr, self).__init__(parent, opname, [val])
|
|
285
|
+
self.default = default
|
|
286
|
+
self.cases = []
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def value(self):
|
|
290
|
+
return self.operands[0]
|
|
291
|
+
|
|
292
|
+
def add_case(self, val, block):
|
|
293
|
+
assert isinstance(block, Block)
|
|
294
|
+
if not isinstance(val, Value):
|
|
295
|
+
val = Constant(self.value.type, val)
|
|
296
|
+
self.cases.append((val, block))
|
|
297
|
+
|
|
298
|
+
def descr(self, buf):
|
|
299
|
+
cases = ["{0} {1}, label {2}".format(val.type, val.get_reference(),
|
|
300
|
+
blk.get_reference())
|
|
301
|
+
for val, blk in self.cases]
|
|
302
|
+
buf.append("switch {0} {1}, label {2} [{3}] {4}\n".format(
|
|
303
|
+
self.value.type,
|
|
304
|
+
self.value.get_reference(),
|
|
305
|
+
self.default.get_reference(),
|
|
306
|
+
' '.join(cases),
|
|
307
|
+
self._stringify_metadata(leading_comma=True),
|
|
308
|
+
))
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class Resume(Terminator):
|
|
312
|
+
pass
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class SelectInstr(Instruction):
|
|
316
|
+
def __init__(self, parent, cond, lhs, rhs, name='', flags=()):
|
|
317
|
+
assert lhs.type == rhs.type
|
|
318
|
+
super(SelectInstr, self).__init__(parent, lhs.type, "select",
|
|
319
|
+
[cond, lhs, rhs], name=name,
|
|
320
|
+
flags=flags)
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def cond(self):
|
|
324
|
+
return self.operands[0]
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def lhs(self):
|
|
328
|
+
return self.operands[1]
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def rhs(self):
|
|
332
|
+
return self.operands[2]
|
|
333
|
+
|
|
334
|
+
def descr(self, buf):
|
|
335
|
+
buf.append("select {0} {1} {2}, {3} {4}, {5} {6} {7}\n".format(
|
|
336
|
+
' '.join(self.flags),
|
|
337
|
+
self.cond.type, self.cond.get_reference(),
|
|
338
|
+
self.lhs.type, self.lhs.get_reference(),
|
|
339
|
+
self.rhs.type, self.rhs.get_reference(),
|
|
340
|
+
self._stringify_metadata(leading_comma=True),
|
|
341
|
+
))
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class CompareInstr(Instruction):
|
|
345
|
+
# Define the following in subclasses
|
|
346
|
+
OPNAME = 'invalid-compare'
|
|
347
|
+
VALID_OP = {}
|
|
348
|
+
|
|
349
|
+
def __init__(self, parent, op, lhs, rhs, name='', flags=[]):
|
|
350
|
+
if op not in self.VALID_OP:
|
|
351
|
+
raise ValueError("invalid comparison %r for %s" % (op, self.OPNAME))
|
|
352
|
+
for flag in flags:
|
|
353
|
+
if flag not in self.VALID_FLAG:
|
|
354
|
+
raise ValueError("invalid flag %r for %s" % (flag, self.OPNAME))
|
|
355
|
+
opname = self.OPNAME
|
|
356
|
+
if isinstance(lhs.type, types.VectorType):
|
|
357
|
+
typ = types.VectorType(types.IntType(1), lhs.type.count)
|
|
358
|
+
else:
|
|
359
|
+
typ = types.IntType(1)
|
|
360
|
+
super(CompareInstr, self).__init__(parent, typ,
|
|
361
|
+
opname, [lhs, rhs], flags=flags,
|
|
362
|
+
name=name)
|
|
363
|
+
self.op = op
|
|
364
|
+
|
|
365
|
+
def descr(self, buf):
|
|
366
|
+
buf.append("{opname}{flags} {op} {ty} {lhs}, {rhs} {meta}\n".format(
|
|
367
|
+
opname=self.opname,
|
|
368
|
+
flags=''.join(' ' + it for it in self.flags),
|
|
369
|
+
op=self.op,
|
|
370
|
+
ty=self.operands[0].type,
|
|
371
|
+
lhs=self.operands[0].get_reference(),
|
|
372
|
+
rhs=self.operands[1].get_reference(),
|
|
373
|
+
meta=self._stringify_metadata(leading_comma=True),
|
|
374
|
+
))
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class ICMPInstr(CompareInstr):
|
|
378
|
+
OPNAME = 'icmp'
|
|
379
|
+
VALID_OP = {
|
|
380
|
+
'eq': 'equal',
|
|
381
|
+
'ne': 'not equal',
|
|
382
|
+
'ugt': 'unsigned greater than',
|
|
383
|
+
'uge': 'unsigned greater or equal',
|
|
384
|
+
'ult': 'unsigned less than',
|
|
385
|
+
'ule': 'unsigned less or equal',
|
|
386
|
+
'sgt': 'signed greater than',
|
|
387
|
+
'sge': 'signed greater or equal',
|
|
388
|
+
'slt': 'signed less than',
|
|
389
|
+
'sle': 'signed less or equal',
|
|
390
|
+
}
|
|
391
|
+
VALID_FLAG = set()
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class FCMPInstr(CompareInstr):
|
|
395
|
+
OPNAME = 'fcmp'
|
|
396
|
+
VALID_OP = {
|
|
397
|
+
'false': 'no comparison, always returns false',
|
|
398
|
+
'oeq': 'ordered and equal',
|
|
399
|
+
'ogt': 'ordered and greater than',
|
|
400
|
+
'oge': 'ordered and greater than or equal',
|
|
401
|
+
'olt': 'ordered and less than',
|
|
402
|
+
'ole': 'ordered and less than or equal',
|
|
403
|
+
'one': 'ordered and not equal',
|
|
404
|
+
'ord': 'ordered (no nans)',
|
|
405
|
+
'ueq': 'unordered or equal',
|
|
406
|
+
'ugt': 'unordered or greater than',
|
|
407
|
+
'uge': 'unordered or greater than or equal',
|
|
408
|
+
'ult': 'unordered or less than',
|
|
409
|
+
'ule': 'unordered or less than or equal',
|
|
410
|
+
'une': 'unordered or not equal',
|
|
411
|
+
'uno': 'unordered (either nans)',
|
|
412
|
+
'true': 'no comparison, always returns true',
|
|
413
|
+
}
|
|
414
|
+
VALID_FLAG = {'nnan', 'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc',
|
|
415
|
+
'fast'}
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class CastInstr(Instruction):
|
|
419
|
+
def __init__(self, parent, op, val, typ, name=''):
|
|
420
|
+
super(CastInstr, self).__init__(parent, typ, op, [val], name=name)
|
|
421
|
+
|
|
422
|
+
def descr(self, buf):
|
|
423
|
+
buf.append("{0} {1} {2} to {3} {4}\n".format(
|
|
424
|
+
self.opname,
|
|
425
|
+
self.operands[0].type,
|
|
426
|
+
self.operands[0].get_reference(),
|
|
427
|
+
self.type,
|
|
428
|
+
self._stringify_metadata(leading_comma=True),
|
|
429
|
+
))
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class LoadInstr(Instruction):
|
|
433
|
+
|
|
434
|
+
def __init__(self, parent, ptr, name='', typ=None):
|
|
435
|
+
if typ is None:
|
|
436
|
+
if isinstance(ptr, AllocaInstr):
|
|
437
|
+
typ = ptr.allocated_type
|
|
438
|
+
# For compatibility with typed pointers. Eventually this should
|
|
439
|
+
# probably be removed (when typed pointers are fully removed).
|
|
440
|
+
elif not ptr.type.is_opaque:
|
|
441
|
+
typ = ptr.type.pointee
|
|
442
|
+
else:
|
|
443
|
+
raise ValueError("Load lacks type.")
|
|
444
|
+
super(LoadInstr, self).__init__(parent, typ, "load", [ptr], name=name)
|
|
445
|
+
self.align = None
|
|
446
|
+
|
|
447
|
+
def descr(self, buf):
|
|
448
|
+
[val] = self.operands
|
|
449
|
+
if self.align is not None:
|
|
450
|
+
align = ', align %d' % (self.align)
|
|
451
|
+
else:
|
|
452
|
+
align = ''
|
|
453
|
+
buf.append("load {0}, {1} {2}{3}{4}\n".format(
|
|
454
|
+
self.type,
|
|
455
|
+
val.type,
|
|
456
|
+
val.get_reference(),
|
|
457
|
+
align,
|
|
458
|
+
self._stringify_metadata(leading_comma=True),
|
|
459
|
+
))
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class StoreInstr(Instruction):
|
|
463
|
+
def __init__(self, parent, val, ptr):
|
|
464
|
+
super(StoreInstr, self).__init__(parent, types.VoidType(), "store",
|
|
465
|
+
[val, ptr])
|
|
466
|
+
|
|
467
|
+
def descr(self, buf):
|
|
468
|
+
val, ptr = self.operands
|
|
469
|
+
if self.align is not None:
|
|
470
|
+
align = ', align %d' % (self.align)
|
|
471
|
+
else:
|
|
472
|
+
align = ''
|
|
473
|
+
buf.append("store {0} {1}, {2} {3}{4}{5}\n".format(
|
|
474
|
+
val.type,
|
|
475
|
+
val.get_reference(),
|
|
476
|
+
ptr.type,
|
|
477
|
+
ptr.get_reference(),
|
|
478
|
+
align,
|
|
479
|
+
self._stringify_metadata(leading_comma=True),
|
|
480
|
+
))
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class LoadAtomicInstr(Instruction):
|
|
484
|
+
def __init__(self, parent, ptr, ordering, align, name='', typ=None):
|
|
485
|
+
if typ is None:
|
|
486
|
+
if isinstance(ptr, AllocaInstr):
|
|
487
|
+
typ = ptr.allocated_type
|
|
488
|
+
# For compatibility with typed pointers. Eventually this should
|
|
489
|
+
# probably be removed (when typed pointers are fully removed).
|
|
490
|
+
elif not ptr.type.is_opaque:
|
|
491
|
+
typ = ptr.type.pointee
|
|
492
|
+
else:
|
|
493
|
+
raise ValueError("Load atomic lacks type.")
|
|
494
|
+
super(LoadAtomicInstr, self).__init__(parent, typ, "load atomic",
|
|
495
|
+
[ptr], name=name)
|
|
496
|
+
self.ordering = ordering
|
|
497
|
+
self.align = align
|
|
498
|
+
|
|
499
|
+
def descr(self, buf):
|
|
500
|
+
[val] = self.operands
|
|
501
|
+
buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format(
|
|
502
|
+
self.type,
|
|
503
|
+
val.type,
|
|
504
|
+
val.get_reference(),
|
|
505
|
+
self.ordering,
|
|
506
|
+
self.align,
|
|
507
|
+
self._stringify_metadata(leading_comma=True),
|
|
508
|
+
))
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
class StoreAtomicInstr(Instruction):
|
|
512
|
+
def __init__(self, parent, val, ptr, ordering, align):
|
|
513
|
+
super(StoreAtomicInstr, self).__init__(parent, types.VoidType(),
|
|
514
|
+
"store atomic", [val, ptr])
|
|
515
|
+
self.ordering = ordering
|
|
516
|
+
self.align = align
|
|
517
|
+
|
|
518
|
+
def descr(self, buf):
|
|
519
|
+
val, ptr = self.operands
|
|
520
|
+
buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format(
|
|
521
|
+
val.type,
|
|
522
|
+
val.get_reference(),
|
|
523
|
+
ptr.type,
|
|
524
|
+
ptr.get_reference(),
|
|
525
|
+
self.ordering,
|
|
526
|
+
self.align,
|
|
527
|
+
self._stringify_metadata(leading_comma=True),
|
|
528
|
+
))
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class AllocaInstr(Instruction):
|
|
532
|
+
def __init__(self, parent, typ, count, name):
|
|
533
|
+
operands = [count] if count else ()
|
|
534
|
+
super(AllocaInstr, self).__init__(parent, typ.as_pointer(), "alloca",
|
|
535
|
+
operands, name)
|
|
536
|
+
self.allocated_type = typ
|
|
537
|
+
self.align = None
|
|
538
|
+
|
|
539
|
+
def descr(self, buf):
|
|
540
|
+
buf.append("{0} {1}".format(self.opname, self.allocated_type))
|
|
541
|
+
if self.operands:
|
|
542
|
+
op, = self.operands
|
|
543
|
+
buf.append(", {0} {1}".format(op.type, op.get_reference()))
|
|
544
|
+
if self.align is not None:
|
|
545
|
+
buf.append(", align {0}".format(self.align))
|
|
546
|
+
if self.metadata:
|
|
547
|
+
buf.append(self._stringify_metadata(leading_comma=True))
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class GEPInstr(Instruction):
|
|
551
|
+
def __init__(self, parent, ptr, indices, inbounds, name,
|
|
552
|
+
source_etype=None):
|
|
553
|
+
if source_etype is not None:
|
|
554
|
+
typ = ptr.type
|
|
555
|
+
self.source_etype = source_etype
|
|
556
|
+
# For compatibility with typed pointers. Eventually this should
|
|
557
|
+
# probably be removed (when typed pointers are fully removed).
|
|
558
|
+
elif not ptr.type.is_opaque:
|
|
559
|
+
typ = ptr.type
|
|
560
|
+
lasttyp = None
|
|
561
|
+
lastaddrspace = 0
|
|
562
|
+
for i in indices:
|
|
563
|
+
lasttyp, typ = typ, typ.gep(i)
|
|
564
|
+
# inherit the addrspace from the last seen pointer
|
|
565
|
+
if isinstance(lasttyp, types.PointerType):
|
|
566
|
+
lastaddrspace = lasttyp.addrspace
|
|
567
|
+
|
|
568
|
+
if (not isinstance(typ, types.PointerType) and
|
|
569
|
+
isinstance(lasttyp, types.PointerType)):
|
|
570
|
+
typ = lasttyp
|
|
571
|
+
else:
|
|
572
|
+
typ = typ.as_pointer(lastaddrspace)
|
|
573
|
+
self.source_etype = ptr.type.pointee
|
|
574
|
+
else:
|
|
575
|
+
raise ValueError("GEP lacks type.")
|
|
576
|
+
super(GEPInstr, self).__init__(parent, typ, "getelementptr",
|
|
577
|
+
[ptr] + list(indices), name=name)
|
|
578
|
+
self.pointer = ptr
|
|
579
|
+
self.indices = indices
|
|
580
|
+
self.inbounds = inbounds
|
|
581
|
+
|
|
582
|
+
def descr(self, buf):
|
|
583
|
+
indices = ['{0} {1}'.format(i.type, i.get_reference())
|
|
584
|
+
for i in self.indices]
|
|
585
|
+
op = "getelementptr inbounds" if self.inbounds else "getelementptr"
|
|
586
|
+
buf.append("{0} {1}, {2} {3}, {4} {5}\n".format(
|
|
587
|
+
op,
|
|
588
|
+
self.source_etype,
|
|
589
|
+
self.pointer.type,
|
|
590
|
+
self.pointer.get_reference(),
|
|
591
|
+
', '.join(indices),
|
|
592
|
+
self._stringify_metadata(leading_comma=True),
|
|
593
|
+
))
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
class PhiInstr(Instruction):
|
|
597
|
+
def __init__(self, parent, typ, name, flags=()):
|
|
598
|
+
super(PhiInstr, self).__init__(parent, typ, "phi", (), name=name,
|
|
599
|
+
flags=flags)
|
|
600
|
+
self.incomings = []
|
|
601
|
+
|
|
602
|
+
def descr(self, buf):
|
|
603
|
+
incs = ', '.join('[{0}, {1}]'.format(v.get_reference(),
|
|
604
|
+
b.get_reference())
|
|
605
|
+
for v, b in self.incomings)
|
|
606
|
+
buf.append("phi {0} {1} {2} {3}\n".format(
|
|
607
|
+
' '.join(self.flags),
|
|
608
|
+
self.type,
|
|
609
|
+
incs,
|
|
610
|
+
self._stringify_metadata(leading_comma=True),
|
|
611
|
+
))
|
|
612
|
+
|
|
613
|
+
def add_incoming(self, value, block):
|
|
614
|
+
assert isinstance(block, Block)
|
|
615
|
+
self.incomings.append((value, block))
|
|
616
|
+
|
|
617
|
+
def replace_usage(self, old, new):
|
|
618
|
+
self.incomings = [((new if val is old else val), blk)
|
|
619
|
+
for (val, blk) in self.incomings]
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
class ExtractElement(Instruction):
|
|
623
|
+
def __init__(self, parent, vector, index, name=''):
|
|
624
|
+
if not isinstance(vector.type, types.VectorType):
|
|
625
|
+
raise TypeError("vector needs to be of VectorType.")
|
|
626
|
+
if not isinstance(index.type, types.IntType):
|
|
627
|
+
raise TypeError("index needs to be of IntType.")
|
|
628
|
+
typ = vector.type.element
|
|
629
|
+
super(ExtractElement, self).__init__(parent, typ, "extractelement",
|
|
630
|
+
[vector, index], name=name)
|
|
631
|
+
|
|
632
|
+
def descr(self, buf):
|
|
633
|
+
operands = ", ".join("{0} {1}".format(
|
|
634
|
+
op.type, op.get_reference()) for op in self.operands)
|
|
635
|
+
buf.append("{opname} {operands}\n".format(
|
|
636
|
+
opname=self.opname, operands=operands))
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
class InsertElement(Instruction):
|
|
640
|
+
def __init__(self, parent, vector, value, index, name=''):
|
|
641
|
+
if not isinstance(vector.type, types.VectorType):
|
|
642
|
+
raise TypeError("vector needs to be of VectorType.")
|
|
643
|
+
if not value.type == vector.type.element:
|
|
644
|
+
raise TypeError(
|
|
645
|
+
"value needs to be of type {} not {}.".format(
|
|
646
|
+
vector.type.element, value.type))
|
|
647
|
+
if not isinstance(index.type, types.IntType):
|
|
648
|
+
raise TypeError("index needs to be of IntType.")
|
|
649
|
+
typ = vector.type
|
|
650
|
+
super(InsertElement, self).__init__(parent, typ, "insertelement",
|
|
651
|
+
[vector, value, index], name=name)
|
|
652
|
+
|
|
653
|
+
def descr(self, buf):
|
|
654
|
+
operands = ", ".join("{0} {1}".format(
|
|
655
|
+
op.type, op.get_reference()) for op in self.operands)
|
|
656
|
+
buf.append("{opname} {operands}\n".format(
|
|
657
|
+
opname=self.opname, operands=operands))
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
class ShuffleVector(Instruction):
|
|
661
|
+
def __init__(self, parent, vector1, vector2, mask, name=''):
|
|
662
|
+
if not isinstance(vector1.type, types.VectorType):
|
|
663
|
+
raise TypeError("vector1 needs to be of VectorType.")
|
|
664
|
+
if vector2 != Undefined:
|
|
665
|
+
if vector2.type != vector1.type:
|
|
666
|
+
raise TypeError("vector2 needs to be " +
|
|
667
|
+
"Undefined or of the same type as vector1.")
|
|
668
|
+
if (not isinstance(mask, Constant) or
|
|
669
|
+
not isinstance(mask.type, types.VectorType) or
|
|
670
|
+
not (isinstance(mask.type.element, types.IntType) and
|
|
671
|
+
mask.type.element.width == 32)):
|
|
672
|
+
raise TypeError("mask needs to be a constant i32 vector.")
|
|
673
|
+
typ = types.VectorType(vector1.type.element, mask.type.count)
|
|
674
|
+
index_range = range(vector1.type.count
|
|
675
|
+
if vector2 == Undefined
|
|
676
|
+
else 2 * vector1.type.count)
|
|
677
|
+
if not all(ii.constant in index_range for ii in mask.constant):
|
|
678
|
+
raise IndexError(
|
|
679
|
+
"mask values need to be in {0}".format(index_range),
|
|
680
|
+
)
|
|
681
|
+
super(ShuffleVector, self).__init__(parent, typ, "shufflevector",
|
|
682
|
+
[vector1, vector2, mask], name=name)
|
|
683
|
+
|
|
684
|
+
def descr(self, buf):
|
|
685
|
+
buf.append("shufflevector {0} {1}\n".format(
|
|
686
|
+
", ".join("{0} {1}".format(op.type, op.get_reference())
|
|
687
|
+
for op in self.operands),
|
|
688
|
+
self._stringify_metadata(leading_comma=True),
|
|
689
|
+
))
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
class ExtractValue(Instruction):
|
|
693
|
+
def __init__(self, parent, agg, indices, name=''):
|
|
694
|
+
typ = agg.type
|
|
695
|
+
try:
|
|
696
|
+
for i in indices:
|
|
697
|
+
typ = typ.elements[i]
|
|
698
|
+
except (AttributeError, IndexError):
|
|
699
|
+
raise TypeError("Can't index at %r in %s"
|
|
700
|
+
% (list(indices), agg.type))
|
|
701
|
+
|
|
702
|
+
super(ExtractValue, self).__init__(parent, typ, "extractvalue",
|
|
703
|
+
[agg], name=name)
|
|
704
|
+
|
|
705
|
+
self.aggregate = agg
|
|
706
|
+
self.indices = indices
|
|
707
|
+
|
|
708
|
+
def descr(self, buf):
|
|
709
|
+
indices = [str(i) for i in self.indices]
|
|
710
|
+
|
|
711
|
+
buf.append("extractvalue {0} {1}, {2} {3}\n".format(
|
|
712
|
+
self.aggregate.type,
|
|
713
|
+
self.aggregate.get_reference(),
|
|
714
|
+
', '.join(indices),
|
|
715
|
+
self._stringify_metadata(leading_comma=True),
|
|
716
|
+
))
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
class InsertValue(Instruction):
|
|
720
|
+
def __init__(self, parent, agg, elem, indices, name=''):
|
|
721
|
+
typ = agg.type
|
|
722
|
+
try:
|
|
723
|
+
for i in indices:
|
|
724
|
+
typ = typ.elements[i]
|
|
725
|
+
except (AttributeError, IndexError):
|
|
726
|
+
raise TypeError("Can't index at %r in %s"
|
|
727
|
+
% (list(indices), agg.type))
|
|
728
|
+
if elem.type != typ:
|
|
729
|
+
raise TypeError("Can only insert %s at %r in %s: got %s"
|
|
730
|
+
% (typ, list(indices), agg.type, elem.type))
|
|
731
|
+
super(InsertValue, self).__init__(parent, agg.type, "insertvalue",
|
|
732
|
+
[agg, elem], name=name)
|
|
733
|
+
|
|
734
|
+
self.aggregate = agg
|
|
735
|
+
self.value = elem
|
|
736
|
+
self.indices = indices
|
|
737
|
+
|
|
738
|
+
def descr(self, buf):
|
|
739
|
+
indices = [str(i) for i in self.indices]
|
|
740
|
+
|
|
741
|
+
buf.append("insertvalue {0} {1}, {2} {3}, {4} {5}\n".format(
|
|
742
|
+
self.aggregate.type, self.aggregate.get_reference(),
|
|
743
|
+
self.value.type, self.value.get_reference(),
|
|
744
|
+
', '.join(indices),
|
|
745
|
+
self._stringify_metadata(leading_comma=True),
|
|
746
|
+
))
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
class Unreachable(Instruction):
|
|
750
|
+
def __init__(self, parent):
|
|
751
|
+
super(Unreachable, self).__init__(parent, types.VoidType(),
|
|
752
|
+
"unreachable", (), name='')
|
|
753
|
+
|
|
754
|
+
def descr(self, buf):
|
|
755
|
+
buf += (self.opname, "\n")
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
class InlineAsm(object):
|
|
759
|
+
def __init__(self, ftype, asm, constraint, side_effect=False):
|
|
760
|
+
self.type = ftype.return_type
|
|
761
|
+
self.function_type = ftype
|
|
762
|
+
self.asm = asm
|
|
763
|
+
self.constraint = constraint
|
|
764
|
+
self.side_effect = side_effect
|
|
765
|
+
|
|
766
|
+
def descr(self, buf):
|
|
767
|
+
sideeffect = 'sideeffect' if self.side_effect else ''
|
|
768
|
+
fmt = 'asm {sideeffect} "{asm}", "{constraint}"\n'
|
|
769
|
+
buf.append(fmt.format(sideeffect=sideeffect, asm=self.asm,
|
|
770
|
+
constraint=self.constraint))
|
|
771
|
+
|
|
772
|
+
def get_reference(self):
|
|
773
|
+
buf = []
|
|
774
|
+
self.descr(buf)
|
|
775
|
+
return "".join(buf)
|
|
776
|
+
|
|
777
|
+
def __str__(self):
|
|
778
|
+
return "{0} {1}".format(self.type, self.get_reference())
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
class AtomicRMW(Instruction):
|
|
782
|
+
def __init__(self, parent, op, ptr, val, ordering, name):
|
|
783
|
+
super(AtomicRMW, self).__init__(parent, val.type, "atomicrmw",
|
|
784
|
+
(ptr, val), name=name)
|
|
785
|
+
self.operation = op
|
|
786
|
+
self.ordering = ordering
|
|
787
|
+
|
|
788
|
+
def descr(self, buf):
|
|
789
|
+
ptr, val = self.operands
|
|
790
|
+
fmt = ("atomicrmw {op} {ptrty} {ptr}, {valty} {val} {ordering} "
|
|
791
|
+
"{metadata}\n")
|
|
792
|
+
buf.append(fmt.format(op=self.operation,
|
|
793
|
+
ptrty=ptr.type,
|
|
794
|
+
ptr=ptr.get_reference(),
|
|
795
|
+
valty=val.type,
|
|
796
|
+
val=val.get_reference(),
|
|
797
|
+
ordering=self.ordering,
|
|
798
|
+
metadata=self._stringify_metadata(
|
|
799
|
+
leading_comma=True),
|
|
800
|
+
))
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
class CmpXchg(Instruction):
|
|
804
|
+
"""This instruction has changed since llvm3.5. It is not compatible with
|
|
805
|
+
older llvm versions.
|
|
806
|
+
"""
|
|
807
|
+
|
|
808
|
+
def __init__(self, parent, ptr, cmp, val, ordering, failordering, name):
|
|
809
|
+
outtype = types.LiteralStructType([val.type, types.IntType(1)])
|
|
810
|
+
super(CmpXchg, self).__init__(parent, outtype, "cmpxchg",
|
|
811
|
+
(ptr, cmp, val), name=name)
|
|
812
|
+
self.ordering = ordering
|
|
813
|
+
self.failordering = failordering
|
|
814
|
+
|
|
815
|
+
def descr(self, buf):
|
|
816
|
+
ptr, cmpval, val = self.operands
|
|
817
|
+
fmt = "cmpxchg {ptrty} {ptr}, {ty} {cmp}, {ty} {val} {ordering} " \
|
|
818
|
+
"{failordering} {metadata}\n"
|
|
819
|
+
buf.append(fmt.format(ptrty=ptr.type,
|
|
820
|
+
ptr=ptr.get_reference(),
|
|
821
|
+
ty=cmpval.type,
|
|
822
|
+
cmp=cmpval.get_reference(),
|
|
823
|
+
val=val.get_reference(),
|
|
824
|
+
ordering=self.ordering,
|
|
825
|
+
failordering=self.failordering,
|
|
826
|
+
metadata=self._stringify_metadata(
|
|
827
|
+
leading_comma=True),
|
|
828
|
+
))
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
class _LandingPadClause(object):
|
|
832
|
+
def __init__(self, value):
|
|
833
|
+
self.value = value
|
|
834
|
+
|
|
835
|
+
def __str__(self):
|
|
836
|
+
return "{kind} {type} {value}".format(
|
|
837
|
+
kind=self.kind,
|
|
838
|
+
type=self.value.type,
|
|
839
|
+
value=self.value.get_reference())
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
class CatchClause(_LandingPadClause):
|
|
843
|
+
kind = 'catch'
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
class FilterClause(_LandingPadClause):
|
|
847
|
+
kind = 'filter'
|
|
848
|
+
|
|
849
|
+
def __init__(self, value):
|
|
850
|
+
assert isinstance(value, Constant)
|
|
851
|
+
assert isinstance(value.type, types.ArrayType)
|
|
852
|
+
super(FilterClause, self).__init__(value)
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
class LandingPadInstr(Instruction):
|
|
856
|
+
def __init__(self, parent, typ, name='', cleanup=False):
|
|
857
|
+
super(LandingPadInstr, self).__init__(parent, typ, "landingpad", [],
|
|
858
|
+
name=name)
|
|
859
|
+
self.cleanup = cleanup
|
|
860
|
+
self.clauses = []
|
|
861
|
+
|
|
862
|
+
def add_clause(self, clause):
|
|
863
|
+
assert isinstance(clause, _LandingPadClause)
|
|
864
|
+
self.clauses.append(clause)
|
|
865
|
+
|
|
866
|
+
def descr(self, buf):
|
|
867
|
+
fmt = "landingpad {type}{cleanup}{clauses}\n"
|
|
868
|
+
buf.append(fmt.format(type=self.type,
|
|
869
|
+
cleanup=' cleanup' if self.cleanup else '',
|
|
870
|
+
clauses=''.join(["\n {0}".format(clause)
|
|
871
|
+
for clause in self.clauses]),
|
|
872
|
+
))
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
class Fence(Instruction):
|
|
876
|
+
"""
|
|
877
|
+
The `fence` instruction.
|
|
878
|
+
|
|
879
|
+
As of LLVM 5.0.1:
|
|
880
|
+
|
|
881
|
+
fence [syncscope("<target-scope>")] <ordering> ; yields void
|
|
882
|
+
"""
|
|
883
|
+
|
|
884
|
+
VALID_FENCE_ORDERINGS = {"acquire", "release", "acq_rel", "seq_cst"}
|
|
885
|
+
|
|
886
|
+
def __init__(self, parent, ordering, targetscope=None, name=''):
|
|
887
|
+
super(Fence, self).__init__(parent, types.VoidType(), "fence", (),
|
|
888
|
+
name=name)
|
|
889
|
+
if ordering not in self.VALID_FENCE_ORDERINGS:
|
|
890
|
+
msg = "Invalid fence ordering \"{0}\"! Should be one of {1}."
|
|
891
|
+
raise ValueError(msg .format(ordering,
|
|
892
|
+
", ".join(self.VALID_FENCE_ORDERINGS)))
|
|
893
|
+
self.ordering = ordering
|
|
894
|
+
self.targetscope = targetscope
|
|
895
|
+
|
|
896
|
+
def descr(self, buf):
|
|
897
|
+
if self.targetscope is None:
|
|
898
|
+
syncscope = ""
|
|
899
|
+
else:
|
|
900
|
+
syncscope = 'syncscope("{0}") '.format(self.targetscope)
|
|
901
|
+
|
|
902
|
+
fmt = "fence {syncscope}{ordering}\n"
|
|
903
|
+
buf.append(fmt.format(syncscope=syncscope,
|
|
904
|
+
ordering=self.ordering,
|
|
905
|
+
))
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
class Comment(Instruction):
|
|
909
|
+
"""
|
|
910
|
+
A line comment.
|
|
911
|
+
"""
|
|
912
|
+
|
|
913
|
+
def __init__(self, parent, text):
|
|
914
|
+
super(Comment, self).__init__(parent, types.VoidType(), ";", (),
|
|
915
|
+
name='')
|
|
916
|
+
assert "\n" not in text, "Comment cannot contain new line"
|
|
917
|
+
self.text = text
|
|
918
|
+
|
|
919
|
+
def descr(self, buf):
|
|
920
|
+
buf.append(f"; {self.text}")
|