llvmlite 0.46.0b1__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.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
|
@@ -0,0 +1,3095 @@
|
|
|
1
|
+
"""
|
|
2
|
+
IR Construction Tests
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
import itertools
|
|
7
|
+
import pickle
|
|
8
|
+
import re
|
|
9
|
+
import textwrap
|
|
10
|
+
import unittest
|
|
11
|
+
|
|
12
|
+
from . import TestCase
|
|
13
|
+
from llvmlite import ir
|
|
14
|
+
from llvmlite import binding as llvm
|
|
15
|
+
from llvmlite import ir_layer_typed_pointers_enabled
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
int1 = ir.IntType(1)
|
|
19
|
+
int8 = ir.IntType(8)
|
|
20
|
+
int16 = ir.IntType(16)
|
|
21
|
+
int32 = ir.IntType(32)
|
|
22
|
+
int64 = ir.IntType(64)
|
|
23
|
+
hlf = ir.HalfType()
|
|
24
|
+
flt = ir.FloatType()
|
|
25
|
+
dbl = ir.DoubleType()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestBase(TestCase):
|
|
29
|
+
"""
|
|
30
|
+
Utilities for IR tests.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def assertInText(self, pattern, text):
|
|
34
|
+
"""
|
|
35
|
+
Assert *pattern* is in *text*, ignoring any whitespace differences
|
|
36
|
+
(including newlines).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def escape(c):
|
|
40
|
+
if not c.isalnum() and not c.isspace():
|
|
41
|
+
return '\\' + c
|
|
42
|
+
return c
|
|
43
|
+
|
|
44
|
+
pattern = ''.join(map(escape, pattern))
|
|
45
|
+
regex = re.sub(r'\s+', r'\\s*', pattern)
|
|
46
|
+
self.assertRegex(text, regex)
|
|
47
|
+
|
|
48
|
+
def assert_ir_line(self, line, mod):
|
|
49
|
+
lines = [line.strip() for line in str(mod).splitlines()]
|
|
50
|
+
self.assertIn(line, lines)
|
|
51
|
+
|
|
52
|
+
def assert_valid_ir(self, mod):
|
|
53
|
+
llvm.parse_assembly(str(mod))
|
|
54
|
+
|
|
55
|
+
def assert_pickle_correctly(self, irobject):
|
|
56
|
+
"""Assert that the IR object pickles and unpickles correctly.
|
|
57
|
+
The IR string is equal and that their type is equal
|
|
58
|
+
"""
|
|
59
|
+
newobject = pickle.loads(pickle.dumps(irobject, protocol=-1))
|
|
60
|
+
self.assertIs(irobject.__class__, newobject.__class__)
|
|
61
|
+
self.assertEqual(str(irobject), str(newobject))
|
|
62
|
+
return newobject
|
|
63
|
+
|
|
64
|
+
def module(self):
|
|
65
|
+
return ir.Module()
|
|
66
|
+
|
|
67
|
+
def function(self, module=None, name='my_func'):
|
|
68
|
+
module = module or self.module()
|
|
69
|
+
fnty = ir.FunctionType(int32, (int32, int32, dbl,
|
|
70
|
+
ir.PointerType(int32)))
|
|
71
|
+
return ir.Function(module, fnty, name)
|
|
72
|
+
|
|
73
|
+
def block(self, func=None, name=''):
|
|
74
|
+
func = func or self.function()
|
|
75
|
+
return func.append_basic_block(name)
|
|
76
|
+
|
|
77
|
+
def descr(self, thing):
|
|
78
|
+
buf = []
|
|
79
|
+
thing.descr(buf)
|
|
80
|
+
return "".join(buf)
|
|
81
|
+
|
|
82
|
+
def _normalize_asm(self, asm):
|
|
83
|
+
asm = textwrap.dedent(asm)
|
|
84
|
+
# Normalize indent
|
|
85
|
+
asm = asm.replace("\n ", "\n ")
|
|
86
|
+
return asm
|
|
87
|
+
|
|
88
|
+
def check_descr_regex(self, descr, asm):
|
|
89
|
+
expected = self._normalize_asm(asm)
|
|
90
|
+
self.assertRegex(descr, expected)
|
|
91
|
+
|
|
92
|
+
def check_descr(self, descr, asm):
|
|
93
|
+
expected = self._normalize_asm(asm)
|
|
94
|
+
self.assertEqual(descr, expected)
|
|
95
|
+
|
|
96
|
+
def check_block(self, block, asm):
|
|
97
|
+
self.check_descr(self.descr(block), asm)
|
|
98
|
+
|
|
99
|
+
def check_block_regex(self, block, asm):
|
|
100
|
+
self.check_descr_regex(self.descr(block), asm)
|
|
101
|
+
|
|
102
|
+
def check_module_body(self, module, asm):
|
|
103
|
+
expected = self._normalize_asm(asm)
|
|
104
|
+
actual = module._stringify_body()
|
|
105
|
+
self.assertEqual(actual.strip(), expected.strip())
|
|
106
|
+
|
|
107
|
+
def check_metadata(self, module, asm):
|
|
108
|
+
"""
|
|
109
|
+
Check module metadata against *asm*.
|
|
110
|
+
"""
|
|
111
|
+
expected = self._normalize_asm(asm)
|
|
112
|
+
actual = module._stringify_metadata()
|
|
113
|
+
self.assertEqual(actual.strip(), expected.strip())
|
|
114
|
+
|
|
115
|
+
def check_func_body(self, func, asm):
|
|
116
|
+
expected = self._normalize_asm(asm)
|
|
117
|
+
actual = self.descr(func)
|
|
118
|
+
actual = actual.partition('{')[2].rpartition('}')[0]
|
|
119
|
+
self.assertEqual(actual.strip(), expected.strip())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class TestFunction(TestBase):
|
|
123
|
+
|
|
124
|
+
proto = \
|
|
125
|
+
"""i32 @"my_func"(i32 %".1", i32 %".2", double %".3", ptr %".4")""" \
|
|
126
|
+
if not ir_layer_typed_pointers_enabled else \
|
|
127
|
+
"""i32 @"my_func"(i32 %".1", i32 %".2", double %".3", i32* %".4")"""
|
|
128
|
+
|
|
129
|
+
def test_declare(self):
|
|
130
|
+
# A simple declaration
|
|
131
|
+
func = self.function()
|
|
132
|
+
asm = self.descr(func).strip()
|
|
133
|
+
self.assertEqual(asm.strip(), "declare %s" % self.proto)
|
|
134
|
+
|
|
135
|
+
def test_declare_attributes(self):
|
|
136
|
+
# Now with function attributes
|
|
137
|
+
func = self.function()
|
|
138
|
+
func.attributes.add("optsize")
|
|
139
|
+
func.attributes.add("alwaysinline")
|
|
140
|
+
func.attributes.add("convergent")
|
|
141
|
+
func.attributes.alignstack = 16
|
|
142
|
+
tp_pers = ir.FunctionType(int8, (), var_arg=True)
|
|
143
|
+
pers = ir.Function(self.module(), tp_pers, '__gxx_personality_v0')
|
|
144
|
+
func.attributes.personality = pers
|
|
145
|
+
asm = self.descr(func).strip()
|
|
146
|
+
if not ir_layer_typed_pointers_enabled:
|
|
147
|
+
self.assertEqual(asm,
|
|
148
|
+
("declare %s alwaysinline convergent optsize "
|
|
149
|
+
"alignstack(16) "
|
|
150
|
+
"personality ptr @\"__gxx_personality_v0\"") %
|
|
151
|
+
self.proto)
|
|
152
|
+
else:
|
|
153
|
+
self.assertEqual(asm,
|
|
154
|
+
("declare %s alwaysinline convergent optsize "
|
|
155
|
+
"alignstack(16) personality "
|
|
156
|
+
"i8 (...)* @\"__gxx_personality_v0\"") %
|
|
157
|
+
self.proto)
|
|
158
|
+
# Check pickling
|
|
159
|
+
self.assert_pickle_correctly(func)
|
|
160
|
+
|
|
161
|
+
def test_function_attributes(self):
|
|
162
|
+
# Now with parameter attributes
|
|
163
|
+
func = self.function()
|
|
164
|
+
func.args[0].add_attribute("zeroext")
|
|
165
|
+
func.args[1].attributes.dereferenceable = 5
|
|
166
|
+
func.args[1].attributes.dereferenceable_or_null = 10
|
|
167
|
+
func.args[3].attributes.align = 4
|
|
168
|
+
func.args[3].add_attribute("nonnull")
|
|
169
|
+
func.return_value.add_attribute("noalias")
|
|
170
|
+
asm = self.descr(func).strip()
|
|
171
|
+
if not ir_layer_typed_pointers_enabled:
|
|
172
|
+
self.assertEqual(asm,
|
|
173
|
+
"""declare noalias i32 @"my_func"(i32 zeroext %".1", i32 dereferenceable(5) dereferenceable_or_null(10) %".2", double %".3", ptr nonnull align 4 %".4")""" # noqa E501
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
self.assertEqual(asm,
|
|
177
|
+
"""declare noalias i32 @"my_func"(i32 zeroext %".1", i32 dereferenceable(5) dereferenceable_or_null(10) %".2", double %".3", i32* nonnull align 4 %".4")""" # noqa E501
|
|
178
|
+
)
|
|
179
|
+
# Check pickling
|
|
180
|
+
self.assert_pickle_correctly(func)
|
|
181
|
+
|
|
182
|
+
def test_function_metadata(self):
|
|
183
|
+
# Now with function metadata
|
|
184
|
+
module = self.module()
|
|
185
|
+
func = self.function(module)
|
|
186
|
+
func.set_metadata('dbg', module.add_metadata([]))
|
|
187
|
+
asm = self.descr(func).strip()
|
|
188
|
+
self.assertEqual(asm,
|
|
189
|
+
f'declare {self.proto} !dbg !0'
|
|
190
|
+
)
|
|
191
|
+
# Check pickling
|
|
192
|
+
self.assert_pickle_correctly(func)
|
|
193
|
+
|
|
194
|
+
def test_function_section(self):
|
|
195
|
+
# Test function with section
|
|
196
|
+
func = self.function()
|
|
197
|
+
func.section = "a_section"
|
|
198
|
+
asm = self.descr(func).strip()
|
|
199
|
+
self.assertEqual(asm,
|
|
200
|
+
f'declare {self.proto} section "a_section"'
|
|
201
|
+
)
|
|
202
|
+
# Check pickling
|
|
203
|
+
self.assert_pickle_correctly(func)
|
|
204
|
+
|
|
205
|
+
def test_function_section_meta(self):
|
|
206
|
+
# Test function with section and metadata
|
|
207
|
+
module = self.module()
|
|
208
|
+
func = self.function(module)
|
|
209
|
+
func.section = "a_section"
|
|
210
|
+
func.set_metadata('dbg', module.add_metadata([]))
|
|
211
|
+
asm = self.descr(func).strip()
|
|
212
|
+
self.assertEqual(asm,
|
|
213
|
+
f'declare {self.proto} section "a_section" !dbg !0'
|
|
214
|
+
)
|
|
215
|
+
# Check pickling
|
|
216
|
+
self.assert_pickle_correctly(func)
|
|
217
|
+
|
|
218
|
+
def test_function_attr_meta(self):
|
|
219
|
+
# Test function with attributes and metadata
|
|
220
|
+
module = self.module()
|
|
221
|
+
func = self.function(module)
|
|
222
|
+
func.attributes.add("alwaysinline")
|
|
223
|
+
func.set_metadata('dbg', module.add_metadata([]))
|
|
224
|
+
asm = self.descr(func).strip()
|
|
225
|
+
self.assertEqual(asm,
|
|
226
|
+
f'declare {self.proto} alwaysinline !dbg !0'
|
|
227
|
+
)
|
|
228
|
+
# Check pickling
|
|
229
|
+
self.assert_pickle_correctly(func)
|
|
230
|
+
|
|
231
|
+
def test_function_attr_section(self):
|
|
232
|
+
# Test function with attributes and section
|
|
233
|
+
func = self.function()
|
|
234
|
+
func.attributes.add("optsize")
|
|
235
|
+
func.section = "a_section"
|
|
236
|
+
asm = self.descr(func).strip()
|
|
237
|
+
self.assertEqual(asm,
|
|
238
|
+
f'declare {self.proto} optsize section "a_section"')
|
|
239
|
+
# Check pickling
|
|
240
|
+
self.assert_pickle_correctly(func)
|
|
241
|
+
|
|
242
|
+
def test_function_attr_section_meta(self):
|
|
243
|
+
# Test function with attributes, section and metadata
|
|
244
|
+
module = self.module()
|
|
245
|
+
func = self.function(module)
|
|
246
|
+
func.attributes.add("alwaysinline")
|
|
247
|
+
func.section = "a_section"
|
|
248
|
+
func.set_metadata('dbg', module.add_metadata([]))
|
|
249
|
+
asm = self.descr(func).strip()
|
|
250
|
+
self.assertEqual(asm,
|
|
251
|
+
f'declare {self.proto} alwaysinline section "a_section" !dbg !0' # noqa E501
|
|
252
|
+
)
|
|
253
|
+
# Check pickling
|
|
254
|
+
self.assert_pickle_correctly(func)
|
|
255
|
+
|
|
256
|
+
def test_define(self):
|
|
257
|
+
# A simple definition
|
|
258
|
+
func = self.function()
|
|
259
|
+
func.attributes.add("alwaysinline")
|
|
260
|
+
block = func.append_basic_block('my_block')
|
|
261
|
+
builder = ir.IRBuilder(block)
|
|
262
|
+
builder.ret_void()
|
|
263
|
+
asm = self.descr(func)
|
|
264
|
+
self.check_descr(asm, """\
|
|
265
|
+
define {proto} alwaysinline
|
|
266
|
+
{{
|
|
267
|
+
my_block:
|
|
268
|
+
ret void
|
|
269
|
+
}}
|
|
270
|
+
""".format(proto=self.proto))
|
|
271
|
+
|
|
272
|
+
def test_declare_intrinsics(self):
|
|
273
|
+
module = self.module()
|
|
274
|
+
pint8 = int8.as_pointer()
|
|
275
|
+
|
|
276
|
+
powi = module.declare_intrinsic('llvm.powi', [dbl])
|
|
277
|
+
memset = module.declare_intrinsic('llvm.memset', [pint8, int32])
|
|
278
|
+
memcpy = module.declare_intrinsic('llvm.memcpy', [pint8, pint8, int32])
|
|
279
|
+
assume = module.declare_intrinsic('llvm.assume')
|
|
280
|
+
self.check_descr(self.descr(powi).strip(), """\
|
|
281
|
+
declare double @"llvm.powi.f64"(double %".1", i32 %".2")""")
|
|
282
|
+
if not ir_layer_typed_pointers_enabled:
|
|
283
|
+
self.check_descr(self.descr(memset).strip(), """\
|
|
284
|
+
declare void @"llvm.memset.p0.i32"(ptr %".1", i8 %".2", i32 %".3", i1 %".4")""") # noqa E501
|
|
285
|
+
self.check_descr(self.descr(memcpy).strip(), """\
|
|
286
|
+
declare void @"llvm.memcpy.p0.p0.i32"(ptr %".1", ptr %".2", i32 %".3", i1 %".4")""") # noqa E501
|
|
287
|
+
else:
|
|
288
|
+
self.check_descr(self.descr(memset).strip(), """\
|
|
289
|
+
declare void @"llvm.memset.p0i8.i32"(i8* %".1", i8 %".2", i32 %".3", i1 %".4")""") # noqa E501
|
|
290
|
+
self.check_descr(self.descr(memcpy).strip(), """\
|
|
291
|
+
declare void @"llvm.memcpy.p0i8.p0i8.i32"(i8* %".1", i8* %".2", i32 %".3", i1 %".4")""") # noqa E501
|
|
292
|
+
self.check_descr(self.descr(assume).strip(), """\
|
|
293
|
+
declare void @"llvm.assume"(i1 %".1")""")
|
|
294
|
+
|
|
295
|
+
def test_redeclare_intrinsic(self):
|
|
296
|
+
module = self.module()
|
|
297
|
+
powi = module.declare_intrinsic('llvm.powi', [dbl])
|
|
298
|
+
powi2 = module.declare_intrinsic('llvm.powi', [dbl])
|
|
299
|
+
self.assertIs(powi, powi2)
|
|
300
|
+
|
|
301
|
+
def test_pickling(self):
|
|
302
|
+
fn = self.function()
|
|
303
|
+
self.assert_pickle_correctly(fn)
|
|
304
|
+
|
|
305
|
+
def test_alwaysinline_noinline_disallowed(self):
|
|
306
|
+
module = self.module()
|
|
307
|
+
func = self.function(module)
|
|
308
|
+
func.attributes.add('alwaysinline')
|
|
309
|
+
|
|
310
|
+
msg = "Can't have alwaysinline and noinline"
|
|
311
|
+
with self.assertRaisesRegex(ValueError, msg):
|
|
312
|
+
func.attributes.add('noinline')
|
|
313
|
+
|
|
314
|
+
def test_noinline_alwaysinline_disallowed(self):
|
|
315
|
+
module = self.module()
|
|
316
|
+
func = self.function(module)
|
|
317
|
+
func.attributes.add('noinline')
|
|
318
|
+
|
|
319
|
+
msg = "Can't have alwaysinline and noinline"
|
|
320
|
+
with self.assertRaisesRegex(ValueError, msg):
|
|
321
|
+
func.attributes.add('alwaysinline')
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class TestIR(TestBase):
|
|
325
|
+
|
|
326
|
+
def test_unnamed_metadata(self):
|
|
327
|
+
# An unnamed metadata node
|
|
328
|
+
mod = self.module()
|
|
329
|
+
mod.add_metadata([int32(123), int8(42)])
|
|
330
|
+
self.assert_ir_line("!0 = !{ i32 123, i8 42 }", mod)
|
|
331
|
+
self.assert_valid_ir(mod)
|
|
332
|
+
|
|
333
|
+
def test_unnamed_metadata_2(self):
|
|
334
|
+
# Several unnamed metadata nodes
|
|
335
|
+
mod = self.module()
|
|
336
|
+
# First node has a literal metadata string
|
|
337
|
+
m0 = mod.add_metadata([int32(123), "kernel"])
|
|
338
|
+
# Second node refers to the first one
|
|
339
|
+
m1 = mod.add_metadata([int64(456), m0])
|
|
340
|
+
# Third node is the same as the second one
|
|
341
|
+
m2 = mod.add_metadata([int64(456), m0])
|
|
342
|
+
self.assertIs(m2, m1)
|
|
343
|
+
# Fourth node refers to the first three
|
|
344
|
+
mod.add_metadata([m0, m1, m2])
|
|
345
|
+
self.assert_ir_line('!0 = !{ i32 123, !"kernel" }', mod)
|
|
346
|
+
self.assert_ir_line('!1 = !{ i64 456, !0 }', mod)
|
|
347
|
+
self.assert_ir_line('!2 = !{ !0, !1, !1 }', mod)
|
|
348
|
+
|
|
349
|
+
def test_unnamed_metadata_3(self):
|
|
350
|
+
# Passing nested metadata as a sequence
|
|
351
|
+
mod = self.module()
|
|
352
|
+
mod.add_metadata([int32(123), [int32(456)], [int32(789)], [int32(456)]])
|
|
353
|
+
self.assert_ir_line('!0 = !{ i32 456 }', mod)
|
|
354
|
+
self.assert_ir_line('!1 = !{ i32 789 }', mod)
|
|
355
|
+
self.assert_ir_line('!2 = !{ i32 123, !0, !1, !0 }', mod)
|
|
356
|
+
|
|
357
|
+
def test_metadata_string(self):
|
|
358
|
+
# Escaping contents of a metadata string
|
|
359
|
+
mod = self.module()
|
|
360
|
+
mod.add_metadata(["\"\\$"])
|
|
361
|
+
self.assert_ir_line('!0 = !{ !"\\22\\5c$" }', mod)
|
|
362
|
+
|
|
363
|
+
def test_named_metadata(self):
|
|
364
|
+
# Add a named metadata node and add metadata values to it
|
|
365
|
+
mod = self.module()
|
|
366
|
+
m0 = mod.add_metadata([int32(123)])
|
|
367
|
+
m1 = mod.add_metadata([int64(456)])
|
|
368
|
+
nmd = mod.add_named_metadata("foo")
|
|
369
|
+
nmd.add(m0)
|
|
370
|
+
nmd.add(m1)
|
|
371
|
+
nmd.add(m0)
|
|
372
|
+
self.assert_ir_line("!foo = !{ !0, !1, !0 }", mod)
|
|
373
|
+
self.assert_valid_ir(mod)
|
|
374
|
+
# Check get_named_metadata()
|
|
375
|
+
self.assertIs(nmd, mod.get_named_metadata("foo"))
|
|
376
|
+
with self.assertRaises(KeyError):
|
|
377
|
+
mod.get_named_metadata("bar")
|
|
378
|
+
|
|
379
|
+
def test_named_metadata_2(self):
|
|
380
|
+
# Add and set named metadata through a single add_named_metadata() call
|
|
381
|
+
mod = self.module()
|
|
382
|
+
m0 = mod.add_metadata([int32(123)])
|
|
383
|
+
mod.add_named_metadata("foo", m0)
|
|
384
|
+
mod.add_named_metadata("foo", [int64(456)])
|
|
385
|
+
mod.add_named_metadata("foo", ["kernel"])
|
|
386
|
+
mod.add_named_metadata("bar", [])
|
|
387
|
+
self.assert_ir_line("!foo = !{ !0, !1, !2 }", mod)
|
|
388
|
+
self.assert_ir_line("!0 = !{ i32 123 }", mod)
|
|
389
|
+
self.assert_ir_line("!1 = !{ i64 456 }", mod)
|
|
390
|
+
self.assert_ir_line('!2 = !{ !"kernel" }', mod)
|
|
391
|
+
self.assert_ir_line("!bar = !{ !3 }", mod)
|
|
392
|
+
self.assert_ir_line('!3 = !{ }', mod)
|
|
393
|
+
self.assert_valid_ir(mod)
|
|
394
|
+
|
|
395
|
+
def test_metadata_null(self):
|
|
396
|
+
# A null metadata (typed) value
|
|
397
|
+
mod = self.module()
|
|
398
|
+
mod.add_metadata([int32.as_pointer()(None)])
|
|
399
|
+
if not ir_layer_typed_pointers_enabled:
|
|
400
|
+
self.assert_ir_line("!0 = !{ ptr null }", mod)
|
|
401
|
+
else:
|
|
402
|
+
self.assert_ir_line("!0 = !{ i32* null }", mod)
|
|
403
|
+
self.assert_valid_ir(mod)
|
|
404
|
+
# A null metadata (untyped) value
|
|
405
|
+
mod = self.module()
|
|
406
|
+
mod.add_metadata([None, int32(123)])
|
|
407
|
+
self.assert_ir_line("!0 = !{ null, i32 123 }", mod)
|
|
408
|
+
self.assert_valid_ir(mod)
|
|
409
|
+
|
|
410
|
+
def test_debug_info(self):
|
|
411
|
+
# Add real world-looking debug information to a module
|
|
412
|
+
# (with various value types)
|
|
413
|
+
mod = self.module()
|
|
414
|
+
di_file = mod.add_debug_info("DIFile", {
|
|
415
|
+
"filename": "foo",
|
|
416
|
+
"directory": "bar",
|
|
417
|
+
})
|
|
418
|
+
di_func_type = mod.add_debug_info("DISubroutineType", {
|
|
419
|
+
# None as `null`
|
|
420
|
+
"types": mod.add_metadata([None]),
|
|
421
|
+
})
|
|
422
|
+
di_compileunit = mod.add_debug_info("DICompileUnit", {
|
|
423
|
+
"language": ir.DIToken("DW_LANG_Python"),
|
|
424
|
+
"file": di_file,
|
|
425
|
+
"producer": "ARTIQ",
|
|
426
|
+
"runtimeVersion": 0,
|
|
427
|
+
"isOptimized": True,
|
|
428
|
+
}, is_distinct=True)
|
|
429
|
+
mod.add_debug_info("DISubprogram", {
|
|
430
|
+
"name": "my_func",
|
|
431
|
+
"file": di_file,
|
|
432
|
+
"line": 11,
|
|
433
|
+
"type": di_func_type,
|
|
434
|
+
"isLocal": False,
|
|
435
|
+
"unit": di_compileunit,
|
|
436
|
+
}, is_distinct=True)
|
|
437
|
+
|
|
438
|
+
# Check output
|
|
439
|
+
strmod = str(mod)
|
|
440
|
+
self.assert_ir_line('!0 = !DIFile(directory: "bar", filename: "foo")',
|
|
441
|
+
strmod)
|
|
442
|
+
self.assert_ir_line('!1 = !{ null }', strmod)
|
|
443
|
+
self.assert_ir_line('!2 = !DISubroutineType(types: !1)', strmod)
|
|
444
|
+
# self.assert_ir_line('!4 = !{ !3 }', strmod)
|
|
445
|
+
self.assert_ir_line('!3 = distinct !DICompileUnit(file: !0, '
|
|
446
|
+
'isOptimized: true, language: DW_LANG_Python, '
|
|
447
|
+
'producer: "ARTIQ", runtimeVersion: 0)',
|
|
448
|
+
strmod)
|
|
449
|
+
self.assert_ir_line('!4 = distinct !DISubprogram(file: !0, isLocal: '
|
|
450
|
+
'false, line: 11, name: "my_func", type: !2, unit: '
|
|
451
|
+
'!3)',
|
|
452
|
+
strmod)
|
|
453
|
+
self.assert_valid_ir(mod)
|
|
454
|
+
|
|
455
|
+
def test_debug_info_2(self):
|
|
456
|
+
# Identical debug info nodes should be merged
|
|
457
|
+
mod = self.module()
|
|
458
|
+
di1 = mod.add_debug_info("DIFile",
|
|
459
|
+
{"filename": "foo",
|
|
460
|
+
"directory": "bar",
|
|
461
|
+
})
|
|
462
|
+
di2 = mod.add_debug_info("DIFile",
|
|
463
|
+
{"filename": "foo",
|
|
464
|
+
"directory": "bar",
|
|
465
|
+
})
|
|
466
|
+
di3 = mod.add_debug_info("DIFile",
|
|
467
|
+
{"filename": "bar",
|
|
468
|
+
"directory": "foo",
|
|
469
|
+
})
|
|
470
|
+
di4 = mod.add_debug_info("DIFile",
|
|
471
|
+
{"filename": "foo",
|
|
472
|
+
"directory": "bar",
|
|
473
|
+
}, is_distinct=True)
|
|
474
|
+
self.assertIs(di1, di2)
|
|
475
|
+
self.assertEqual(len({di1, di2, di3, di4}), 3)
|
|
476
|
+
# Check output
|
|
477
|
+
strmod = str(mod)
|
|
478
|
+
self.assert_ir_line('!0 = !DIFile(directory: "bar", filename: "foo")',
|
|
479
|
+
strmod)
|
|
480
|
+
self.assert_ir_line('!1 = !DIFile(directory: "foo", filename: "bar")',
|
|
481
|
+
strmod)
|
|
482
|
+
self.assert_ir_line('!2 = distinct !DIFile(directory: "bar", filename: '
|
|
483
|
+
'"foo")', strmod)
|
|
484
|
+
self.assert_valid_ir(mod)
|
|
485
|
+
|
|
486
|
+
def test_debug_info_3(self):
|
|
487
|
+
# Identical DIBasicType metadata nodes should be merged
|
|
488
|
+
mod = self.module()
|
|
489
|
+
di1 = mod.add_debug_info("DIBasicType", {
|
|
490
|
+
"name": "i8",
|
|
491
|
+
"size": 8,
|
|
492
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
493
|
+
})
|
|
494
|
+
di2 = mod.add_debug_info("DIBasicType", {
|
|
495
|
+
"name": "i8",
|
|
496
|
+
"size": 8,
|
|
497
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
498
|
+
})
|
|
499
|
+
di3 = mod.add_debug_info("DIBasicType", {
|
|
500
|
+
"name": "i32",
|
|
501
|
+
"size": 32,
|
|
502
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
503
|
+
})
|
|
504
|
+
di4 = mod.add_debug_info("DIBasicType", {
|
|
505
|
+
"name": "i8",
|
|
506
|
+
"size": 8,
|
|
507
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
508
|
+
})
|
|
509
|
+
di5 = mod.add_debug_info("DIBasicType", {
|
|
510
|
+
"name": "i8",
|
|
511
|
+
"size": 8,
|
|
512
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
513
|
+
})
|
|
514
|
+
di6 = mod.add_debug_info("DIBasicType", {
|
|
515
|
+
"name": "i32",
|
|
516
|
+
"size": 32,
|
|
517
|
+
"encoding": ir.DIToken("DW_ATE_unsigned")
|
|
518
|
+
})
|
|
519
|
+
di7 = mod.add_debug_info("DIBasicType", {
|
|
520
|
+
"name": "i64",
|
|
521
|
+
"size": 64,
|
|
522
|
+
"encoding": ir.DIToken("DW_ATE_signed")
|
|
523
|
+
})
|
|
524
|
+
di8 = mod.add_debug_info("DIBasicType", {
|
|
525
|
+
"name": "i64",
|
|
526
|
+
"size": 64,
|
|
527
|
+
"encoding": ir.DIToken("DW_ATE_signed")
|
|
528
|
+
})
|
|
529
|
+
di9 = mod.add_debug_info("DIBasicType", {
|
|
530
|
+
"name": "i64",
|
|
531
|
+
"size": 64,
|
|
532
|
+
"encoding": ir.DIToken("DW_ATE_signed")
|
|
533
|
+
})
|
|
534
|
+
self.assertIs(di1, di2)
|
|
535
|
+
self.assertIs(di1, di4)
|
|
536
|
+
self.assertIs(di1, di5)
|
|
537
|
+
self.assertIs(di3, di6)
|
|
538
|
+
self.assertIs(di7, di8)
|
|
539
|
+
self.assertIs(di7, di9)
|
|
540
|
+
self.assertEqual(len({di1, di2, di3, di4, di5, di6, di7, di8, di9}), 3)
|
|
541
|
+
# Check output
|
|
542
|
+
strmod = str(mod)
|
|
543
|
+
self.assert_ir_line('!0 = !DIBasicType(encoding: DW_ATE_unsigned, '
|
|
544
|
+
'name: "i8", size: 8)', strmod)
|
|
545
|
+
self.assert_ir_line('!1 = !DIBasicType(encoding: DW_ATE_unsigned, '
|
|
546
|
+
'name: "i32", size: 32)', strmod)
|
|
547
|
+
self.assert_ir_line('!2 = !DIBasicType(encoding: DW_ATE_signed, '
|
|
548
|
+
'name: "i64", size: 64)', strmod)
|
|
549
|
+
self.assert_valid_ir(mod)
|
|
550
|
+
|
|
551
|
+
def test_debug_info_gvar(self):
|
|
552
|
+
# This test defines a module with a global variable named 'gvar'.
|
|
553
|
+
# When the module is compiled and linked with a main function, gdb can
|
|
554
|
+
# be used to interpret and print the the value of 'gvar'.
|
|
555
|
+
mod = self.module()
|
|
556
|
+
|
|
557
|
+
gvar = ir.GlobalVariable(mod, ir.FloatType(), 'gvar')
|
|
558
|
+
gvar.initializer = ir.Constant(ir.FloatType(), 42)
|
|
559
|
+
|
|
560
|
+
di_float = mod.add_debug_info("DIBasicType", {
|
|
561
|
+
"name": "float",
|
|
562
|
+
"size": 32,
|
|
563
|
+
"encoding": ir.DIToken("DW_ATE_float")
|
|
564
|
+
})
|
|
565
|
+
di_gvar = mod.add_debug_info("DIGlobalVariableExpression", {
|
|
566
|
+
"expr": mod.add_debug_info("DIExpression", {}),
|
|
567
|
+
"var": mod.add_debug_info("DIGlobalVariable", {
|
|
568
|
+
"name": gvar.name,
|
|
569
|
+
"type": di_float,
|
|
570
|
+
"isDefinition": True
|
|
571
|
+
}, is_distinct=True)
|
|
572
|
+
})
|
|
573
|
+
gvar.set_metadata('dbg', di_gvar)
|
|
574
|
+
|
|
575
|
+
# Check output
|
|
576
|
+
strmod = str(mod)
|
|
577
|
+
self.assert_ir_line('!0 = !DIBasicType(encoding: DW_ATE_float, '
|
|
578
|
+
'name: "float", size: 32)', strmod)
|
|
579
|
+
self.assert_ir_line('!1 = !DIExpression()', strmod)
|
|
580
|
+
self.assert_ir_line('!2 = distinct !DIGlobalVariable(isDefinition: '
|
|
581
|
+
'true, name: "gvar", type: !0)', strmod)
|
|
582
|
+
self.assert_ir_line('!3 = !DIGlobalVariableExpression(expr: !1, '
|
|
583
|
+
'var: !2)', strmod)
|
|
584
|
+
self.assert_ir_line('@"gvar" = global float 0x4045000000000000, '
|
|
585
|
+
'!dbg !3', strmod)
|
|
586
|
+
|
|
587
|
+
# The remaining debug info is not part of the automated test, but
|
|
588
|
+
# can be used to produce an object file that can be loaded into a
|
|
589
|
+
# debugger to print the value of gvar. This can be done by printing the
|
|
590
|
+
# module then compiling it with clang and inspecting with gdb:
|
|
591
|
+
#
|
|
592
|
+
# clang test_debug_info_gvar.ll -c
|
|
593
|
+
# printf "file test_debug_info_gvar.o \n p gvar" | gdb
|
|
594
|
+
#
|
|
595
|
+
# Which should result in the output:
|
|
596
|
+
#
|
|
597
|
+
# (gdb) $1 = 42
|
|
598
|
+
|
|
599
|
+
dver = [ir.IntType(32)(2), 'Dwarf Version', ir.IntType(32)(4)]
|
|
600
|
+
diver = [ir.IntType(32)(2), 'Debug Info Version', ir.IntType(32)(3)]
|
|
601
|
+
dver = mod.add_metadata(dver)
|
|
602
|
+
diver = mod.add_metadata(diver)
|
|
603
|
+
flags = mod.add_named_metadata('llvm.module.flags')
|
|
604
|
+
flags.add(dver)
|
|
605
|
+
flags.add(diver)
|
|
606
|
+
|
|
607
|
+
di_file = mod.add_debug_info("DIFile", {
|
|
608
|
+
"filename": "foo",
|
|
609
|
+
"directory": "bar",
|
|
610
|
+
})
|
|
611
|
+
di_cu = mod.add_debug_info("DICompileUnit", {
|
|
612
|
+
"language": ir.DIToken("DW_LANG_Python"),
|
|
613
|
+
"file": di_file,
|
|
614
|
+
'emissionKind': ir.DIToken('FullDebug'),
|
|
615
|
+
"globals": mod.add_metadata([di_gvar])
|
|
616
|
+
}, is_distinct=True)
|
|
617
|
+
mod.add_named_metadata('llvm.dbg.cu', di_cu)
|
|
618
|
+
|
|
619
|
+
def test_debug_info_unicode_string(self):
|
|
620
|
+
mod = self.module()
|
|
621
|
+
mod.add_debug_info("DILocalVariable", {"name": "a∆"})
|
|
622
|
+
# Check output
|
|
623
|
+
strmod = str(mod)
|
|
624
|
+
# The unicode character is utf8 encoded with \XX format, where XX is hex
|
|
625
|
+
name = ''.join(map(lambda x: f"\\{x:02x}", "∆".encode()))
|
|
626
|
+
self.assert_ir_line(f'!0 = !DILocalVariable(name: "a{name}")', strmod)
|
|
627
|
+
|
|
628
|
+
def test_inline_assembly(self):
|
|
629
|
+
mod = self.module()
|
|
630
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'foo')
|
|
631
|
+
builder = ir.IRBuilder(foo.append_basic_block(''))
|
|
632
|
+
asmty = ir.FunctionType(int32, [int32])
|
|
633
|
+
asm = ir.InlineAsm(asmty, "mov $1, $2", "=r,r", side_effect=True)
|
|
634
|
+
builder.call(asm, [int32(123)])
|
|
635
|
+
builder.ret_void()
|
|
636
|
+
pat = 'call i32 asm sideeffect "mov $1, $2", "=r,r" ( i32 123 )'
|
|
637
|
+
self.assertInText(pat, str(mod))
|
|
638
|
+
self.assert_valid_ir(mod)
|
|
639
|
+
|
|
640
|
+
def test_builder_asm(self):
|
|
641
|
+
mod = self.module()
|
|
642
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'foo')
|
|
643
|
+
builder = ir.IRBuilder(foo.append_basic_block(''))
|
|
644
|
+
asmty = ir.FunctionType(int32, [int32])
|
|
645
|
+
builder.asm(asmty, "mov $1, $2", "=r,r", [int32(123)], side_effect=True)
|
|
646
|
+
builder.ret_void()
|
|
647
|
+
pat = 'call i32 asm sideeffect "mov $1, $2", "=r,r" ( i32 123 )'
|
|
648
|
+
self.assertInText(pat, str(mod))
|
|
649
|
+
self.assert_valid_ir(mod)
|
|
650
|
+
|
|
651
|
+
def test_builder_load_reg(self):
|
|
652
|
+
mod = self.module()
|
|
653
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'foo')
|
|
654
|
+
builder = ir.IRBuilder(foo.append_basic_block(''))
|
|
655
|
+
builder.load_reg(ir.IntType(64), "rax")
|
|
656
|
+
builder.ret_void()
|
|
657
|
+
pat = 'call i64 asm "", "={rax}"'
|
|
658
|
+
self.assertInText(pat, str(mod))
|
|
659
|
+
self.assert_valid_ir(mod)
|
|
660
|
+
|
|
661
|
+
def test_builder_store_reg(self):
|
|
662
|
+
mod = self.module()
|
|
663
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'foo')
|
|
664
|
+
builder = ir.IRBuilder(foo.append_basic_block(''))
|
|
665
|
+
builder.store_reg(int64(123), ir.IntType(64), "rax")
|
|
666
|
+
builder.ret_void()
|
|
667
|
+
pat = 'call void asm sideeffect "", "{rax}" ( i64 123 )'
|
|
668
|
+
self.assertInText(pat, str(mod))
|
|
669
|
+
self.assert_valid_ir(mod)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
class TestGlobalValues(TestBase):
|
|
673
|
+
|
|
674
|
+
def test_globals_access(self):
|
|
675
|
+
mod = self.module()
|
|
676
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'foo')
|
|
677
|
+
ir.Function(mod, ir.FunctionType(ir.VoidType(), []), 'bar')
|
|
678
|
+
globdouble = ir.GlobalVariable(mod, ir.DoubleType(), 'globdouble')
|
|
679
|
+
self.assertEqual(mod.get_global('foo'), foo)
|
|
680
|
+
self.assertEqual(mod.get_global('globdouble'), globdouble)
|
|
681
|
+
with self.assertRaises(KeyError):
|
|
682
|
+
mod.get_global('kkk')
|
|
683
|
+
# Globals should have a useful repr()
|
|
684
|
+
if not ir_layer_typed_pointers_enabled:
|
|
685
|
+
self.assertEqual(repr(globdouble),
|
|
686
|
+
"<ir.GlobalVariable 'globdouble' of type 'ptr'>")
|
|
687
|
+
else:
|
|
688
|
+
self.assertEqual(
|
|
689
|
+
repr(globdouble),
|
|
690
|
+
"<ir.GlobalVariable 'globdouble' of type 'double*'>")
|
|
691
|
+
|
|
692
|
+
def test_functions_global_values_access(self):
|
|
693
|
+
"""
|
|
694
|
+
Accessing functions and global values through Module.functions
|
|
695
|
+
and Module.global_values.
|
|
696
|
+
"""
|
|
697
|
+
mod = self.module()
|
|
698
|
+
fty = ir.FunctionType(ir.VoidType(), [])
|
|
699
|
+
foo = ir.Function(mod, fty, 'foo')
|
|
700
|
+
bar = ir.Function(mod, fty, 'bar')
|
|
701
|
+
globdouble = ir.GlobalVariable(mod, ir.DoubleType(), 'globdouble')
|
|
702
|
+
self.assertEqual(set(mod.functions), set((foo, bar)))
|
|
703
|
+
self.assertEqual(set(mod.global_values), set((foo, bar, globdouble)))
|
|
704
|
+
|
|
705
|
+
def test_global_variables_ir(self):
|
|
706
|
+
"""
|
|
707
|
+
IR serialization of global variables.
|
|
708
|
+
"""
|
|
709
|
+
mod = self.module()
|
|
710
|
+
# the following have side effects and write to self.module()
|
|
711
|
+
a = ir.GlobalVariable(mod, int8, 'a') # noqa F841
|
|
712
|
+
b = ir.GlobalVariable(mod, int8, 'b', addrspace=42) # noqa F841
|
|
713
|
+
# Initialized global variable doesn't default to "external"
|
|
714
|
+
c = ir.GlobalVariable(mod, int32, 'c')
|
|
715
|
+
c.initializer = int32(123)
|
|
716
|
+
d = ir.GlobalVariable(mod, int32, 'd')
|
|
717
|
+
d.global_constant = True
|
|
718
|
+
# Non-external linkage implies default "undef" initializer
|
|
719
|
+
e = ir.GlobalVariable(mod, int32, 'e')
|
|
720
|
+
e.linkage = "internal"
|
|
721
|
+
f = ir.GlobalVariable(mod, int32, 'f', addrspace=456)
|
|
722
|
+
f.unnamed_addr = True
|
|
723
|
+
g = ir.GlobalVariable(mod, int32, 'g')
|
|
724
|
+
g.linkage = "internal"
|
|
725
|
+
g.initializer = int32(123)
|
|
726
|
+
g.align = 16
|
|
727
|
+
h = ir.GlobalVariable(mod, int32, 'h')
|
|
728
|
+
h.linkage = "internal"
|
|
729
|
+
h.initializer = int32(123)
|
|
730
|
+
h.section = "h_section"
|
|
731
|
+
i = ir.GlobalVariable(mod, int32, 'i')
|
|
732
|
+
i.linkage = "internal"
|
|
733
|
+
i.initializer = int32(456)
|
|
734
|
+
i.align = 8
|
|
735
|
+
i.section = "i_section"
|
|
736
|
+
self.check_module_body(mod, """\
|
|
737
|
+
@"a" = external global i8
|
|
738
|
+
@"b" = external addrspace(42) global i8
|
|
739
|
+
@"c" = global i32 123
|
|
740
|
+
@"d" = external constant i32
|
|
741
|
+
@"e" = internal global i32 undef
|
|
742
|
+
@"f" = external unnamed_addr addrspace(456) global i32
|
|
743
|
+
@"g" = internal global i32 123, align 16
|
|
744
|
+
@"h" = internal global i32 123, section "h_section"
|
|
745
|
+
@"i" = internal global i32 456, section "i_section", align 8
|
|
746
|
+
""")
|
|
747
|
+
|
|
748
|
+
def test_pickle(self):
|
|
749
|
+
mod = self.module()
|
|
750
|
+
self.assert_pickle_correctly(mod)
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
class TestBlock(TestBase):
|
|
754
|
+
|
|
755
|
+
def test_attributes(self):
|
|
756
|
+
func = self.function()
|
|
757
|
+
block = ir.Block(parent=func, name='start')
|
|
758
|
+
self.assertIs(block.parent, func)
|
|
759
|
+
self.assertFalse(block.is_terminated)
|
|
760
|
+
|
|
761
|
+
def test_descr(self):
|
|
762
|
+
block = self.block(name='my_block')
|
|
763
|
+
self.assertEqual(self.descr(block), "my_block:\n")
|
|
764
|
+
block.instructions.extend(['a', 'b'])
|
|
765
|
+
self.assertEqual(self.descr(block), "my_block:\n a\n b\n")
|
|
766
|
+
|
|
767
|
+
def test_replace(self):
|
|
768
|
+
block = self.block(name='my_block')
|
|
769
|
+
builder = ir.IRBuilder(block)
|
|
770
|
+
a, b = builder.function.args[:2]
|
|
771
|
+
c = builder.add(a, b, 'c')
|
|
772
|
+
d = builder.sub(a, b, 'd')
|
|
773
|
+
builder.mul(d, b, 'e')
|
|
774
|
+
f = ir.Instruction(block, a.type, 'sdiv', (c, b), 'f')
|
|
775
|
+
self.check_block(block, """\
|
|
776
|
+
my_block:
|
|
777
|
+
%"c" = add i32 %".1", %".2"
|
|
778
|
+
%"d" = sub i32 %".1", %".2"
|
|
779
|
+
%"e" = mul i32 %"d", %".2"
|
|
780
|
+
""")
|
|
781
|
+
block.replace(d, f)
|
|
782
|
+
self.check_block(block, """\
|
|
783
|
+
my_block:
|
|
784
|
+
%"c" = add i32 %".1", %".2"
|
|
785
|
+
%"f" = sdiv i32 %"c", %".2"
|
|
786
|
+
%"e" = mul i32 %"f", %".2"
|
|
787
|
+
""")
|
|
788
|
+
|
|
789
|
+
def test_repr(self):
|
|
790
|
+
"""
|
|
791
|
+
Blocks should have a useful repr()
|
|
792
|
+
"""
|
|
793
|
+
func = self.function()
|
|
794
|
+
block = ir.Block(parent=func, name='start')
|
|
795
|
+
self.assertEqual(repr(block), "<ir.Block 'start' of type 'label'>")
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
class TestBuildInstructions(TestBase):
|
|
799
|
+
"""
|
|
800
|
+
Test IR generation of LLVM instructions through the IRBuilder class.
|
|
801
|
+
"""
|
|
802
|
+
|
|
803
|
+
maxDiff = 4000
|
|
804
|
+
|
|
805
|
+
def test_simple(self):
|
|
806
|
+
block = self.block(name='my_block')
|
|
807
|
+
builder = ir.IRBuilder(block)
|
|
808
|
+
a, b = builder.function.args[:2]
|
|
809
|
+
inst = builder.add(a, b, 'res')
|
|
810
|
+
self.check_block(block, """\
|
|
811
|
+
my_block:
|
|
812
|
+
%"res" = add i32 %".1", %".2"
|
|
813
|
+
""")
|
|
814
|
+
# Instructions should have a useful repr()
|
|
815
|
+
self.assertEqual(repr(inst),
|
|
816
|
+
"<ir.Instruction 'res' of type 'i32', opname 'add', "
|
|
817
|
+
"operands (<ir.Argument '.1' of type i32>, "
|
|
818
|
+
"<ir.Argument '.2' of type i32>)>")
|
|
819
|
+
|
|
820
|
+
def test_binops(self):
|
|
821
|
+
block = self.block(name='my_block')
|
|
822
|
+
builder = ir.IRBuilder(block)
|
|
823
|
+
a, b, ff = builder.function.args[:3]
|
|
824
|
+
builder.add(a, b, 'c')
|
|
825
|
+
builder.fadd(a, b, 'd')
|
|
826
|
+
builder.sub(a, b, 'e')
|
|
827
|
+
builder.fsub(a, b, 'f')
|
|
828
|
+
builder.mul(a, b, 'g')
|
|
829
|
+
builder.fmul(a, b, 'h')
|
|
830
|
+
builder.udiv(a, b, 'i')
|
|
831
|
+
builder.sdiv(a, b, 'j')
|
|
832
|
+
builder.fdiv(a, b, 'k')
|
|
833
|
+
builder.urem(a, b, 'l')
|
|
834
|
+
builder.srem(a, b, 'm')
|
|
835
|
+
builder.frem(a, b, 'n')
|
|
836
|
+
builder.or_(a, b, 'o')
|
|
837
|
+
builder.and_(a, b, 'p')
|
|
838
|
+
builder.xor(a, b, 'q')
|
|
839
|
+
builder.shl(a, b, 'r')
|
|
840
|
+
builder.ashr(a, b, 's')
|
|
841
|
+
builder.lshr(a, b, 't')
|
|
842
|
+
with self.assertRaises(ValueError) as cm:
|
|
843
|
+
builder.add(a, ff)
|
|
844
|
+
self.assertEqual(str(cm.exception),
|
|
845
|
+
"Operands must be the same type, got (i32, double)")
|
|
846
|
+
self.assertFalse(block.is_terminated)
|
|
847
|
+
self.check_block(block, """\
|
|
848
|
+
my_block:
|
|
849
|
+
%"c" = add i32 %".1", %".2"
|
|
850
|
+
%"d" = fadd i32 %".1", %".2"
|
|
851
|
+
%"e" = sub i32 %".1", %".2"
|
|
852
|
+
%"f" = fsub i32 %".1", %".2"
|
|
853
|
+
%"g" = mul i32 %".1", %".2"
|
|
854
|
+
%"h" = fmul i32 %".1", %".2"
|
|
855
|
+
%"i" = udiv i32 %".1", %".2"
|
|
856
|
+
%"j" = sdiv i32 %".1", %".2"
|
|
857
|
+
%"k" = fdiv i32 %".1", %".2"
|
|
858
|
+
%"l" = urem i32 %".1", %".2"
|
|
859
|
+
%"m" = srem i32 %".1", %".2"
|
|
860
|
+
%"n" = frem i32 %".1", %".2"
|
|
861
|
+
%"o" = or i32 %".1", %".2"
|
|
862
|
+
%"p" = and i32 %".1", %".2"
|
|
863
|
+
%"q" = xor i32 %".1", %".2"
|
|
864
|
+
%"r" = shl i32 %".1", %".2"
|
|
865
|
+
%"s" = ashr i32 %".1", %".2"
|
|
866
|
+
%"t" = lshr i32 %".1", %".2"
|
|
867
|
+
""")
|
|
868
|
+
|
|
869
|
+
def test_binop_flags(self):
|
|
870
|
+
block = self.block(name='my_block')
|
|
871
|
+
builder = ir.IRBuilder(block)
|
|
872
|
+
a, b = builder.function.args[:2]
|
|
873
|
+
# As tuple
|
|
874
|
+
builder.add(a, b, 'c', flags=('nuw',))
|
|
875
|
+
# and as list
|
|
876
|
+
builder.sub(a, b, 'd', flags=['nuw', 'nsw'])
|
|
877
|
+
self.check_block(block, """\
|
|
878
|
+
my_block:
|
|
879
|
+
%"c" = add nuw i32 %".1", %".2"
|
|
880
|
+
%"d" = sub nuw nsw i32 %".1", %".2"
|
|
881
|
+
""")
|
|
882
|
+
|
|
883
|
+
def test_binop_fastmath_flags(self):
|
|
884
|
+
block = self.block(name='my_block')
|
|
885
|
+
builder = ir.IRBuilder(block)
|
|
886
|
+
a, b = builder.function.args[:2]
|
|
887
|
+
# As tuple
|
|
888
|
+
builder.fadd(a, b, 'c', flags=('fast',))
|
|
889
|
+
# and as list
|
|
890
|
+
builder.fsub(a, b, 'd', flags=['ninf', 'nsz'])
|
|
891
|
+
self.check_block(block, """\
|
|
892
|
+
my_block:
|
|
893
|
+
%"c" = fadd fast i32 %".1", %".2"
|
|
894
|
+
%"d" = fsub ninf nsz i32 %".1", %".2"
|
|
895
|
+
""")
|
|
896
|
+
|
|
897
|
+
def test_binops_with_overflow(self):
|
|
898
|
+
block = self.block(name='my_block')
|
|
899
|
+
builder = ir.IRBuilder(block)
|
|
900
|
+
a, b = builder.function.args[:2]
|
|
901
|
+
builder.sadd_with_overflow(a, b, 'c')
|
|
902
|
+
builder.smul_with_overflow(a, b, 'd')
|
|
903
|
+
builder.ssub_with_overflow(a, b, 'e')
|
|
904
|
+
builder.uadd_with_overflow(a, b, 'f')
|
|
905
|
+
builder.umul_with_overflow(a, b, 'g')
|
|
906
|
+
builder.usub_with_overflow(a, b, 'h')
|
|
907
|
+
self.check_block(block, """\
|
|
908
|
+
my_block:
|
|
909
|
+
%"c" = call {i32, i1} @"llvm.sadd.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
910
|
+
%"d" = call {i32, i1} @"llvm.smul.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
911
|
+
%"e" = call {i32, i1} @"llvm.ssub.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
912
|
+
%"f" = call {i32, i1} @"llvm.uadd.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
913
|
+
%"g" = call {i32, i1} @"llvm.umul.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
914
|
+
%"h" = call {i32, i1} @"llvm.usub.with.overflow.i32"(i32 %".1", i32 %".2")
|
|
915
|
+
""")
|
|
916
|
+
|
|
917
|
+
def test_unary_ops(self):
|
|
918
|
+
block = self.block(name='my_block')
|
|
919
|
+
builder = ir.IRBuilder(block)
|
|
920
|
+
a, b, c = builder.function.args[:3]
|
|
921
|
+
builder.neg(a, 'd')
|
|
922
|
+
builder.not_(b, 'e')
|
|
923
|
+
builder.fneg(c, 'f')
|
|
924
|
+
self.assertFalse(block.is_terminated)
|
|
925
|
+
self.check_block(block, """\
|
|
926
|
+
my_block:
|
|
927
|
+
%"d" = sub i32 0, %".1"
|
|
928
|
+
%"e" = xor i32 %".2", -1
|
|
929
|
+
%"f" = fneg double %".3"
|
|
930
|
+
""")
|
|
931
|
+
|
|
932
|
+
def test_replace_operand(self):
|
|
933
|
+
block = self.block(name='my_block')
|
|
934
|
+
builder = ir.IRBuilder(block)
|
|
935
|
+
a, b = builder.function.args[:2]
|
|
936
|
+
undef1 = ir.Constant(ir.IntType(32), ir.Undefined)
|
|
937
|
+
undef2 = ir.Constant(ir.IntType(32), ir.Undefined)
|
|
938
|
+
c = builder.add(undef1, undef2, 'c')
|
|
939
|
+
self.check_block(block, """\
|
|
940
|
+
my_block:
|
|
941
|
+
%"c" = add i32 undef, undef
|
|
942
|
+
""")
|
|
943
|
+
c.replace_usage(undef1, a)
|
|
944
|
+
c.replace_usage(undef2, b)
|
|
945
|
+
self.check_block(block, """\
|
|
946
|
+
my_block:
|
|
947
|
+
%"c" = add i32 %".1", %".2"
|
|
948
|
+
""")
|
|
949
|
+
|
|
950
|
+
def test_integer_comparisons(self):
|
|
951
|
+
block = self.block(name='my_block')
|
|
952
|
+
builder = ir.IRBuilder(block)
|
|
953
|
+
a, b = builder.function.args[:2]
|
|
954
|
+
builder.icmp_unsigned('==', a, b, 'c')
|
|
955
|
+
builder.icmp_unsigned('!=', a, b, 'd')
|
|
956
|
+
builder.icmp_unsigned('<', a, b, 'e')
|
|
957
|
+
builder.icmp_unsigned('<=', a, b, 'f')
|
|
958
|
+
builder.icmp_unsigned('>', a, b, 'g')
|
|
959
|
+
builder.icmp_unsigned('>=', a, b, 'h')
|
|
960
|
+
builder.icmp_signed('==', a, b, 'i')
|
|
961
|
+
builder.icmp_signed('!=', a, b, 'j')
|
|
962
|
+
builder.icmp_signed('<', a, b, 'k')
|
|
963
|
+
builder.icmp_signed('<=', a, b, 'l')
|
|
964
|
+
builder.icmp_signed('>', a, b, 'm')
|
|
965
|
+
builder.icmp_signed('>=', a, b, 'n')
|
|
966
|
+
with self.assertRaises(ValueError):
|
|
967
|
+
builder.icmp_signed('uno', a, b, 'zz')
|
|
968
|
+
with self.assertRaises(ValueError):
|
|
969
|
+
builder.icmp_signed('foo', a, b, 'zz')
|
|
970
|
+
self.assertFalse(block.is_terminated)
|
|
971
|
+
self.check_block(block, """\
|
|
972
|
+
my_block:
|
|
973
|
+
%"c" = icmp eq i32 %".1", %".2"
|
|
974
|
+
%"d" = icmp ne i32 %".1", %".2"
|
|
975
|
+
%"e" = icmp ult i32 %".1", %".2"
|
|
976
|
+
%"f" = icmp ule i32 %".1", %".2"
|
|
977
|
+
%"g" = icmp ugt i32 %".1", %".2"
|
|
978
|
+
%"h" = icmp uge i32 %".1", %".2"
|
|
979
|
+
%"i" = icmp eq i32 %".1", %".2"
|
|
980
|
+
%"j" = icmp ne i32 %".1", %".2"
|
|
981
|
+
%"k" = icmp slt i32 %".1", %".2"
|
|
982
|
+
%"l" = icmp sle i32 %".1", %".2"
|
|
983
|
+
%"m" = icmp sgt i32 %".1", %".2"
|
|
984
|
+
%"n" = icmp sge i32 %".1", %".2"
|
|
985
|
+
""")
|
|
986
|
+
|
|
987
|
+
def test_float_comparisons(self):
|
|
988
|
+
block = self.block(name='my_block')
|
|
989
|
+
builder = ir.IRBuilder(block)
|
|
990
|
+
a, b = builder.function.args[:2]
|
|
991
|
+
builder.fcmp_ordered('==', a, b, 'c')
|
|
992
|
+
builder.fcmp_ordered('!=', a, b, 'd')
|
|
993
|
+
builder.fcmp_ordered('<', a, b, 'e')
|
|
994
|
+
builder.fcmp_ordered('<=', a, b, 'f')
|
|
995
|
+
builder.fcmp_ordered('>', a, b, 'g')
|
|
996
|
+
builder.fcmp_ordered('>=', a, b, 'h')
|
|
997
|
+
builder.fcmp_unordered('==', a, b, 'i')
|
|
998
|
+
builder.fcmp_unordered('!=', a, b, 'j')
|
|
999
|
+
builder.fcmp_unordered('<', a, b, 'k')
|
|
1000
|
+
builder.fcmp_unordered('<=', a, b, 'l')
|
|
1001
|
+
builder.fcmp_unordered('>', a, b, 'm')
|
|
1002
|
+
builder.fcmp_unordered('>=', a, b, 'n')
|
|
1003
|
+
# fcmp_ordered and fcmp_unordered are the same for these cases
|
|
1004
|
+
builder.fcmp_ordered('ord', a, b, 'u')
|
|
1005
|
+
builder.fcmp_ordered('uno', a, b, 'v')
|
|
1006
|
+
builder.fcmp_unordered('ord', a, b, 'w')
|
|
1007
|
+
builder.fcmp_unordered('uno', a, b, 'x')
|
|
1008
|
+
builder.fcmp_unordered('olt', a, b, 'y',
|
|
1009
|
+
flags=['nnan', 'ninf', 'nsz', 'arcp', 'fast'])
|
|
1010
|
+
self.assertFalse(block.is_terminated)
|
|
1011
|
+
self.check_block(block, """\
|
|
1012
|
+
my_block:
|
|
1013
|
+
%"c" = fcmp oeq i32 %".1", %".2"
|
|
1014
|
+
%"d" = fcmp one i32 %".1", %".2"
|
|
1015
|
+
%"e" = fcmp olt i32 %".1", %".2"
|
|
1016
|
+
%"f" = fcmp ole i32 %".1", %".2"
|
|
1017
|
+
%"g" = fcmp ogt i32 %".1", %".2"
|
|
1018
|
+
%"h" = fcmp oge i32 %".1", %".2"
|
|
1019
|
+
%"i" = fcmp ueq i32 %".1", %".2"
|
|
1020
|
+
%"j" = fcmp une i32 %".1", %".2"
|
|
1021
|
+
%"k" = fcmp ult i32 %".1", %".2"
|
|
1022
|
+
%"l" = fcmp ule i32 %".1", %".2"
|
|
1023
|
+
%"m" = fcmp ugt i32 %".1", %".2"
|
|
1024
|
+
%"n" = fcmp uge i32 %".1", %".2"
|
|
1025
|
+
%"u" = fcmp ord i32 %".1", %".2"
|
|
1026
|
+
%"v" = fcmp uno i32 %".1", %".2"
|
|
1027
|
+
%"w" = fcmp ord i32 %".1", %".2"
|
|
1028
|
+
%"x" = fcmp uno i32 %".1", %".2"
|
|
1029
|
+
%"y" = fcmp nnan ninf nsz arcp fast olt i32 %".1", %".2"
|
|
1030
|
+
""")
|
|
1031
|
+
|
|
1032
|
+
def test_misc_ops(self):
|
|
1033
|
+
block = self.block(name='my_block')
|
|
1034
|
+
t = ir.Constant(int1, True)
|
|
1035
|
+
builder = ir.IRBuilder(block)
|
|
1036
|
+
a, b = builder.function.args[:2]
|
|
1037
|
+
builder.select(t, a, b, 'c', flags=('arcp', 'nnan'))
|
|
1038
|
+
self.assertFalse(block.is_terminated)
|
|
1039
|
+
builder.unreachable()
|
|
1040
|
+
self.assertTrue(block.is_terminated)
|
|
1041
|
+
self.check_block(block, """\
|
|
1042
|
+
my_block:
|
|
1043
|
+
%"c" = select arcp nnan i1 true, i32 %".1", i32 %".2"
|
|
1044
|
+
unreachable
|
|
1045
|
+
""")
|
|
1046
|
+
|
|
1047
|
+
def test_phi(self):
|
|
1048
|
+
block = self.block(name='my_block')
|
|
1049
|
+
builder = ir.IRBuilder(block)
|
|
1050
|
+
a, b = builder.function.args[:2]
|
|
1051
|
+
bb2 = builder.function.append_basic_block('b2')
|
|
1052
|
+
bb3 = builder.function.append_basic_block('b3')
|
|
1053
|
+
phi = builder.phi(int32, 'my_phi', flags=('fast',))
|
|
1054
|
+
phi.add_incoming(a, bb2)
|
|
1055
|
+
phi.add_incoming(b, bb3)
|
|
1056
|
+
self.assertFalse(block.is_terminated)
|
|
1057
|
+
self.check_block(block, """\
|
|
1058
|
+
my_block:
|
|
1059
|
+
%"my_phi" = phi fast i32 [%".1", %"b2"], [%".2", %"b3"]
|
|
1060
|
+
""")
|
|
1061
|
+
|
|
1062
|
+
def test_mem_ops(self):
|
|
1063
|
+
block = self.block(name='my_block')
|
|
1064
|
+
builder = ir.IRBuilder(block)
|
|
1065
|
+
a, b, z = builder.function.args[:3]
|
|
1066
|
+
c = builder.alloca(int32, name='c')
|
|
1067
|
+
d = builder.alloca(int32, size=42, name='d') # noqa F841
|
|
1068
|
+
e = builder.alloca(dbl, size=a, name='e')
|
|
1069
|
+
e.align = 8
|
|
1070
|
+
self.assertEqual(e.type, ir.PointerType(dbl))
|
|
1071
|
+
ee = builder.store(z, e)
|
|
1072
|
+
self.assertEqual(ee.type, ir.VoidType())
|
|
1073
|
+
f = builder.store(b, c)
|
|
1074
|
+
self.assertEqual(f.type, ir.VoidType())
|
|
1075
|
+
g = builder.load(c, 'g')
|
|
1076
|
+
self.assertEqual(g.type, int32)
|
|
1077
|
+
# With alignment
|
|
1078
|
+
h = builder.store(b, c, align=1)
|
|
1079
|
+
self.assertEqual(h.type, ir.VoidType())
|
|
1080
|
+
i = builder.load(c, 'i', align=1)
|
|
1081
|
+
self.assertEqual(i.type, int32)
|
|
1082
|
+
# Atomics
|
|
1083
|
+
j = builder.store_atomic(b, c, ordering="seq_cst", align=4)
|
|
1084
|
+
self.assertEqual(j.type, ir.VoidType())
|
|
1085
|
+
k = builder.load_atomic(c, ordering="seq_cst", align=4, name='k')
|
|
1086
|
+
self.assertEqual(k.type, int32)
|
|
1087
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1088
|
+
ptr = ir.Constant(ir.PointerType(), None)
|
|
1089
|
+
else:
|
|
1090
|
+
ptr = ir.Constant(ir.PointerType(int32), None)
|
|
1091
|
+
builder.store(ir.Constant(int32, 5), ptr)
|
|
1092
|
+
# Not pointer types
|
|
1093
|
+
with self.assertRaises(TypeError):
|
|
1094
|
+
builder.store(b, a)
|
|
1095
|
+
with self.assertRaises(TypeError):
|
|
1096
|
+
builder.load(b)
|
|
1097
|
+
# Mismatching pointer type
|
|
1098
|
+
with self.assertRaises(TypeError) as cm:
|
|
1099
|
+
builder.store(b, e)
|
|
1100
|
+
|
|
1101
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1102
|
+
self.assertEqual(str(cm.exception),
|
|
1103
|
+
"cannot store i32 to ptr: mismatching types")
|
|
1104
|
+
self.check_block(block, """\
|
|
1105
|
+
my_block:
|
|
1106
|
+
%"c" = alloca i32
|
|
1107
|
+
%"d" = alloca i32, i32 42
|
|
1108
|
+
%"e" = alloca double, i32 %".1", align 8
|
|
1109
|
+
store double %".3", ptr %"e"
|
|
1110
|
+
store i32 %".2", ptr %"c"
|
|
1111
|
+
%"g" = load i32, ptr %"c"
|
|
1112
|
+
store i32 %".2", ptr %"c", align 1
|
|
1113
|
+
%"i" = load i32, ptr %"c", align 1
|
|
1114
|
+
store atomic i32 %".2", ptr %"c" seq_cst, align 4
|
|
1115
|
+
%"k" = load atomic i32, ptr %"c" seq_cst, align 4
|
|
1116
|
+
store i32 5, ptr null
|
|
1117
|
+
""")
|
|
1118
|
+
else:
|
|
1119
|
+
self.assertEqual(str(cm.exception),
|
|
1120
|
+
"cannot store i32 to double*: mismatching types")
|
|
1121
|
+
self.check_block(block, """\
|
|
1122
|
+
my_block:
|
|
1123
|
+
%"c" = alloca i32
|
|
1124
|
+
%"d" = alloca i32, i32 42
|
|
1125
|
+
%"e" = alloca double, i32 %".1", align 8
|
|
1126
|
+
store double %".3", double* %"e"
|
|
1127
|
+
store i32 %".2", i32* %"c"
|
|
1128
|
+
%"g" = load i32, i32* %"c"
|
|
1129
|
+
store i32 %".2", i32* %"c", align 1
|
|
1130
|
+
%"i" = load i32, i32* %"c", align 1
|
|
1131
|
+
store atomic i32 %".2", i32* %"c" seq_cst, align 4
|
|
1132
|
+
%"k" = load atomic i32, i32* %"c" seq_cst, align 4
|
|
1133
|
+
store i32 5, i32* null
|
|
1134
|
+
""")
|
|
1135
|
+
|
|
1136
|
+
def test_gep(self):
|
|
1137
|
+
block = self.block(name='my_block')
|
|
1138
|
+
builder = ir.IRBuilder(block)
|
|
1139
|
+
a, b = builder.function.args[:2]
|
|
1140
|
+
c = builder.alloca(ir.PointerType(int32), name='c')
|
|
1141
|
+
d = builder.gep(c, [ir.Constant(int32, 5), a], name='d')
|
|
1142
|
+
self.assertEqual(d.type, ir.PointerType(int32))
|
|
1143
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1144
|
+
self.check_block(block, """\
|
|
1145
|
+
my_block:
|
|
1146
|
+
%"c" = alloca ptr
|
|
1147
|
+
%"d" = getelementptr ptr, ptr %"c", i32 5, i32 %".1"
|
|
1148
|
+
""")
|
|
1149
|
+
else:
|
|
1150
|
+
self.check_block(block, """\
|
|
1151
|
+
my_block:
|
|
1152
|
+
%"c" = alloca i32*
|
|
1153
|
+
%"d" = getelementptr i32*, i32** %"c", i32 5, i32 %".1"
|
|
1154
|
+
""")
|
|
1155
|
+
# XXX test with more complex types
|
|
1156
|
+
|
|
1157
|
+
def test_gep_castinstr(self):
|
|
1158
|
+
# similar to:
|
|
1159
|
+
# numba::runtime::nrtdynmod.py_define_nrt_meminfo_data()
|
|
1160
|
+
block = self.block(name='my_block')
|
|
1161
|
+
builder = ir.IRBuilder(block)
|
|
1162
|
+
a, b = builder.function.args[:2]
|
|
1163
|
+
int8ptr = int8.as_pointer()
|
|
1164
|
+
ls = ir.LiteralStructType([int64, int8ptr, int8ptr, int8ptr, int64])
|
|
1165
|
+
d = builder.bitcast(a, ls.as_pointer(), name='d')
|
|
1166
|
+
e = builder.gep(d, [ir.Constant(int32, x) for x in [0, 3]], name='e')
|
|
1167
|
+
self.assertEqual(e.type, ir.PointerType(int8ptr))
|
|
1168
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1169
|
+
self.check_block(block, """\
|
|
1170
|
+
my_block:
|
|
1171
|
+
%"d" = bitcast i32 %".1" to ptr
|
|
1172
|
+
%"e" = getelementptr {i64, ptr, ptr, ptr, i64}, ptr %"d", i32 0, i32 3
|
|
1173
|
+
""") # noqa E501
|
|
1174
|
+
else:
|
|
1175
|
+
self.check_block(block, """\
|
|
1176
|
+
my_block:
|
|
1177
|
+
%"d" = bitcast i32 %".1" to {i64, i8*, i8*, i8*, i64}*
|
|
1178
|
+
%"e" = getelementptr {i64, i8*, i8*, i8*, i64}, {i64, i8*, i8*, i8*, i64}* %"d", i32 0, i32 3
|
|
1179
|
+
""") # noqa E501
|
|
1180
|
+
|
|
1181
|
+
def test_gep_castinstr_addrspace(self):
|
|
1182
|
+
# similar to:
|
|
1183
|
+
# numba::runtime::nrtdynmod.py_define_nrt_meminfo_data()
|
|
1184
|
+
block = self.block(name='my_block')
|
|
1185
|
+
builder = ir.IRBuilder(block)
|
|
1186
|
+
a, b = builder.function.args[:2]
|
|
1187
|
+
addrspace = 4
|
|
1188
|
+
int8ptr = int8.as_pointer()
|
|
1189
|
+
ls = ir.LiteralStructType([int64, int8ptr, int8ptr, int8ptr, int64])
|
|
1190
|
+
d = builder.bitcast(a, ls.as_pointer(addrspace=addrspace), name='d')
|
|
1191
|
+
e = builder.gep(d, [ir.Constant(int32, x) for x in [0, 3]], name='e')
|
|
1192
|
+
self.assertEqual(e.type.addrspace, addrspace)
|
|
1193
|
+
self.assertEqual(e.type, ir.PointerType(int8ptr, addrspace=addrspace))
|
|
1194
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1195
|
+
self.check_block(block, """\
|
|
1196
|
+
my_block:
|
|
1197
|
+
%"d" = bitcast i32 %".1" to ptr addrspace(4)
|
|
1198
|
+
%"e" = getelementptr {i64, ptr, ptr, ptr, i64}, ptr addrspace(4) %"d", i32 0, i32 3
|
|
1199
|
+
""") # noqa E501
|
|
1200
|
+
else:
|
|
1201
|
+
self.check_block(block, """\
|
|
1202
|
+
my_block:
|
|
1203
|
+
%"d" = bitcast i32 %".1" to {i64, i8*, i8*, i8*, i64} addrspace(4)*
|
|
1204
|
+
%"e" = getelementptr {i64, i8*, i8*, i8*, i64}, {i64, i8*, i8*, i8*, i64} addrspace(4)* %"d", i32 0, i32 3
|
|
1205
|
+
""") # noqa E501
|
|
1206
|
+
|
|
1207
|
+
def test_gep_addrspace(self):
|
|
1208
|
+
block = self.block(name='my_block')
|
|
1209
|
+
builder = ir.IRBuilder(block)
|
|
1210
|
+
a, b = builder.function.args[:2]
|
|
1211
|
+
addrspace = 4
|
|
1212
|
+
c = builder.alloca(ir.PointerType(int32, addrspace=addrspace), name='c')
|
|
1213
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1214
|
+
self.assertEqual(str(c.type), 'ptr')
|
|
1215
|
+
else:
|
|
1216
|
+
self.assertEqual(str(c.type), 'i32 addrspace(4)**')
|
|
1217
|
+
self.assertEqual(c.type.pointee.addrspace, addrspace)
|
|
1218
|
+
d = builder.gep(c, [ir.Constant(int32, 5), a], name='d')
|
|
1219
|
+
self.assertEqual(d.type.addrspace, addrspace)
|
|
1220
|
+
e = builder.gep(d, [ir.Constant(int32, 10)], name='e')
|
|
1221
|
+
self.assertEqual(e.type.addrspace, addrspace)
|
|
1222
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1223
|
+
self.check_block(block, """\
|
|
1224
|
+
my_block:
|
|
1225
|
+
%"c" = alloca ptr addrspace(4)
|
|
1226
|
+
%"d" = getelementptr ptr addrspace(4), ptr %"c", i32 5, i32 %".1"
|
|
1227
|
+
%"e" = getelementptr i32, ptr addrspace(4) %"d", i32 10
|
|
1228
|
+
""") # noqa E501
|
|
1229
|
+
else:
|
|
1230
|
+
self.check_block(block, """\
|
|
1231
|
+
my_block:
|
|
1232
|
+
%"c" = alloca i32 addrspace(4)*
|
|
1233
|
+
%"d" = getelementptr i32 addrspace(4)*, i32 addrspace(4)** %"c", i32 5, i32 %".1"
|
|
1234
|
+
%"e" = getelementptr i32, i32 addrspace(4)* %"d", i32 10
|
|
1235
|
+
""") # noqa E501
|
|
1236
|
+
|
|
1237
|
+
def test_extract_insert_value(self):
|
|
1238
|
+
block = self.block(name='my_block')
|
|
1239
|
+
builder = ir.IRBuilder(block)
|
|
1240
|
+
a, b = builder.function.args[:2]
|
|
1241
|
+
tp_inner = ir.LiteralStructType([int32, int1])
|
|
1242
|
+
tp_outer = ir.LiteralStructType([int8, tp_inner])
|
|
1243
|
+
c_inner = ir.Constant(tp_inner, (ir.Constant(int32, 4),
|
|
1244
|
+
ir.Constant(int1, True)))
|
|
1245
|
+
# Flat structure
|
|
1246
|
+
c = builder.extract_value(c_inner, 0, name='c') # noqa F841
|
|
1247
|
+
d = builder.insert_value(c_inner, a, 0, name='d') # noqa F841
|
|
1248
|
+
e = builder.insert_value(d, ir.Constant(int1, False), 1, name='e') # noqa F841 E501
|
|
1249
|
+
self.assertEqual(d.type, tp_inner)
|
|
1250
|
+
self.assertEqual(e.type, tp_inner)
|
|
1251
|
+
# Nested structure
|
|
1252
|
+
p_outer = builder.alloca(tp_outer, name='ptr')
|
|
1253
|
+
j = builder.load(p_outer, name='j')
|
|
1254
|
+
k = builder.extract_value(j, 0, name='k')
|
|
1255
|
+
l = builder.extract_value(j, 1, name='l')
|
|
1256
|
+
m = builder.extract_value(j, (1, 0), name='m')
|
|
1257
|
+
n = builder.extract_value(j, (1, 1), name='n')
|
|
1258
|
+
o = builder.insert_value(j, l, 1, name='o')
|
|
1259
|
+
p = builder.insert_value(j, a, (1, 0), name='p')
|
|
1260
|
+
self.assertEqual(k.type, int8)
|
|
1261
|
+
self.assertEqual(l.type, tp_inner)
|
|
1262
|
+
self.assertEqual(m.type, int32)
|
|
1263
|
+
self.assertEqual(n.type, int1)
|
|
1264
|
+
self.assertEqual(o.type, tp_outer)
|
|
1265
|
+
self.assertEqual(p.type, tp_outer)
|
|
1266
|
+
|
|
1267
|
+
with self.assertRaises(TypeError):
|
|
1268
|
+
# Not an aggregate
|
|
1269
|
+
builder.extract_value(p_outer, 0)
|
|
1270
|
+
with self.assertRaises(TypeError):
|
|
1271
|
+
# Indexing too deep
|
|
1272
|
+
builder.extract_value(c_inner, (0, 0))
|
|
1273
|
+
with self.assertRaises(TypeError):
|
|
1274
|
+
# Index out of structure bounds
|
|
1275
|
+
builder.extract_value(c_inner, 5)
|
|
1276
|
+
with self.assertRaises(TypeError):
|
|
1277
|
+
# Not an aggregate
|
|
1278
|
+
builder.insert_value(a, b, 0)
|
|
1279
|
+
with self.assertRaises(TypeError):
|
|
1280
|
+
# Replacement value has the wrong type
|
|
1281
|
+
builder.insert_value(c_inner, a, 1)
|
|
1282
|
+
|
|
1283
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1284
|
+
self.check_block(block, """\
|
|
1285
|
+
my_block:
|
|
1286
|
+
%"c" = extractvalue {i32, i1} {i32 4, i1 true}, 0
|
|
1287
|
+
%"d" = insertvalue {i32, i1} {i32 4, i1 true}, i32 %".1", 0
|
|
1288
|
+
%"e" = insertvalue {i32, i1} %"d", i1 false, 1
|
|
1289
|
+
%"ptr" = alloca {i8, {i32, i1}}
|
|
1290
|
+
%"j" = load {i8, {i32, i1}}, ptr %"ptr"
|
|
1291
|
+
%"k" = extractvalue {i8, {i32, i1}} %"j", 0
|
|
1292
|
+
%"l" = extractvalue {i8, {i32, i1}} %"j", 1
|
|
1293
|
+
%"m" = extractvalue {i8, {i32, i1}} %"j", 1, 0
|
|
1294
|
+
%"n" = extractvalue {i8, {i32, i1}} %"j", 1, 1
|
|
1295
|
+
%"o" = insertvalue {i8, {i32, i1}} %"j", {i32, i1} %"l", 1
|
|
1296
|
+
%"p" = insertvalue {i8, {i32, i1}} %"j", i32 %".1", 1, 0
|
|
1297
|
+
""")
|
|
1298
|
+
else:
|
|
1299
|
+
self.check_block(block, """\
|
|
1300
|
+
my_block:
|
|
1301
|
+
%"c" = extractvalue {i32, i1} {i32 4, i1 true}, 0
|
|
1302
|
+
%"d" = insertvalue {i32, i1} {i32 4, i1 true}, i32 %".1", 0
|
|
1303
|
+
%"e" = insertvalue {i32, i1} %"d", i1 false, 1
|
|
1304
|
+
%"ptr" = alloca {i8, {i32, i1}}
|
|
1305
|
+
%"j" = load {i8, {i32, i1}}, {i8, {i32, i1}}* %"ptr"
|
|
1306
|
+
%"k" = extractvalue {i8, {i32, i1}} %"j", 0
|
|
1307
|
+
%"l" = extractvalue {i8, {i32, i1}} %"j", 1
|
|
1308
|
+
%"m" = extractvalue {i8, {i32, i1}} %"j", 1, 0
|
|
1309
|
+
%"n" = extractvalue {i8, {i32, i1}} %"j", 1, 1
|
|
1310
|
+
%"o" = insertvalue {i8, {i32, i1}} %"j", {i32, i1} %"l", 1
|
|
1311
|
+
%"p" = insertvalue {i8, {i32, i1}} %"j", i32 %".1", 1, 0
|
|
1312
|
+
""")
|
|
1313
|
+
|
|
1314
|
+
def test_cast_ops(self):
|
|
1315
|
+
block = self.block(name='my_block')
|
|
1316
|
+
builder = ir.IRBuilder(block)
|
|
1317
|
+
a, b, fa, ptr = builder.function.args[:4]
|
|
1318
|
+
c = builder.trunc(a, int8, name='c')
|
|
1319
|
+
d = builder.zext(c, int32, name='d') # noqa F841
|
|
1320
|
+
e = builder.sext(c, int32, name='e') # noqa F841
|
|
1321
|
+
fb = builder.fptrunc(fa, flt, 'fb')
|
|
1322
|
+
fc = builder.fpext(fb, dbl, 'fc') # noqa F841
|
|
1323
|
+
g = builder.fptoui(fa, int32, 'g')
|
|
1324
|
+
h = builder.fptosi(fa, int8, 'h')
|
|
1325
|
+
fd = builder.uitofp(g, flt, 'fd') # noqa F841
|
|
1326
|
+
fe = builder.sitofp(h, dbl, 'fe') # noqa F841
|
|
1327
|
+
i = builder.ptrtoint(ptr, int32, 'i')
|
|
1328
|
+
j = builder.inttoptr(i, ir.PointerType(int8), 'j') # noqa F841
|
|
1329
|
+
k = builder.bitcast(a, flt, "k") # noqa F841
|
|
1330
|
+
self.assertFalse(block.is_terminated)
|
|
1331
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1332
|
+
self.check_block(block, """\
|
|
1333
|
+
my_block:
|
|
1334
|
+
%"c" = trunc i32 %".1" to i8
|
|
1335
|
+
%"d" = zext i8 %"c" to i32
|
|
1336
|
+
%"e" = sext i8 %"c" to i32
|
|
1337
|
+
%"fb" = fptrunc double %".3" to float
|
|
1338
|
+
%"fc" = fpext float %"fb" to double
|
|
1339
|
+
%"g" = fptoui double %".3" to i32
|
|
1340
|
+
%"h" = fptosi double %".3" to i8
|
|
1341
|
+
%"fd" = uitofp i32 %"g" to float
|
|
1342
|
+
%"fe" = sitofp i8 %"h" to double
|
|
1343
|
+
%"i" = ptrtoint ptr %".4" to i32
|
|
1344
|
+
%"j" = inttoptr i32 %"i" to ptr
|
|
1345
|
+
%"k" = bitcast i32 %".1" to float
|
|
1346
|
+
""")
|
|
1347
|
+
else:
|
|
1348
|
+
self.check_block(block, """\
|
|
1349
|
+
my_block:
|
|
1350
|
+
%"c" = trunc i32 %".1" to i8
|
|
1351
|
+
%"d" = zext i8 %"c" to i32
|
|
1352
|
+
%"e" = sext i8 %"c" to i32
|
|
1353
|
+
%"fb" = fptrunc double %".3" to float
|
|
1354
|
+
%"fc" = fpext float %"fb" to double
|
|
1355
|
+
%"g" = fptoui double %".3" to i32
|
|
1356
|
+
%"h" = fptosi double %".3" to i8
|
|
1357
|
+
%"fd" = uitofp i32 %"g" to float
|
|
1358
|
+
%"fe" = sitofp i8 %"h" to double
|
|
1359
|
+
%"i" = ptrtoint i32* %".4" to i32
|
|
1360
|
+
%"j" = inttoptr i32 %"i" to i8*
|
|
1361
|
+
%"k" = bitcast i32 %".1" to float
|
|
1362
|
+
""")
|
|
1363
|
+
|
|
1364
|
+
def test_atomicrmw(self):
|
|
1365
|
+
block = self.block(name='my_block')
|
|
1366
|
+
builder = ir.IRBuilder(block)
|
|
1367
|
+
a, b = builder.function.args[:2]
|
|
1368
|
+
c = builder.alloca(int32, name='c')
|
|
1369
|
+
d = builder.atomic_rmw('add', c, a, 'monotonic', 'd')
|
|
1370
|
+
self.assertEqual(d.type, int32)
|
|
1371
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1372
|
+
self.check_block(block, """\
|
|
1373
|
+
my_block:
|
|
1374
|
+
%"c" = alloca i32
|
|
1375
|
+
%"d" = atomicrmw add ptr %"c", i32 %".1" monotonic
|
|
1376
|
+
""")
|
|
1377
|
+
else:
|
|
1378
|
+
self.check_block(block, """\
|
|
1379
|
+
my_block:
|
|
1380
|
+
%"c" = alloca i32
|
|
1381
|
+
%"d" = atomicrmw add i32* %"c", i32 %".1" monotonic
|
|
1382
|
+
""")
|
|
1383
|
+
|
|
1384
|
+
def test_branch(self):
|
|
1385
|
+
block = self.block(name='my_block')
|
|
1386
|
+
builder = ir.IRBuilder(block)
|
|
1387
|
+
bb_target = builder.function.append_basic_block(name='target')
|
|
1388
|
+
builder.branch(bb_target)
|
|
1389
|
+
self.assertTrue(block.is_terminated)
|
|
1390
|
+
self.check_block(block, """\
|
|
1391
|
+
my_block:
|
|
1392
|
+
br label %"target"
|
|
1393
|
+
""")
|
|
1394
|
+
|
|
1395
|
+
def test_cbranch(self):
|
|
1396
|
+
block = self.block(name='my_block')
|
|
1397
|
+
builder = ir.IRBuilder(block)
|
|
1398
|
+
bb_true = builder.function.append_basic_block(name='b_true')
|
|
1399
|
+
bb_false = builder.function.append_basic_block(name='b_false')
|
|
1400
|
+
builder.cbranch(ir.Constant(int1, False), bb_true, bb_false)
|
|
1401
|
+
self.assertTrue(block.is_terminated)
|
|
1402
|
+
self.check_block(block, """\
|
|
1403
|
+
my_block:
|
|
1404
|
+
br i1 false, label %"b_true", label %"b_false"
|
|
1405
|
+
""")
|
|
1406
|
+
|
|
1407
|
+
def test_cbranch_weights(self):
|
|
1408
|
+
block = self.block(name='my_block')
|
|
1409
|
+
builder = ir.IRBuilder(block)
|
|
1410
|
+
bb_true = builder.function.append_basic_block(name='b_true')
|
|
1411
|
+
bb_false = builder.function.append_basic_block(name='b_false')
|
|
1412
|
+
br = builder.cbranch(ir.Constant(int1, False), bb_true, bb_false)
|
|
1413
|
+
br.set_weights([5, 42])
|
|
1414
|
+
self.assertTrue(block.is_terminated)
|
|
1415
|
+
self.check_block(block, """\
|
|
1416
|
+
my_block:
|
|
1417
|
+
br i1 false, label %"b_true", label %"b_false", !prof !0
|
|
1418
|
+
""")
|
|
1419
|
+
self.check_metadata(builder.module, """\
|
|
1420
|
+
!0 = !{ !"branch_weights", i32 5, i32 42 }
|
|
1421
|
+
""")
|
|
1422
|
+
|
|
1423
|
+
def test_branch_indirect(self):
|
|
1424
|
+
block = self.block(name='my_block')
|
|
1425
|
+
builder = ir.IRBuilder(block)
|
|
1426
|
+
bb_1 = builder.function.append_basic_block(name='b_1')
|
|
1427
|
+
bb_2 = builder.function.append_basic_block(name='b_2')
|
|
1428
|
+
indirectbr = builder.branch_indirect(
|
|
1429
|
+
ir.BlockAddress(builder.function, bb_1))
|
|
1430
|
+
indirectbr.add_destination(bb_1)
|
|
1431
|
+
indirectbr.add_destination(bb_2)
|
|
1432
|
+
self.assertTrue(block.is_terminated)
|
|
1433
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1434
|
+
self.check_block(block, """\
|
|
1435
|
+
my_block:
|
|
1436
|
+
indirectbr ptr blockaddress(@"my_func", %"b_1"), [label %"b_1", label %"b_2"]
|
|
1437
|
+
""") # noqa E501
|
|
1438
|
+
else:
|
|
1439
|
+
self.check_block(block, """\
|
|
1440
|
+
my_block:
|
|
1441
|
+
indirectbr i8* blockaddress(@"my_func", %"b_1"), [label %"b_1", label %"b_2"]
|
|
1442
|
+
""") # noqa E501
|
|
1443
|
+
|
|
1444
|
+
def test_returns(self):
|
|
1445
|
+
def check(block, expected_ir):
|
|
1446
|
+
self.assertTrue(block.is_terminated)
|
|
1447
|
+
self.check_block(block, expected_ir)
|
|
1448
|
+
|
|
1449
|
+
block = self.block(name='my_block')
|
|
1450
|
+
builder = ir.IRBuilder(block)
|
|
1451
|
+
builder.ret_void()
|
|
1452
|
+
check(block, """\
|
|
1453
|
+
my_block:
|
|
1454
|
+
ret void
|
|
1455
|
+
""")
|
|
1456
|
+
|
|
1457
|
+
block = self.block(name='other_block')
|
|
1458
|
+
builder = ir.IRBuilder(block)
|
|
1459
|
+
builder.ret(int32(5))
|
|
1460
|
+
check(block, """\
|
|
1461
|
+
other_block:
|
|
1462
|
+
ret i32 5
|
|
1463
|
+
""")
|
|
1464
|
+
|
|
1465
|
+
# With metadata
|
|
1466
|
+
block = self.block(name='my_block')
|
|
1467
|
+
builder = ir.IRBuilder(block)
|
|
1468
|
+
inst = builder.ret_void()
|
|
1469
|
+
inst.set_metadata("dbg", block.module.add_metadata(()))
|
|
1470
|
+
check(block, """\
|
|
1471
|
+
my_block:
|
|
1472
|
+
ret void, !dbg !0
|
|
1473
|
+
""")
|
|
1474
|
+
|
|
1475
|
+
block = self.block(name='my_block')
|
|
1476
|
+
builder = ir.IRBuilder(block)
|
|
1477
|
+
inst = builder.ret(int32(6))
|
|
1478
|
+
inst.set_metadata("dbg", block.module.add_metadata(()))
|
|
1479
|
+
check(block, """\
|
|
1480
|
+
my_block:
|
|
1481
|
+
ret i32 6, !dbg !0
|
|
1482
|
+
""")
|
|
1483
|
+
|
|
1484
|
+
def test_switch(self):
|
|
1485
|
+
block = self.block(name='my_block')
|
|
1486
|
+
builder = ir.IRBuilder(block)
|
|
1487
|
+
a, b = builder.function.args[:2]
|
|
1488
|
+
bb_onzero = builder.function.append_basic_block(name='onzero')
|
|
1489
|
+
bb_onone = builder.function.append_basic_block(name='onone')
|
|
1490
|
+
bb_ontwo = builder.function.append_basic_block(name='ontwo')
|
|
1491
|
+
bb_else = builder.function.append_basic_block(name='otherwise')
|
|
1492
|
+
sw = builder.switch(a, bb_else)
|
|
1493
|
+
sw.add_case(ir.Constant(int32, 0), bb_onzero)
|
|
1494
|
+
sw.add_case(ir.Constant(int32, 1), bb_onone)
|
|
1495
|
+
# A plain Python value gets converted into the right IR constant
|
|
1496
|
+
sw.add_case(2, bb_ontwo)
|
|
1497
|
+
self.assertTrue(block.is_terminated)
|
|
1498
|
+
self.check_block(block, """\
|
|
1499
|
+
my_block:
|
|
1500
|
+
switch i32 %".1", label %"otherwise" [i32 0, label %"onzero" i32 1, label %"onone" i32 2, label %"ontwo"]
|
|
1501
|
+
""") # noqa E501
|
|
1502
|
+
|
|
1503
|
+
def test_call(self):
|
|
1504
|
+
block = self.block(name='my_block')
|
|
1505
|
+
builder = ir.IRBuilder(block)
|
|
1506
|
+
a, b = builder.function.args[:2]
|
|
1507
|
+
tp_f = ir.FunctionType(flt, (int32, int32))
|
|
1508
|
+
tp_g = ir.FunctionType(dbl, (int32,), var_arg=True)
|
|
1509
|
+
tp_h = ir.FunctionType(hlf, (int32, int32))
|
|
1510
|
+
f = ir.Function(builder.function.module, tp_f, 'f')
|
|
1511
|
+
g = ir.Function(builder.function.module, tp_g, 'g')
|
|
1512
|
+
h = ir.Function(builder.function.module, tp_h, 'h')
|
|
1513
|
+
builder.call(f, (a, b), 'res_f')
|
|
1514
|
+
builder.call(g, (b, a), 'res_g')
|
|
1515
|
+
builder.call(h, (a, b), 'res_h')
|
|
1516
|
+
builder.call(f, (a, b), 'res_f_fast', cconv='fastcc')
|
|
1517
|
+
res_f_readonly = builder.call(f, (a, b), 'res_f_readonly')
|
|
1518
|
+
res_f_readonly.attributes.add('readonly')
|
|
1519
|
+
builder.call(f, (a, b), 'res_fast', fastmath='fast')
|
|
1520
|
+
builder.call(f, (a, b), 'res_nnan_ninf', fastmath=('nnan', 'ninf'))
|
|
1521
|
+
builder.call(f, (a, b), 'res_noinline', attrs='noinline')
|
|
1522
|
+
builder.call(f, (a, b), 'res_alwaysinline', attrs='alwaysinline')
|
|
1523
|
+
builder.call(f, (a, b), 'res_noinline_ro', attrs=('noinline',
|
|
1524
|
+
'readonly'))
|
|
1525
|
+
builder.call(f, (a, b), 'res_convergent', attrs='convergent')
|
|
1526
|
+
self.check_block(block, """\
|
|
1527
|
+
my_block:
|
|
1528
|
+
%"res_f" = call float @"f"(i32 %".1", i32 %".2")
|
|
1529
|
+
%"res_g" = call double (i32, ...) @"g"(i32 %".2", i32 %".1")
|
|
1530
|
+
%"res_h" = call half @"h"(i32 %".1", i32 %".2")
|
|
1531
|
+
%"res_f_fast" = call fastcc float @"f"(i32 %".1", i32 %".2")
|
|
1532
|
+
%"res_f_readonly" = call float @"f"(i32 %".1", i32 %".2") readonly
|
|
1533
|
+
%"res_fast" = call fast float @"f"(i32 %".1", i32 %".2")
|
|
1534
|
+
%"res_nnan_ninf" = call ninf nnan float @"f"(i32 %".1", i32 %".2")
|
|
1535
|
+
%"res_noinline" = call float @"f"(i32 %".1", i32 %".2") noinline
|
|
1536
|
+
%"res_alwaysinline" = call float @"f"(i32 %".1", i32 %".2") alwaysinline
|
|
1537
|
+
%"res_noinline_ro" = call float @"f"(i32 %".1", i32 %".2") noinline readonly
|
|
1538
|
+
%"res_convergent" = call float @"f"(i32 %".1", i32 %".2") convergent
|
|
1539
|
+
""") # noqa E501
|
|
1540
|
+
|
|
1541
|
+
def test_call_metadata(self):
|
|
1542
|
+
"""
|
|
1543
|
+
Function calls with metadata arguments.
|
|
1544
|
+
"""
|
|
1545
|
+
block = self.block(name='my_block')
|
|
1546
|
+
builder = ir.IRBuilder(block)
|
|
1547
|
+
dbg_declare_ty = ir.FunctionType(ir.VoidType(), [ir.MetaDataType()] * 3)
|
|
1548
|
+
dbg_declare = ir.Function(
|
|
1549
|
+
builder.module,
|
|
1550
|
+
dbg_declare_ty,
|
|
1551
|
+
'llvm.dbg.declare')
|
|
1552
|
+
a = builder.alloca(int32, name="a")
|
|
1553
|
+
b = builder.module.add_metadata(())
|
|
1554
|
+
builder.call(dbg_declare, (a, b, b))
|
|
1555
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1556
|
+
self.check_block(block, """\
|
|
1557
|
+
my_block:
|
|
1558
|
+
%"a" = alloca i32
|
|
1559
|
+
call void @"llvm.dbg.declare"(metadata ptr %"a", metadata !0, metadata !0)
|
|
1560
|
+
""") # noqa E501
|
|
1561
|
+
else:
|
|
1562
|
+
self.check_block(block, """\
|
|
1563
|
+
my_block:
|
|
1564
|
+
%"a" = alloca i32
|
|
1565
|
+
call void @"llvm.dbg.declare"(metadata i32* %"a", metadata !0, metadata !0)
|
|
1566
|
+
""") # noqa E501
|
|
1567
|
+
|
|
1568
|
+
def test_call_attributes(self):
|
|
1569
|
+
block = self.block(name='my_block')
|
|
1570
|
+
builder = ir.IRBuilder(block)
|
|
1571
|
+
fun_ty = ir.FunctionType(
|
|
1572
|
+
ir.VoidType(), (int32.as_pointer(), int32, int32.as_pointer()))
|
|
1573
|
+
fun = ir.Function(builder.function.module, fun_ty, 'fun')
|
|
1574
|
+
fun.args[0].add_attribute('sret')
|
|
1575
|
+
retval = builder.alloca(int32, name='retval')
|
|
1576
|
+
other = builder.alloca(int32, name='other')
|
|
1577
|
+
builder.call(
|
|
1578
|
+
fun,
|
|
1579
|
+
(retval, ir.Constant(int32, 42), other),
|
|
1580
|
+
arg_attrs={
|
|
1581
|
+
0: ('sret', 'noalias'),
|
|
1582
|
+
2: 'noalias'
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1586
|
+
self.check_block_regex(block, """\
|
|
1587
|
+
my_block:
|
|
1588
|
+
%"retval" = alloca i32
|
|
1589
|
+
%"other" = alloca i32
|
|
1590
|
+
call void @"fun"\\(ptr noalias sret(\\(i32\\))? %"retval", i32 42, ptr noalias %"other"\\)
|
|
1591
|
+
""") # noqa E501
|
|
1592
|
+
else:
|
|
1593
|
+
self.check_block_regex(block, """\
|
|
1594
|
+
my_block:
|
|
1595
|
+
%"retval" = alloca i32
|
|
1596
|
+
%"other" = alloca i32
|
|
1597
|
+
call void @"fun"\\(i32\\* noalias sret(\\(i32\\))? %"retval", i32 42, i32\\* noalias %"other"\\)
|
|
1598
|
+
""") # noqa E501
|
|
1599
|
+
|
|
1600
|
+
def test_call_tail(self):
|
|
1601
|
+
block = self.block(name='my_block')
|
|
1602
|
+
builder = ir.IRBuilder(block)
|
|
1603
|
+
fun_ty = ir.FunctionType(ir.VoidType(), ())
|
|
1604
|
+
fun = ir.Function(builder.function.module, fun_ty, 'my_fun')
|
|
1605
|
+
|
|
1606
|
+
builder.call(fun, ())
|
|
1607
|
+
builder.call(fun, (), tail=False)
|
|
1608
|
+
builder.call(fun, (), tail=True)
|
|
1609
|
+
builder.call(fun, (), tail='tail')
|
|
1610
|
+
builder.call(fun, (), tail='notail')
|
|
1611
|
+
builder.call(fun, (), tail='musttail')
|
|
1612
|
+
builder.call(fun, (), tail=[]) # This is a falsy value
|
|
1613
|
+
builder.call(fun, (), tail='not a marker') # This is a truthy value
|
|
1614
|
+
|
|
1615
|
+
self.check_block(block, """\
|
|
1616
|
+
my_block:
|
|
1617
|
+
call void @"my_fun"()
|
|
1618
|
+
call void @"my_fun"()
|
|
1619
|
+
tail call void @"my_fun"()
|
|
1620
|
+
tail call void @"my_fun"()
|
|
1621
|
+
notail call void @"my_fun"()
|
|
1622
|
+
musttail call void @"my_fun"()
|
|
1623
|
+
call void @"my_fun"()
|
|
1624
|
+
tail call void @"my_fun"()
|
|
1625
|
+
""") # noqa E501
|
|
1626
|
+
|
|
1627
|
+
def test_invalid_call_attributes(self):
|
|
1628
|
+
block = self.block()
|
|
1629
|
+
builder = ir.IRBuilder(block)
|
|
1630
|
+
fun_ty = ir.FunctionType(ir.VoidType(), ())
|
|
1631
|
+
fun = ir.Function(builder.function.module, fun_ty, 'fun')
|
|
1632
|
+
with self.assertRaises(ValueError):
|
|
1633
|
+
# The function has no arguments, so this should fail.
|
|
1634
|
+
builder.call(fun, (), arg_attrs={0: 'sret'})
|
|
1635
|
+
|
|
1636
|
+
def test_invoke(self):
|
|
1637
|
+
block = self.block(name='my_block')
|
|
1638
|
+
builder = ir.IRBuilder(block)
|
|
1639
|
+
a, b = builder.function.args[:2]
|
|
1640
|
+
tp_f = ir.FunctionType(flt, (int32, int32))
|
|
1641
|
+
f = ir.Function(builder.function.module, tp_f, 'f')
|
|
1642
|
+
bb_normal = builder.function.append_basic_block(name='normal')
|
|
1643
|
+
bb_unwind = builder.function.append_basic_block(name='unwind')
|
|
1644
|
+
builder.invoke(f, (a, b), bb_normal, bb_unwind, 'res_f')
|
|
1645
|
+
self.check_block(block, """\
|
|
1646
|
+
my_block:
|
|
1647
|
+
%"res_f" = invoke float @"f"(i32 %".1", i32 %".2")
|
|
1648
|
+
to label %"normal" unwind label %"unwind"
|
|
1649
|
+
""")
|
|
1650
|
+
|
|
1651
|
+
def test_invoke_attributes(self):
|
|
1652
|
+
block = self.block(name='my_block')
|
|
1653
|
+
builder = ir.IRBuilder(block)
|
|
1654
|
+
fun_ty = ir.FunctionType(
|
|
1655
|
+
ir.VoidType(), (int32.as_pointer(), int32, int32.as_pointer()))
|
|
1656
|
+
fun = ir.Function(builder.function.module, fun_ty, 'fun')
|
|
1657
|
+
fun.calling_convention = "fastcc"
|
|
1658
|
+
fun.args[0].add_attribute('sret')
|
|
1659
|
+
retval = builder.alloca(int32, name='retval')
|
|
1660
|
+
other = builder.alloca(int32, name='other')
|
|
1661
|
+
bb_normal = builder.function.append_basic_block(name='normal')
|
|
1662
|
+
bb_unwind = builder.function.append_basic_block(name='unwind')
|
|
1663
|
+
builder.invoke(
|
|
1664
|
+
fun,
|
|
1665
|
+
(retval, ir.Constant(int32, 42), other),
|
|
1666
|
+
bb_normal,
|
|
1667
|
+
bb_unwind,
|
|
1668
|
+
cconv='fastcc',
|
|
1669
|
+
fastmath='fast',
|
|
1670
|
+
attrs='noinline',
|
|
1671
|
+
arg_attrs={
|
|
1672
|
+
0: ('sret', 'noalias'),
|
|
1673
|
+
2: 'noalias'
|
|
1674
|
+
}
|
|
1675
|
+
)
|
|
1676
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1677
|
+
self.check_block_regex(block, """\
|
|
1678
|
+
my_block:
|
|
1679
|
+
%"retval" = alloca i32
|
|
1680
|
+
%"other" = alloca i32
|
|
1681
|
+
invoke fast fastcc void @"fun"\\(ptr noalias sret(\\(i32\\))? %"retval", i32 42, ptr noalias %"other"\\) noinline
|
|
1682
|
+
to label %"normal" unwind label %"unwind"
|
|
1683
|
+
""") # noqa E501
|
|
1684
|
+
else:
|
|
1685
|
+
self.check_block_regex(block, """\
|
|
1686
|
+
my_block:
|
|
1687
|
+
%"retval" = alloca i32
|
|
1688
|
+
%"other" = alloca i32
|
|
1689
|
+
invoke fast fastcc void @"fun"\\(i32\\* noalias sret(\\(i32\\))? %"retval", i32 42, i32\\* noalias %"other"\\) noinline
|
|
1690
|
+
to label %"normal" unwind label %"unwind"
|
|
1691
|
+
""") # noqa E501
|
|
1692
|
+
|
|
1693
|
+
def test_landingpad(self):
|
|
1694
|
+
block = self.block(name='my_block')
|
|
1695
|
+
builder = ir.IRBuilder(block)
|
|
1696
|
+
lp = builder.landingpad(ir.LiteralStructType([int32,
|
|
1697
|
+
int8.as_pointer()]), 'lp')
|
|
1698
|
+
int_typeinfo = ir.GlobalVariable(builder.function.module,
|
|
1699
|
+
int8.as_pointer(), "_ZTIi")
|
|
1700
|
+
int_typeinfo.global_constant = True
|
|
1701
|
+
lp.add_clause(ir.CatchClause(int_typeinfo))
|
|
1702
|
+
lp.add_clause(ir.FilterClause(ir.Constant(ir.ArrayType(
|
|
1703
|
+
int_typeinfo.type, 1), [int_typeinfo])))
|
|
1704
|
+
builder.resume(lp)
|
|
1705
|
+
if not ir_layer_typed_pointers_enabled:
|
|
1706
|
+
self.check_block(block, """\
|
|
1707
|
+
my_block:
|
|
1708
|
+
%"lp" = landingpad {i32, ptr}
|
|
1709
|
+
catch ptr @"_ZTIi"
|
|
1710
|
+
filter [1 x ptr] [ptr @"_ZTIi"]
|
|
1711
|
+
resume {i32, ptr} %"lp"
|
|
1712
|
+
""")
|
|
1713
|
+
else:
|
|
1714
|
+
self.check_block(block, """\
|
|
1715
|
+
my_block:
|
|
1716
|
+
%"lp" = landingpad {i32, i8*}
|
|
1717
|
+
catch i8** @"_ZTIi"
|
|
1718
|
+
filter [1 x i8**] [i8** @"_ZTIi"]
|
|
1719
|
+
resume {i32, i8*} %"lp"
|
|
1720
|
+
""")
|
|
1721
|
+
|
|
1722
|
+
def test_assume(self):
|
|
1723
|
+
block = self.block(name='my_block')
|
|
1724
|
+
builder = ir.IRBuilder(block)
|
|
1725
|
+
a, b = builder.function.args[:2]
|
|
1726
|
+
c = builder.icmp_signed('>', a, b, name='c')
|
|
1727
|
+
builder.assume(c)
|
|
1728
|
+
self.check_block(block, """\
|
|
1729
|
+
my_block:
|
|
1730
|
+
%"c" = icmp sgt i32 %".1", %".2"
|
|
1731
|
+
call void @"llvm.assume"(i1 %"c")
|
|
1732
|
+
""")
|
|
1733
|
+
|
|
1734
|
+
def test_vector_ops(self):
|
|
1735
|
+
block = self.block(name='insert_block')
|
|
1736
|
+
builder = ir.IRBuilder(block)
|
|
1737
|
+
a, b = builder.function.args[:2]
|
|
1738
|
+
a.name = 'a'
|
|
1739
|
+
b.name = 'b'
|
|
1740
|
+
|
|
1741
|
+
vecty = ir.VectorType(a.type, 2)
|
|
1742
|
+
vec = ir.Constant(vecty, ir.Undefined)
|
|
1743
|
+
idxty = ir.IntType(32)
|
|
1744
|
+
vec = builder.insert_element(vec, a, idxty(0), name='vec1')
|
|
1745
|
+
vec = builder.insert_element(vec, b, idxty(1), name='vec2')
|
|
1746
|
+
|
|
1747
|
+
self.check_block(block, """\
|
|
1748
|
+
insert_block:
|
|
1749
|
+
%"vec1" = insertelement <2 x i32> <i32 undef, i32 undef>, i32 %"a", i32 0
|
|
1750
|
+
%"vec2" = insertelement <2 x i32> %"vec1", i32 %"b", i32 1
|
|
1751
|
+
""")
|
|
1752
|
+
|
|
1753
|
+
block = builder.append_basic_block("shuffle_block")
|
|
1754
|
+
builder.branch(block)
|
|
1755
|
+
builder.position_at_end(block)
|
|
1756
|
+
|
|
1757
|
+
mask = ir.Constant(vecty, [1, 0])
|
|
1758
|
+
builder.shuffle_vector(vec, vec, mask, name='shuf')
|
|
1759
|
+
|
|
1760
|
+
self.check_block(block, """\
|
|
1761
|
+
shuffle_block:
|
|
1762
|
+
%"shuf" = shufflevector <2 x i32> %"vec2", <2 x i32> %"vec2", <2 x i32> <i32 1, i32 0>
|
|
1763
|
+
""") # noqa E501
|
|
1764
|
+
|
|
1765
|
+
block = builder.append_basic_block("add_block")
|
|
1766
|
+
builder.branch(block)
|
|
1767
|
+
builder.position_at_end(block)
|
|
1768
|
+
|
|
1769
|
+
builder.add(vec, vec, name='sum')
|
|
1770
|
+
|
|
1771
|
+
self.check_block(block, """\
|
|
1772
|
+
add_block:
|
|
1773
|
+
%"sum" = add <2 x i32> %"vec2", %"vec2"
|
|
1774
|
+
""")
|
|
1775
|
+
|
|
1776
|
+
block = builder.append_basic_block("extract_block")
|
|
1777
|
+
builder.branch(block)
|
|
1778
|
+
builder.position_at_end(block)
|
|
1779
|
+
|
|
1780
|
+
c = builder.extract_element(vec, idxty(0), name='ex1')
|
|
1781
|
+
d = builder.extract_element(vec, idxty(1), name='ex2')
|
|
1782
|
+
|
|
1783
|
+
self.check_block(block, """\
|
|
1784
|
+
extract_block:
|
|
1785
|
+
%"ex1" = extractelement <2 x i32> %"vec2", i32 0
|
|
1786
|
+
%"ex2" = extractelement <2 x i32> %"vec2", i32 1
|
|
1787
|
+
""")
|
|
1788
|
+
|
|
1789
|
+
builder.ret(builder.add(c, d))
|
|
1790
|
+
self.assert_valid_ir(builder.module)
|
|
1791
|
+
|
|
1792
|
+
def test_bitreverse(self):
|
|
1793
|
+
block = self.block(name='my_block')
|
|
1794
|
+
builder = ir.IRBuilder(block)
|
|
1795
|
+
a = ir.Constant(int64, 5)
|
|
1796
|
+
c = builder.bitreverse(a, name='c')
|
|
1797
|
+
builder.ret(c)
|
|
1798
|
+
self.check_block(block, """\
|
|
1799
|
+
my_block:
|
|
1800
|
+
%"c" = call i64 @"llvm.bitreverse.i64"(i64 5)
|
|
1801
|
+
ret i64 %"c"
|
|
1802
|
+
""")
|
|
1803
|
+
|
|
1804
|
+
def test_bitreverse_wrongtype(self):
|
|
1805
|
+
block = self.block(name='my_block')
|
|
1806
|
+
builder = ir.IRBuilder(block)
|
|
1807
|
+
a = ir.Constant(flt, 5)
|
|
1808
|
+
|
|
1809
|
+
with self.assertRaises(TypeError) as raises:
|
|
1810
|
+
builder.bitreverse(a, name='c')
|
|
1811
|
+
self.assertIn(
|
|
1812
|
+
"expected an integer type, got float",
|
|
1813
|
+
str(raises.exception))
|
|
1814
|
+
|
|
1815
|
+
def test_fence(self):
|
|
1816
|
+
block = self.block(name='my_block')
|
|
1817
|
+
builder = ir.IRBuilder(block)
|
|
1818
|
+
with self.assertRaises(ValueError) as raises:
|
|
1819
|
+
builder.fence("monotonic", None)
|
|
1820
|
+
self.assertIn(
|
|
1821
|
+
"Invalid fence ordering \"monotonic\"!",
|
|
1822
|
+
str(raises.exception))
|
|
1823
|
+
with self.assertRaises(ValueError) as raises:
|
|
1824
|
+
builder.fence(None, "monotonic")
|
|
1825
|
+
self.assertIn(
|
|
1826
|
+
"Invalid fence ordering \"None\"!",
|
|
1827
|
+
str(raises.exception))
|
|
1828
|
+
builder.fence("acquire", None)
|
|
1829
|
+
builder.fence("release", "singlethread")
|
|
1830
|
+
builder.fence("acq_rel", "singlethread")
|
|
1831
|
+
builder.fence("seq_cst")
|
|
1832
|
+
builder.ret_void()
|
|
1833
|
+
self.check_block(block, """\
|
|
1834
|
+
my_block:
|
|
1835
|
+
fence acquire
|
|
1836
|
+
fence syncscope("singlethread") release
|
|
1837
|
+
fence syncscope("singlethread") acq_rel
|
|
1838
|
+
fence seq_cst
|
|
1839
|
+
ret void
|
|
1840
|
+
""")
|
|
1841
|
+
|
|
1842
|
+
def test_comment(self):
|
|
1843
|
+
block = self.block(name='my_block')
|
|
1844
|
+
builder = ir.IRBuilder(block)
|
|
1845
|
+
with self.assertRaises(AssertionError):
|
|
1846
|
+
builder.comment("so\nmany lines")
|
|
1847
|
+
builder.comment("my comment")
|
|
1848
|
+
builder.ret_void()
|
|
1849
|
+
self.check_block(block, """\
|
|
1850
|
+
my_block:
|
|
1851
|
+
; my comment
|
|
1852
|
+
ret void
|
|
1853
|
+
""")
|
|
1854
|
+
|
|
1855
|
+
def test_bswap(self):
|
|
1856
|
+
block = self.block(name='my_block')
|
|
1857
|
+
builder = ir.IRBuilder(block)
|
|
1858
|
+
a = ir.Constant(int32, 5)
|
|
1859
|
+
c = builder.bswap(a, name='c')
|
|
1860
|
+
builder.ret(c)
|
|
1861
|
+
self.check_block(block, """\
|
|
1862
|
+
my_block:
|
|
1863
|
+
%"c" = call i32 @"llvm.bswap.i32"(i32 5)
|
|
1864
|
+
ret i32 %"c"
|
|
1865
|
+
""")
|
|
1866
|
+
|
|
1867
|
+
def test_ctpop(self):
|
|
1868
|
+
block = self.block(name='my_block')
|
|
1869
|
+
builder = ir.IRBuilder(block)
|
|
1870
|
+
a = ir.Constant(int16, 5)
|
|
1871
|
+
c = builder.ctpop(a, name='c')
|
|
1872
|
+
builder.ret(c)
|
|
1873
|
+
self.check_block(block, """\
|
|
1874
|
+
my_block:
|
|
1875
|
+
%"c" = call i16 @"llvm.ctpop.i16"(i16 5)
|
|
1876
|
+
ret i16 %"c"
|
|
1877
|
+
""")
|
|
1878
|
+
|
|
1879
|
+
def test_ctlz(self):
|
|
1880
|
+
block = self.block(name='my_block')
|
|
1881
|
+
builder = ir.IRBuilder(block)
|
|
1882
|
+
a = ir.Constant(int16, 5)
|
|
1883
|
+
b = ir.Constant(int1, 1)
|
|
1884
|
+
c = builder.ctlz(a, b, name='c')
|
|
1885
|
+
builder.ret(c)
|
|
1886
|
+
self.check_block(block, """\
|
|
1887
|
+
my_block:
|
|
1888
|
+
%"c" = call i16 @"llvm.ctlz.i16"(i16 5, i1 1)
|
|
1889
|
+
ret i16 %"c"
|
|
1890
|
+
""")
|
|
1891
|
+
|
|
1892
|
+
def test_convert_to_fp16_f32(self):
|
|
1893
|
+
block = self.block(name='my_block')
|
|
1894
|
+
builder = ir.IRBuilder(block)
|
|
1895
|
+
a = ir.Constant(flt, 5.0)
|
|
1896
|
+
b = builder.convert_to_fp16(a, name='b')
|
|
1897
|
+
builder.ret(b)
|
|
1898
|
+
self.check_block(block, """\
|
|
1899
|
+
my_block:
|
|
1900
|
+
%"b" = call i16 @"llvm.convert.to.fp16.f32"(float 0x4014000000000000)
|
|
1901
|
+
ret i16 %"b"
|
|
1902
|
+
""") # noqa E501
|
|
1903
|
+
|
|
1904
|
+
def test_convert_to_fp16_f32_wrongtype(self):
|
|
1905
|
+
block = self.block(name='my_block')
|
|
1906
|
+
builder = ir.IRBuilder(block)
|
|
1907
|
+
a = ir.Constant(int16, 5)
|
|
1908
|
+
|
|
1909
|
+
with self.assertRaises(TypeError) as raises:
|
|
1910
|
+
builder.convert_to_fp16(a, name='b')
|
|
1911
|
+
self.assertIn(
|
|
1912
|
+
"expected a float type, got i16",
|
|
1913
|
+
str(raises.exception))
|
|
1914
|
+
|
|
1915
|
+
def test_convert_from_fp16_f32(self):
|
|
1916
|
+
block = self.block(name='my_block')
|
|
1917
|
+
builder = ir.IRBuilder(block)
|
|
1918
|
+
a = ir.Constant(int16, 5)
|
|
1919
|
+
b = builder.convert_from_fp16(a, name='b', to=flt)
|
|
1920
|
+
builder.ret(b)
|
|
1921
|
+
self.check_block(block, """\
|
|
1922
|
+
my_block:
|
|
1923
|
+
%"b" = call float @"llvm.convert.from.fp16.f32"(i16 5)
|
|
1924
|
+
ret float %"b"
|
|
1925
|
+
""")
|
|
1926
|
+
|
|
1927
|
+
def test_convert_from_fp16_f32_notype(self):
|
|
1928
|
+
block = self.block(name='my_block')
|
|
1929
|
+
builder = ir.IRBuilder(block)
|
|
1930
|
+
a = ir.Constant(flt, 5.5)
|
|
1931
|
+
|
|
1932
|
+
with self.assertRaises(TypeError) as raises:
|
|
1933
|
+
builder.convert_from_fp16(a, name='b')
|
|
1934
|
+
self.assertIn(
|
|
1935
|
+
"expected a float return type",
|
|
1936
|
+
str(raises.exception))
|
|
1937
|
+
|
|
1938
|
+
def test_convert_from_fp16_f32_wrongtype(self):
|
|
1939
|
+
block = self.block(name='my_block')
|
|
1940
|
+
builder = ir.IRBuilder(block)
|
|
1941
|
+
a = ir.Constant(flt, 5.5)
|
|
1942
|
+
|
|
1943
|
+
with self.assertRaises(TypeError) as raises:
|
|
1944
|
+
builder.convert_from_fp16(a, name='b', to=flt)
|
|
1945
|
+
self.assertIn(
|
|
1946
|
+
"expected an i16 type, got float",
|
|
1947
|
+
str(raises.exception))
|
|
1948
|
+
|
|
1949
|
+
def test_convert_from_fp16_f32_wrongtype2(self):
|
|
1950
|
+
block = self.block(name='my_block')
|
|
1951
|
+
builder = ir.IRBuilder(block)
|
|
1952
|
+
a = ir.Constant(flt, 5.5)
|
|
1953
|
+
|
|
1954
|
+
with self.assertRaises(TypeError) as raises:
|
|
1955
|
+
builder.convert_from_fp16(a, name='b', to=int16)
|
|
1956
|
+
self.assertIn(
|
|
1957
|
+
"expected a float type, got i16",
|
|
1958
|
+
str(raises.exception))
|
|
1959
|
+
|
|
1960
|
+
def test_cttz(self):
|
|
1961
|
+
block = self.block(name='my_block')
|
|
1962
|
+
builder = ir.IRBuilder(block)
|
|
1963
|
+
a = ir.Constant(int64, 5)
|
|
1964
|
+
b = ir.Constant(int1, 1)
|
|
1965
|
+
c = builder.cttz(a, b, name='c')
|
|
1966
|
+
builder.ret(c)
|
|
1967
|
+
self.check_block(block, """\
|
|
1968
|
+
my_block:
|
|
1969
|
+
%"c" = call i64 @"llvm.cttz.i64"(i64 5, i1 1)
|
|
1970
|
+
ret i64 %"c"
|
|
1971
|
+
""")
|
|
1972
|
+
|
|
1973
|
+
def test_cttz_wrongflag(self):
|
|
1974
|
+
block = self.block(name='my_block')
|
|
1975
|
+
builder = ir.IRBuilder(block)
|
|
1976
|
+
a = ir.Constant(int64, 5)
|
|
1977
|
+
b = ir.Constant(int32, 3)
|
|
1978
|
+
|
|
1979
|
+
with self.assertRaises(TypeError) as raises:
|
|
1980
|
+
builder.cttz(a, b, name='c')
|
|
1981
|
+
self.assertIn(
|
|
1982
|
+
"expected an i1 type, got i32",
|
|
1983
|
+
str(raises.exception))
|
|
1984
|
+
|
|
1985
|
+
def test_cttz_wrongtype(self):
|
|
1986
|
+
block = self.block(name='my_block')
|
|
1987
|
+
builder = ir.IRBuilder(block)
|
|
1988
|
+
a = ir.Constant(flt, 5)
|
|
1989
|
+
b = ir.Constant(int1, 1)
|
|
1990
|
+
|
|
1991
|
+
with self.assertRaises(TypeError) as raises:
|
|
1992
|
+
builder.cttz(a, b, name='c')
|
|
1993
|
+
self.assertIn(
|
|
1994
|
+
"expected an integer type, got float",
|
|
1995
|
+
str(raises.exception))
|
|
1996
|
+
|
|
1997
|
+
def test_fma(self):
|
|
1998
|
+
block = self.block(name='my_block')
|
|
1999
|
+
builder = ir.IRBuilder(block)
|
|
2000
|
+
a = ir.Constant(flt, 5)
|
|
2001
|
+
b = ir.Constant(flt, 1)
|
|
2002
|
+
c = ir.Constant(flt, 2)
|
|
2003
|
+
fma = builder.fma(a, b, c, name='fma')
|
|
2004
|
+
builder.ret(fma)
|
|
2005
|
+
self.check_block(block, """\
|
|
2006
|
+
my_block:
|
|
2007
|
+
%"fma" = call float @"llvm.fma.f32"(float 0x4014000000000000, float 0x3ff0000000000000, float 0x4000000000000000)
|
|
2008
|
+
ret float %"fma"
|
|
2009
|
+
""") # noqa E501
|
|
2010
|
+
|
|
2011
|
+
def test_fma_wrongtype(self):
|
|
2012
|
+
block = self.block(name='my_block')
|
|
2013
|
+
builder = ir.IRBuilder(block)
|
|
2014
|
+
a = ir.Constant(int32, 5)
|
|
2015
|
+
b = ir.Constant(int32, 1)
|
|
2016
|
+
c = ir.Constant(int32, 2)
|
|
2017
|
+
|
|
2018
|
+
with self.assertRaises(TypeError) as raises:
|
|
2019
|
+
builder.fma(a, b, c, name='fma')
|
|
2020
|
+
self.assertIn(
|
|
2021
|
+
"expected an floating point type, got i32",
|
|
2022
|
+
str(raises.exception))
|
|
2023
|
+
|
|
2024
|
+
def test_fma_mixedtypes(self):
|
|
2025
|
+
block = self.block(name='my_block')
|
|
2026
|
+
builder = ir.IRBuilder(block)
|
|
2027
|
+
a = ir.Constant(flt, 5)
|
|
2028
|
+
b = ir.Constant(dbl, 1)
|
|
2029
|
+
c = ir.Constant(flt, 2)
|
|
2030
|
+
|
|
2031
|
+
with self.assertRaises(TypeError) as raises:
|
|
2032
|
+
builder.fma(a, b, c, name='fma')
|
|
2033
|
+
self.assertIn(
|
|
2034
|
+
"expected types to be the same, got float, double, float",
|
|
2035
|
+
str(raises.exception))
|
|
2036
|
+
|
|
2037
|
+
def test_arg_attributes(self):
|
|
2038
|
+
def gen_code(attr_name):
|
|
2039
|
+
fnty = ir.FunctionType(ir.IntType(32), [ir.IntType(32).as_pointer(),
|
|
2040
|
+
ir.IntType(32)])
|
|
2041
|
+
module = ir.Module()
|
|
2042
|
+
|
|
2043
|
+
func = ir.Function(module, fnty, name="sum")
|
|
2044
|
+
|
|
2045
|
+
bb_entry = func.append_basic_block()
|
|
2046
|
+
bb_loop = func.append_basic_block()
|
|
2047
|
+
bb_exit = func.append_basic_block()
|
|
2048
|
+
|
|
2049
|
+
builder = ir.IRBuilder()
|
|
2050
|
+
builder.position_at_end(bb_entry)
|
|
2051
|
+
|
|
2052
|
+
builder.branch(bb_loop)
|
|
2053
|
+
builder.position_at_end(bb_loop)
|
|
2054
|
+
|
|
2055
|
+
index = builder.phi(ir.IntType(32))
|
|
2056
|
+
index.add_incoming(ir.Constant(index.type, 0), bb_entry)
|
|
2057
|
+
accum = builder.phi(ir.IntType(32))
|
|
2058
|
+
accum.add_incoming(ir.Constant(accum.type, 0), bb_entry)
|
|
2059
|
+
|
|
2060
|
+
func.args[0].add_attribute(attr_name)
|
|
2061
|
+
ptr = builder.gep(func.args[0], [index])
|
|
2062
|
+
value = builder.load(ptr)
|
|
2063
|
+
|
|
2064
|
+
added = builder.add(accum, value)
|
|
2065
|
+
accum.add_incoming(added, bb_loop)
|
|
2066
|
+
|
|
2067
|
+
indexp1 = builder.add(index, ir.Constant(index.type, 1))
|
|
2068
|
+
index.add_incoming(indexp1, bb_loop)
|
|
2069
|
+
|
|
2070
|
+
cond = builder.icmp_unsigned('<', indexp1, func.args[1])
|
|
2071
|
+
builder.cbranch(cond, bb_loop, bb_exit)
|
|
2072
|
+
|
|
2073
|
+
builder.position_at_end(bb_exit)
|
|
2074
|
+
builder.ret(added)
|
|
2075
|
+
|
|
2076
|
+
return str(module)
|
|
2077
|
+
|
|
2078
|
+
for attr_name in (
|
|
2079
|
+
'byref',
|
|
2080
|
+
'byval',
|
|
2081
|
+
'elementtype',
|
|
2082
|
+
'immarg',
|
|
2083
|
+
'inalloca',
|
|
2084
|
+
'inreg',
|
|
2085
|
+
'nest',
|
|
2086
|
+
'noalias',
|
|
2087
|
+
'nocapture',
|
|
2088
|
+
'nofree',
|
|
2089
|
+
'nonnull',
|
|
2090
|
+
'noundef',
|
|
2091
|
+
'preallocated',
|
|
2092
|
+
'returned',
|
|
2093
|
+
'signext',
|
|
2094
|
+
'swiftasync',
|
|
2095
|
+
'swifterror',
|
|
2096
|
+
'swiftself',
|
|
2097
|
+
'zeroext',
|
|
2098
|
+
):
|
|
2099
|
+
# If this parses, we emitted the right byval attribute format
|
|
2100
|
+
llvm.parse_assembly(gen_code(attr_name))
|
|
2101
|
+
# sret doesn't fit this pattern and is tested in test_call_attributes
|
|
2102
|
+
|
|
2103
|
+
|
|
2104
|
+
class TestBuilderMisc(TestBase):
|
|
2105
|
+
"""
|
|
2106
|
+
Test various other features of the IRBuilder class.
|
|
2107
|
+
"""
|
|
2108
|
+
|
|
2109
|
+
def test_attributes(self):
|
|
2110
|
+
block = self.block(name='start')
|
|
2111
|
+
builder = ir.IRBuilder(block)
|
|
2112
|
+
self.assertIs(builder.function, block.parent)
|
|
2113
|
+
self.assertIsInstance(builder.function, ir.Function)
|
|
2114
|
+
self.assertIs(builder.module, block.parent.module)
|
|
2115
|
+
self.assertIsInstance(builder.module, ir.Module)
|
|
2116
|
+
|
|
2117
|
+
def test_goto_block(self):
|
|
2118
|
+
block = self.block(name='my_block')
|
|
2119
|
+
builder = ir.IRBuilder(block)
|
|
2120
|
+
a, b = builder.function.args[:2]
|
|
2121
|
+
builder.add(a, b, 'c')
|
|
2122
|
+
bb_new = builder.append_basic_block(name='foo')
|
|
2123
|
+
with builder.goto_block(bb_new):
|
|
2124
|
+
builder.fadd(a, b, 'd')
|
|
2125
|
+
with builder.goto_entry_block():
|
|
2126
|
+
builder.sub(a, b, 'e')
|
|
2127
|
+
builder.fsub(a, b, 'f')
|
|
2128
|
+
builder.branch(bb_new)
|
|
2129
|
+
builder.mul(a, b, 'g')
|
|
2130
|
+
with builder.goto_block(bb_new):
|
|
2131
|
+
builder.fmul(a, b, 'h')
|
|
2132
|
+
self.check_block(block, """\
|
|
2133
|
+
my_block:
|
|
2134
|
+
%"c" = add i32 %".1", %".2"
|
|
2135
|
+
%"e" = sub i32 %".1", %".2"
|
|
2136
|
+
%"g" = mul i32 %".1", %".2"
|
|
2137
|
+
""")
|
|
2138
|
+
self.check_block(bb_new, """\
|
|
2139
|
+
foo:
|
|
2140
|
+
%"d" = fadd i32 %".1", %".2"
|
|
2141
|
+
%"f" = fsub i32 %".1", %".2"
|
|
2142
|
+
%"h" = fmul i32 %".1", %".2"
|
|
2143
|
+
br label %"foo"
|
|
2144
|
+
""")
|
|
2145
|
+
|
|
2146
|
+
def test_if_then(self):
|
|
2147
|
+
block = self.block(name='one')
|
|
2148
|
+
builder = ir.IRBuilder(block)
|
|
2149
|
+
z = ir.Constant(int1, 0)
|
|
2150
|
+
a = builder.add(z, z, 'a')
|
|
2151
|
+
with builder.if_then(a) as bbend:
|
|
2152
|
+
builder.add(z, z, 'b')
|
|
2153
|
+
# Block will be terminated implicitly
|
|
2154
|
+
self.assertIs(builder.block, bbend)
|
|
2155
|
+
c = builder.add(z, z, 'c')
|
|
2156
|
+
with builder.if_then(c):
|
|
2157
|
+
builder.add(z, z, 'd')
|
|
2158
|
+
builder.branch(block)
|
|
2159
|
+
# No implicit termination
|
|
2160
|
+
self.check_func_body(builder.function, """\
|
|
2161
|
+
one:
|
|
2162
|
+
%"a" = add i1 0, 0
|
|
2163
|
+
br i1 %"a", label %"one.if", label %"one.endif"
|
|
2164
|
+
one.if:
|
|
2165
|
+
%"b" = add i1 0, 0
|
|
2166
|
+
br label %"one.endif"
|
|
2167
|
+
one.endif:
|
|
2168
|
+
%"c" = add i1 0, 0
|
|
2169
|
+
br i1 %"c", label %"one.endif.if", label %"one.endif.endif"
|
|
2170
|
+
one.endif.if:
|
|
2171
|
+
%"d" = add i1 0, 0
|
|
2172
|
+
br label %"one"
|
|
2173
|
+
one.endif.endif:
|
|
2174
|
+
""")
|
|
2175
|
+
|
|
2176
|
+
def test_if_then_nested(self):
|
|
2177
|
+
# Implicit termination in a nested if/then
|
|
2178
|
+
block = self.block(name='one')
|
|
2179
|
+
builder = ir.IRBuilder(block)
|
|
2180
|
+
z = ir.Constant(int1, 0)
|
|
2181
|
+
a = builder.add(z, z, 'a')
|
|
2182
|
+
with builder.if_then(a):
|
|
2183
|
+
b = builder.add(z, z, 'b')
|
|
2184
|
+
with builder.if_then(b):
|
|
2185
|
+
builder.add(z, z, 'c')
|
|
2186
|
+
builder.ret_void()
|
|
2187
|
+
self.check_func_body(builder.function, """\
|
|
2188
|
+
one:
|
|
2189
|
+
%"a" = add i1 0, 0
|
|
2190
|
+
br i1 %"a", label %"one.if", label %"one.endif"
|
|
2191
|
+
one.if:
|
|
2192
|
+
%"b" = add i1 0, 0
|
|
2193
|
+
br i1 %"b", label %"one.if.if", label %"one.if.endif"
|
|
2194
|
+
one.endif:
|
|
2195
|
+
ret void
|
|
2196
|
+
one.if.if:
|
|
2197
|
+
%"c" = add i1 0, 0
|
|
2198
|
+
br label %"one.if.endif"
|
|
2199
|
+
one.if.endif:
|
|
2200
|
+
br label %"one.endif"
|
|
2201
|
+
""")
|
|
2202
|
+
|
|
2203
|
+
def test_if_then_long_label(self):
|
|
2204
|
+
full_label = 'Long' * 20
|
|
2205
|
+
block = self.block(name=full_label)
|
|
2206
|
+
builder = ir.IRBuilder(block)
|
|
2207
|
+
z = ir.Constant(int1, 0)
|
|
2208
|
+
a = builder.add(z, z, 'a')
|
|
2209
|
+
with builder.if_then(a):
|
|
2210
|
+
b = builder.add(z, z, 'b')
|
|
2211
|
+
with builder.if_then(b):
|
|
2212
|
+
builder.add(z, z, 'c')
|
|
2213
|
+
builder.ret_void()
|
|
2214
|
+
self.check_func_body(builder.function, """\
|
|
2215
|
+
{full_label}:
|
|
2216
|
+
%"a" = add i1 0, 0
|
|
2217
|
+
br i1 %"a", label %"{label}.if", label %"{label}.endif"
|
|
2218
|
+
{label}.if:
|
|
2219
|
+
%"b" = add i1 0, 0
|
|
2220
|
+
br i1 %"b", label %"{label}.if.if", label %"{label}.if.endif"
|
|
2221
|
+
{label}.endif:
|
|
2222
|
+
ret void
|
|
2223
|
+
{label}.if.if:
|
|
2224
|
+
%"c" = add i1 0, 0
|
|
2225
|
+
br label %"{label}.if.endif"
|
|
2226
|
+
{label}.if.endif:
|
|
2227
|
+
br label %"{label}.endif"
|
|
2228
|
+
""".format(full_label=full_label, label=full_label[:25] + '..'))
|
|
2229
|
+
|
|
2230
|
+
def test_if_then_likely(self):
|
|
2231
|
+
def check(likely):
|
|
2232
|
+
block = self.block(name='one')
|
|
2233
|
+
builder = ir.IRBuilder(block)
|
|
2234
|
+
z = ir.Constant(int1, 0)
|
|
2235
|
+
with builder.if_then(z, likely=likely):
|
|
2236
|
+
pass
|
|
2237
|
+
self.check_block(block, """\
|
|
2238
|
+
one:
|
|
2239
|
+
br i1 0, label %"one.if", label %"one.endif", !prof !0
|
|
2240
|
+
""")
|
|
2241
|
+
return builder
|
|
2242
|
+
builder = check(True)
|
|
2243
|
+
self.check_metadata(builder.module, """\
|
|
2244
|
+
!0 = !{ !"branch_weights", i32 99, i32 1 }
|
|
2245
|
+
""")
|
|
2246
|
+
builder = check(False)
|
|
2247
|
+
self.check_metadata(builder.module, """\
|
|
2248
|
+
!0 = !{ !"branch_weights", i32 1, i32 99 }
|
|
2249
|
+
""")
|
|
2250
|
+
|
|
2251
|
+
def test_if_else(self):
|
|
2252
|
+
block = self.block(name='one')
|
|
2253
|
+
builder = ir.IRBuilder(block)
|
|
2254
|
+
z = ir.Constant(int1, 0)
|
|
2255
|
+
a = builder.add(z, z, 'a')
|
|
2256
|
+
with builder.if_else(a) as (then, otherwise):
|
|
2257
|
+
with then:
|
|
2258
|
+
builder.add(z, z, 'b')
|
|
2259
|
+
with otherwise:
|
|
2260
|
+
builder.add(z, z, 'c')
|
|
2261
|
+
# Each block will be terminated implicitly
|
|
2262
|
+
with builder.if_else(a) as (then, otherwise):
|
|
2263
|
+
with then:
|
|
2264
|
+
builder.branch(block)
|
|
2265
|
+
with otherwise:
|
|
2266
|
+
builder.ret_void()
|
|
2267
|
+
# No implicit termination
|
|
2268
|
+
self.check_func_body(builder.function, """\
|
|
2269
|
+
one:
|
|
2270
|
+
%"a" = add i1 0, 0
|
|
2271
|
+
br i1 %"a", label %"one.if", label %"one.else"
|
|
2272
|
+
one.if:
|
|
2273
|
+
%"b" = add i1 0, 0
|
|
2274
|
+
br label %"one.endif"
|
|
2275
|
+
one.else:
|
|
2276
|
+
%"c" = add i1 0, 0
|
|
2277
|
+
br label %"one.endif"
|
|
2278
|
+
one.endif:
|
|
2279
|
+
br i1 %"a", label %"one.endif.if", label %"one.endif.else"
|
|
2280
|
+
one.endif.if:
|
|
2281
|
+
br label %"one"
|
|
2282
|
+
one.endif.else:
|
|
2283
|
+
ret void
|
|
2284
|
+
one.endif.endif:
|
|
2285
|
+
""")
|
|
2286
|
+
|
|
2287
|
+
def test_if_else_likely(self):
|
|
2288
|
+
def check(likely):
|
|
2289
|
+
block = self.block(name='one')
|
|
2290
|
+
builder = ir.IRBuilder(block)
|
|
2291
|
+
z = ir.Constant(int1, 0)
|
|
2292
|
+
with builder.if_else(z, likely=likely) as (then, otherwise):
|
|
2293
|
+
with then:
|
|
2294
|
+
builder.branch(block)
|
|
2295
|
+
with otherwise:
|
|
2296
|
+
builder.ret_void()
|
|
2297
|
+
self.check_func_body(builder.function, """\
|
|
2298
|
+
one:
|
|
2299
|
+
br i1 0, label %"one.if", label %"one.else", !prof !0
|
|
2300
|
+
one.if:
|
|
2301
|
+
br label %"one"
|
|
2302
|
+
one.else:
|
|
2303
|
+
ret void
|
|
2304
|
+
one.endif:
|
|
2305
|
+
""")
|
|
2306
|
+
return builder
|
|
2307
|
+
builder = check(True)
|
|
2308
|
+
self.check_metadata(builder.module, """\
|
|
2309
|
+
!0 = !{ !"branch_weights", i32 99, i32 1 }
|
|
2310
|
+
""")
|
|
2311
|
+
builder = check(False)
|
|
2312
|
+
self.check_metadata(builder.module, """\
|
|
2313
|
+
!0 = !{ !"branch_weights", i32 1, i32 99 }
|
|
2314
|
+
""")
|
|
2315
|
+
|
|
2316
|
+
def test_positioning(self):
|
|
2317
|
+
"""
|
|
2318
|
+
Test IRBuilder.position_{before,after,at_start,at_end}.
|
|
2319
|
+
"""
|
|
2320
|
+
func = self.function()
|
|
2321
|
+
builder = ir.IRBuilder()
|
|
2322
|
+
z = ir.Constant(int32, 0)
|
|
2323
|
+
bb_one = func.append_basic_block(name='one')
|
|
2324
|
+
bb_two = func.append_basic_block(name='two')
|
|
2325
|
+
bb_three = func.append_basic_block(name='three')
|
|
2326
|
+
# .at_start(empty block)
|
|
2327
|
+
builder.position_at_start(bb_one)
|
|
2328
|
+
builder.add(z, z, 'a')
|
|
2329
|
+
# .at_end(empty block)
|
|
2330
|
+
builder.position_at_end(bb_two)
|
|
2331
|
+
builder.add(z, z, 'm')
|
|
2332
|
+
builder.add(z, z, 'n')
|
|
2333
|
+
# .at_start(block)
|
|
2334
|
+
builder.position_at_start(bb_two)
|
|
2335
|
+
o = builder.add(z, z, 'o')
|
|
2336
|
+
builder.add(z, z, 'p')
|
|
2337
|
+
# .at_end(block)
|
|
2338
|
+
builder.position_at_end(bb_one)
|
|
2339
|
+
b = builder.add(z, z, 'b')
|
|
2340
|
+
# .after(instr)
|
|
2341
|
+
builder.position_after(o)
|
|
2342
|
+
builder.add(z, z, 'q')
|
|
2343
|
+
# .before(instr)
|
|
2344
|
+
builder.position_before(b)
|
|
2345
|
+
builder.add(z, z, 'c')
|
|
2346
|
+
self.check_block(bb_one, """\
|
|
2347
|
+
one:
|
|
2348
|
+
%"a" = add i32 0, 0
|
|
2349
|
+
%"c" = add i32 0, 0
|
|
2350
|
+
%"b" = add i32 0, 0
|
|
2351
|
+
""")
|
|
2352
|
+
self.check_block(bb_two, """\
|
|
2353
|
+
two:
|
|
2354
|
+
%"o" = add i32 0, 0
|
|
2355
|
+
%"q" = add i32 0, 0
|
|
2356
|
+
%"p" = add i32 0, 0
|
|
2357
|
+
%"m" = add i32 0, 0
|
|
2358
|
+
%"n" = add i32 0, 0
|
|
2359
|
+
""")
|
|
2360
|
+
self.check_block(bb_three, """\
|
|
2361
|
+
three:
|
|
2362
|
+
""")
|
|
2363
|
+
|
|
2364
|
+
def test_instruction_removal(self):
|
|
2365
|
+
func = self.function()
|
|
2366
|
+
builder = ir.IRBuilder()
|
|
2367
|
+
blk = func.append_basic_block(name='entry')
|
|
2368
|
+
builder.position_at_end(blk)
|
|
2369
|
+
k = ir.Constant(int32, 1234)
|
|
2370
|
+
a = builder.add(k, k, 'a')
|
|
2371
|
+
retvoid = builder.ret_void()
|
|
2372
|
+
self.assertTrue(blk.is_terminated)
|
|
2373
|
+
builder.remove(retvoid)
|
|
2374
|
+
self.assertFalse(blk.is_terminated)
|
|
2375
|
+
b = builder.mul(a, a, 'b')
|
|
2376
|
+
c = builder.add(b, b, 'c')
|
|
2377
|
+
builder.remove(c)
|
|
2378
|
+
builder.ret_void()
|
|
2379
|
+
self.assertTrue(blk.is_terminated)
|
|
2380
|
+
self.check_block(blk, """\
|
|
2381
|
+
entry:
|
|
2382
|
+
%"a" = add i32 1234, 1234
|
|
2383
|
+
%"b" = mul i32 %"a", %"a"
|
|
2384
|
+
ret void
|
|
2385
|
+
""")
|
|
2386
|
+
|
|
2387
|
+
def test_metadata(self):
|
|
2388
|
+
block = self.block(name='my_block')
|
|
2389
|
+
builder = ir.IRBuilder(block)
|
|
2390
|
+
builder.debug_metadata = builder.module.add_metadata([])
|
|
2391
|
+
builder.alloca(ir.PointerType(int32), name='c')
|
|
2392
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2393
|
+
self.check_block(block, """\
|
|
2394
|
+
my_block:
|
|
2395
|
+
%"c" = alloca ptr, !dbg !0
|
|
2396
|
+
""")
|
|
2397
|
+
else:
|
|
2398
|
+
self.check_block(block, """\
|
|
2399
|
+
my_block:
|
|
2400
|
+
%"c" = alloca i32*, !dbg !0
|
|
2401
|
+
""")
|
|
2402
|
+
|
|
2403
|
+
|
|
2404
|
+
class TestTypes(TestBase):
|
|
2405
|
+
|
|
2406
|
+
def has_logical_equality(self, ty):
|
|
2407
|
+
while isinstance(ty, ir.PointerType):
|
|
2408
|
+
ty = ty.pointee
|
|
2409
|
+
return not isinstance(ty, ir.LabelType)
|
|
2410
|
+
|
|
2411
|
+
def assorted_types(self):
|
|
2412
|
+
"""
|
|
2413
|
+
A bunch of mutually unequal types
|
|
2414
|
+
"""
|
|
2415
|
+
# Avoid polluting the namespace
|
|
2416
|
+
context = ir.Context()
|
|
2417
|
+
types = [
|
|
2418
|
+
ir.LabelType(), ir.VoidType(),
|
|
2419
|
+
ir.FunctionType(int1, (int8, int8)), ir.FunctionType(int1, (int8,)),
|
|
2420
|
+
ir.FunctionType(int1, (int8,), var_arg=True),
|
|
2421
|
+
ir.FunctionType(int8, (int8,)),
|
|
2422
|
+
int1, int8, int32, flt, dbl,
|
|
2423
|
+
ir.ArrayType(flt, 5), ir.ArrayType(dbl, 5), ir.ArrayType(dbl, 4),
|
|
2424
|
+
ir.LiteralStructType((int1, int8)), ir.LiteralStructType((int8,
|
|
2425
|
+
int1)),
|
|
2426
|
+
context.get_identified_type("MyType1"),
|
|
2427
|
+
context.get_identified_type("MyType2"),
|
|
2428
|
+
]
|
|
2429
|
+
types += [ir.PointerType(tp) for tp in types
|
|
2430
|
+
if not isinstance(tp, (ir.VoidType, ir.LabelType))]
|
|
2431
|
+
|
|
2432
|
+
return types
|
|
2433
|
+
|
|
2434
|
+
def test_pickling(self):
|
|
2435
|
+
types = self.assorted_types()
|
|
2436
|
+
for ty in types:
|
|
2437
|
+
newty = self.assert_pickle_correctly(ty)
|
|
2438
|
+
if self.has_logical_equality(ty):
|
|
2439
|
+
self.assertEqual(newty, ty)
|
|
2440
|
+
|
|
2441
|
+
def test_comparisons(self):
|
|
2442
|
+
types = self.assorted_types()
|
|
2443
|
+
for a, b in itertools.product(types, types):
|
|
2444
|
+
if a is not b:
|
|
2445
|
+
self.assertFalse(a == b, (a, b))
|
|
2446
|
+
self.assertTrue(a != b, (a, b))
|
|
2447
|
+
# We assume copy.copy() works fine here...
|
|
2448
|
+
for tp in types:
|
|
2449
|
+
other = copy.copy(tp)
|
|
2450
|
+
if self.has_logical_equality(tp):
|
|
2451
|
+
self.assertTrue(tp == other, (tp, other))
|
|
2452
|
+
self.assertFalse(tp != other, (tp, other))
|
|
2453
|
+
else:
|
|
2454
|
+
self.assertFalse(tp == other, (tp, other))
|
|
2455
|
+
self.assertTrue(tp != other, (tp, other))
|
|
2456
|
+
|
|
2457
|
+
def test_ptr_comparisons(self):
|
|
2458
|
+
# Create instances of:
|
|
2459
|
+
# * Opaque pointers.
|
|
2460
|
+
# * Typed pointers of i1's.
|
|
2461
|
+
# * Typed pointers of i8's.
|
|
2462
|
+
# The choice of types for the typed pointers are not consequential -
|
|
2463
|
+
# they just need to differ. Each pointer class has two instances, one
|
|
2464
|
+
# in address space 0, another in address space 1.
|
|
2465
|
+
ptrs = {
|
|
2466
|
+
'op_a0': ir.PointerType(),
|
|
2467
|
+
'op_a1': ir.PointerType(addrspace=1),
|
|
2468
|
+
'tp_i1_a0': ir.PointerType(int1),
|
|
2469
|
+
'tp_i1_a1': ir.PointerType(int1, addrspace=1),
|
|
2470
|
+
'tp_i8_a0': ir.PointerType(int8),
|
|
2471
|
+
'tp_i8_a1': ir.PointerType(int8, addrspace=1),
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
def assert_eq(ptr1, ptr2):
|
|
2475
|
+
self.assertTrue(ptr1 == ptr2, (ptr1, ptr2))
|
|
2476
|
+
self.assertTrue(ptr2 == ptr1, (ptr2, ptr1))
|
|
2477
|
+
|
|
2478
|
+
self.assertFalse(ptr1 != ptr2, (ptr1, ptr2))
|
|
2479
|
+
self.assertFalse(ptr2 != ptr1, (ptr2, ptr1))
|
|
2480
|
+
|
|
2481
|
+
def assert_ne(ptr1, ptr2):
|
|
2482
|
+
self.assertFalse(ptr1 == ptr2, (ptr1, ptr2))
|
|
2483
|
+
self.assertFalse(ptr2 == ptr1, (ptr2, ptr1))
|
|
2484
|
+
|
|
2485
|
+
self.assertTrue(ptr1 != ptr2, (ptr1, ptr2))
|
|
2486
|
+
self.assertTrue(ptr2 != ptr1, (ptr2, ptr1))
|
|
2487
|
+
|
|
2488
|
+
for ptr in ptrs.values():
|
|
2489
|
+
# Compare the pointers against any non-pointer type.
|
|
2490
|
+
for other in self.assorted_types():
|
|
2491
|
+
if not isinstance(other, ir.PointerType):
|
|
2492
|
+
assert_ne(ptr, other)
|
|
2493
|
+
# Compare the pointers against themselves.
|
|
2494
|
+
assert_eq(ptr, ptr)
|
|
2495
|
+
|
|
2496
|
+
# Compare the pointers against each other.
|
|
2497
|
+
# Opaque pointers are always equal, unless their address space differs.
|
|
2498
|
+
# Typed pointers always differ, unless their pointee type and address
|
|
2499
|
+
# space match.
|
|
2500
|
+
assert_ne(ptrs['op_a0'], ptrs['op_a1'])
|
|
2501
|
+
assert_eq(ptrs['op_a0'], ptrs['tp_i1_a0'])
|
|
2502
|
+
assert_ne(ptrs['op_a0'], ptrs['tp_i1_a1'])
|
|
2503
|
+
assert_eq(ptrs['op_a0'], ptrs['tp_i8_a0'])
|
|
2504
|
+
assert_ne(ptrs['op_a0'], ptrs['tp_i8_a1'])
|
|
2505
|
+
assert_ne(ptrs['op_a1'], ptrs['tp_i1_a0'])
|
|
2506
|
+
assert_eq(ptrs['op_a1'], ptrs['tp_i1_a1'])
|
|
2507
|
+
assert_ne(ptrs['op_a1'], ptrs['tp_i8_a0'])
|
|
2508
|
+
assert_eq(ptrs['op_a1'], ptrs['tp_i8_a1'])
|
|
2509
|
+
assert_ne(ptrs['tp_i1_a0'], ptrs['tp_i1_a1'])
|
|
2510
|
+
assert_ne(ptrs['tp_i1_a0'], ptrs['tp_i8_a0'])
|
|
2511
|
+
assert_ne(ptrs['tp_i1_a0'], ptrs['tp_i8_a1'])
|
|
2512
|
+
assert_ne(ptrs['tp_i1_a1'], ptrs['tp_i8_a0'])
|
|
2513
|
+
assert_ne(ptrs['tp_i1_a1'], ptrs['tp_i8_a1'])
|
|
2514
|
+
assert_ne(ptrs['tp_i8_a0'], ptrs['tp_i8_a1'])
|
|
2515
|
+
|
|
2516
|
+
def test_ptr_intrinsic_name(self):
|
|
2517
|
+
self.assertEqual(ir.PointerType().intrinsic_name, 'p0')
|
|
2518
|
+
self.assertEqual(ir.PointerType(addrspace=1).intrinsic_name, 'p1')
|
|
2519
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2520
|
+
self.assertEqual(ir.PointerType(int1).intrinsic_name, 'p0')
|
|
2521
|
+
self.assertEqual(ir.PointerType(int1, 1).intrinsic_name, 'p1')
|
|
2522
|
+
else:
|
|
2523
|
+
self.assertEqual(ir.PointerType(int1).intrinsic_name, 'p0i1')
|
|
2524
|
+
self.assertEqual(ir.PointerType(int1, 1).intrinsic_name, 'p1i1')
|
|
2525
|
+
|
|
2526
|
+
def test_str(self):
|
|
2527
|
+
"""
|
|
2528
|
+
Test the string representation of types.
|
|
2529
|
+
"""
|
|
2530
|
+
self.assertEqual(str(int1), 'i1')
|
|
2531
|
+
self.assertEqual(str(ir.IntType(29)), 'i29')
|
|
2532
|
+
self.assertEqual(str(flt), 'float')
|
|
2533
|
+
self.assertEqual(str(dbl), 'double')
|
|
2534
|
+
self.assertEqual(str(ir.VoidType()), 'void')
|
|
2535
|
+
self.assertEqual(str(ir.FunctionType(int1, ())), 'i1 ()')
|
|
2536
|
+
self.assertEqual(str(ir.FunctionType(int1, (flt,))), 'i1 (float)')
|
|
2537
|
+
self.assertEqual(str(ir.FunctionType(int1, (flt, dbl))),
|
|
2538
|
+
'i1 (float, double)')
|
|
2539
|
+
self.assertEqual(str(ir.FunctionType(int1, (), var_arg=True)),
|
|
2540
|
+
'i1 (...)')
|
|
2541
|
+
self.assertEqual(str(ir.FunctionType(int1, (flt,), var_arg=True)),
|
|
2542
|
+
'i1 (float, ...)')
|
|
2543
|
+
self.assertEqual(str(ir.FunctionType(int1, (flt, dbl), var_arg=True)),
|
|
2544
|
+
'i1 (float, double, ...)')
|
|
2545
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2546
|
+
self.assertEqual(str(ir.PointerType(int32)), 'ptr')
|
|
2547
|
+
self.assertEqual(str(ir.PointerType(ir.PointerType(int32))), 'ptr')
|
|
2548
|
+
else:
|
|
2549
|
+
self.assertEqual(str(ir.PointerType(int32)), 'i32*')
|
|
2550
|
+
self.assertEqual(str(ir.PointerType(ir.PointerType(int32))),
|
|
2551
|
+
'i32**')
|
|
2552
|
+
self.assertEqual(str(ir.ArrayType(int1, 5)), '[5 x i1]')
|
|
2553
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2554
|
+
self.assertEqual(str(ir.ArrayType(ir.PointerType(int1), 5)),
|
|
2555
|
+
'[5 x ptr]')
|
|
2556
|
+
self.assertEqual(str(ir.PointerType(ir.ArrayType(int1, 5))), 'ptr')
|
|
2557
|
+
else:
|
|
2558
|
+
self.assertEqual(str(ir.ArrayType(ir.PointerType(int1), 5)),
|
|
2559
|
+
'[5 x i1*]')
|
|
2560
|
+
self.assertEqual(str(ir.PointerType(ir.ArrayType(int1, 5))),
|
|
2561
|
+
'[5 x i1]*')
|
|
2562
|
+
self.assertEqual(str(ir.LiteralStructType((int1,))), '{i1}')
|
|
2563
|
+
self.assertEqual(str(ir.LiteralStructType((int1, flt))), '{i1, float}')
|
|
2564
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2565
|
+
self.assertEqual(str(ir.LiteralStructType((
|
|
2566
|
+
ir.PointerType(int1), ir.LiteralStructType((int32, int8))))),
|
|
2567
|
+
'{ptr, {i32, i8}}')
|
|
2568
|
+
else:
|
|
2569
|
+
self.assertEqual(str(ir.LiteralStructType((
|
|
2570
|
+
ir.PointerType(int1), ir.LiteralStructType((int32, int8))))),
|
|
2571
|
+
'{i1*, {i32, i8}}')
|
|
2572
|
+
self.assertEqual(str(ir.LiteralStructType((int1,), packed=True)),
|
|
2573
|
+
'<{i1}>')
|
|
2574
|
+
self.assertEqual(str(ir.LiteralStructType((int1, flt), packed=True)),
|
|
2575
|
+
'<{i1, float}>')
|
|
2576
|
+
|
|
2577
|
+
# Avoid polluting the namespace
|
|
2578
|
+
context = ir.Context()
|
|
2579
|
+
mytype = context.get_identified_type("MyType")
|
|
2580
|
+
self.assertEqual(str(mytype), "%\"MyType\"")
|
|
2581
|
+
mytype1 = context.get_identified_type("MyType\\")
|
|
2582
|
+
self.assertEqual(str(mytype1), "%\"MyType\\5c\"")
|
|
2583
|
+
mytype2 = context.get_identified_type("MyType\"")
|
|
2584
|
+
self.assertEqual(str(mytype2), "%\"MyType\\22\"")
|
|
2585
|
+
|
|
2586
|
+
def test_hash(self):
|
|
2587
|
+
for typ in filter(self.has_logical_equality, self.assorted_types()):
|
|
2588
|
+
self.assertEqual(hash(typ), hash(copy.copy(typ)))
|
|
2589
|
+
|
|
2590
|
+
def test_gep(self):
|
|
2591
|
+
def check_constant(tp, i, expected):
|
|
2592
|
+
actual = tp.gep(ir.Constant(int32, i))
|
|
2593
|
+
self.assertEqual(actual, expected)
|
|
2594
|
+
|
|
2595
|
+
def check_index_type(tp):
|
|
2596
|
+
index = ir.Constant(dbl, 1.0)
|
|
2597
|
+
with self.assertRaises(TypeError):
|
|
2598
|
+
tp.gep(index)
|
|
2599
|
+
|
|
2600
|
+
tp = ir.PointerType(dbl)
|
|
2601
|
+
for i in range(5):
|
|
2602
|
+
check_constant(tp, i, dbl)
|
|
2603
|
+
check_index_type(tp)
|
|
2604
|
+
|
|
2605
|
+
tp = ir.ArrayType(int1, 3)
|
|
2606
|
+
for i in range(3):
|
|
2607
|
+
check_constant(tp, i, int1)
|
|
2608
|
+
check_index_type(tp)
|
|
2609
|
+
|
|
2610
|
+
tp = ir.LiteralStructType((dbl, ir.LiteralStructType((int1, int8))))
|
|
2611
|
+
check_constant(tp, 0, dbl)
|
|
2612
|
+
check_constant(tp, 1, ir.LiteralStructType((int1, int8)))
|
|
2613
|
+
with self.assertRaises(IndexError):
|
|
2614
|
+
tp.gep(ir.Constant(int32, 2))
|
|
2615
|
+
check_index_type(tp)
|
|
2616
|
+
|
|
2617
|
+
context = ir.Context()
|
|
2618
|
+
tp = ir.IdentifiedStructType(context, "MyType")
|
|
2619
|
+
tp.set_body(dbl, ir.LiteralStructType((int1, int8)))
|
|
2620
|
+
check_constant(tp, 0, dbl)
|
|
2621
|
+
check_constant(tp, 1, ir.LiteralStructType((int1, int8)))
|
|
2622
|
+
with self.assertRaises(IndexError):
|
|
2623
|
+
tp.gep(ir.Constant(int32, 2))
|
|
2624
|
+
check_index_type(tp)
|
|
2625
|
+
|
|
2626
|
+
def test_abi_size(self):
|
|
2627
|
+
td = llvm.create_target_data("e-m:e-i64:64-f80:128-n8:16:32:64-S128")
|
|
2628
|
+
|
|
2629
|
+
def check(tp, expected):
|
|
2630
|
+
self.assertEqual(tp.get_abi_size(td), expected)
|
|
2631
|
+
check(int8, 1)
|
|
2632
|
+
check(int32, 4)
|
|
2633
|
+
check(int64, 8)
|
|
2634
|
+
check(ir.ArrayType(int8, 5), 5)
|
|
2635
|
+
check(ir.ArrayType(int32, 5), 20)
|
|
2636
|
+
check(ir.LiteralStructType((dbl, flt, flt)), 16)
|
|
2637
|
+
|
|
2638
|
+
def test_abi_alignment(self):
|
|
2639
|
+
td = llvm.create_target_data("e-m:e-i64:64-f80:128-n8:16:32:64-S128")
|
|
2640
|
+
|
|
2641
|
+
def check(tp, expected):
|
|
2642
|
+
self.assertIn(tp.get_abi_alignment(td), expected)
|
|
2643
|
+
check(int8, (1, 2, 4))
|
|
2644
|
+
check(int32, (4,))
|
|
2645
|
+
check(int64, (8,))
|
|
2646
|
+
check(ir.ArrayType(int8, 5), (1, 2, 4))
|
|
2647
|
+
check(ir.ArrayType(int32, 5), (4,))
|
|
2648
|
+
check(ir.LiteralStructType((dbl, flt, flt)), (8,))
|
|
2649
|
+
|
|
2650
|
+
def test_identified_struct(self):
|
|
2651
|
+
context = ir.Context()
|
|
2652
|
+
mytype = context.get_identified_type("MyType")
|
|
2653
|
+
module = ir.Module(context=context)
|
|
2654
|
+
self.assertTrue(mytype.is_opaque)
|
|
2655
|
+
self.assert_valid_ir(module)
|
|
2656
|
+
oldstr = str(module)
|
|
2657
|
+
mytype.set_body(ir.IntType(32), ir.IntType(64), ir.FloatType())
|
|
2658
|
+
self.assertFalse(mytype.is_opaque)
|
|
2659
|
+
self.assert_valid_ir(module)
|
|
2660
|
+
self.assertNotEqual(oldstr, str(module))
|
|
2661
|
+
|
|
2662
|
+
def test_identified_struct_packed(self):
|
|
2663
|
+
td = llvm.create_target_data("e-m:e-i64:64-f80:128-n8:16:32:64-S128")
|
|
2664
|
+
context = ir.Context()
|
|
2665
|
+
mytype = context.get_identified_type("MyType", True)
|
|
2666
|
+
module = ir.Module(context=context)
|
|
2667
|
+
self.assertTrue(mytype.is_opaque)
|
|
2668
|
+
self.assert_valid_ir(module)
|
|
2669
|
+
oldstr = str(module)
|
|
2670
|
+
mytype.set_body(ir.IntType(16), ir.IntType(64), ir.FloatType())
|
|
2671
|
+
self.assertEqual(mytype.get_element_offset(td, 1, context), 2)
|
|
2672
|
+
self.assertFalse(mytype.is_opaque)
|
|
2673
|
+
self.assert_valid_ir(module)
|
|
2674
|
+
self.assertNotEqual(oldstr, str(module))
|
|
2675
|
+
|
|
2676
|
+
def test_target_data_non_default_context(self):
|
|
2677
|
+
context = ir.Context()
|
|
2678
|
+
mytype = context.get_identified_type("MyType")
|
|
2679
|
+
mytype.elements = [ir.IntType(32)]
|
|
2680
|
+
td = llvm.create_target_data("e-m:e-i64:64-f80:128-n8:16:32:64-S128")
|
|
2681
|
+
self.assertEqual(mytype.get_abi_size(td, context=context), 4)
|
|
2682
|
+
|
|
2683
|
+
def test_vector(self):
|
|
2684
|
+
vecty = ir.VectorType(ir.IntType(32), 8)
|
|
2685
|
+
self.assertEqual(str(vecty), "<8 x i32>")
|
|
2686
|
+
|
|
2687
|
+
|
|
2688
|
+
def c32(i):
|
|
2689
|
+
return ir.Constant(int32, i)
|
|
2690
|
+
|
|
2691
|
+
|
|
2692
|
+
class TestConstant(TestBase):
|
|
2693
|
+
|
|
2694
|
+
def test_integers(self):
|
|
2695
|
+
c = ir.Constant(int32, 42)
|
|
2696
|
+
self.assertEqual(str(c), 'i32 42')
|
|
2697
|
+
c = ir.Constant(int1, 1)
|
|
2698
|
+
self.assertEqual(str(c), 'i1 1')
|
|
2699
|
+
c = ir.Constant(int1, 0)
|
|
2700
|
+
self.assertEqual(str(c), 'i1 0')
|
|
2701
|
+
c = ir.Constant(int1, True)
|
|
2702
|
+
self.assertEqual(str(c), 'i1 true')
|
|
2703
|
+
c = ir.Constant(int1, False)
|
|
2704
|
+
self.assertEqual(str(c), 'i1 false')
|
|
2705
|
+
c = ir.Constant(int1, ir.Undefined)
|
|
2706
|
+
self.assertEqual(str(c), 'i1 undef')
|
|
2707
|
+
c = ir.Constant(int1, None)
|
|
2708
|
+
self.assertEqual(str(c), 'i1 0')
|
|
2709
|
+
|
|
2710
|
+
def test_reals(self):
|
|
2711
|
+
# XXX Test NaNs and infs
|
|
2712
|
+
c = ir.Constant(flt, 1.5)
|
|
2713
|
+
self.assertEqual(str(c), 'float 0x3ff8000000000000')
|
|
2714
|
+
c = ir.Constant(flt, -1.5)
|
|
2715
|
+
self.assertEqual(str(c), 'float 0xbff8000000000000')
|
|
2716
|
+
c = ir.Constant(dbl, 1.5)
|
|
2717
|
+
self.assertEqual(str(c), 'double 0x3ff8000000000000')
|
|
2718
|
+
c = ir.Constant(dbl, -1.5)
|
|
2719
|
+
self.assertEqual(str(c), 'double 0xbff8000000000000')
|
|
2720
|
+
c = ir.Constant(dbl, ir.Undefined)
|
|
2721
|
+
self.assertEqual(str(c), 'double undef')
|
|
2722
|
+
c = ir.Constant(dbl, None)
|
|
2723
|
+
self.assertEqual(str(c), 'double 0.0')
|
|
2724
|
+
|
|
2725
|
+
def test_arrays(self):
|
|
2726
|
+
c = ir.Constant(ir.ArrayType(int32, 3), (c32(5), c32(6), c32(4)))
|
|
2727
|
+
self.assertEqual(str(c), '[3 x i32] [i32 5, i32 6, i32 4]')
|
|
2728
|
+
c = ir.Constant(ir.ArrayType(int32, 2), (c32(5), c32(ir.Undefined)))
|
|
2729
|
+
self.assertEqual(str(c), '[2 x i32] [i32 5, i32 undef]')
|
|
2730
|
+
|
|
2731
|
+
c = ir.Constant.literal_array((c32(5), c32(6), c32(ir.Undefined)))
|
|
2732
|
+
self.assertEqual(str(c), '[3 x i32] [i32 5, i32 6, i32 undef]')
|
|
2733
|
+
with self.assertRaises(TypeError) as raises:
|
|
2734
|
+
ir.Constant.literal_array((c32(5), ir.Constant(flt, 1.5)))
|
|
2735
|
+
self.assertEqual(str(raises.exception),
|
|
2736
|
+
"all elements must have the same type")
|
|
2737
|
+
|
|
2738
|
+
c = ir.Constant(ir.ArrayType(int32, 2), ir.Undefined)
|
|
2739
|
+
self.assertEqual(str(c), '[2 x i32] undef')
|
|
2740
|
+
c = ir.Constant(ir.ArrayType(int32, 2), None)
|
|
2741
|
+
self.assertEqual(str(c), '[2 x i32] zeroinitializer')
|
|
2742
|
+
# Raw array syntax
|
|
2743
|
+
c = ir.Constant(ir.ArrayType(int8, 11), bytearray(b"foobar_123\x80"))
|
|
2744
|
+
self.assertEqual(str(c), r'[11 x i8] c"foobar_123\80"')
|
|
2745
|
+
c = ir.Constant(ir.ArrayType(int8, 4), bytearray(b"\x00\x01\x04\xff"))
|
|
2746
|
+
self.assertEqual(str(c), r'[4 x i8] c"\00\01\04\ff"')
|
|
2747
|
+
# Recursive instantiation of inner constants
|
|
2748
|
+
c = ir.Constant(ir.ArrayType(int32, 3), (5, ir.Undefined, 6))
|
|
2749
|
+
self.assertEqual(str(c), '[3 x i32] [i32 5, i32 undef, i32 6]')
|
|
2750
|
+
# Invalid number of args
|
|
2751
|
+
with self.assertRaises(ValueError):
|
|
2752
|
+
ir.Constant(ir.ArrayType(int32, 3), (5, 6))
|
|
2753
|
+
|
|
2754
|
+
def test_vector(self):
|
|
2755
|
+
vecty = ir.VectorType(ir.IntType(32), 8)
|
|
2756
|
+
vals = [1, 2, 4, 3, 8, 6, 9, 7]
|
|
2757
|
+
vec = ir.Constant(vecty, vals)
|
|
2758
|
+
vec_repr = "<8 x i32> <{}>".format(
|
|
2759
|
+
', '.join(map('i32 {}'.format, vals)))
|
|
2760
|
+
self.assertEqual(str(vec), vec_repr)
|
|
2761
|
+
|
|
2762
|
+
def test_non_nullable_int(self):
|
|
2763
|
+
constant = ir.Constant(ir.IntType(32), None).constant
|
|
2764
|
+
self.assertEqual(constant, 0)
|
|
2765
|
+
|
|
2766
|
+
def test_structs(self):
|
|
2767
|
+
st1 = ir.LiteralStructType((flt, int1))
|
|
2768
|
+
st2 = ir.LiteralStructType((int32, st1))
|
|
2769
|
+
c = ir.Constant(st1, (ir.Constant(ir.FloatType(), 1.5),
|
|
2770
|
+
ir.Constant(int1, True)))
|
|
2771
|
+
self.assertEqual(str(c),
|
|
2772
|
+
'{float, i1} {float 0x3ff8000000000000, i1 true}')
|
|
2773
|
+
c = ir.Constant.literal_struct((ir.Constant(ir.FloatType(), 1.5),
|
|
2774
|
+
ir.Constant(int1, True)))
|
|
2775
|
+
self.assertEqual(c.type, st1)
|
|
2776
|
+
self.assertEqual(str(c),
|
|
2777
|
+
'{float, i1} {float 0x3ff8000000000000, i1 true}')
|
|
2778
|
+
c = ir.Constant.literal_struct((ir.Constant(ir.FloatType(), 1.5),
|
|
2779
|
+
ir.Constant(int1, ir.Undefined)))
|
|
2780
|
+
self.assertEqual(c.type, st1)
|
|
2781
|
+
self.assertEqual(str(c),
|
|
2782
|
+
'{float, i1} {float 0x3ff8000000000000, i1 undef}')
|
|
2783
|
+
c = ir.Constant(st1, ir.Undefined)
|
|
2784
|
+
self.assertEqual(str(c), '{float, i1} undef')
|
|
2785
|
+
c = ir.Constant(st1, None)
|
|
2786
|
+
self.assertEqual(str(c), '{float, i1} zeroinitializer')
|
|
2787
|
+
# Recursive instantiation of inner constants
|
|
2788
|
+
c1 = ir.Constant(st1, (1.5, True))
|
|
2789
|
+
self.assertEqual(str(c1),
|
|
2790
|
+
'{float, i1} {float 0x3ff8000000000000, i1 true}')
|
|
2791
|
+
c2 = ir.Constant(st2, (42, c1))
|
|
2792
|
+
self.assertEqual(str(c2), ('{i32, {float, i1}} {i32 42, {float, i1} '
|
|
2793
|
+
'{float 0x3ff8000000000000, i1 true}}'))
|
|
2794
|
+
c3 = ir.Constant(st2, (42, (1.5, True)))
|
|
2795
|
+
self.assertEqual(str(c3), str(c2))
|
|
2796
|
+
# Invalid number of args
|
|
2797
|
+
with self.assertRaises(ValueError):
|
|
2798
|
+
ir.Constant(st2, (4, 5, 6))
|
|
2799
|
+
|
|
2800
|
+
def test_undefined_literal_struct_pickling(self):
|
|
2801
|
+
i8 = ir.IntType(8)
|
|
2802
|
+
st = ir.Constant(ir.LiteralStructType([i8, i8]), ir.Undefined)
|
|
2803
|
+
self.assert_pickle_correctly(st)
|
|
2804
|
+
|
|
2805
|
+
def test_type_instantiaton(self):
|
|
2806
|
+
"""
|
|
2807
|
+
Instantiating a type should create a constant.
|
|
2808
|
+
"""
|
|
2809
|
+
c = int8(42)
|
|
2810
|
+
self.assertIsInstance(c, ir.Constant)
|
|
2811
|
+
self.assertEqual(str(c), 'i8 42')
|
|
2812
|
+
c = int1(True)
|
|
2813
|
+
self.assertIsInstance(c, ir.Constant)
|
|
2814
|
+
self.assertEqual(str(c), 'i1 true')
|
|
2815
|
+
# Arrays
|
|
2816
|
+
at = ir.ArrayType(int32, 3)
|
|
2817
|
+
c = at([c32(4), c32(5), c32(6)])
|
|
2818
|
+
self.assertEqual(str(c), '[3 x i32] [i32 4, i32 5, i32 6]')
|
|
2819
|
+
c = at([4, 5, 6])
|
|
2820
|
+
self.assertEqual(str(c), '[3 x i32] [i32 4, i32 5, i32 6]')
|
|
2821
|
+
c = at(None)
|
|
2822
|
+
self.assertEqual(str(c), '[3 x i32] zeroinitializer')
|
|
2823
|
+
with self.assertRaises(ValueError):
|
|
2824
|
+
at([4, 5, 6, 7])
|
|
2825
|
+
# Structs
|
|
2826
|
+
st1 = ir.LiteralStructType((flt, int1))
|
|
2827
|
+
st2 = ir.LiteralStructType((int32, st1))
|
|
2828
|
+
c = st1((1.5, True))
|
|
2829
|
+
self.assertEqual(str(c), ('{float, i1} {float 0x3ff8000000000000, i1 '
|
|
2830
|
+
'true}'))
|
|
2831
|
+
c = st2((42, (1.5, True)))
|
|
2832
|
+
self.assertEqual(str(c), ('{i32, {float, i1}} {i32 42, {float, i1} '
|
|
2833
|
+
'{float 0x3ff8000000000000, i1 true}}'))
|
|
2834
|
+
|
|
2835
|
+
def test_repr(self):
|
|
2836
|
+
"""
|
|
2837
|
+
Constants should have a useful repr().
|
|
2838
|
+
"""
|
|
2839
|
+
c = int32(42)
|
|
2840
|
+
self.assertEqual(repr(c), "<ir.Constant type='i32' value=42>")
|
|
2841
|
+
|
|
2842
|
+
def test_encoding_problem(self):
|
|
2843
|
+
c = ir.Constant(ir.ArrayType(ir.IntType(8), 256),
|
|
2844
|
+
bytearray(range(256)))
|
|
2845
|
+
m = self.module()
|
|
2846
|
+
gv = ir.GlobalVariable(m, c.type, "myconstant")
|
|
2847
|
+
gv.global_constant = True
|
|
2848
|
+
gv.initializer = c
|
|
2849
|
+
# With utf-8, the following will cause:
|
|
2850
|
+
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position
|
|
2851
|
+
# 136: invalid continuation byte
|
|
2852
|
+
parsed = llvm.parse_assembly(str(m))
|
|
2853
|
+
# Make sure the encoding does not modify the IR
|
|
2854
|
+
reparsed = llvm.parse_assembly(str(parsed))
|
|
2855
|
+
self.assertEqual(str(parsed), str(reparsed))
|
|
2856
|
+
|
|
2857
|
+
def test_gep(self):
|
|
2858
|
+
m = self.module()
|
|
2859
|
+
tp = ir.LiteralStructType((flt, int1))
|
|
2860
|
+
gv = ir.GlobalVariable(m, tp, "myconstant")
|
|
2861
|
+
c = gv.gep([ir.Constant(int32, x) for x in (0, 1)])
|
|
2862
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2863
|
+
self.assertEqual(str(c),
|
|
2864
|
+
'getelementptr ({float, i1}, ptr @"myconstant", i32 0, i32 1)') # noqa E501
|
|
2865
|
+
else:
|
|
2866
|
+
self.assertEqual(str(c),
|
|
2867
|
+
'getelementptr ({float, i1}, {float, i1}* @"myconstant", i32 0, i32 1)') # noqa E501
|
|
2868
|
+
self.assertEqual(c.type, ir.PointerType(int1))
|
|
2869
|
+
|
|
2870
|
+
const = ir.Constant(tp, None)
|
|
2871
|
+
with self.assertRaises(TypeError):
|
|
2872
|
+
const.gep([ir.Constant(int32, 0)])
|
|
2873
|
+
|
|
2874
|
+
const_ptr = ir.Constant(tp.as_pointer(), None)
|
|
2875
|
+
c2 = const_ptr.gep([ir.Constant(int32, 0)])
|
|
2876
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2877
|
+
self.assertEqual(str(c2),
|
|
2878
|
+
'getelementptr ({float, i1}, ptr null, i32 0)') # noqa E501
|
|
2879
|
+
else:
|
|
2880
|
+
self.assertEqual(str(c2),
|
|
2881
|
+
'getelementptr ({float, i1}, {float, i1}* null, i32 0)') # noqa E501
|
|
2882
|
+
self.assertEqual(c.type, ir.PointerType(int1))
|
|
2883
|
+
|
|
2884
|
+
def test_gep_addrspace_globalvar(self):
|
|
2885
|
+
m = self.module()
|
|
2886
|
+
tp = ir.LiteralStructType((flt, int1))
|
|
2887
|
+
addrspace = 4
|
|
2888
|
+
|
|
2889
|
+
gv = ir.GlobalVariable(m, tp, "myconstant", addrspace=addrspace)
|
|
2890
|
+
self.assertEqual(gv.addrspace, addrspace)
|
|
2891
|
+
c = gv.gep([ir.Constant(int32, x) for x in (0, 1)])
|
|
2892
|
+
self.assertEqual(c.type.addrspace, addrspace)
|
|
2893
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2894
|
+
self.assertEqual(str(c),
|
|
2895
|
+
('getelementptr ({float, i1}, ptr '
|
|
2896
|
+
'addrspace(4) @"myconstant", i32 0, i32 1)'))
|
|
2897
|
+
else:
|
|
2898
|
+
self.assertEqual(str(c),
|
|
2899
|
+
('getelementptr ({float, i1}, {float, i1} '
|
|
2900
|
+
'addrspace(4)* @"myconstant", i32 0, i32 1)'))
|
|
2901
|
+
self.assertEqual(c.type, ir.PointerType(int1, addrspace=addrspace))
|
|
2902
|
+
|
|
2903
|
+
def test_trunc(self):
|
|
2904
|
+
c = ir.Constant(int64, 1).trunc(int32)
|
|
2905
|
+
self.assertEqual(str(c), 'trunc (i64 1 to i32)')
|
|
2906
|
+
|
|
2907
|
+
def test_zext(self):
|
|
2908
|
+
c = ir.Constant(int32, 1).zext(int64)
|
|
2909
|
+
self.assertEqual(str(c), 'zext (i32 1 to i64)')
|
|
2910
|
+
|
|
2911
|
+
def test_sext(self):
|
|
2912
|
+
c = ir.Constant(int32, -1).sext(int64)
|
|
2913
|
+
self.assertEqual(str(c), 'sext (i32 -1 to i64)')
|
|
2914
|
+
|
|
2915
|
+
def test_fptrunc(self):
|
|
2916
|
+
c = ir.Constant(flt, 1).fptrunc(hlf)
|
|
2917
|
+
self.assertEqual(str(c), 'fptrunc (float 0x3ff0000000000000 to half)')
|
|
2918
|
+
|
|
2919
|
+
def test_fpext(self):
|
|
2920
|
+
c = ir.Constant(flt, 1).fpext(dbl)
|
|
2921
|
+
self.assertEqual(str(c), 'fpext (float 0x3ff0000000000000 to double)')
|
|
2922
|
+
|
|
2923
|
+
def test_bitcast(self):
|
|
2924
|
+
m = self.module()
|
|
2925
|
+
gv = ir.GlobalVariable(m, int32, "myconstant")
|
|
2926
|
+
c = gv.bitcast(int64.as_pointer())
|
|
2927
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2928
|
+
self.assertEqual(str(c), 'bitcast (ptr @"myconstant" to ptr)')
|
|
2929
|
+
else:
|
|
2930
|
+
self.assertEqual(str(c), 'bitcast (i32* @"myconstant" to i64*)')
|
|
2931
|
+
|
|
2932
|
+
def test_fptoui(self):
|
|
2933
|
+
c = ir.Constant(flt, 1).fptoui(int32)
|
|
2934
|
+
self.assertEqual(str(c), 'fptoui (float 0x3ff0000000000000 to i32)')
|
|
2935
|
+
|
|
2936
|
+
def test_uitofp(self):
|
|
2937
|
+
c = ir.Constant(int32, 1).uitofp(flt)
|
|
2938
|
+
self.assertEqual(str(c), 'uitofp (i32 1 to float)')
|
|
2939
|
+
|
|
2940
|
+
def test_fptosi(self):
|
|
2941
|
+
c = ir.Constant(flt, 1).fptosi(int32)
|
|
2942
|
+
self.assertEqual(str(c), 'fptosi (float 0x3ff0000000000000 to i32)')
|
|
2943
|
+
|
|
2944
|
+
def test_sitofp(self):
|
|
2945
|
+
c = ir.Constant(int32, 1).sitofp(flt)
|
|
2946
|
+
self.assertEqual(str(c), 'sitofp (i32 1 to float)')
|
|
2947
|
+
|
|
2948
|
+
def test_ptrtoint_1(self):
|
|
2949
|
+
ptr = ir.Constant(int64.as_pointer(), None)
|
|
2950
|
+
one = ir.Constant(int32, 1)
|
|
2951
|
+
c = ptr.ptrtoint(int32)
|
|
2952
|
+
|
|
2953
|
+
self.assertRaises(TypeError, one.ptrtoint, int64)
|
|
2954
|
+
self.assertRaises(TypeError, ptr.ptrtoint, flt)
|
|
2955
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2956
|
+
self.assertEqual(str(c), 'ptrtoint (ptr null to i32)')
|
|
2957
|
+
else:
|
|
2958
|
+
self.assertEqual(str(c), 'ptrtoint (i64* null to i32)')
|
|
2959
|
+
|
|
2960
|
+
def test_ptrtoint_2(self):
|
|
2961
|
+
m = self.module()
|
|
2962
|
+
gv = ir.GlobalVariable(m, int32, "myconstant")
|
|
2963
|
+
c = gv.ptrtoint(int64)
|
|
2964
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2965
|
+
self.assertEqual(str(c), 'ptrtoint (ptr @"myconstant" to i64)')
|
|
2966
|
+
|
|
2967
|
+
self.assertRaisesRegex(
|
|
2968
|
+
TypeError,
|
|
2969
|
+
r"can only ptrtoint\(\) to integer type, not 'ptr'",
|
|
2970
|
+
gv.ptrtoint,
|
|
2971
|
+
int64.as_pointer())
|
|
2972
|
+
else:
|
|
2973
|
+
self.assertEqual(str(c), 'ptrtoint (i32* @"myconstant" to i64)')
|
|
2974
|
+
|
|
2975
|
+
self.assertRaisesRegex(
|
|
2976
|
+
TypeError,
|
|
2977
|
+
r"can only ptrtoint\(\) to integer type, not 'i64\*'",
|
|
2978
|
+
gv.ptrtoint,
|
|
2979
|
+
int64.as_pointer())
|
|
2980
|
+
|
|
2981
|
+
c2 = ir.Constant(int32, 0)
|
|
2982
|
+
self.assertRaisesRegex(
|
|
2983
|
+
TypeError,
|
|
2984
|
+
r"can only call ptrtoint\(\) on pointer type, not 'i32'",
|
|
2985
|
+
c2.ptrtoint,
|
|
2986
|
+
int64)
|
|
2987
|
+
|
|
2988
|
+
def test_inttoptr(self):
|
|
2989
|
+
one = ir.Constant(int32, 1)
|
|
2990
|
+
pi = ir.Constant(flt, 3.14)
|
|
2991
|
+
c = one.inttoptr(int64.as_pointer())
|
|
2992
|
+
|
|
2993
|
+
self.assertRaises(TypeError, one.inttoptr, int64)
|
|
2994
|
+
self.assertRaises(TypeError, pi.inttoptr, int64.as_pointer())
|
|
2995
|
+
if not ir_layer_typed_pointers_enabled:
|
|
2996
|
+
self.assertEqual(str(c), 'inttoptr (i32 1 to ptr)')
|
|
2997
|
+
else:
|
|
2998
|
+
self.assertEqual(str(c), 'inttoptr (i32 1 to i64*)')
|
|
2999
|
+
|
|
3000
|
+
def test_neg(self):
|
|
3001
|
+
one = ir.Constant(int32, 1)
|
|
3002
|
+
self.assertEqual(str(one.neg()), 'sub (i32 0, i32 1)')
|
|
3003
|
+
|
|
3004
|
+
def test_not(self):
|
|
3005
|
+
one = ir.Constant(int32, 1)
|
|
3006
|
+
self.assertEqual(str(one.not_()), 'xor (i32 1, i32 -1)')
|
|
3007
|
+
|
|
3008
|
+
def test_fneg(self):
|
|
3009
|
+
one = ir.Constant(flt, 1)
|
|
3010
|
+
self.assertEqual(str(one.fneg()), 'fneg (float 0x3ff0000000000000)')
|
|
3011
|
+
|
|
3012
|
+
def test_int_binops(self):
|
|
3013
|
+
one = ir.Constant(int32, 1)
|
|
3014
|
+
two = ir.Constant(int32, 2)
|
|
3015
|
+
|
|
3016
|
+
oracle = {one.shl: 'shl', one.lshr: 'lshr', one.ashr: 'ashr',
|
|
3017
|
+
one.add: 'add', one.sub: 'sub', one.mul: 'mul',
|
|
3018
|
+
one.udiv: 'udiv', one.sdiv: 'sdiv', one.urem: 'urem',
|
|
3019
|
+
one.srem: 'srem', one.or_: 'or', one.and_: 'and',
|
|
3020
|
+
one.xor: 'xor'}
|
|
3021
|
+
for fn, irop in oracle.items():
|
|
3022
|
+
self.assertEqual(str(fn(two)), irop + ' (i32 1, i32 2)')
|
|
3023
|
+
|
|
3024
|
+
# unsigned integer compare
|
|
3025
|
+
oracle = {'==': 'eq', '!=': 'ne', '>':
|
|
3026
|
+
'ugt', '>=': 'uge', '<': 'ult', '<=': 'ule'}
|
|
3027
|
+
for cop, cond in oracle.items():
|
|
3028
|
+
actual = str(one.icmp_unsigned(cop, two))
|
|
3029
|
+
expected = 'icmp ' + cond + ' (i32 1, i32 2)'
|
|
3030
|
+
self.assertEqual(actual, expected)
|
|
3031
|
+
|
|
3032
|
+
# signed integer compare
|
|
3033
|
+
oracle = {'==': 'eq', '!=': 'ne',
|
|
3034
|
+
'>': 'sgt', '>=': 'sge', '<': 'slt', '<=': 'sle'}
|
|
3035
|
+
for cop, cond in oracle.items():
|
|
3036
|
+
actual = str(one.icmp_signed(cop, two))
|
|
3037
|
+
expected = 'icmp ' + cond + ' (i32 1, i32 2)'
|
|
3038
|
+
self.assertEqual(actual, expected)
|
|
3039
|
+
|
|
3040
|
+
def test_flt_binops(self):
|
|
3041
|
+
one = ir.Constant(flt, 1)
|
|
3042
|
+
two = ir.Constant(flt, 2)
|
|
3043
|
+
|
|
3044
|
+
oracle = {one.fadd: 'fadd', one.fsub: 'fsub', one.fmul: 'fmul',
|
|
3045
|
+
one.fdiv: 'fdiv', one.frem: 'frem'}
|
|
3046
|
+
for fn, irop in oracle.items():
|
|
3047
|
+
actual = str(fn(two))
|
|
3048
|
+
expected = irop + (' (float 0x3ff0000000000000,'
|
|
3049
|
+
' float 0x4000000000000000)')
|
|
3050
|
+
self.assertEqual(actual, expected)
|
|
3051
|
+
|
|
3052
|
+
# ordered float compare
|
|
3053
|
+
oracle = {'==': 'oeq', '!=': 'one', '>': 'ogt', '>=': 'oge',
|
|
3054
|
+
'<': 'olt', '<=': 'ole'}
|
|
3055
|
+
for cop, cond in oracle.items():
|
|
3056
|
+
actual = str(one.fcmp_ordered(cop, two))
|
|
3057
|
+
expected = 'fcmp ' + cond + (' (float 0x3ff0000000000000,'
|
|
3058
|
+
' float 0x4000000000000000)')
|
|
3059
|
+
self.assertEqual(actual, expected)
|
|
3060
|
+
|
|
3061
|
+
# unordered float compare
|
|
3062
|
+
oracle = {'==': 'ueq', '!=': 'une', '>': 'ugt', '>=': 'uge',
|
|
3063
|
+
'<': 'ult', '<=': 'ule'}
|
|
3064
|
+
for cop, cond in oracle.items():
|
|
3065
|
+
actual = str(one.fcmp_unordered(cop, two))
|
|
3066
|
+
expected = 'fcmp ' + cond + (' (float 0x3ff0000000000000,'
|
|
3067
|
+
' float 0x4000000000000000)')
|
|
3068
|
+
self.assertEqual(actual, expected)
|
|
3069
|
+
|
|
3070
|
+
|
|
3071
|
+
class TestTransforms(TestBase):
|
|
3072
|
+
def test_call_transform(self):
|
|
3073
|
+
mod = ir.Module()
|
|
3074
|
+
foo = ir.Function(mod, ir.FunctionType(ir.VoidType(), ()), "foo")
|
|
3075
|
+
bar = ir.Function(mod, ir.FunctionType(ir.VoidType(), ()), "bar")
|
|
3076
|
+
builder = ir.IRBuilder()
|
|
3077
|
+
builder.position_at_end(foo.append_basic_block())
|
|
3078
|
+
call = builder.call(foo, ())
|
|
3079
|
+
self.assertEqual(call.callee, foo)
|
|
3080
|
+
modified = ir.replace_all_calls(mod, foo, bar)
|
|
3081
|
+
self.assertIn(call, modified)
|
|
3082
|
+
self.assertNotEqual(call.callee, foo)
|
|
3083
|
+
self.assertEqual(call.callee, bar)
|
|
3084
|
+
|
|
3085
|
+
|
|
3086
|
+
class TestSingleton(TestBase):
|
|
3087
|
+
def test_undefined(self):
|
|
3088
|
+
self.assertIs(ir.Undefined, ir.values._Undefined())
|
|
3089
|
+
self.assertIs(ir.Undefined, copy.copy(ir.Undefined))
|
|
3090
|
+
self.assertIs(ir.Undefined, copy.deepcopy(ir.Undefined))
|
|
3091
|
+
self.assert_pickle_correctly(ir.Undefined)
|
|
3092
|
+
|
|
3093
|
+
|
|
3094
|
+
if __name__ == '__main__':
|
|
3095
|
+
unittest.main()
|