llvmlite 0.44.0__cp311-cp311-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.

Files changed (46) hide show
  1. llvmlite/__init__.py +10 -0
  2. llvmlite/_version.py +11 -0
  3. llvmlite/binding/__init__.py +19 -0
  4. llvmlite/binding/analysis.py +69 -0
  5. llvmlite/binding/common.py +34 -0
  6. llvmlite/binding/context.py +39 -0
  7. llvmlite/binding/dylib.py +45 -0
  8. llvmlite/binding/executionengine.py +330 -0
  9. llvmlite/binding/ffi.py +395 -0
  10. llvmlite/binding/initfini.py +73 -0
  11. llvmlite/binding/libllvmlite.so +0 -0
  12. llvmlite/binding/linker.py +20 -0
  13. llvmlite/binding/module.py +349 -0
  14. llvmlite/binding/newpassmanagers.py +357 -0
  15. llvmlite/binding/object_file.py +82 -0
  16. llvmlite/binding/options.py +17 -0
  17. llvmlite/binding/orcjit.py +342 -0
  18. llvmlite/binding/passmanagers.py +946 -0
  19. llvmlite/binding/targets.py +520 -0
  20. llvmlite/binding/transforms.py +151 -0
  21. llvmlite/binding/typeref.py +285 -0
  22. llvmlite/binding/value.py +632 -0
  23. llvmlite/ir/__init__.py +11 -0
  24. llvmlite/ir/_utils.py +80 -0
  25. llvmlite/ir/builder.py +1120 -0
  26. llvmlite/ir/context.py +20 -0
  27. llvmlite/ir/instructions.py +920 -0
  28. llvmlite/ir/module.py +246 -0
  29. llvmlite/ir/transforms.py +64 -0
  30. llvmlite/ir/types.py +734 -0
  31. llvmlite/ir/values.py +1217 -0
  32. llvmlite/tests/__init__.py +57 -0
  33. llvmlite/tests/__main__.py +3 -0
  34. llvmlite/tests/customize.py +407 -0
  35. llvmlite/tests/refprune_proto.py +329 -0
  36. llvmlite/tests/test_binding.py +3208 -0
  37. llvmlite/tests/test_ir.py +2994 -0
  38. llvmlite/tests/test_refprune.py +730 -0
  39. llvmlite/tests/test_valuerepr.py +60 -0
  40. llvmlite/utils.py +29 -0
  41. llvmlite-0.44.0.dist-info/LICENSE +24 -0
  42. llvmlite-0.44.0.dist-info/LICENSE.thirdparty +225 -0
  43. llvmlite-0.44.0.dist-info/METADATA +138 -0
  44. llvmlite-0.44.0.dist-info/RECORD +46 -0
  45. llvmlite-0.44.0.dist-info/WHEEL +6 -0
  46. llvmlite-0.44.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3208 @@
1
+ import ctypes
2
+ import threading
3
+ from ctypes import CFUNCTYPE, c_int, c_int32
4
+ from ctypes.util import find_library
5
+ import gc
6
+ import locale
7
+ import os
8
+ import platform
9
+ import re
10
+ import subprocess
11
+ import sys
12
+ import unittest
13
+ from contextlib import contextmanager
14
+ from tempfile import mkstemp
15
+
16
+ from llvmlite import ir
17
+ from llvmlite import binding as llvm
18
+ from llvmlite.binding import ffi
19
+ from llvmlite.tests import TestCase
20
+
21
+ # FIXME: Remove me once typed pointers are no longer supported.
22
+ from llvmlite import opaque_pointers_enabled
23
+
24
+ # arvm7l needs extra ABI symbols to link successfully
25
+ if platform.machine() == 'armv7l':
26
+ llvm.load_library_permanently('libgcc_s.so.1')
27
+
28
+
29
+ def no_de_locale():
30
+ cur = locale.setlocale(locale.LC_ALL)
31
+ try:
32
+ locale.setlocale(locale.LC_ALL, 'de_DE')
33
+ except locale.Error:
34
+ return True
35
+ else:
36
+ return False
37
+ finally:
38
+ locale.setlocale(locale.LC_ALL, cur)
39
+
40
+
41
+ asm_sum = r"""
42
+ ; ModuleID = '<string>'
43
+ source_filename = "asm_sum.c"
44
+ target triple = "{triple}"
45
+ %struct.glob_type = type {{ i64, [2 x i64]}}
46
+ %struct.glob_type_vec = type {{ i64, <2 x i64>}}
47
+
48
+ @glob = global i32 0
49
+ @glob_b = global i8 0
50
+ @glob_f = global float 1.5
51
+ @glob_struct = global %struct.glob_type {{i64 0, [2 x i64] [i64 0, i64 0]}}
52
+
53
+ define i32 @sum(i32 %.1, i32 %.2) {{
54
+ %.3 = add i32 %.1, %.2
55
+ %.4 = add i32 0, %.3
56
+ ret i32 %.4
57
+ }}
58
+ """
59
+
60
+ asm_sum2 = r"""
61
+ ; ModuleID = '<string>'
62
+ target triple = "{triple}"
63
+
64
+ define i32 @sum(i32 %.1, i32 %.2) {{
65
+ %.3 = add i32 %.1, %.2
66
+ ret i32 %.3
67
+ }}
68
+ """
69
+
70
+ asm_sum3 = r"""
71
+ ; ModuleID = '<string>'
72
+ target triple = "{triple}"
73
+
74
+ define i64 @sum(i64 %.1, i64 %.2) {{
75
+ %.3 = add i64 %.1, %.2
76
+ %.4 = add i64 5, %.3
77
+ %.5 = add i64 -5, %.4
78
+ ret i64 %.5
79
+ }}
80
+ """
81
+
82
+ asm_sum4 = r"""
83
+ ; ModuleID = '<string>'
84
+ target triple = "{triple}"
85
+
86
+ define i32 @sum(i32 %.1, i32 %.2) {{
87
+ %.3 = add i32 %.1, %.2
88
+ ret i32 0
89
+ }}
90
+ """
91
+
92
+ asm_mul = r"""
93
+ ; ModuleID = '<string>'
94
+ target triple = "{triple}"
95
+ @mul_glob = global i32 0
96
+
97
+ define i32 @mul(i32 %.1, i32 %.2) {{
98
+ %.3 = mul i32 %.1, %.2
99
+ ret i32 %.3
100
+ }}
101
+ """
102
+
103
+ asm_square_sum = r"""
104
+ ; ModuleID = '<string>'
105
+ target triple = "{triple}"
106
+ @mul_glob = global i32 0
107
+
108
+ declare i32 @sum(i32, i32)
109
+ define i32 @square_sum(i32 %.1, i32 %.2) {{
110
+ %.3 = call i32 @sum(i32 %.1, i32 %.2)
111
+ %.4 = mul i32 %.3, %.3
112
+ ret i32 %.4
113
+ }}
114
+ """
115
+
116
+ asm_getversion = r"""
117
+ ; ModuleID = '<string>'
118
+ target triple = "{triple}"
119
+
120
+ declare i8* @Py_GetVersion()
121
+
122
+ define void @getversion(i32 %.1, i32 %.2) {{
123
+ %1 = call i8* @Py_GetVersion()
124
+ ret void
125
+ }}
126
+ """
127
+
128
+ if platform.python_implementation() == 'PyPy':
129
+ asm_getversion = asm_getversion.replace('Py_GetVersion', 'PyPy_GetVersion')
130
+
131
+ # `fadd` used on integer inputs
132
+ asm_parse_error = r"""
133
+ ; ModuleID = '<string>'
134
+ target triple = "{triple}"
135
+
136
+ define i32 @sum(i32 %.1, i32 %.2) {{
137
+ %.3 = fadd i32 %.1, %.2
138
+ ret i32 %.3
139
+ }}
140
+ """
141
+
142
+ # "%.bug" definition references itself
143
+ asm_verification_fail = r"""
144
+ ; ModuleID = '<string>'
145
+ target triple = "{triple}"
146
+
147
+ define void @sum() {{
148
+ %.bug = add i32 1, %.bug
149
+ ret void
150
+ }}
151
+ """
152
+
153
+ asm_sum_declare = r"""
154
+ ; ModuleID = '<string>'
155
+ target triple = "{triple}"
156
+
157
+ declare i32 @sum(i32 %.1, i32 %.2)
158
+ """
159
+
160
+ asm_vararg_declare = r"""
161
+ ; ModuleID = '<string>'
162
+ target triple = "{triple}"
163
+
164
+ declare i32 @vararg(i32 %.1, ...)
165
+ """
166
+
167
+ asm_double_inaccurate = r"""
168
+ ; ModuleID = '<string>'
169
+ target triple = "{triple}"
170
+
171
+ define void @foo() {{
172
+ %const = fadd fp128 0xLF3CB1CCF26FBC178452FB4EC7F91DEAD, 0xL00000000000000000000000000000001
173
+ ret void
174
+ }}
175
+ """ # noqa E501
176
+
177
+ asm_double_locale = r"""
178
+ ; ModuleID = '<string>'
179
+ target triple = "{triple}"
180
+
181
+ define void @foo() {{
182
+ %const = fadd double 0.0, 3.14
183
+ ret void
184
+ }}
185
+ """
186
+
187
+
188
+ asm_inlineasm = r"""
189
+ ; ModuleID = '<string>'
190
+ target triple = "{triple}"
191
+
192
+ define void @foo() {{
193
+ call void asm sideeffect "nop", ""()
194
+ ret void
195
+ }}
196
+ """
197
+
198
+ asm_inlineasm2 = """
199
+ ; ModuleID = '<string>'
200
+ target triple = "{triple}"
201
+
202
+ define void @inlineme() {{
203
+ ret void
204
+ }}
205
+
206
+ define i32 @caller(i32 %.1, i32 %.2) {{
207
+ entry:
208
+ %stack = alloca i32
209
+ store i32 %.1, i32* %stack
210
+ br label %main
211
+ main:
212
+ %loaded = load i32, i32* %stack
213
+ %.3 = add i32 %loaded, %.2
214
+ %.4 = add i32 0, %.3
215
+ call void @inlineme()
216
+ ret i32 %.4
217
+ }}
218
+ """
219
+
220
+ asm_inlineasm3 = """
221
+ ; ModuleID = 'test.c'
222
+ source_filename = "test.c"
223
+ target triple = "{triple}"
224
+
225
+ ; Function Attrs: noinline nounwind optnone ssp uwtable
226
+ define void @inlineme() noinline !dbg !15 {{
227
+ ret void, !dbg !18
228
+ }}
229
+
230
+ ; Function Attrs: noinline nounwind optnone ssp uwtable
231
+ define i32 @foo(i32 %0, i32 %1) !dbg !19 {{
232
+ %3 = alloca i32, align 4
233
+ %4 = alloca i32, align 4
234
+ store i32 %0, i32* %3, align 4
235
+ call void @llvm.dbg.declare(metadata i32* %3, metadata !23, metadata !DIExpression()), !dbg !24
236
+ store i32 %1, i32* %4, align 4
237
+ call void @llvm.dbg.declare(metadata i32* %4, metadata !25, metadata !DIExpression()), !dbg !26
238
+ call void @inlineme(), !dbg !27
239
+ %5 = load i32, i32* %3, align 4, !dbg !28
240
+ %6 = load i32, i32* %4, align 4, !dbg !29
241
+ %7 = add nsw i32 %5, %6, !dbg !30
242
+ ret i32 %7, !dbg !31
243
+ }}
244
+
245
+ ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
246
+ declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
247
+
248
+ attributes #1 = {{ nofree nosync nounwind readnone speculatable willreturn }}
249
+
250
+ !llvm.module.flags = !{{!1, !2, !3, !4, !5, !6, !7, !8, !9, !10}}
251
+ !llvm.dbg.cu = !{{!11}}
252
+ !llvm.ident = !{{!14}}
253
+
254
+ !0 = !{{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 3]}}
255
+ !1 = !{{i32 7, !"Dwarf Version", i32 4}}
256
+ !2 = !{{i32 2, !"Debug Info Version", i32 3}}
257
+ !3 = !{{i32 1, !"wchar_size", i32 4}}
258
+ !4 = !{{i32 1, !"branch-target-enforcement", i32 0}}
259
+ !5 = !{{i32 1, !"sign-return-address", i32 0}}
260
+ !6 = !{{i32 1, !"sign-return-address-all", i32 0}}
261
+ !7 = !{{i32 1, !"sign-return-address-with-bkey", i32 0}}
262
+ !8 = !{{i32 7, !"PIC Level", i32 2}}
263
+ !9 = !{{i32 7, !"uwtable", i32 1}}
264
+ !10 = !{{i32 7, !"frame-pointer", i32 1}}
265
+ !11 = distinct !DICompileUnit(language: DW_LANG_C99, file: !12, producer: "Apple clang version 13.1.6 (clang-1316.0.21.2.3)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !13, splitDebugInlining: false, nameTableKind: None, sysroot: "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk", sdk: "MacOSX.sdk")
266
+ !12 = !DIFile(filename: "test.c", directory: "/")
267
+ !13 = !{{}}
268
+ !14 = !{{!"Apple clang version 13.1.6 (clang-1316.0.21.2.3)"}}
269
+ !15 = distinct !DISubprogram(name: "inlineme", scope: !12, file: !12, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !11, retainedNodes: !13)
270
+ !16 = !DISubroutineType(types: !17)
271
+ !17 = !{{null}}
272
+ !18 = !DILocation(line: 1, column: 22, scope: !15)
273
+ !19 = distinct !DISubprogram(name: "foo", scope: !12, file: !12, line: 3, type: !20, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !11, retainedNodes: !13)
274
+ !20 = !DISubroutineType(types: !21)
275
+ !21 = !{{!22, !22, !22}}
276
+ !22 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
277
+ !23 = !DILocalVariable(name: "a", arg: 1, scope: !19, file: !12, line: 3, type: !22)
278
+ !24 = !DILocation(line: 3, column: 13, scope: !19)
279
+ !25 = !DILocalVariable(name: "b", arg: 2, scope: !19, file: !12, line: 3, type: !22)
280
+ !26 = !DILocation(line: 3, column: 20, scope: !19)
281
+ !27 = !DILocation(line: 4, column: 5, scope: !19)
282
+ !28 = !DILocation(line: 5, column: 12, scope: !19)
283
+ !29 = !DILocation(line: 5, column: 16, scope: !19)
284
+ !30 = !DILocation(line: 5, column: 14, scope: !19)
285
+ !31 = !DILocation(line: 5, column: 5, scope: !19)
286
+ """ # noqa E501
287
+
288
+ licm_asm = r"""
289
+ ; ModuleID = "<string>"
290
+ target triple = "{triple}"
291
+
292
+ define double @licm(i32 %0) {{
293
+ %2 = alloca i32, align 4
294
+ %3 = alloca double, align 8
295
+ %4 = alloca i32, align 4
296
+ %5 = alloca double, align 8
297
+ store i32 %0, i32* %2, align 4
298
+ store double 0.000000e+00, double* %3, align 8
299
+ store i32 0, i32* %4, align 4
300
+ br label %6
301
+
302
+ 6: ; preds = %14, %1
303
+ %7 = load i32, i32* %4, align 4
304
+ %8 = load i32, i32* %2, align 4
305
+ %9 = icmp slt i32 %7, %8
306
+ br i1 %9, label %10, label %17
307
+
308
+ 10: ; preds = %6
309
+ store double 7.000000e+00, double* %5, align 8
310
+ %11 = load double, double* %5, align 8
311
+ %12 = load double, double* %3, align 8
312
+ %13 = fadd double %12, %11
313
+ store double %13, double* %3, align 8
314
+ br label %14
315
+
316
+ 14: ; preds = %10
317
+ %15 = load i32, i32* %4, align 4
318
+ %16 = add nsw i32 %15, 1
319
+ store i32 %16, i32* %4, align 4
320
+ br label %6
321
+
322
+ 17: ; preds = %6
323
+ %18 = load double, double* %3, align 8
324
+ ret double %18
325
+ }}
326
+ """ # noqa E501
327
+
328
+ asm_global_ctors = r"""
329
+ ; ModuleID = "<string>"
330
+ target triple = "{triple}"
331
+
332
+ @A = global i32 undef
333
+
334
+ define void @ctor_A()
335
+ {{
336
+ store i32 10, i32* @A
337
+ ret void
338
+ }}
339
+
340
+ define void @dtor_A()
341
+ {{
342
+ store i32 20, i32* @A
343
+ ret void
344
+ }}
345
+
346
+ define i32 @foo()
347
+ {{
348
+ %.2 = load i32, i32* @A
349
+ %.3 = add i32 %.2, 2
350
+ ret i32 %.3
351
+ }}
352
+
353
+ @llvm.global_ctors = appending global [1 x {{i32, void ()*, i8*}}] [{{i32, void ()*, i8*}} {{i32 0, void ()* @ctor_A, i8* null}}]
354
+ @llvm.global_dtors = appending global [1 x {{i32, void ()*, i8*}}] [{{i32, void ()*, i8*}} {{i32 0, void ()* @dtor_A, i8* null}}]
355
+ """ # noqa E501
356
+
357
+ asm_ext_ctors = r"""
358
+ ; ModuleID = "<string>"
359
+ target triple = "{triple}"
360
+
361
+ @A = external global i32
362
+
363
+ define void @ctor_A()
364
+ {{
365
+ store i32 10, i32* @A
366
+ ret void
367
+ }}
368
+
369
+ define void @dtor_A()
370
+ {{
371
+ store i32 20, i32* @A
372
+ ret void
373
+ }}
374
+
375
+ define i32 @foo()
376
+ {{
377
+ %.2 = load i32, i32* @A
378
+ %.3 = add i32 %.2, 2
379
+ ret i32 %.3
380
+ }}
381
+
382
+ @llvm.global_ctors = appending global [1 x {{i32, void ()*, i8*}}] [{{i32, void ()*, i8*}} {{i32 0, void ()* @ctor_A, i8* null}}]
383
+ @llvm.global_dtors = appending global [1 x {{i32, void ()*, i8*}}] [{{i32, void ()*, i8*}} {{i32 0, void ()* @dtor_A, i8* null}}]
384
+ """ # noqa E501
385
+
386
+
387
+ asm_nonalphanum_blocklabel = """; ModuleID = ""
388
+ target triple = "unknown-unknown-unknown"
389
+ target datalayout = ""
390
+
391
+ define i32 @"foo"()
392
+ {
393
+ "<>!*''#":
394
+ ret i32 12345
395
+ }
396
+ """ # noqa W291 # trailing space needed for match later
397
+
398
+
399
+ asm_null_constant = r"""
400
+ ; ModuleID = '<string>'
401
+ target triple = "{triple}"
402
+
403
+ define void @foo(i64* %.1) {{
404
+ ret void
405
+ }}
406
+
407
+ define void @bar() {{
408
+ call void @foo(i64* null)
409
+ ret void
410
+ }}
411
+ """
412
+
413
+
414
+ riscv_asm_ilp32 = [
415
+ 'addi\tsp, sp, -16',
416
+ 'sw\ta1, 8(sp)',
417
+ 'sw\ta2, 12(sp)',
418
+ 'fld\tft0, 8(sp)',
419
+ 'fmv.w.x\tft1, a0',
420
+ 'fcvt.d.s\tft1, ft1',
421
+ 'fadd.d\tft0, ft1, ft0',
422
+ 'fsd\tft0, 8(sp)',
423
+ 'lw\ta0, 8(sp)',
424
+ 'lw\ta1, 12(sp)',
425
+ 'addi\tsp, sp, 16',
426
+ 'ret'
427
+ ]
428
+
429
+
430
+ riscv_asm_ilp32f = [
431
+ 'addi\tsp, sp, -16',
432
+ 'sw\ta0, 8(sp)',
433
+ 'sw\ta1, 12(sp)',
434
+ 'fld\tft0, 8(sp)',
435
+ 'fcvt.d.s\tft1, fa0',
436
+ 'fadd.d\tft0, ft1, ft0',
437
+ 'fsd\tft0, 8(sp)',
438
+ 'lw\ta0, 8(sp)',
439
+ 'lw\ta1, 12(sp)',
440
+ 'addi\tsp, sp, 16',
441
+ 'ret'
442
+ ]
443
+
444
+
445
+ riscv_asm_ilp32d = [
446
+ 'fcvt.d.s\tft0, fa0',
447
+ 'fadd.d\tfa0, ft0, fa1',
448
+ 'ret'
449
+ ]
450
+
451
+
452
+ asm_attributes = r"""
453
+ declare void @a_readonly_func(i8 *) readonly
454
+
455
+ declare i8* @a_arg0_return_func(i8* returned, i32*)
456
+ """
457
+
458
+ asm_alloca_optnone = r"""
459
+ define double @foo(i32 %i, double %j) optnone noinline {
460
+ %I = alloca i32 ; <i32*> [#uses=4]
461
+ %J = alloca double ; <double*> [#uses=2]
462
+ store i32 %i, i32* %I
463
+ store double %j, double* %J
464
+ %t1 = load i32, i32* %I ; <i32> [#uses=1]
465
+ %t2 = add i32 %t1, 1 ; <i32> [#uses=1]
466
+ store i32 %t2, i32* %I
467
+ %t3 = load i32, i32* %I ; <i32> [#uses=1]
468
+ %t4 = sitofp i32 %t3 to double ; <double> [#uses=1]
469
+ %t5 = load double, double* %J ; <double> [#uses=1]
470
+ %t6 = fmul double %t4, %t5 ; <double> [#uses=1]
471
+ ret double %t6
472
+ }
473
+ """
474
+
475
+ asm_declaration = r"""
476
+ declare void @test_declare(i32* )
477
+ """
478
+
479
+ # This produces the following output from objdump:
480
+ #
481
+ # $ objdump -D 632.elf
482
+ #
483
+ # 632.elf: file format elf64-x86-64
484
+ #
485
+ #
486
+ # Disassembly of section .text:
487
+ #
488
+ # 0000000000000000 <__arybo>:
489
+ # 0: 48 c1 e2 20 shl $0x20,%rdx
490
+ # 4: 48 09 c2 or %rax,%rdx
491
+ # 7: 48 89 d0 mov %rdx,%rax
492
+ # a: 48 c1 c0 3d rol $0x3d,%rax
493
+ # e: 48 31 d0 xor %rdx,%rax
494
+ # 11: 48 b9 01 20 00 04 80 movabs $0x7010008004002001,%rcx
495
+ # 18: 00 10 70
496
+ # 1b: 48 0f af c8 imul %rax,%rcx
497
+
498
+ issue_632_elf = \
499
+ "7f454c4602010100000000000000000001003e00010000000000000000000000000000" \
500
+ "0000000000e0000000000000000000000040000000000040000500010048c1e2204809" \
501
+ "c24889d048c1c03d4831d048b90120000480001070480fafc800000000000000000000" \
502
+ "0000000000000000000000000000002f0000000400f1ff000000000000000000000000" \
503
+ "00000000070000001200020000000000000000001f00000000000000002e7465787400" \
504
+ "5f5f617279626f002e6e6f74652e474e552d737461636b002e737472746162002e7379" \
505
+ "6d746162003c737472696e673e00000000000000000000000000000000000000000000" \
506
+ "0000000000000000000000000000000000000000000000000000000000000000000000" \
507
+ "00000000000000001f0000000300000000000000000000000000000000000000a80000" \
508
+ "0000000000380000000000000000000000000000000100000000000000000000000000" \
509
+ "000001000000010000000600000000000000000000000000000040000000000000001f" \
510
+ "000000000000000000000000000000100000000000000000000000000000000f000000" \
511
+ "01000000000000000000000000000000000000005f0000000000000000000000000000" \
512
+ "0000000000000000000100000000000000000000000000000027000000020000000000" \
513
+ "0000000000000000000000000000600000000000000048000000000000000100000002" \
514
+ "00000008000000000000001800000000000000"
515
+
516
+
517
+ issue_632_text = \
518
+ "48c1e2204809c24889d048c1c03d4831d048b90120000480001070480fafc8"
519
+
520
+
521
+ asm_tli_exp2 = r"""
522
+ ; ModuleID = '<lambda>'
523
+ source_filename = "<string>"
524
+ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
525
+ target triple = "x86_64-pc-windows-msvc"
526
+
527
+ declare float @llvm.exp2.f32(float %casted)
528
+
529
+ define float @foo(i16 %arg) {
530
+ entry:
531
+ %casted = sitofp i16 %arg to float
532
+ %ret = call float @llvm.exp2.f32(float %casted)
533
+ ret float %ret
534
+ }
535
+ """ # noqa E501
536
+
537
+ asm_phi_blocks = r"""
538
+ ; ModuleID = '<string>'
539
+ target triple = "{triple}"
540
+
541
+ define void @foo(i32 %N) {{
542
+ ; unnamed block for testing
543
+ %cmp4 = icmp sgt i32 %N, 0
544
+ br i1 %cmp4, label %for.body, label %for.cond.cleanup
545
+
546
+ for.cond.cleanup:
547
+ ret void
548
+
549
+ for.body:
550
+ %i.05 = phi i32 [ %inc, %for.body ], [ 0, %0 ]
551
+ %inc = add nuw nsw i32 %i.05, 1
552
+ %exitcond.not = icmp eq i32 %inc, %N
553
+ br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
554
+ }}
555
+ """
556
+
557
+ asm_cpp_class = r"""
558
+ ; Source C++
559
+ ;-----------------------------------------
560
+ ; class MyClass;
561
+ ;
562
+ ; class MyClassDefined{
563
+ ; MyClass *member;
564
+ ; MyClass *m2;
565
+ ; MyClass *m3;
566
+ ; };
567
+ ;
568
+ ; void foo(MyClass *c, MyClassDefined){ }
569
+ ;-----------------------------------------
570
+ ; LLVM-IR by: clang -arch arm64 -S -emit-llvm file.cpp
571
+ ; ModuleID = 'file.cpp'
572
+ source_filename = "class.cpp"
573
+ target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
574
+ target triple = "arm64-apple-macosx13.3.0"
575
+
576
+ %class.MyClass = type opaque
577
+ %class.MyClassDefined = type { %class.MyClass*, %class.MyClass*, %class.MyClass* }
578
+
579
+ ; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
580
+ define void @_Z3fooP7MyClass14MyClassDefined(%class.MyClass* noundef %0, %class.MyClassDefined* noundef %1) {
581
+ %3 = alloca %class.MyClass*, align 8
582
+ store %class.MyClass* %0, %class.MyClass** %3, align 8
583
+ ret void
584
+ }
585
+
586
+ !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
587
+ !llvm.ident = !{!9}
588
+
589
+ !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 3]}
590
+ !1 = !{i32 1, !"wchar_size", i32 4}
591
+ !2 = !{i32 8, !"branch-target-enforcement", i32 0}
592
+ !3 = !{i32 8, !"sign-return-address", i32 0}
593
+ !4 = !{i32 8, !"sign-return-address-all", i32 0}
594
+ !5 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
595
+ !6 = !{i32 7, !"PIC Level", i32 2}
596
+ !7 = !{i32 7, !"uwtable", i32 1}
597
+ !8 = !{i32 7, !"frame-pointer", i32 1}
598
+ !9 = !{!"Apple clang version 14.0.3 (clang-1403.0.22.14.1)"}
599
+
600
+ """ # noqa
601
+
602
+ asm_cpp_vector = r"""; Source C++
603
+ ;-----------------------------------------
604
+
605
+ ; struct Vector2D{
606
+ ; float x, y;
607
+ ; };
608
+ ;
609
+ ; void foo(Vector2D vec, Vector2D *out) {
610
+ ; *out = vec;
611
+ ; }
612
+ ;-----------------------------------------
613
+ ; LLVM-IR by: clang -arch x86_64 -S -emit-llvm file.cpp
614
+ ; ModuleID = 'file.cpp'
615
+ source_filename = "class.cpp"
616
+ target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
617
+ target triple = "x86_64-apple-macosx13.3.0"
618
+
619
+ %struct.Vector2D = type { float, float }
620
+
621
+ ; Function Attrs: noinline nounwind optnone ssp uwtable
622
+ define void @_Z3foo8Vector2DPS_(<2 x float> %0, %struct.Vector2D* noundef %1) #0 {
623
+ %3 = alloca %struct.Vector2D, align 4
624
+ %4 = alloca %struct.Vector2D*, align 8
625
+ %5 = bitcast %struct.Vector2D* %3 to <2 x float>*
626
+ store <2 x float> %0, <2 x float>* %5, align 4
627
+ store %struct.Vector2D* %1, %struct.Vector2D** %4, align 8
628
+ %6 = load %struct.Vector2D*, %struct.Vector2D** %4, align 8
629
+ %7 = bitcast %struct.Vector2D* %6 to i8*
630
+ %8 = bitcast %struct.Vector2D* %3 to i8*
631
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %8, i64 8, i1 false)
632
+ ret void
633
+ }
634
+
635
+ ; Function Attrs: argmemonly nofree nounwind willreturn
636
+ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
637
+
638
+ attributes #0 = { noinline nounwind optnone ssp uwtable "darwin-stkchk-strong-link" "frame-pointer"="all" "min-legal-vector-width"="64" "no-trapping-math"="true" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
639
+ attributes #1 = { argmemonly nofree nounwind willreturn }
640
+
641
+ !llvm.module.flags = !{!0, !1, !2, !3, !4}
642
+ !llvm.ident = !{!5}
643
+
644
+ !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 3]}
645
+ !1 = !{i32 1, !"wchar_size", i32 4}
646
+ !2 = !{i32 7, !"PIC Level", i32 2}
647
+ !3 = !{i32 7, !"uwtable", i32 2}
648
+ !4 = !{i32 7, !"frame-pointer", i32 2}
649
+ !5 = !{!"Apple clang version 14.0.3 (clang-1403.0.22.14.1)"}
650
+
651
+ """ # noqa
652
+
653
+
654
+ class BaseTest(TestCase):
655
+
656
+ def setUp(self):
657
+ llvm.initialize()
658
+ llvm.initialize_native_target()
659
+ llvm.initialize_native_asmprinter()
660
+ gc.collect()
661
+ self.old_garbage = gc.garbage[:]
662
+ gc.garbage[:] = []
663
+
664
+ def tearDown(self):
665
+ # Test that no uncollectable objects were created
666
+ # (llvmlite objects have a __del__ so a reference cycle could
667
+ # create some).
668
+ gc.collect()
669
+ self.assertEqual(gc.garbage, [])
670
+ # This will probably put any existing garbage in gc.garbage again
671
+ del self.old_garbage
672
+
673
+ def module(self, asm=asm_sum, context=None):
674
+ asm = asm.format(triple=llvm.get_default_triple())
675
+ mod = llvm.parse_assembly(asm, context)
676
+ return mod
677
+
678
+ def glob(self, name='glob', mod=None):
679
+ if mod is None:
680
+ mod = self.module()
681
+ return mod.get_global_variable(name)
682
+
683
+ def target_machine(self, *, jit):
684
+ target = llvm.Target.from_default_triple()
685
+ return target.create_target_machine(jit=jit)
686
+
687
+
688
+ class TestDependencies(BaseTest):
689
+ """
690
+ Test DLL dependencies are within a certain expected set.
691
+ """
692
+
693
+ @unittest.skipUnless(sys.platform.startswith('linux'),
694
+ "Linux-specific test")
695
+ @unittest.skipUnless(os.environ.get('LLVMLITE_DIST_TEST'),
696
+ "Distribution-specific test")
697
+ def test_linux(self):
698
+ lib_path = ffi.lib._name
699
+ env = os.environ.copy()
700
+ env['LANG'] = 'C'
701
+ p = subprocess.Popen(["objdump", "-p", lib_path],
702
+ stdout=subprocess.PIPE, env=env)
703
+ out, _ = p.communicate()
704
+ self.assertEqual(0, p.returncode)
705
+ # Parse library dependencies
706
+ lib_pat = re.compile(r'^([+-_a-zA-Z0-9]+)\.so(?:\.\d+){0,3}$')
707
+ deps = set()
708
+ for line in out.decode().splitlines():
709
+ parts = line.split()
710
+ if parts and parts[0] == 'NEEDED':
711
+ dep = parts[1]
712
+ m = lib_pat.match(dep)
713
+ if len(parts) != 2 or not m:
714
+ self.fail("invalid NEEDED line: %r" % (line,))
715
+ deps.add(m.group(1))
716
+ # Sanity check that our dependencies were parsed ok
717
+ if 'libc' not in deps or 'libpthread' not in deps:
718
+ self.fail("failed parsing dependencies? got %r" % (deps,))
719
+ # Ensure all dependencies are expected
720
+ allowed = set(['librt', 'libdl', 'libpthread', 'libz', 'libm',
721
+ 'libgcc_s', 'libc', 'ld-linux', 'ld64'])
722
+ if platform.python_implementation() == 'PyPy':
723
+ allowed.add('libtinfo')
724
+
725
+ for dep in deps:
726
+ if not dep.startswith('ld-linux-') and dep not in allowed:
727
+ self.fail("unexpected dependency %r in %r" % (dep, deps))
728
+
729
+
730
+ class TestRISCVABI(BaseTest):
731
+ """
732
+ Test calling convention of floating point arguments of RISC-V
733
+ using different ABI.
734
+ """
735
+ triple = "riscv32-unknown-linux"
736
+
737
+ def setUp(self):
738
+ super().setUp()
739
+ llvm.initialize_all_targets()
740
+ llvm.initialize_all_asmprinters()
741
+
742
+ def check_riscv_target(self):
743
+ try:
744
+ llvm.Target.from_triple(self.triple)
745
+ except RuntimeError as e:
746
+ if "No available targets are compatible with triple" in str(e):
747
+ self.skipTest("RISCV target unsupported by linked LLVM.")
748
+ else:
749
+ raise e
750
+
751
+ def riscv_target_machine(self, **kwarg):
752
+ lltarget = llvm.Target.from_triple(self.triple)
753
+ return lltarget.create_target_machine(**kwarg)
754
+
755
+ def fpadd_ll_module(self):
756
+ f64 = ir.DoubleType()
757
+ f32 = ir.FloatType()
758
+ fnty = ir.FunctionType(f64, (f32, f64))
759
+ module = ir.Module()
760
+ func = ir.Function(module, fnty, name="fpadd")
761
+ block = func.append_basic_block()
762
+ builder = ir.IRBuilder(block)
763
+ a, b = func.args
764
+ arg0 = builder.fpext(a, f64)
765
+ result = builder.fadd(arg0, b)
766
+ builder.ret(result)
767
+
768
+ llmod = llvm.parse_assembly(str(module))
769
+ llmod.verify()
770
+ return llmod
771
+
772
+ def break_up_asm(self, asm):
773
+ asm_list = []
774
+ for line in asm.splitlines():
775
+ s_line = line.strip()
776
+ if not (s_line.startswith(".") or s_line.startswith("fpadd")
777
+ or s_line == ""):
778
+ asm_list.append(s_line)
779
+ return asm_list
780
+
781
+ def test_rv32d_ilp32(self):
782
+ self.check_riscv_target()
783
+ llmod = self.fpadd_ll_module()
784
+ target = self.riscv_target_machine(features="+f,+d", abiname="ilp32")
785
+ self.assertEqual(self.break_up_asm(target.emit_assembly(llmod)),
786
+ riscv_asm_ilp32)
787
+
788
+ def test_rv32d_ilp32f(self):
789
+ self.check_riscv_target()
790
+ llmod = self.fpadd_ll_module()
791
+ target = self.riscv_target_machine(features="+f,+d", abiname="ilp32f")
792
+ self.assertEqual(self.break_up_asm(target.emit_assembly(llmod)),
793
+ riscv_asm_ilp32f)
794
+
795
+ def test_rv32d_ilp32d(self):
796
+ self.check_riscv_target()
797
+ llmod = self.fpadd_ll_module()
798
+ target = self.riscv_target_machine(features="+f,+d", abiname="ilp32d")
799
+ self.assertEqual(self.break_up_asm(target.emit_assembly(llmod)),
800
+ riscv_asm_ilp32d)
801
+
802
+
803
+ class TestMisc(BaseTest):
804
+ """
805
+ Test miscellaneous functions in llvm.binding.
806
+ """
807
+
808
+ def test_parse_assembly(self):
809
+ self.module(asm_sum)
810
+
811
+ def test_parse_assembly_error(self):
812
+ with self.assertRaises(RuntimeError) as cm:
813
+ self.module(asm_parse_error)
814
+ s = str(cm.exception)
815
+ self.assertIn("parsing error", s)
816
+ self.assertIn("invalid operand type", s)
817
+
818
+ def test_nonalphanum_block_name(self):
819
+ mod = ir.Module()
820
+ ft = ir.FunctionType(ir.IntType(32), [])
821
+ fn = ir.Function(mod, ft, "foo")
822
+ bd = ir.IRBuilder(fn.append_basic_block(name="<>!*''#"))
823
+ bd.ret(ir.Constant(ir.IntType(32), 12345))
824
+ asm = str(mod)
825
+ self.assertEqual(asm, asm_nonalphanum_blocklabel)
826
+
827
+ def test_global_context(self):
828
+ gcontext1 = llvm.context.get_global_context()
829
+ gcontext2 = llvm.context.get_global_context()
830
+ assert gcontext1 == gcontext2
831
+
832
+ def test_dylib_symbols(self):
833
+ llvm.add_symbol("__xyzzy", 1234)
834
+ llvm.add_symbol("__xyzzy", 5678)
835
+ addr = llvm.address_of_symbol("__xyzzy")
836
+ self.assertEqual(addr, 5678)
837
+ addr = llvm.address_of_symbol("__foobar")
838
+ self.assertIs(addr, None)
839
+
840
+ def test_get_default_triple(self):
841
+ triple = llvm.get_default_triple()
842
+ self.assertIsInstance(triple, str)
843
+ self.assertTrue(triple)
844
+
845
+ def test_get_process_triple(self):
846
+ # Sometimes we get synonyms for PPC
847
+ def normalize_ppc(arch):
848
+ if arch == 'powerpc64le':
849
+ return 'ppc64le'
850
+ else:
851
+ return arch
852
+
853
+ triple = llvm.get_process_triple()
854
+ default = llvm.get_default_triple()
855
+ self.assertIsInstance(triple, str)
856
+ self.assertTrue(triple)
857
+
858
+ default_arch = normalize_ppc(default.split('-')[0])
859
+ triple_arch = normalize_ppc(triple.split('-')[0])
860
+ # Arch must be equal
861
+ self.assertEqual(default_arch, triple_arch)
862
+
863
+ def test_get_host_cpu_features(self):
864
+ features = llvm.get_host_cpu_features()
865
+ # Check the content of `features`
866
+ self.assertIsInstance(features, dict)
867
+ self.assertIsInstance(features, llvm.FeatureMap)
868
+ for k, v in features.items():
869
+ self.assertIsInstance(k, str)
870
+ self.assertTrue(k) # single feature string cannot be empty
871
+ self.assertIsInstance(v, bool)
872
+ self.assertIsInstance(features.flatten(), str)
873
+
874
+ re_term = r"[+\-][a-zA-Z0-9\._-]+"
875
+ regex = r"^({0}|{0}(,{0})*)?$".format(re_term)
876
+ # quick check for our regex
877
+ self.assertIsNotNone(re.match(regex, ""))
878
+ self.assertIsNotNone(re.match(regex, "+aa"))
879
+ self.assertIsNotNone(re.match(regex, "+a,-bb"))
880
+ # check CpuFeature.flatten()
881
+ if len(features) == 0:
882
+ self.assertEqual(features.flatten(), "")
883
+ else:
884
+ self.assertIsNotNone(re.match(regex, features.flatten()))
885
+
886
+ def test_get_host_cpu_name(self):
887
+ cpu = llvm.get_host_cpu_name()
888
+ self.assertIsInstance(cpu, str)
889
+ self.assertTrue(cpu)
890
+
891
+ def test_initfini(self):
892
+ code = """if 1:
893
+ from llvmlite import binding as llvm
894
+
895
+ llvm.initialize()
896
+ llvm.initialize_native_target()
897
+ llvm.initialize_native_asmprinter()
898
+ llvm.initialize_all_targets()
899
+ llvm.initialize_all_asmprinters()
900
+ llvm.shutdown()
901
+ """
902
+ subprocess.check_call([sys.executable, "-c", code])
903
+
904
+ def test_set_option(self):
905
+ # We cannot set an option multiple times (LLVM would exit() the
906
+ # process), so run the code in a subprocess.
907
+ code = """if 1:
908
+ from llvmlite import binding as llvm
909
+
910
+ llvm.set_option("progname", "-debug-pass=Disabled")
911
+ """
912
+ subprocess.check_call([sys.executable, "-c", code])
913
+
914
+ def test_version(self):
915
+ major, minor, patch = llvm.llvm_version_info
916
+ # one of these can be valid
917
+ valid = (15, 16)
918
+ self.assertIn(major, valid)
919
+ self.assertIn(patch, range(8))
920
+
921
+ def test_check_jit_execution(self):
922
+ llvm.check_jit_execution()
923
+
924
+ @unittest.skipIf(no_de_locale(), "Locale not available")
925
+ def test_print_double_locale(self):
926
+ m = self.module(asm_double_locale)
927
+ expect = str(m)
928
+ # Change the locale so that comma is used as decimal-point
929
+ # to trigger the LLVM bug (llvmlite issue #80)
930
+ locale.setlocale(locale.LC_ALL, 'de_DE')
931
+ # The LLVM bug is trigged by print the module with double constant
932
+ got = str(m)
933
+ # Changing the locale should not affect the LLVM IR
934
+ self.assertEqual(expect, got)
935
+
936
+ def test_no_accidental_warnings(self):
937
+ code = "from llvmlite import binding"
938
+ flags = "-Werror"
939
+ cmdargs = [sys.executable, flags, "-c", code]
940
+ subprocess.check_call(cmdargs)
941
+
942
+
943
+ class TestModuleRef(BaseTest):
944
+
945
+ def test_str(self):
946
+ mod = self.module()
947
+ s = str(mod).strip()
948
+ self.assertTrue(s.startswith('; ModuleID ='), s)
949
+
950
+ def test_close(self):
951
+ mod = self.module()
952
+ str(mod)
953
+ mod.close()
954
+ with self.assertRaises(ctypes.ArgumentError):
955
+ str(mod)
956
+ mod.close()
957
+
958
+ def test_with(self):
959
+ mod = self.module()
960
+ str(mod)
961
+ with mod:
962
+ str(mod)
963
+ with self.assertRaises(ctypes.ArgumentError):
964
+ str(mod)
965
+ with self.assertRaises(RuntimeError):
966
+ with mod:
967
+ pass
968
+
969
+ def test_name(self):
970
+ mod = self.module()
971
+ mod.name = "foo"
972
+ self.assertEqual(mod.name, "foo")
973
+ mod.name = "bar"
974
+ self.assertEqual(mod.name, "bar")
975
+
976
+ def test_source_file(self):
977
+ mod = self.module()
978
+ self.assertEqual(mod.source_file, "asm_sum.c")
979
+
980
+ def test_data_layout(self):
981
+ mod = self.module()
982
+ s = mod.data_layout
983
+ self.assertIsInstance(s, str)
984
+ mod.data_layout = s
985
+ self.assertEqual(s, mod.data_layout)
986
+
987
+ def test_triple(self):
988
+ mod = self.module()
989
+ s = mod.triple
990
+ self.assertEqual(s, llvm.get_default_triple())
991
+ mod.triple = ''
992
+ self.assertEqual(mod.triple, '')
993
+
994
+ def test_verify(self):
995
+ # Verify successful
996
+ mod = self.module()
997
+ self.assertIs(mod.verify(), None)
998
+ # Verify failed
999
+ mod = self.module(asm_verification_fail)
1000
+ with self.assertRaises(RuntimeError) as cm:
1001
+ mod.verify()
1002
+ s = str(cm.exception)
1003
+ self.assertIn("%.bug = add i32 1, %.bug", s)
1004
+
1005
+ def test_get_function(self):
1006
+ mod = self.module()
1007
+ fn = mod.get_function("sum")
1008
+ self.assertIsInstance(fn, llvm.ValueRef)
1009
+ self.assertEqual(fn.name, "sum")
1010
+
1011
+ with self.assertRaises(NameError):
1012
+ mod.get_function("foo")
1013
+
1014
+ # Check that fn keeps the module instance alive
1015
+ del mod
1016
+ str(fn.module)
1017
+
1018
+ def test_get_struct_type(self):
1019
+ mod = self.module()
1020
+ st_ty = mod.get_struct_type("struct.glob_type")
1021
+ self.assertEqual(st_ty.name, "struct.glob_type")
1022
+ # also match struct names of form "%struct.glob_type.{some_index}"
1023
+ self.assertIsNotNone(re.match(
1024
+ r'%struct\.glob_type(\.[\d]+)? = type { i64, \[2 x i64\] }',
1025
+ str(st_ty)))
1026
+
1027
+ with self.assertRaises(NameError):
1028
+ mod.get_struct_type("struct.doesnt_exist")
1029
+
1030
+ def test_get_global_variable(self):
1031
+ mod = self.module()
1032
+ gv = mod.get_global_variable("glob")
1033
+ self.assertIsInstance(gv, llvm.ValueRef)
1034
+ self.assertEqual(gv.name, "glob")
1035
+
1036
+ with self.assertRaises(NameError):
1037
+ mod.get_global_variable("bar")
1038
+
1039
+ # Check that gv keeps the module instance alive
1040
+ del mod
1041
+ str(gv.module)
1042
+
1043
+ def test_global_variables(self):
1044
+ mod = self.module()
1045
+ it = mod.global_variables
1046
+ del mod
1047
+ globs = sorted(it, key=lambda value: value.name)
1048
+ self.assertEqual(len(globs), 4)
1049
+ self.assertEqual([g.name for g in globs],
1050
+ ["glob", "glob_b", "glob_f", "glob_struct"])
1051
+
1052
+ def test_functions(self):
1053
+ mod = self.module()
1054
+ it = mod.functions
1055
+ del mod
1056
+ funcs = list(it)
1057
+ self.assertEqual(len(funcs), 1)
1058
+ self.assertEqual(funcs[0].name, "sum")
1059
+
1060
+ def test_structs(self):
1061
+ mod = self.module()
1062
+ it = mod.struct_types
1063
+ del mod
1064
+ structs = list(it)
1065
+ self.assertEqual(len(structs), 1)
1066
+ self.assertIsNotNone(re.match(r'struct\.glob_type(\.[\d]+)?',
1067
+ structs[0].name))
1068
+ self.assertIsNotNone(re.match(
1069
+ r'%struct\.glob_type(\.[\d]+)? = type { i64, \[2 x i64\] }',
1070
+ str(structs[0])))
1071
+
1072
+ def test_link_in(self):
1073
+ dest = self.module()
1074
+ src = self.module(asm_mul)
1075
+ dest.link_in(src)
1076
+ self.assertEqual(
1077
+ sorted(f.name for f in dest.functions), ["mul", "sum"])
1078
+ dest.get_function("mul")
1079
+ dest.close()
1080
+ with self.assertRaises(ctypes.ArgumentError):
1081
+ src.get_function("mul")
1082
+
1083
+ def test_link_in_preserve(self):
1084
+ dest = self.module()
1085
+ src2 = self.module(asm_mul)
1086
+ dest.link_in(src2, preserve=True)
1087
+ self.assertEqual(
1088
+ sorted(f.name for f in dest.functions), ["mul", "sum"])
1089
+ dest.close()
1090
+ self.assertEqual(sorted(f.name for f in src2.functions), ["mul"])
1091
+ src2.get_function("mul")
1092
+
1093
+ def test_link_in_error(self):
1094
+ # Raise an error by trying to link two modules with the same global
1095
+ # definition "sum".
1096
+ dest = self.module()
1097
+ src = self.module(asm_sum2)
1098
+ with self.assertRaises(RuntimeError) as cm:
1099
+ dest.link_in(src)
1100
+ self.assertIn("symbol multiply defined", str(cm.exception))
1101
+
1102
+ def test_as_bitcode(self):
1103
+ mod = self.module()
1104
+ bc = mod.as_bitcode()
1105
+ # Refer to http://llvm.org/docs/doxygen/html/ReaderWriter_8h_source.html#l00064 # noqa E501
1106
+ # and http://llvm.org/docs/doxygen/html/ReaderWriter_8h_source.html#l00092 # noqa E501
1107
+ bitcode_wrapper_magic = b'\xde\xc0\x17\x0b'
1108
+ bitcode_magic = b'BC'
1109
+ self.assertTrue(bc.startswith(bitcode_magic) or
1110
+ bc.startswith(bitcode_wrapper_magic))
1111
+
1112
+ def test_parse_bitcode_error(self):
1113
+ with self.assertRaises(RuntimeError) as cm:
1114
+ llvm.parse_bitcode(b"")
1115
+ self.assertIn("LLVM bitcode parsing error", str(cm.exception))
1116
+ self.assertIn(
1117
+ "file too small to contain bitcode header", str(cm.exception),
1118
+ )
1119
+
1120
+ def test_bitcode_roundtrip(self):
1121
+ # create a new context to avoid struct renaming
1122
+ context1 = llvm.create_context()
1123
+ bc = self.module(context=context1).as_bitcode()
1124
+ context2 = llvm.create_context()
1125
+ mod = llvm.parse_bitcode(bc, context2)
1126
+ self.assertEqual(mod.as_bitcode(), bc)
1127
+
1128
+ mod.get_function("sum")
1129
+ mod.get_global_variable("glob")
1130
+
1131
+ def test_cloning(self):
1132
+ m = self.module()
1133
+ cloned = m.clone()
1134
+ self.assertIsNot(cloned, m)
1135
+ self.assertEqual(cloned.as_bitcode(), m.as_bitcode())
1136
+
1137
+
1138
+ class JITTestMixin(object):
1139
+ """
1140
+ Mixin for ExecutionEngine tests.
1141
+ """
1142
+
1143
+ def get_sum(self, ee, func_name="sum"):
1144
+ ee.finalize_object()
1145
+ cfptr = ee.get_function_address(func_name)
1146
+ self.assertTrue(cfptr)
1147
+ return CFUNCTYPE(c_int, c_int, c_int)(cfptr)
1148
+
1149
+ def test_run_code(self):
1150
+ mod = self.module()
1151
+ with self.jit(mod) as ee:
1152
+ cfunc = self.get_sum(ee)
1153
+ res = cfunc(2, -5)
1154
+ self.assertEqual(-3, res)
1155
+
1156
+ def test_close(self):
1157
+ ee = self.jit(self.module())
1158
+ ee.close()
1159
+ ee.close()
1160
+ with self.assertRaises(ctypes.ArgumentError):
1161
+ ee.finalize_object()
1162
+
1163
+ def test_with(self):
1164
+ ee = self.jit(self.module())
1165
+ with ee:
1166
+ pass
1167
+ with self.assertRaises(RuntimeError):
1168
+ with ee:
1169
+ pass
1170
+ with self.assertRaises(ctypes.ArgumentError):
1171
+ ee.finalize_object()
1172
+
1173
+ def test_module_lifetime(self):
1174
+ mod = self.module()
1175
+ ee = self.jit(mod)
1176
+ ee.close()
1177
+ mod.close()
1178
+
1179
+ def test_module_lifetime2(self):
1180
+ mod = self.module()
1181
+ ee = self.jit(mod)
1182
+ mod.close()
1183
+ ee.close()
1184
+
1185
+ def test_add_module(self):
1186
+ ee = self.jit(self.module())
1187
+ mod = self.module(asm_mul)
1188
+ ee.add_module(mod)
1189
+ with self.assertRaises(KeyError):
1190
+ ee.add_module(mod)
1191
+ self.assertFalse(mod.closed)
1192
+ ee.close()
1193
+ self.assertTrue(mod.closed)
1194
+
1195
+ def test_add_module_lifetime(self):
1196
+ ee = self.jit(self.module())
1197
+ mod = self.module(asm_mul)
1198
+ ee.add_module(mod)
1199
+ mod.close()
1200
+ ee.close()
1201
+
1202
+ def test_add_module_lifetime2(self):
1203
+ ee = self.jit(self.module())
1204
+ mod = self.module(asm_mul)
1205
+ ee.add_module(mod)
1206
+ ee.close()
1207
+ mod.close()
1208
+
1209
+ def test_remove_module(self):
1210
+ ee = self.jit(self.module())
1211
+ mod = self.module(asm_mul)
1212
+ ee.add_module(mod)
1213
+ ee.remove_module(mod)
1214
+ with self.assertRaises(KeyError):
1215
+ ee.remove_module(mod)
1216
+ self.assertFalse(mod.closed)
1217
+ ee.close()
1218
+ self.assertFalse(mod.closed)
1219
+
1220
+ def test_target_data(self):
1221
+ mod = self.module()
1222
+ ee = self.jit(mod)
1223
+ td = ee.target_data
1224
+ # A singleton is returned
1225
+ self.assertIs(ee.target_data, td)
1226
+ str(td)
1227
+ del mod, ee
1228
+ str(td)
1229
+
1230
+ def test_target_data_abi_enquiries(self):
1231
+ mod = self.module()
1232
+ ee = self.jit(mod)
1233
+ td = ee.target_data
1234
+ gv_i32 = mod.get_global_variable("glob")
1235
+ gv_i8 = mod.get_global_variable("glob_b")
1236
+ gv_struct = mod.get_global_variable("glob_struct")
1237
+ # A global is a pointer, it has the ABI size of a pointer
1238
+ pointer_size = 4 if sys.maxsize < 2 ** 32 else 8
1239
+ for g in (gv_i32, gv_i8, gv_struct):
1240
+ self.assertEqual(td.get_abi_size(g.type), pointer_size)
1241
+
1242
+ self.assertEqual(td.get_abi_size(gv_i32.global_value_type), 4)
1243
+ self.assertEqual(td.get_abi_alignment(gv_i32.global_value_type), 4)
1244
+
1245
+ self.assertEqual(td.get_abi_size(gv_i8.global_value_type), 1)
1246
+ self.assertIn(td.get_abi_alignment(gv_i8.global_value_type), (1, 2, 4))
1247
+
1248
+ self.assertEqual(td.get_abi_size(gv_struct.global_value_type), 24)
1249
+ self.assertIn(td.get_abi_alignment(gv_struct.global_value_type), (4, 8))
1250
+
1251
+ def test_object_cache_notify(self):
1252
+ notifies = []
1253
+
1254
+ def notify(mod, buf):
1255
+ notifies.append((mod, buf))
1256
+
1257
+ mod = self.module()
1258
+ ee = self.jit(mod)
1259
+ ee.set_object_cache(notify)
1260
+
1261
+ self.assertEqual(len(notifies), 0)
1262
+ cfunc = self.get_sum(ee)
1263
+ cfunc(2, -5)
1264
+ self.assertEqual(len(notifies), 1)
1265
+ # The right module object was found
1266
+ self.assertIs(notifies[0][0], mod)
1267
+ self.assertIsInstance(notifies[0][1], bytes)
1268
+
1269
+ notifies[:] = []
1270
+ mod2 = self.module(asm_mul)
1271
+ ee.add_module(mod2)
1272
+ cfunc = self.get_sum(ee, "mul")
1273
+ self.assertEqual(len(notifies), 1)
1274
+ # The right module object was found
1275
+ self.assertIs(notifies[0][0], mod2)
1276
+ self.assertIsInstance(notifies[0][1], bytes)
1277
+
1278
+ def test_object_cache_getbuffer(self):
1279
+ notifies = []
1280
+ getbuffers = []
1281
+
1282
+ def notify(mod, buf):
1283
+ notifies.append((mod, buf))
1284
+
1285
+ def getbuffer(mod):
1286
+ getbuffers.append(mod)
1287
+
1288
+ mod = self.module()
1289
+ ee = self.jit(mod)
1290
+ ee.set_object_cache(notify, getbuffer)
1291
+
1292
+ # First return None from getbuffer(): the object is compiled normally
1293
+ self.assertEqual(len(notifies), 0)
1294
+ self.assertEqual(len(getbuffers), 0)
1295
+ cfunc = self.get_sum(ee)
1296
+ self.assertEqual(len(notifies), 1)
1297
+ self.assertEqual(len(getbuffers), 1)
1298
+ self.assertIs(getbuffers[0], mod)
1299
+ sum_buffer = notifies[0][1]
1300
+
1301
+ # Recreate a new EE, and use getbuffer() to return the previously
1302
+ # compiled object.
1303
+
1304
+ def getbuffer_successful(mod):
1305
+ getbuffers.append(mod)
1306
+ return sum_buffer
1307
+
1308
+ notifies[:] = []
1309
+ getbuffers[:] = []
1310
+ # Use another source module to make sure it is ignored
1311
+ mod = self.module(asm_mul)
1312
+ ee = self.jit(mod)
1313
+ ee.set_object_cache(notify, getbuffer_successful)
1314
+
1315
+ self.assertEqual(len(notifies), 0)
1316
+ self.assertEqual(len(getbuffers), 0)
1317
+ cfunc = self.get_sum(ee)
1318
+ self.assertEqual(cfunc(2, -5), -3)
1319
+ self.assertEqual(len(notifies), 0)
1320
+ self.assertEqual(len(getbuffers), 1)
1321
+
1322
+
1323
+ class JITWithTMTestMixin(JITTestMixin):
1324
+
1325
+ def test_emit_assembly(self):
1326
+ """Test TargetMachineRef.emit_assembly()"""
1327
+ target_machine = self.target_machine(jit=True)
1328
+ mod = self.module()
1329
+ ee = self.jit(mod, target_machine) # noqa F841 # Keeps pointers alive
1330
+ raw_asm = target_machine.emit_assembly(mod)
1331
+ self.assertIn("sum", raw_asm)
1332
+ target_machine.set_asm_verbosity(True)
1333
+ raw_asm_verbose = target_machine.emit_assembly(mod)
1334
+ self.assertIn("sum", raw_asm)
1335
+ self.assertNotEqual(raw_asm, raw_asm_verbose)
1336
+
1337
+ def test_emit_object(self):
1338
+ """Test TargetMachineRef.emit_object()"""
1339
+ target_machine = self.target_machine(jit=True)
1340
+ mod = self.module()
1341
+ ee = self.jit(mod, target_machine) # noqa F841 # Keeps pointers alive
1342
+ code_object = target_machine.emit_object(mod)
1343
+ self.assertIsInstance(code_object, bytes)
1344
+ if sys.platform.startswith('linux'):
1345
+ # Sanity check
1346
+ self.assertIn(b"ELF", code_object[:10])
1347
+
1348
+
1349
+ class TestMCJit(BaseTest, JITWithTMTestMixin):
1350
+ """
1351
+ Test JIT engines created with create_mcjit_compiler().
1352
+ """
1353
+
1354
+ def jit(self, mod, target_machine=None):
1355
+ if target_machine is None:
1356
+ target_machine = self.target_machine(jit=True)
1357
+ return llvm.create_mcjit_compiler(mod, target_machine)
1358
+
1359
+
1360
+ # There are some memory corruption issues with OrcJIT on AArch64 - see Issue
1361
+ # #1000. Since OrcJIT is experimental, and we don't test regularly during
1362
+ # llvmlite development on non-x86 platforms, it seems safest to skip these
1363
+ # tests on non-x86 platforms.
1364
+ @unittest.skipUnless(platform.machine().startswith("x86"), "x86 only")
1365
+ class TestOrcLLJIT(BaseTest):
1366
+
1367
+ def jit(self, asm=asm_sum, func_name="sum", target_machine=None,
1368
+ add_process=False, func_type=CFUNCTYPE(c_int, c_int, c_int),
1369
+ suppress_errors=False):
1370
+ lljit = llvm.create_lljit_compiler(target_machine,
1371
+ use_jit_link=False,
1372
+ suppress_errors=suppress_errors)
1373
+ builder = llvm.JITLibraryBuilder()
1374
+ if add_process:
1375
+ builder.add_current_process()
1376
+ rt = builder\
1377
+ .add_ir(asm.format(triple=llvm.get_default_triple()))\
1378
+ .export_symbol(func_name)\
1379
+ .link(lljit, func_name)
1380
+ cfptr = rt[func_name]
1381
+ self.assertTrue(cfptr)
1382
+ self.assertEqual(func_name, rt.name)
1383
+ return lljit, rt, func_type(cfptr)
1384
+
1385
+ # From test_dylib_symbols
1386
+ def test_define_symbol(self):
1387
+ lljit = llvm.create_lljit_compiler()
1388
+ rt = llvm.JITLibraryBuilder().import_symbol("__xyzzy", 1234)\
1389
+ .export_symbol("__xyzzy").link(lljit, "foo")
1390
+ self.assertEqual(rt["__xyzzy"], 1234)
1391
+
1392
+ def test_lookup_undefined_symbol_fails(self):
1393
+ lljit = llvm.create_lljit_compiler()
1394
+ with self.assertRaisesRegex(RuntimeError, 'No such library'):
1395
+ lljit.lookup("foo", "__foobar")
1396
+ rt = llvm.JITLibraryBuilder().import_symbol("__xyzzy", 1234)\
1397
+ .export_symbol("__xyzzy").link(lljit, "foo")
1398
+ self.assertNotEqual(rt["__xyzzy"], 0)
1399
+ with self.assertRaisesRegex(RuntimeError,
1400
+ 'Symbols not found.*__foobar'):
1401
+ lljit.lookup("foo", "__foobar")
1402
+
1403
+ def test_jit_link(self):
1404
+ if sys.platform == "win32":
1405
+ with self.assertRaisesRegex(RuntimeError,
1406
+ 'JITLink .* Windows'):
1407
+ llvm.create_lljit_compiler(use_jit_link=True)
1408
+ else:
1409
+ self.assertIsNotNone(llvm.create_lljit_compiler(use_jit_link=True))
1410
+
1411
+ def test_run_code(self):
1412
+ (lljit, rt, cfunc) = self.jit()
1413
+ with lljit:
1414
+ res = cfunc(2, -5)
1415
+ self.assertEqual(-3, res)
1416
+
1417
+ def test_close(self):
1418
+ (lljit, rt, cfunc) = self.jit()
1419
+ lljit.close()
1420
+ lljit.close()
1421
+ with self.assertRaises(AssertionError):
1422
+ lljit.lookup("foo", "fn")
1423
+
1424
+ def test_with(self):
1425
+ (lljit, rt, cfunc) = self.jit()
1426
+ with lljit:
1427
+ pass
1428
+ with self.assertRaises(RuntimeError):
1429
+ with lljit:
1430
+ pass
1431
+ with self.assertRaises(AssertionError):
1432
+ lljit.lookup("foo", "fn")
1433
+
1434
+ def test_add_ir_module(self):
1435
+ (lljit, rt_sum, cfunc_sum) = self.jit()
1436
+ rt_mul = llvm.JITLibraryBuilder() \
1437
+ .add_ir(asm_mul.format(triple=llvm.get_default_triple())) \
1438
+ .export_symbol("mul") \
1439
+ .link(lljit, "mul")
1440
+ res = CFUNCTYPE(c_int, c_int, c_int)(rt_mul["mul"])(2, -5)
1441
+ self.assertEqual(-10, res)
1442
+ self.assertNotEqual(lljit.lookup("sum", "sum")["sum"], 0)
1443
+ self.assertNotEqual(lljit.lookup("mul", "mul")["mul"], 0)
1444
+ with self.assertRaises(RuntimeError):
1445
+ lljit.lookup("sum", "mul")
1446
+ with self.assertRaises(RuntimeError):
1447
+ lljit.lookup("mul", "sum")
1448
+
1449
+ def test_remove_module(self):
1450
+ (lljit, rt_sum, _) = self.jit()
1451
+ del rt_sum
1452
+ gc.collect()
1453
+ with self.assertRaises(RuntimeError):
1454
+ lljit.lookup("sum", "sum")
1455
+ lljit.close()
1456
+
1457
+ def test_lib_depends(self):
1458
+ (lljit, rt_sum, cfunc_sum) = self.jit()
1459
+ rt_mul = llvm.JITLibraryBuilder() \
1460
+ .add_ir(asm_square_sum.format(triple=llvm.get_default_triple())) \
1461
+ .export_symbol("square_sum") \
1462
+ .add_jit_library("sum") \
1463
+ .link(lljit, "square_sum")
1464
+ res = CFUNCTYPE(c_int, c_int, c_int)(rt_mul["square_sum"])(2, -5)
1465
+ self.assertEqual(9, res)
1466
+
1467
+ def test_target_data(self):
1468
+ (lljit, rt, _) = self.jit()
1469
+ td = lljit.target_data
1470
+ # A singleton is returned
1471
+ self.assertIs(lljit.target_data, td)
1472
+ str(td)
1473
+ del lljit
1474
+ str(td)
1475
+
1476
+ def test_global_ctors_dtors(self):
1477
+ # test issue #303
1478
+ # (https://github.com/numba/llvmlite/issues/303)
1479
+ shared_value = c_int32(0)
1480
+ lljit = llvm.create_lljit_compiler()
1481
+ builder = llvm.JITLibraryBuilder()
1482
+ rt = builder \
1483
+ .add_ir(asm_ext_ctors.format(triple=llvm.get_default_triple())) \
1484
+ .import_symbol("A", ctypes.addressof(shared_value)) \
1485
+ .export_symbol("foo") \
1486
+ .link(lljit, "foo")
1487
+ foo = rt["foo"]
1488
+ self.assertTrue(foo)
1489
+ self.assertEqual(CFUNCTYPE(c_int)(foo)(), 12)
1490
+ del rt
1491
+ self.assertNotEqual(shared_value.value, 20)
1492
+
1493
+ def test_lookup_current_process_symbol_fails(self):
1494
+ # An attempt to lookup a symbol in the current process (Py_GetVersion,
1495
+ # in this case) should fail with an appropriate error if we have not
1496
+ # enabled searching the current process for symbols.
1497
+ msg = 'Failed to materialize symbols:.*getversion'
1498
+ with self.assertRaisesRegex(RuntimeError, msg):
1499
+ self.jit(asm_getversion, "getversion", suppress_errors=True)
1500
+
1501
+ def test_lookup_current_process_symbol(self):
1502
+ self.jit(asm_getversion, "getversion", None, True)
1503
+
1504
+ def test_thread_safe(self):
1505
+ lljit = llvm.create_lljit_compiler()
1506
+ llvm_ir = asm_sum.format(triple=llvm.get_default_triple())
1507
+
1508
+ def compile_many(i):
1509
+ def do_work():
1510
+ tracking = []
1511
+ for c in range(50):
1512
+ tracking.append(llvm.JITLibraryBuilder()
1513
+ .add_ir(llvm_ir)
1514
+ .export_symbol("sum")
1515
+ .link(lljit, f"sum_{i}_{c}"))
1516
+
1517
+ return do_work
1518
+
1519
+ ths = [threading.Thread(target=compile_many(i))
1520
+ for i in range(os.cpu_count())]
1521
+ for th in ths:
1522
+ th.start()
1523
+ for th in ths:
1524
+ th.join()
1525
+
1526
+ def test_add_object_file(self):
1527
+ target_machine = self.target_machine(jit=False)
1528
+ mod = self.module()
1529
+ lljit = llvm.create_lljit_compiler(target_machine)
1530
+ rt = llvm.JITLibraryBuilder()\
1531
+ .add_object_img(target_machine.emit_object(mod))\
1532
+ .export_symbol("sum")\
1533
+ .link(lljit, "sum")
1534
+ sum = CFUNCTYPE(c_int, c_int, c_int)(rt["sum"])
1535
+ self.assertEqual(sum(2, 3), 5)
1536
+
1537
+ def test_add_object_file_from_filesystem(self):
1538
+ target_machine = self.target_machine(jit=False)
1539
+ mod = self.module()
1540
+ obj_bin = target_machine.emit_object(mod)
1541
+ temp_desc, temp_path = mkstemp()
1542
+
1543
+ try:
1544
+ with os.fdopen(temp_desc, "wb") as f:
1545
+ f.write(obj_bin)
1546
+ lljit = llvm.create_lljit_compiler(target_machine)
1547
+ rt = llvm.JITLibraryBuilder() \
1548
+ .add_object_file(temp_path) \
1549
+ .export_symbol("sum") \
1550
+ .link(lljit, "sum")
1551
+ sum = CFUNCTYPE(c_int, c_int, c_int)(rt["sum"])
1552
+ self.assertEqual(sum(2, 3), 5)
1553
+ finally:
1554
+ os.unlink(temp_path)
1555
+
1556
+
1557
+ class TestValueRef(BaseTest):
1558
+
1559
+ def test_str(self):
1560
+ mod = self.module()
1561
+ glob = mod.get_global_variable("glob")
1562
+ self.assertEqual(str(glob), "@glob = global i32 0")
1563
+
1564
+ def test_name(self):
1565
+ mod = self.module()
1566
+ glob = mod.get_global_variable("glob")
1567
+ self.assertEqual(glob.name, "glob")
1568
+ glob.name = "foobar"
1569
+ self.assertEqual(glob.name, "foobar")
1570
+
1571
+ def test_linkage(self):
1572
+ mod = self.module()
1573
+ glob = mod.get_global_variable("glob")
1574
+ linkage = glob.linkage
1575
+ self.assertIsInstance(glob.linkage, llvm.Linkage)
1576
+ glob.linkage = linkage
1577
+ self.assertEqual(glob.linkage, linkage)
1578
+ for linkage in ("internal", "external"):
1579
+ glob.linkage = linkage
1580
+ self.assertIsInstance(glob.linkage, llvm.Linkage)
1581
+ self.assertEqual(glob.linkage.name, linkage)
1582
+
1583
+ def test_visibility(self):
1584
+ mod = self.module()
1585
+ glob = mod.get_global_variable("glob")
1586
+ visibility = glob.visibility
1587
+ self.assertIsInstance(glob.visibility, llvm.Visibility)
1588
+ glob.visibility = visibility
1589
+ self.assertEqual(glob.visibility, visibility)
1590
+ for visibility in ("hidden", "protected", "default"):
1591
+ glob.visibility = visibility
1592
+ self.assertIsInstance(glob.visibility, llvm.Visibility)
1593
+ self.assertEqual(glob.visibility.name, visibility)
1594
+
1595
+ def test_storage_class(self):
1596
+ mod = self.module()
1597
+ glob = mod.get_global_variable("glob")
1598
+ storage_class = glob.storage_class
1599
+ self.assertIsInstance(glob.storage_class, llvm.StorageClass)
1600
+ glob.storage_class = storage_class
1601
+ self.assertEqual(glob.storage_class, storage_class)
1602
+ for storage_class in ("dllimport", "dllexport", "default"):
1603
+ glob.storage_class = storage_class
1604
+ self.assertIsInstance(glob.storage_class, llvm.StorageClass)
1605
+ self.assertEqual(glob.storage_class.name, storage_class)
1606
+
1607
+ def test_add_function_attribute(self):
1608
+ mod = self.module()
1609
+ fn = mod.get_function("sum")
1610
+ fn.add_function_attribute("nocapture")
1611
+ with self.assertRaises(ValueError) as raises:
1612
+ fn.add_function_attribute("zext")
1613
+ self.assertEqual(str(raises.exception), "no such attribute 'zext'")
1614
+
1615
+ def test_module(self):
1616
+ mod = self.module()
1617
+ glob = mod.get_global_variable("glob")
1618
+ self.assertIs(glob.module, mod)
1619
+
1620
+ def test_type(self):
1621
+ mod = self.module()
1622
+ glob = mod.get_global_variable("glob")
1623
+ tp = glob.type
1624
+ self.assertIsInstance(tp, llvm.TypeRef)
1625
+
1626
+ def test_type_name(self):
1627
+ mod = self.module()
1628
+ glob = mod.get_global_variable("glob")
1629
+ tp = glob.type
1630
+ self.assertEqual(tp.name, "")
1631
+ st = mod.get_global_variable("glob_struct")
1632
+ self.assertIsNotNone(re.match(r"struct\.glob_type(\.[\d]+)?",
1633
+ st.global_value_type.name))
1634
+
1635
+ def test_type_printing_variable(self):
1636
+ mod = self.module()
1637
+ glob = mod.get_global_variable("glob")
1638
+ tp = glob.global_value_type
1639
+ self.assertEqual(str(tp), 'i32')
1640
+
1641
+ def test_type_printing_function(self):
1642
+ mod = self.module()
1643
+ fn = mod.get_function("sum")
1644
+ self.assertEqual(str(fn.global_value_type), "i32 (i32, i32)")
1645
+
1646
+ def test_type_printing_struct(self):
1647
+ mod = self.module()
1648
+ st = mod.get_global_variable("glob_struct")
1649
+ self.assertTrue(st.type.is_pointer)
1650
+ # FIXME: Remove `else' once TP are no longer supported.
1651
+ if opaque_pointers_enabled:
1652
+ self.assertIsNotNone(re.match(r'ptr', str(st.type)))
1653
+ else:
1654
+ self.assertIsNotNone(re.match(r'%struct\.glob_type(\.[\d]+)?\*',
1655
+ str(st.type)))
1656
+ self.assertIsNotNone(re.match(
1657
+ r"%struct\.glob_type(\.[\d]+)? = type { i64, \[2 x i64\] }",
1658
+ str(st.global_value_type)))
1659
+
1660
+ def test_close(self):
1661
+ glob = self.glob()
1662
+ glob.close()
1663
+ glob.close()
1664
+
1665
+ def test_is_declaration(self):
1666
+ defined = self.module().get_function('sum')
1667
+ declared = self.module(asm_sum_declare).get_function('sum')
1668
+ self.assertFalse(defined.is_declaration)
1669
+ self.assertTrue(declared.is_declaration)
1670
+
1671
+ def test_module_global_variables(self):
1672
+ mod = self.module(asm_sum)
1673
+ gvars = list(mod.global_variables)
1674
+ self.assertEqual(len(gvars), 4)
1675
+ for v in gvars:
1676
+ self.assertTrue(v.is_global)
1677
+
1678
+ def test_module_functions(self):
1679
+ mod = self.module()
1680
+ funcs = list(mod.functions)
1681
+ self.assertEqual(len(funcs), 1)
1682
+ func = funcs[0]
1683
+ self.assertTrue(func.is_function)
1684
+ self.assertEqual(func.name, 'sum')
1685
+
1686
+ with self.assertRaises(ValueError):
1687
+ func.instructions
1688
+ with self.assertRaises(ValueError):
1689
+ func.operands
1690
+ with self.assertRaises(ValueError):
1691
+ func.opcode
1692
+
1693
+ def test_function_arguments(self):
1694
+ mod = self.module()
1695
+ func = mod.get_function('sum')
1696
+ self.assertTrue(func.is_function)
1697
+ args = list(func.arguments)
1698
+ self.assertEqual(len(args), 2)
1699
+ self.assertTrue(args[0].is_argument)
1700
+ self.assertTrue(args[1].is_argument)
1701
+ self.assertEqual(args[0].name, '.1')
1702
+ self.assertEqual(str(args[0].type), 'i32')
1703
+ self.assertEqual(args[1].name, '.2')
1704
+ self.assertEqual(str(args[1].type), 'i32')
1705
+
1706
+ with self.assertRaises(ValueError):
1707
+ args[0].blocks
1708
+ with self.assertRaises(ValueError):
1709
+ args[0].arguments
1710
+
1711
+ def test_function_blocks(self):
1712
+ func = self.module().get_function('sum')
1713
+ blocks = list(func.blocks)
1714
+ self.assertEqual(len(blocks), 1)
1715
+ block = blocks[0]
1716
+ self.assertTrue(block.is_block)
1717
+
1718
+ def test_block_instructions(self):
1719
+ func = self.module().get_function('sum')
1720
+ insts = list(list(func.blocks)[0].instructions)
1721
+ self.assertEqual(len(insts), 3)
1722
+ self.assertTrue(insts[0].is_instruction)
1723
+ self.assertTrue(insts[1].is_instruction)
1724
+ self.assertTrue(insts[2].is_instruction)
1725
+ self.assertEqual(insts[0].opcode, 'add')
1726
+ self.assertEqual(insts[1].opcode, 'add')
1727
+ self.assertEqual(insts[2].opcode, 'ret')
1728
+
1729
+ def test_instruction_operands(self):
1730
+ func = self.module().get_function('sum')
1731
+ add = list(list(func.blocks)[0].instructions)[0]
1732
+ self.assertEqual(add.opcode, 'add')
1733
+ operands = list(add.operands)
1734
+ self.assertEqual(len(operands), 2)
1735
+ self.assertTrue(operands[0].is_operand)
1736
+ self.assertTrue(operands[1].is_operand)
1737
+ self.assertEqual(operands[0].name, '.1')
1738
+ self.assertEqual(str(operands[0].type), 'i32')
1739
+ self.assertEqual(operands[1].name, '.2')
1740
+ self.assertEqual(str(operands[1].type), 'i32')
1741
+
1742
+ def test_function_attributes(self):
1743
+ ver = llvm.llvm_version_info[0]
1744
+ readonly_attrs = [b'memory(read)' if ver == 16 else b'readonly']
1745
+ mod = self.module(asm_attributes)
1746
+ for func in mod.functions:
1747
+ attrs = list(func.attributes)
1748
+ if func.name == 'a_readonly_func':
1749
+ self.assertEqual(attrs, readonly_attrs)
1750
+ elif func.name == 'a_arg0_return_func':
1751
+ self.assertEqual(attrs, [])
1752
+ args = list(func.arguments)
1753
+ self.assertEqual(list(args[0].attributes), [b'returned'])
1754
+ self.assertEqual(list(args[1].attributes), [])
1755
+
1756
+ def test_value_kind(self):
1757
+ mod = self.module()
1758
+ self.assertEqual(mod.get_global_variable('glob').value_kind,
1759
+ llvm.ValueKind.global_variable)
1760
+ func = mod.get_function('sum')
1761
+ self.assertEqual(func.value_kind, llvm.ValueKind.function)
1762
+ block = list(func.blocks)[0]
1763
+ self.assertEqual(block.value_kind, llvm.ValueKind.basic_block)
1764
+ inst = list(block.instructions)[1]
1765
+ self.assertEqual(inst.value_kind, llvm.ValueKind.instruction)
1766
+ self.assertEqual(list(inst.operands)[0].value_kind,
1767
+ llvm.ValueKind.constant_int)
1768
+ self.assertEqual(list(inst.operands)[1].value_kind,
1769
+ llvm.ValueKind.instruction)
1770
+
1771
+ iasm_func = self.module(asm_inlineasm).get_function('foo')
1772
+ iasm_inst = list(list(iasm_func.blocks)[0].instructions)[0]
1773
+ self.assertEqual(list(iasm_inst.operands)[0].value_kind,
1774
+ llvm.ValueKind.inline_asm)
1775
+
1776
+ def test_is_constant(self):
1777
+ mod = self.module()
1778
+ self.assertTrue(mod.get_global_variable('glob').is_constant)
1779
+ constant_operands = 0
1780
+ for func in mod.functions:
1781
+ self.assertTrue(func.is_constant)
1782
+ for block in func.blocks:
1783
+ self.assertFalse(block.is_constant)
1784
+ for inst in block.instructions:
1785
+ self.assertFalse(inst.is_constant)
1786
+ for op in inst.operands:
1787
+ if op.is_constant:
1788
+ constant_operands += 1
1789
+
1790
+ self.assertEqual(constant_operands, 1)
1791
+
1792
+ def test_constant_int(self):
1793
+ mod = self.module()
1794
+ func = mod.get_function('sum')
1795
+ insts = list(list(func.blocks)[0].instructions)
1796
+ self.assertEqual(insts[1].opcode, 'add')
1797
+ operands = list(insts[1].operands)
1798
+ self.assertTrue(operands[0].is_constant)
1799
+ self.assertFalse(operands[1].is_constant)
1800
+ self.assertEqual(operands[0].get_constant_value(), 0)
1801
+ with self.assertRaises(ValueError):
1802
+ operands[1].get_constant_value()
1803
+
1804
+ mod = self.module(asm_sum3)
1805
+ func = mod.get_function('sum')
1806
+ insts = list(list(func.blocks)[0].instructions)
1807
+ posint64 = list(insts[1].operands)[0]
1808
+ negint64 = list(insts[2].operands)[0]
1809
+ self.assertEqual(posint64.get_constant_value(), 5)
1810
+ self.assertEqual(negint64.get_constant_value(signed_int=True), -5)
1811
+
1812
+ # Convert from unsigned arbitrary-precision integer to signed i64
1813
+ as_u64 = negint64.get_constant_value(signed_int=False)
1814
+ as_i64 = int.from_bytes(as_u64.to_bytes(8, 'little'), 'little',
1815
+ signed=True)
1816
+ self.assertEqual(as_i64, -5)
1817
+
1818
+ def test_constant_fp(self):
1819
+ mod = self.module(asm_double_locale)
1820
+ func = mod.get_function('foo')
1821
+ insts = list(list(func.blocks)[0].instructions)
1822
+ self.assertEqual(len(insts), 2)
1823
+ self.assertEqual(insts[0].opcode, 'fadd')
1824
+ operands = list(insts[0].operands)
1825
+ self.assertTrue(operands[0].is_constant)
1826
+ self.assertAlmostEqual(operands[0].get_constant_value(), 0.0)
1827
+ self.assertTrue(operands[1].is_constant)
1828
+ self.assertAlmostEqual(operands[1].get_constant_value(), 3.14)
1829
+
1830
+ mod = self.module(asm_double_inaccurate)
1831
+ func = mod.get_function('foo')
1832
+ inst = list(list(func.blocks)[0].instructions)[0]
1833
+ operands = list(inst.operands)
1834
+ with self.assertRaises(ValueError):
1835
+ operands[0].get_constant_value()
1836
+ self.assertAlmostEqual(operands[1].get_constant_value(round_fp=True), 0)
1837
+
1838
+ def test_constant_as_string(self):
1839
+ mod = self.module(asm_null_constant)
1840
+ func = mod.get_function('bar')
1841
+ inst = list(list(func.blocks)[0].instructions)[0]
1842
+ arg = list(inst.operands)[0]
1843
+ self.assertTrue(arg.is_constant)
1844
+ # FIXME: Remove `else' once TP are no longer supported.
1845
+ if opaque_pointers_enabled:
1846
+ self.assertEqual(arg.get_constant_value(), 'ptr null')
1847
+ else:
1848
+ self.assertEqual(arg.get_constant_value(), 'i64* null')
1849
+
1850
+ def test_incoming_phi_blocks(self):
1851
+ mod = self.module(asm_phi_blocks)
1852
+ func = mod.get_function('foo')
1853
+ blocks = list(func.blocks)
1854
+ instructions = list(blocks[-1].instructions)
1855
+ self.assertTrue(instructions[0].is_instruction)
1856
+ self.assertEqual(instructions[0].opcode, 'phi')
1857
+
1858
+ incoming_blocks = list(instructions[0].incoming_blocks)
1859
+ self.assertEqual(len(incoming_blocks), 2)
1860
+ self.assertTrue(incoming_blocks[0].is_block)
1861
+ self.assertTrue(incoming_blocks[1].is_block)
1862
+ # Test reference to blocks (named or unnamed)
1863
+ self.assertEqual(incoming_blocks[0], blocks[-1])
1864
+ self.assertEqual(incoming_blocks[1], blocks[0])
1865
+
1866
+ # Test case that should fail
1867
+ self.assertNotEqual(instructions[1].opcode, 'phi')
1868
+ with self.assertRaises(ValueError):
1869
+ instructions[1].incoming_blocks
1870
+
1871
+
1872
+ class TestTypeRef(BaseTest):
1873
+
1874
+ def test_str(self):
1875
+ mod = self.module()
1876
+ glob = mod.get_global_variable("glob")
1877
+ self.assertEqual(str(glob.global_value_type), "i32")
1878
+ glob_struct_type = mod.get_struct_type("struct.glob_type")
1879
+ self.assertEqual(str(glob_struct_type),
1880
+ "%struct.glob_type = type { i64, [2 x i64] }")
1881
+
1882
+ elements = list(glob_struct_type.elements)
1883
+ self.assertEqual(len(elements), 2)
1884
+ self.assertEqual(str(elements[0]), "i64")
1885
+ self.assertEqual(str(elements[1]), "[2 x i64]")
1886
+
1887
+ def test_type_kind(self):
1888
+ mod = self.module()
1889
+ glob = mod.get_global_variable("glob")
1890
+ self.assertEqual(glob.type.type_kind, llvm.TypeKind.pointer)
1891
+ self.assertTrue(glob.type.is_pointer)
1892
+
1893
+ glob_struct = mod.get_global_variable("glob_struct")
1894
+ self.assertEqual(glob_struct.type.type_kind, llvm.TypeKind.pointer)
1895
+ self.assertTrue(glob_struct.type.is_pointer)
1896
+
1897
+ stype = glob_struct.global_value_type
1898
+ self.assertEqual(stype.type_kind, llvm.TypeKind.struct)
1899
+ self.assertTrue(stype.is_struct)
1900
+
1901
+ stype_a, stype_b = stype.elements
1902
+ self.assertEqual(stype_a.type_kind, llvm.TypeKind.integer)
1903
+ self.assertEqual(stype_b.type_kind, llvm.TypeKind.array)
1904
+ self.assertTrue(stype_b.is_array)
1905
+
1906
+ glob_vec_struct_type = mod.get_struct_type("struct.glob_type_vec")
1907
+ _, vector_type = glob_vec_struct_type.elements
1908
+ self.assertEqual(vector_type.type_kind, llvm.TypeKind.vector)
1909
+ self.assertTrue(vector_type.is_vector)
1910
+
1911
+ funcptr = mod.get_function("sum").type
1912
+ self.assertEqual(funcptr.type_kind, llvm.TypeKind.pointer)
1913
+ functype = mod.get_function("sum").global_value_type
1914
+ self.assertEqual(functype.type_kind, llvm.TypeKind.function)
1915
+
1916
+ def test_element_count(self):
1917
+ mod = self.module()
1918
+ glob_struct_type = mod.get_struct_type("struct.glob_type")
1919
+ _, array_type = glob_struct_type.elements
1920
+ self.assertEqual(array_type.element_count, 2)
1921
+ with self.assertRaises(ValueError):
1922
+ glob_struct_type.element_count
1923
+
1924
+ def test_type_width(self):
1925
+ mod = self.module()
1926
+ glob_struct_type = mod.get_struct_type("struct.glob_type")
1927
+ glob_vec_struct_type = mod.get_struct_type("struct.glob_type_vec")
1928
+ integer_type, array_type = glob_struct_type.elements
1929
+ _, vector_type = glob_vec_struct_type.elements
1930
+ self.assertEqual(integer_type.type_width, 64)
1931
+ self.assertEqual(vector_type.type_width, 64 * 2)
1932
+
1933
+ # Structs and arrays are not primitive types
1934
+ self.assertEqual(glob_struct_type.type_width, 0)
1935
+ self.assertEqual(array_type.type_width, 0)
1936
+
1937
+ def test_vararg_function(self):
1938
+ # Variadic function
1939
+ mod = self.module(asm_vararg_declare)
1940
+ func = mod.get_function('vararg')
1941
+ decltype = func.global_value_type
1942
+ self.assertTrue(decltype.is_function_vararg)
1943
+
1944
+ mod = self.module(asm_sum_declare)
1945
+ func = mod.get_function('sum')
1946
+ decltype = func.global_value_type
1947
+ self.assertFalse(decltype.is_function_vararg)
1948
+
1949
+ # test that the function pointer type cannot use is_function_vararg
1950
+ self.assertTrue(func.type.is_pointer)
1951
+ with self.assertRaises(ValueError) as raises:
1952
+ func.type.is_function_vararg
1953
+ # FIXME: Remove `else' once TP are no longer supported.
1954
+ if opaque_pointers_enabled:
1955
+ self.assertIn("Type ptr is not a function", str(raises.exception))
1956
+ else:
1957
+ self.assertIn("Type i32 (i32, i32)* is not a function",
1958
+ str(raises.exception))
1959
+
1960
+ def test_function_typeref_as_ir(self):
1961
+ mod = self.module()
1962
+
1963
+ [fn] = list(mod.functions)
1964
+ # .type gives a pointer type, a problem if it's opaque (llvm15+)
1965
+ self.assertEqual(fn.type.type_kind, llvm.TypeKind.pointer)
1966
+ self.assertFalse(fn.type.is_function)
1967
+ # Use .global_value_type instead
1968
+ fnty = fn.global_value_type
1969
+ self.assertEqual(fnty.type_kind, llvm.TypeKind.function)
1970
+ self.assertTrue(fnty.is_function)
1971
+ # Run .as_ir() to get llvmlite.ir.FunctionType
1972
+ tyir = fnty.as_ir(ir.global_context)
1973
+ self.assertIsInstance(tyir, ir.FunctionType)
1974
+ self.assertEqual(tyir.args, (ir.IntType(32), ir.IntType(32)))
1975
+ self.assertEqual(tyir.return_type ,ir.IntType(32))
1976
+
1977
+ def test_void_typeref_as_ir(self):
1978
+ # Void type can only be used as return-type of llvmlite.ir.FunctionType.
1979
+ fnty = ir.FunctionType(ir.VoidType(), ())
1980
+ irmod = ir.Module()
1981
+ fn = ir.Function(irmod, fnty, "foo")
1982
+ mod = self.module(str(irmod))
1983
+ fn = mod.get_function("foo")
1984
+ gvty = fn.global_value_type
1985
+ self.assertEqual(fnty.return_type,
1986
+ gvty.as_ir(ir.global_context).return_type)
1987
+
1988
+ def test_global_typeref_as_ir(self):
1989
+ from llvmlite.binding.typeref import _TypeKindToIRType
1990
+ ctx = ir.Context()
1991
+
1992
+ skipped = {
1993
+ "function", # tested in test_function_typeref_as_ir
1994
+ "void", # tested in test_void_typeref_as_ir
1995
+ }
1996
+
1997
+ makers = {}
1998
+
1999
+ def maker_half():
2000
+ yield ir.HalfType()
2001
+
2002
+ makers['half'] = maker_half
2003
+
2004
+ def maker_float():
2005
+ yield ir.FloatType()
2006
+
2007
+ makers['float'] = maker_float
2008
+
2009
+ def maker_double():
2010
+ yield ir.DoubleType()
2011
+
2012
+ makers['double'] = maker_double
2013
+
2014
+ def maker_integer():
2015
+ yield ir.IntType(32)
2016
+
2017
+ makers['integer'] = maker_integer
2018
+
2019
+ def maker_pointer():
2020
+ yield ir.PointerType(ir.IntType(8))
2021
+ # opaque struct ptr
2022
+ yield ctx.get_identified_type("myclass").as_pointer()
2023
+ # named struct with defined body
2024
+ myclass2 = ctx.get_identified_type("myclass2")
2025
+ myclass2.set_body(ir.IntType(8))
2026
+ yield myclass2.as_pointer()
2027
+
2028
+ makers['pointer'] = maker_pointer
2029
+
2030
+ def maker_array():
2031
+ yield ir.ArrayType(ir.IntType(8), 123)
2032
+
2033
+ makers['array'] = maker_array
2034
+
2035
+ def maker_vector():
2036
+ yield ir.VectorType(ir.FloatType(), 2)
2037
+
2038
+ makers['vector'] = maker_vector
2039
+
2040
+ def maker_struct():
2041
+ yield ir.LiteralStructType([ir.FloatType(), ir.IntType(64)])
2042
+ yield ir.LiteralStructType([ir.FloatType(), ir.IntType(64)],
2043
+ packed=True)
2044
+
2045
+ makers['struct'] = maker_struct
2046
+
2047
+ # Ensure that number of supported TypeKind matches number of makers
2048
+ self.assertEqual({x.name for x in _TypeKindToIRType.keys()},
2049
+ set(makers.keys()) | set(skipped))
2050
+
2051
+ # Test each type-kind
2052
+ for type_kind, irtype in _TypeKindToIRType.items():
2053
+ if type_kind.name in skipped:
2054
+ continue
2055
+ for ty in makers[type_kind.name]():
2056
+ with self.subTest(f"{type_kind!s} -> {ty}"):
2057
+ irmod = ir.Module(context=ctx)
2058
+ ir.GlobalVariable(irmod, ty, name='gv')
2059
+ asm = str(irmod)
2060
+ mod = llvm.parse_assembly(asm)
2061
+ gv = mod.get_global_variable("gv")
2062
+ gvty = gv.global_value_type
2063
+ got = gvty.as_ir(ir.Context()) # fresh context
2064
+ self.assertEqual(got, ty)
2065
+ self.assertIsInstance(got, irtype)
2066
+
2067
+ def _check_typeref_as_ir_for_wrappers(self, asm, target_symbol):
2068
+ # Get a clang++ defined function from a llvm ir
2069
+ mod = llvm.parse_assembly(asm)
2070
+ cppfn = mod.get_function(target_symbol)
2071
+ cppfntype = cppfn.global_value_type
2072
+
2073
+ # Get the function type into a new context
2074
+ my_context = ir.Context() # don't populate global context
2075
+ ty = cppfntype.as_ir(ir_ctx=my_context)
2076
+
2077
+ # Build a wrapper module for the cpp function
2078
+ wrapper_mod = ir.Module(context=my_context)
2079
+ # declare the original function
2080
+ declfn = ir.Function(wrapper_mod, ty, name=cppfn.name)
2081
+ # populate the wrapper function
2082
+ wrapfn = ir.Function(wrapper_mod, ty, name="wrapper")
2083
+ builder = ir.IRBuilder(wrapfn.append_basic_block())
2084
+ # just call the original function
2085
+ builder.call(declfn, wrapfn.args)
2086
+ builder.ret_void()
2087
+ # Create a new LLVM module with the wrapper
2088
+ new_mod = llvm.parse_assembly(str(wrapper_mod))
2089
+ self.assertTrue(new_mod.get_function(declfn.name).is_declaration,
2090
+ msg="declfn must not have a body")
2091
+ # Merge/link the original module into the new module
2092
+ new_mod.link_in(mod, preserve=True)
2093
+ self.assertEqual(len(list(new_mod.functions)),
2094
+ len(list(mod.functions)) + 1,
2095
+ msg="the only new function is the wrapper")
2096
+ self.assertFalse(new_mod.get_function(declfn.name).is_declaration,
2097
+ msg="declfn must have a body now")
2098
+ self.assertEqual(new_mod.get_function(declfn.name).global_value_type,
2099
+ new_mod.get_function(wrapfn.name).global_value_type,
2100
+ msg="declfn and wrapfn must have the same llvm Type")
2101
+
2102
+ def test_typeref_as_ir_for_wrappers_of_cpp_class(self):
2103
+ """Exercise extracting C++ defined class types.
2104
+ Contains both opaque and non-opaque class definitions.
2105
+ """
2106
+ self._check_typeref_as_ir_for_wrappers(
2107
+ asm_cpp_class,
2108
+ "_Z3fooP7MyClass14MyClassDefined",
2109
+ )
2110
+
2111
+ def test_typeref_as_ir_for_wrappers_of_cpp_vector_struct(self):
2112
+ """Exercise extracting C++ struct types that are passed as vectors.
2113
+
2114
+ IA64 ABI on x86_64 will put struct with two floats as
2115
+ a vector of two floats.
2116
+ """
2117
+ self._check_typeref_as_ir_for_wrappers(
2118
+ asm_cpp_vector,
2119
+ "_Z3foo8Vector2DPS_",
2120
+ )
2121
+
2122
+
2123
+ class TestTarget(BaseTest):
2124
+
2125
+ def test_from_triple(self):
2126
+ f = llvm.Target.from_triple
2127
+ with self.assertRaises(RuntimeError) as cm:
2128
+ f("foobar")
2129
+ self.assertIn("No available targets are compatible with",
2130
+ str(cm.exception))
2131
+ triple = llvm.get_default_triple()
2132
+ target = f(triple)
2133
+ self.assertEqual(target.triple, triple)
2134
+ target.close()
2135
+
2136
+ def test_create_target_machine(self):
2137
+ target = llvm.Target.from_triple(llvm.get_default_triple())
2138
+ # With the default settings
2139
+ target.create_target_machine('', '', 1, 'default', 'default')
2140
+ # With the host's CPU
2141
+ cpu = llvm.get_host_cpu_name()
2142
+ target.create_target_machine(cpu, '', 1, 'default', 'default')
2143
+
2144
+ def test_name(self):
2145
+ t = llvm.Target.from_triple(llvm.get_default_triple())
2146
+ u = llvm.Target.from_default_triple()
2147
+ self.assertIsInstance(t.name, str)
2148
+ self.assertEqual(t.name, u.name)
2149
+
2150
+ def test_description(self):
2151
+ t = llvm.Target.from_triple(llvm.get_default_triple())
2152
+ u = llvm.Target.from_default_triple()
2153
+ self.assertIsInstance(t.description, str)
2154
+ self.assertEqual(t.description, u.description)
2155
+
2156
+ def test_str(self):
2157
+ target = llvm.Target.from_triple(llvm.get_default_triple())
2158
+ s = str(target)
2159
+ self.assertIn(target.name, s)
2160
+ self.assertIn(target.description, s)
2161
+
2162
+ def test_get_parts_from_triple(self):
2163
+ # Tests adapted from llvm-14::llvm/unittests/ADT/TripleTest.cpp
2164
+ cases = [
2165
+ ("x86_64-scei-ps4",
2166
+ llvm.targets.Triple(Arch="x86_64", SubArch='',
2167
+ Vendor="scei", OS="ps4",
2168
+ Env="unknown", ObjectFormat="ELF")),
2169
+ ("x86_64-sie-ps4",
2170
+ llvm.targets.Triple(Arch="x86_64", SubArch='',
2171
+ Vendor="scei", OS="ps4",
2172
+ Env="unknown", ObjectFormat="ELF")),
2173
+ ("powerpc-dunno-notsure",
2174
+ llvm.targets.Triple(Arch="powerpc", SubArch='',
2175
+ Vendor="unknown", OS="unknown",
2176
+ Env="unknown", ObjectFormat="ELF")),
2177
+ ("powerpcspe-unknown-freebsd",
2178
+ llvm.targets.Triple(Arch="powerpc", SubArch='spe',
2179
+ Vendor="unknown", OS="freebsd",
2180
+ Env="unknown", ObjectFormat="ELF")),
2181
+ ("armv6hl-none-linux-gnueabi",
2182
+ llvm.targets.Triple(Arch="arm", SubArch='v6hl',
2183
+ Vendor="unknown", OS="linux",
2184
+ Env="gnueabi", ObjectFormat="ELF")),
2185
+ ("i686-unknown-linux-gnu",
2186
+ llvm.targets.Triple(Arch="i386", SubArch='',
2187
+ Vendor="unknown", OS="linux",
2188
+ Env="gnu", ObjectFormat="ELF")),
2189
+ ("i686-apple-macosx",
2190
+ llvm.targets.Triple(Arch="i386", SubArch='',
2191
+ Vendor="apple", OS="macosx",
2192
+ Env="unknown", ObjectFormat="MachO")),
2193
+ ("i686-dunno-win32",
2194
+ llvm.targets.Triple(Arch="i386", SubArch='',
2195
+ Vendor="unknown", OS="windows",
2196
+ Env="msvc", ObjectFormat="COFF")),
2197
+ ("s390x-ibm-zos",
2198
+ llvm.targets.Triple(Arch="s390x", SubArch='',
2199
+ Vendor="ibm", OS="zos",
2200
+ Env="unknown", ObjectFormat="GOFF")),
2201
+ ("wasm64-wasi",
2202
+ llvm.targets.Triple(Arch="wasm64", SubArch='',
2203
+ Vendor="unknown", OS="wasi",
2204
+ Env="unknown", ObjectFormat="Wasm")),
2205
+ ]
2206
+
2207
+ for case in cases:
2208
+ triple_str, triple_obj = case
2209
+ res = llvm.get_triple_parts(triple_str)
2210
+
2211
+ self.assertEqual(res, triple_obj)
2212
+
2213
+
2214
+ class TestTargetData(BaseTest):
2215
+
2216
+ def target_data(self):
2217
+ return llvm.create_target_data("e-m:e-i64:64-f80:128-n8:16:32:64-S128")
2218
+
2219
+ def test_get_abi_size(self):
2220
+ td = self.target_data()
2221
+ glob = self.glob()
2222
+ self.assertEqual(td.get_abi_size(glob.type), 8)
2223
+
2224
+ def test_get_pointee_abi_size(self):
2225
+ td = self.target_data()
2226
+
2227
+ glob = self.glob()
2228
+ self.assertEqual(td.get_abi_size(glob.global_value_type), 4)
2229
+
2230
+ glob = self.glob("glob_struct")
2231
+ self.assertEqual(td.get_abi_size(glob.global_value_type), 24)
2232
+
2233
+ def test_get_struct_element_offset(self):
2234
+ td = self.target_data()
2235
+ glob = self.glob("glob_struct")
2236
+
2237
+ with self.assertRaises(ValueError):
2238
+ td.get_element_offset(glob.type, 0)
2239
+
2240
+ struct_type = glob.global_value_type
2241
+ self.assertEqual(td.get_element_offset(struct_type, 0), 0)
2242
+ self.assertEqual(td.get_element_offset(struct_type, 1), 8)
2243
+
2244
+
2245
+ class TestTargetMachine(BaseTest):
2246
+
2247
+ def test_add_analysis_passes(self):
2248
+ tm = self.target_machine(jit=False)
2249
+ pm = llvm.create_module_pass_manager()
2250
+ tm.add_analysis_passes(pm)
2251
+
2252
+ def test_target_data_from_tm(self):
2253
+ tm = self.target_machine(jit=False)
2254
+ td = tm.target_data
2255
+ mod = self.module()
2256
+ gv_i32 = mod.get_global_variable("glob")
2257
+ # A global is a pointer, it has the ABI size of a pointer
2258
+ pointer_size = 4 if sys.maxsize < 2 ** 32 else 8
2259
+ self.assertEqual(td.get_abi_size(gv_i32.type), pointer_size)
2260
+
2261
+
2262
+ class TestPassManagerBuilder(BaseTest):
2263
+
2264
+ def pmb(self):
2265
+ return llvm.PassManagerBuilder()
2266
+
2267
+ def test_old_api(self):
2268
+ # Test the create_pass_manager_builder() factory function
2269
+ pmb = llvm.create_pass_manager_builder()
2270
+ pmb.inlining_threshold = 2
2271
+ pmb.opt_level = 3
2272
+
2273
+ def test_close(self):
2274
+ pmb = self.pmb()
2275
+ pmb.close()
2276
+ pmb.close()
2277
+
2278
+ def test_opt_level(self):
2279
+ pmb = self.pmb()
2280
+ self.assertIsInstance(pmb.opt_level, int)
2281
+ for i in range(4):
2282
+ pmb.opt_level = i
2283
+ self.assertEqual(pmb.opt_level, i)
2284
+
2285
+ def test_size_level(self):
2286
+ pmb = self.pmb()
2287
+ self.assertIsInstance(pmb.size_level, int)
2288
+ for i in range(4):
2289
+ pmb.size_level = i
2290
+ self.assertEqual(pmb.size_level, i)
2291
+
2292
+ def test_inlining_threshold(self):
2293
+ pmb = self.pmb()
2294
+ with self.assertRaises(NotImplementedError):
2295
+ pmb.inlining_threshold
2296
+ for i in (25, 80, 350):
2297
+ pmb.inlining_threshold = i
2298
+
2299
+ def test_disable_unroll_loops(self):
2300
+ pmb = self.pmb()
2301
+ self.assertIsInstance(pmb.disable_unroll_loops, bool)
2302
+ for b in (True, False):
2303
+ pmb.disable_unroll_loops = b
2304
+ self.assertEqual(pmb.disable_unroll_loops, b)
2305
+
2306
+ def test_loop_vectorize(self):
2307
+ pmb = self.pmb()
2308
+ self.assertIsInstance(pmb.loop_vectorize, bool)
2309
+ for b in (True, False):
2310
+ pmb.loop_vectorize = b
2311
+ self.assertEqual(pmb.loop_vectorize, b)
2312
+
2313
+ def test_slp_vectorize(self):
2314
+ pmb = self.pmb()
2315
+ self.assertIsInstance(pmb.slp_vectorize, bool)
2316
+ for b in (True, False):
2317
+ pmb.slp_vectorize = b
2318
+ self.assertEqual(pmb.slp_vectorize, b)
2319
+
2320
+ def test_populate_module_pass_manager(self):
2321
+ pmb = self.pmb()
2322
+ pm = llvm.create_module_pass_manager()
2323
+ pmb.populate(pm)
2324
+ pmb.close()
2325
+ pm.close()
2326
+
2327
+ def test_populate_function_pass_manager(self):
2328
+ mod = self.module()
2329
+ pmb = self.pmb()
2330
+ pm = llvm.create_function_pass_manager(mod)
2331
+ pmb.populate(pm)
2332
+ pmb.close()
2333
+ pm.close()
2334
+
2335
+
2336
+ class PassManagerTestMixin(object):
2337
+
2338
+ def pmb(self):
2339
+ pmb = llvm.create_pass_manager_builder()
2340
+ pmb.opt_level = 2
2341
+ pmb.inlining_threshold = 300
2342
+ return pmb
2343
+
2344
+ def test_close(self):
2345
+ pm = self.pm()
2346
+ pm.close()
2347
+ pm.close()
2348
+
2349
+
2350
+ class TestModulePassManager(BaseTest, PassManagerTestMixin):
2351
+
2352
+ def pm(self):
2353
+ return llvm.create_module_pass_manager()
2354
+
2355
+ def test_run(self):
2356
+ pm = self.pm()
2357
+ self.pmb().populate(pm)
2358
+ mod = self.module()
2359
+ orig_asm = str(mod)
2360
+ pm.run(mod)
2361
+ opt_asm = str(mod)
2362
+ # Quick check that optimizations were run, should get:
2363
+ # define i32 @sum(i32 %.1, i32 %.2) local_unnamed_addr #0 {
2364
+ # %.X = add i32 %.2, %.1
2365
+ # ret i32 %.X
2366
+ # }
2367
+ # where X in %.X is 3 or 4
2368
+ opt_asm_split = opt_asm.splitlines()
2369
+ for idx, l in enumerate(opt_asm_split):
2370
+ if l.strip().startswith('ret i32'):
2371
+ toks = {'%.3', '%.4'}
2372
+ for t in toks:
2373
+ if t in l:
2374
+ break
2375
+ else:
2376
+ raise RuntimeError("expected tokens not found")
2377
+ othertoken = (toks ^ {t}).pop()
2378
+
2379
+ self.assertIn("%.3", orig_asm)
2380
+ self.assertNotIn(othertoken, opt_asm)
2381
+ break
2382
+ else:
2383
+ raise RuntimeError("expected IR not found")
2384
+
2385
+ def test_run_with_remarks_successful_inline(self):
2386
+ pm = self.pm()
2387
+ pm.add_function_inlining_pass(70)
2388
+ self.pmb().populate(pm)
2389
+ mod = self.module(asm_inlineasm2)
2390
+ (status, remarks) = pm.run_with_remarks(mod)
2391
+ self.assertTrue(status)
2392
+ # Inlining has happened? The remark will tell us.
2393
+ self.assertIn("Passed", remarks)
2394
+ self.assertIn("inlineme", remarks)
2395
+
2396
+ def test_run_with_remarks_failed_inline(self):
2397
+ pm = self.pm()
2398
+ pm.add_function_inlining_pass(0)
2399
+ self.pmb().populate(pm)
2400
+ mod = self.module(asm_inlineasm3)
2401
+ (status, remarks) = pm.run_with_remarks(mod)
2402
+ self.assertTrue(status)
2403
+
2404
+ # Inlining has not happened? The remark will tell us.
2405
+ self.assertIn("Missed", remarks)
2406
+ self.assertIn("inlineme", remarks)
2407
+ self.assertIn("noinline function attribute", remarks)
2408
+
2409
+ def test_run_with_remarks_inline_filter_out(self):
2410
+ pm = self.pm()
2411
+ pm.add_function_inlining_pass(70)
2412
+ self.pmb().populate(pm)
2413
+ mod = self.module(asm_inlineasm2)
2414
+ (status, remarks) = pm.run_with_remarks(mod, remarks_filter="nothing")
2415
+ self.assertTrue(status)
2416
+ self.assertEqual("", remarks)
2417
+
2418
+ def test_run_with_remarks_inline_filter_in(self):
2419
+ pm = self.pm()
2420
+ pm.add_function_inlining_pass(70)
2421
+ self.pmb().populate(pm)
2422
+ mod = self.module(asm_inlineasm2)
2423
+ (status, remarks) = pm.run_with_remarks(mod, remarks_filter="inlin.*")
2424
+ self.assertTrue(status)
2425
+ self.assertIn("Passed", remarks)
2426
+ self.assertIn("inlineme", remarks)
2427
+
2428
+
2429
+ class TestFunctionPassManager(BaseTest, PassManagerTestMixin):
2430
+
2431
+ def pm(self, mod=None):
2432
+ mod = mod or self.module()
2433
+ return llvm.create_function_pass_manager(mod)
2434
+
2435
+ def test_initfini(self):
2436
+ pm = self.pm()
2437
+ pm.initialize()
2438
+ pm.finalize()
2439
+
2440
+ def test_run(self):
2441
+ mod = self.module()
2442
+ fn = mod.get_function("sum")
2443
+ pm = self.pm(mod)
2444
+ self.pmb().populate(pm)
2445
+ mod.close()
2446
+ orig_asm = str(fn)
2447
+ pm.initialize()
2448
+ pm.run(fn)
2449
+ pm.finalize()
2450
+ opt_asm = str(fn)
2451
+ # Quick check that optimizations were run
2452
+ self.assertIn("%.4", orig_asm)
2453
+ self.assertNotIn("%.4", opt_asm)
2454
+
2455
+ def test_run_with_remarks(self):
2456
+ mod = self.module(licm_asm)
2457
+ fn = mod.get_function("licm")
2458
+ pm = self.pm(mod)
2459
+ pm.add_licm_pass()
2460
+ self.pmb().populate(pm)
2461
+ mod.close()
2462
+
2463
+ pm.initialize()
2464
+ (ok, remarks) = pm.run_with_remarks(fn)
2465
+ pm.finalize()
2466
+ self.assertTrue(ok)
2467
+ self.assertIn("Passed", remarks)
2468
+ self.assertIn("licm", remarks)
2469
+
2470
+ def test_run_with_remarks_filter_out(self):
2471
+ mod = self.module(licm_asm)
2472
+ fn = mod.get_function("licm")
2473
+ pm = self.pm(mod)
2474
+ pm.add_licm_pass()
2475
+ self.pmb().populate(pm)
2476
+ mod.close()
2477
+
2478
+ pm.initialize()
2479
+ (ok, remarks) = pm.run_with_remarks(fn, remarks_filter="nothing")
2480
+ pm.finalize()
2481
+ self.assertTrue(ok)
2482
+ self.assertEqual("", remarks)
2483
+
2484
+ def test_run_with_remarks_filter_in(self):
2485
+ mod = self.module(licm_asm)
2486
+ fn = mod.get_function("licm")
2487
+ pm = self.pm(mod)
2488
+ pm.add_licm_pass()
2489
+ self.pmb().populate(pm)
2490
+ mod.close()
2491
+
2492
+ pm.initialize()
2493
+ (ok, remarks) = pm.run_with_remarks(fn, remarks_filter="licm")
2494
+ pm.finalize()
2495
+ self.assertTrue(ok)
2496
+ self.assertIn("Passed", remarks)
2497
+ self.assertIn("licm", remarks)
2498
+
2499
+
2500
+ class TestPasses(BaseTest, PassManagerTestMixin):
2501
+
2502
+ def pm(self):
2503
+ return llvm.create_module_pass_manager()
2504
+
2505
+ def test_populate(self):
2506
+ llvm_ver = llvm.llvm_version_info[0]
2507
+
2508
+ pm = self.pm()
2509
+ pm.add_target_library_info("") # unspecified target triple
2510
+ pm.add_constant_merge_pass()
2511
+ pm.add_dead_arg_elimination_pass()
2512
+ pm.add_function_attrs_pass()
2513
+ pm.add_function_inlining_pass(225)
2514
+ pm.add_global_dce_pass()
2515
+ pm.add_global_optimizer_pass()
2516
+ pm.add_ipsccp_pass()
2517
+ pm.add_dead_code_elimination_pass()
2518
+ pm.add_cfg_simplification_pass()
2519
+ pm.add_gvn_pass()
2520
+ pm.add_instruction_combining_pass()
2521
+ pm.add_licm_pass()
2522
+ pm.add_sccp_pass()
2523
+ pm.add_sroa_pass()
2524
+ pm.add_type_based_alias_analysis_pass()
2525
+ pm.add_basic_alias_analysis_pass()
2526
+ pm.add_loop_rotate_pass()
2527
+ pm.add_region_info_pass()
2528
+ pm.add_scalar_evolution_aa_pass()
2529
+ pm.add_aggressive_dead_code_elimination_pass()
2530
+ pm.add_aa_eval_pass()
2531
+ pm.add_always_inliner_pass()
2532
+ pm.add_break_critical_edges_pass()
2533
+ pm.add_dead_store_elimination_pass()
2534
+ pm.add_reverse_post_order_function_attrs_pass()
2535
+
2536
+ if llvm_ver < 16:
2537
+ pm.add_aggressive_instruction_combining_pass()
2538
+
2539
+ pm.add_internalize_pass()
2540
+ pm.add_jump_threading_pass(7)
2541
+ pm.add_lcssa_pass()
2542
+ pm.add_loop_deletion_pass()
2543
+ pm.add_loop_extractor_pass()
2544
+ pm.add_single_loop_extractor_pass()
2545
+ pm.add_loop_strength_reduce_pass()
2546
+ pm.add_loop_simplification_pass()
2547
+ pm.add_loop_unroll_pass()
2548
+ pm.add_loop_unroll_and_jam_pass()
2549
+ pm.add_lower_atomic_pass()
2550
+ pm.add_lower_invoke_pass()
2551
+ pm.add_lower_switch_pass()
2552
+ pm.add_memcpy_optimization_pass()
2553
+ pm.add_merge_functions_pass()
2554
+ pm.add_merge_returns_pass()
2555
+ pm.add_partial_inlining_pass()
2556
+
2557
+ if llvm_ver < 16:
2558
+ pm.add_prune_exception_handling_pass()
2559
+
2560
+ pm.add_reassociate_expressions_pass()
2561
+ pm.add_demote_register_to_memory_pass()
2562
+ pm.add_sink_pass()
2563
+ pm.add_strip_symbols_pass()
2564
+ pm.add_strip_dead_debug_info_pass()
2565
+ pm.add_strip_dead_prototypes_pass()
2566
+ pm.add_strip_debug_declare_pass()
2567
+ pm.add_strip_nondebug_symbols_pass()
2568
+ pm.add_tail_call_elimination_pass()
2569
+ pm.add_basic_aa_pass()
2570
+ pm.add_dependence_analysis_pass()
2571
+ pm.add_dot_call_graph_pass()
2572
+ pm.add_dot_cfg_printer_pass()
2573
+ pm.add_dot_dom_printer_pass()
2574
+ pm.add_dot_postdom_printer_pass()
2575
+ pm.add_globals_mod_ref_aa_pass()
2576
+ pm.add_iv_users_pass()
2577
+ pm.add_lazy_value_info_pass()
2578
+ pm.add_lint_pass()
2579
+ pm.add_module_debug_info_pass()
2580
+ pm.add_refprune_pass()
2581
+ pm.add_instruction_namer_pass()
2582
+
2583
+ @unittest.skipUnless(platform.machine().startswith("x86"), "x86 only")
2584
+ def test_target_library_info_behavior(self):
2585
+ """Test a specific situation that demonstrate TLI is affecting
2586
+ optimization. See https://github.com/numba/numba/issues/8898.
2587
+ """
2588
+ def run(use_tli):
2589
+ mod = llvm.parse_assembly(asm_tli_exp2)
2590
+ target = llvm.Target.from_triple(mod.triple)
2591
+ tm = target.create_target_machine()
2592
+ pm = llvm.ModulePassManager()
2593
+ tm.add_analysis_passes(pm)
2594
+ if use_tli:
2595
+ pm.add_target_library_info(mod.triple)
2596
+ pm.add_instruction_combining_pass()
2597
+ pm.run(mod)
2598
+ return mod
2599
+
2600
+ # Run with TLI should suppress transformation of exp2 -> ldexpf
2601
+ mod = run(use_tli=True)
2602
+ self.assertIn("call float @llvm.exp2.f32", str(mod))
2603
+
2604
+ # Run without TLI will enable the transformation
2605
+ mod = run(use_tli=False)
2606
+ self.assertNotIn("call float @llvm.exp2.f32", str(mod))
2607
+ self.assertIn("call float @ldexpf", str(mod))
2608
+
2609
+ def test_instruction_namer_pass(self):
2610
+ asm = asm_inlineasm3.format(triple=llvm.get_default_triple())
2611
+ mod = llvm.parse_assembly(asm)
2612
+
2613
+ # Run instnamer pass
2614
+ pm = llvm.ModulePassManager()
2615
+ pm.add_instruction_namer_pass()
2616
+ pm.run(mod)
2617
+
2618
+ # Test that unnamed instructions are now named
2619
+ func = mod.get_function('foo')
2620
+ first_block = next(func.blocks)
2621
+ instructions = list(first_block.instructions)
2622
+ self.assertEqual(instructions[0].name, 'i')
2623
+ self.assertEqual(instructions[1].name, 'i2')
2624
+
2625
+
2626
+ class TestDylib(BaseTest):
2627
+
2628
+ def test_bad_library(self):
2629
+ with self.assertRaises(RuntimeError):
2630
+ llvm.load_library_permanently("zzzasdkf;jasd;l")
2631
+
2632
+ @unittest.skipUnless(platform.system() in ["Linux"],
2633
+ "test only works on Linux")
2634
+ def test_libm(self):
2635
+ libm = find_library("m")
2636
+ llvm.load_library_permanently(libm)
2637
+
2638
+
2639
+ class TestAnalysis(BaseTest):
2640
+ def build_ir_module(self):
2641
+ m = ir.Module()
2642
+ ft = ir.FunctionType(ir.IntType(32), [ir.IntType(32), ir.IntType(32)])
2643
+ fn = ir.Function(m, ft, "foo")
2644
+ bd = ir.IRBuilder(fn.append_basic_block())
2645
+ x, y = fn.args
2646
+ z = bd.add(x, y)
2647
+ bd.ret(z)
2648
+ return m
2649
+
2650
+ def test_get_function_cfg_on_ir(self):
2651
+ mod = self.build_ir_module()
2652
+ foo = mod.get_global('foo')
2653
+ dot_showing_inst = llvm.get_function_cfg(foo)
2654
+ dot_without_inst = llvm.get_function_cfg(foo, show_inst=False)
2655
+ inst = "%.5 = add i32 %.1, %.2"
2656
+ self.assertIn(inst, dot_showing_inst)
2657
+ self.assertNotIn(inst, dot_without_inst)
2658
+
2659
+ def test_function_cfg_on_llvm_value(self):
2660
+ defined = self.module().get_function('sum')
2661
+ dot_showing_inst = llvm.get_function_cfg(defined, show_inst=True)
2662
+ dot_without_inst = llvm.get_function_cfg(defined, show_inst=False)
2663
+ # Check "digraph"
2664
+ prefix = 'digraph'
2665
+ self.assertIn(prefix, dot_showing_inst)
2666
+ self.assertIn(prefix, dot_without_inst)
2667
+ # Check function name
2668
+ fname = "CFG for 'sum' function"
2669
+ self.assertIn(fname, dot_showing_inst)
2670
+ self.assertIn(fname, dot_without_inst)
2671
+ # Check instruction
2672
+ inst = "%.3 = add i32 %.1, %.2"
2673
+ self.assertIn(inst, dot_showing_inst)
2674
+ self.assertNotIn(inst, dot_without_inst)
2675
+
2676
+
2677
+ class TestTypeParsing(BaseTest):
2678
+ @contextmanager
2679
+ def check_parsing(self):
2680
+ mod = ir.Module()
2681
+ # Yield to caller and provide the module for adding
2682
+ # new GV.
2683
+ yield mod
2684
+ # Caller yield back and continue with testing
2685
+ asm = str(mod)
2686
+ llvm.parse_assembly(asm)
2687
+
2688
+ def test_literal_struct(self):
2689
+ # Natural layout
2690
+ with self.check_parsing() as mod:
2691
+ typ = ir.LiteralStructType([ir.IntType(32)])
2692
+ gv = ir.GlobalVariable(mod, typ, "foo")
2693
+ # Also test constant text repr
2694
+ gv.initializer = ir.Constant(typ, [1])
2695
+
2696
+ # Packed layout
2697
+ with self.check_parsing() as mod:
2698
+ typ = ir.LiteralStructType([ir.IntType(32)],
2699
+ packed=True)
2700
+ gv = ir.GlobalVariable(mod, typ, "foo")
2701
+ # Also test constant text repr
2702
+ gv.initializer = ir.Constant(typ, [1])
2703
+
2704
+ # Packed layout created from Constant.literal_struct
2705
+ with self.check_parsing() as mod:
2706
+ const = ir.Constant.literal_struct([ir.IntType(32)(1),
2707
+ ir.IntType(32)(2)],
2708
+ packed=True)
2709
+ gv = ir.GlobalVariable(mod, const.type, "foo")
2710
+ gv.initializer = const
2711
+
2712
+
2713
+ class TestGlobalConstructors(TestMCJit):
2714
+ def test_global_ctors_dtors(self):
2715
+ # test issue #303
2716
+ # (https://github.com/numba/llvmlite/issues/303)
2717
+ mod = self.module(asm_global_ctors)
2718
+ ee = self.jit(mod)
2719
+ ee.finalize_object()
2720
+
2721
+ ee.run_static_constructors()
2722
+
2723
+ # global variable should have been initialized
2724
+ ptr_addr = ee.get_global_value_address("A")
2725
+ ptr_t = ctypes.POINTER(ctypes.c_int32)
2726
+ ptr = ctypes.cast(ptr_addr, ptr_t)
2727
+ self.assertEqual(ptr.contents.value, 10)
2728
+
2729
+ foo_addr = ee.get_function_address("foo")
2730
+ foo = ctypes.CFUNCTYPE(ctypes.c_int32)(foo_addr)
2731
+ self.assertEqual(foo(), 12)
2732
+
2733
+ ee.run_static_destructors()
2734
+
2735
+ # destructor should have run
2736
+ self.assertEqual(ptr.contents.value, 20)
2737
+
2738
+
2739
+ class TestGlobalVariables(BaseTest):
2740
+ def check_global_variable_linkage(self, linkage, has_undef=True):
2741
+ # This test default initializer on global variables with different
2742
+ # linkages. Some linkages requires an initializer be present, while
2743
+ # it is optional for others. This test uses ``parse_assembly()``
2744
+ # to verify that we are adding an `undef` automatically if user didn't
2745
+ # specific one for certain linkages. It is a IR syntax error if the
2746
+ # initializer is not present for certain linkages e.g. "external".
2747
+ mod = ir.Module()
2748
+ typ = ir.IntType(32)
2749
+ gv = ir.GlobalVariable(mod, typ, "foo")
2750
+ gv.linkage = linkage
2751
+ asm = str(mod)
2752
+ # check if 'undef' is present
2753
+ if has_undef:
2754
+ self.assertIn('undef', asm)
2755
+ else:
2756
+ self.assertNotIn('undef', asm)
2757
+ # parse assembly to ensure correctness
2758
+ self.module(asm)
2759
+
2760
+ def test_internal_linkage(self):
2761
+ self.check_global_variable_linkage('internal')
2762
+
2763
+ def test_common_linkage(self):
2764
+ self.check_global_variable_linkage('common')
2765
+
2766
+ def test_external_linkage(self):
2767
+ self.check_global_variable_linkage('external', has_undef=False)
2768
+
2769
+ def test_available_externally_linkage(self):
2770
+ self.check_global_variable_linkage('available_externally')
2771
+
2772
+ def test_private_linkage(self):
2773
+ self.check_global_variable_linkage('private')
2774
+
2775
+ def test_linkonce_linkage(self):
2776
+ self.check_global_variable_linkage('linkonce')
2777
+
2778
+ def test_weak_linkage(self):
2779
+ self.check_global_variable_linkage('weak')
2780
+
2781
+ def test_appending_linkage(self):
2782
+ self.check_global_variable_linkage('appending')
2783
+
2784
+ def test_extern_weak_linkage(self):
2785
+ self.check_global_variable_linkage('extern_weak', has_undef=False)
2786
+
2787
+ def test_linkonce_odr_linkage(self):
2788
+ self.check_global_variable_linkage('linkonce_odr')
2789
+
2790
+ def test_weak_odr_linkage(self):
2791
+ self.check_global_variable_linkage('weak_odr')
2792
+
2793
+
2794
+ @unittest.skipUnless(platform.machine().startswith('x86'), "only on x86")
2795
+ class TestInlineAsm(BaseTest):
2796
+ def test_inlineasm(self):
2797
+ llvm.initialize_native_asmparser()
2798
+ m = self.module(asm=asm_inlineasm)
2799
+ tm = self.target_machine(jit=False)
2800
+ asm = tm.emit_assembly(m)
2801
+ self.assertIn('nop', asm)
2802
+
2803
+
2804
+ class TestObjectFile(BaseTest):
2805
+
2806
+ mod_asm = """
2807
+ ;ModuleID = <string>
2808
+ target triple = "{triple}"
2809
+
2810
+ declare i32 @sum(i32 %.1, i32 %.2)
2811
+
2812
+ define i32 @sum_twice(i32 %.1, i32 %.2) {{
2813
+ %.3 = call i32 @sum(i32 %.1, i32 %.2)
2814
+ %.4 = call i32 @sum(i32 %.3, i32 %.3)
2815
+ ret i32 %.4
2816
+ }}
2817
+ """
2818
+
2819
+ def test_object_file(self):
2820
+ target_machine = self.target_machine(jit=False)
2821
+ mod = self.module()
2822
+ obj_bin = target_machine.emit_object(mod)
2823
+ obj = llvm.ObjectFileRef.from_data(obj_bin)
2824
+ # Check that we have a text section, and that she has a name and data
2825
+ has_text = False
2826
+ last_address = -1
2827
+ for s in obj.sections():
2828
+ if s.is_text():
2829
+ has_text = True
2830
+ self.assertIsNotNone(s.name())
2831
+ self.assertTrue(s.size() > 0)
2832
+ self.assertTrue(len(s.data()) > 0)
2833
+ self.assertIsNotNone(s.address())
2834
+ self.assertTrue(last_address < s.address())
2835
+ last_address = s.address()
2836
+ break
2837
+ self.assertTrue(has_text)
2838
+
2839
+ def test_add_object_file(self):
2840
+ target_machine = self.target_machine(jit=False)
2841
+ mod = self.module()
2842
+ obj_bin = target_machine.emit_object(mod)
2843
+ obj = llvm.ObjectFileRef.from_data(obj_bin)
2844
+
2845
+ jit = llvm.create_mcjit_compiler(self.module(self.mod_asm),
2846
+ target_machine)
2847
+
2848
+ jit.add_object_file(obj)
2849
+
2850
+ sum_twice = CFUNCTYPE(c_int, c_int, c_int)(
2851
+ jit.get_function_address("sum_twice"))
2852
+
2853
+ self.assertEqual(sum_twice(2, 3), 10)
2854
+
2855
+ def test_add_object_file_from_filesystem(self):
2856
+ target_machine = self.target_machine(jit=False)
2857
+ mod = self.module()
2858
+ obj_bin = target_machine.emit_object(mod)
2859
+ temp_desc, temp_path = mkstemp()
2860
+
2861
+ try:
2862
+ try:
2863
+ f = os.fdopen(temp_desc, "wb")
2864
+ f.write(obj_bin)
2865
+ f.flush()
2866
+ finally:
2867
+ f.close()
2868
+
2869
+ jit = llvm.create_mcjit_compiler(self.module(self.mod_asm),
2870
+ target_machine)
2871
+
2872
+ jit.add_object_file(temp_path)
2873
+ finally:
2874
+ os.unlink(temp_path)
2875
+
2876
+ sum_twice = CFUNCTYPE(c_int, c_int, c_int)(
2877
+ jit.get_function_address("sum_twice"))
2878
+
2879
+ self.assertEqual(sum_twice(2, 3), 10)
2880
+
2881
+ def test_get_section_content(self):
2882
+ # See Issue #632 - section contents were getting truncated at null
2883
+ # bytes.
2884
+ elf = bytes.fromhex(issue_632_elf)
2885
+ obj = llvm.ObjectFileRef.from_data(elf)
2886
+ for s in obj.sections():
2887
+ if s.is_text():
2888
+ self.assertEqual(len(s.data()), 31)
2889
+ self.assertEqual(s.data().hex(), issue_632_text)
2890
+
2891
+
2892
+ class TestTimePasses(BaseTest):
2893
+ def test_reporting(self):
2894
+ mp = llvm.create_module_pass_manager()
2895
+
2896
+ pmb = llvm.create_pass_manager_builder()
2897
+ pmb.opt_level = 3
2898
+ pmb.populate(mp)
2899
+
2900
+ try:
2901
+ llvm.set_time_passes(True)
2902
+ mp.run(self.module())
2903
+ mp.run(self.module())
2904
+ mp.run(self.module())
2905
+ finally:
2906
+ report = llvm.report_and_reset_timings()
2907
+ llvm.set_time_passes(False)
2908
+
2909
+ self.assertIsInstance(report, str)
2910
+ self.assertEqual(report.count("Pass execution timing report"), 1)
2911
+
2912
+ def test_empty_report(self):
2913
+ # Returns empty str if no data is collected
2914
+ self.assertFalse(llvm.report_and_reset_timings())
2915
+
2916
+
2917
+ class TestLLVMLockCallbacks(BaseTest):
2918
+ def test_lock_callbacks(self):
2919
+ events = []
2920
+
2921
+ def acq():
2922
+ events.append('acq')
2923
+
2924
+ def rel():
2925
+ events.append('rel')
2926
+
2927
+ # register callback
2928
+ llvm.ffi.register_lock_callback(acq, rel)
2929
+
2930
+ # Check: events are initially empty
2931
+ self.assertFalse(events)
2932
+ # Call LLVM functions
2933
+ llvm.create_module_pass_manager()
2934
+ # Check: there must be at least one acq and one rel
2935
+ self.assertIn("acq", events)
2936
+ self.assertIn("rel", events)
2937
+
2938
+ # unregister callback
2939
+ llvm.ffi.unregister_lock_callback(acq, rel)
2940
+
2941
+ # Check: removing non-existent callbacks will trigger a ValueError
2942
+ with self.assertRaises(ValueError):
2943
+ llvm.ffi.unregister_lock_callback(acq, rel)
2944
+
2945
+
2946
+ class TestPipelineTuningOptions(BaseTest):
2947
+
2948
+ def pto(self):
2949
+ return llvm.create_pipeline_tuning_options()
2950
+
2951
+ def test_close(self):
2952
+ pto = self.pto()
2953
+ pto.close()
2954
+
2955
+ def test_speed_level(self):
2956
+ pto = self.pto()
2957
+ self.assertIsInstance(pto.speed_level, int)
2958
+ for i in range(4):
2959
+ pto.speed_level = i
2960
+ self.assertEqual(pto.speed_level, i)
2961
+
2962
+ def test_size_level(self):
2963
+ pto = self.pto()
2964
+ self.assertIsInstance(pto.size_level, int)
2965
+ for i in range(3):
2966
+ pto.size_level = i
2967
+ self.assertEqual(pto.size_level, i)
2968
+
2969
+ # // FIXME: Available from llvm16
2970
+ # def test_inlining_threshold(self):
2971
+ # pto = self.pto()
2972
+ # with self.assertRaises(NotImplementedError):
2973
+ # pto.inlining_threshold
2974
+ # for i in (25, 80, 350):
2975
+ # pto.inlining_threshold = i
2976
+
2977
+ def test_loop_interleaving(self):
2978
+ pto = self.pto()
2979
+ self.assertIsInstance(pto.loop_interleaving, bool)
2980
+ for b in (True, False):
2981
+ pto.loop_interleaving = b
2982
+ self.assertEqual(pto.loop_interleaving, b)
2983
+
2984
+ def test_loop_vectorization(self):
2985
+ pto = self.pto()
2986
+ self.assertIsInstance(pto.loop_vectorization, bool)
2987
+ for b in (True, False):
2988
+ pto.loop_vectorization = b
2989
+ self.assertEqual(pto.loop_vectorization, b)
2990
+
2991
+ def test_slp_vectorization(self):
2992
+ pto = self.pto()
2993
+ self.assertIsInstance(pto.slp_vectorization, bool)
2994
+ for b in (True, False):
2995
+ pto.slp_vectorization = b
2996
+ self.assertEqual(pto.slp_vectorization, b)
2997
+
2998
+ def test_loop_unrolling(self):
2999
+ pto = self.pto()
3000
+ self.assertIsInstance(pto.loop_unrolling, bool)
3001
+ for b in (True, False):
3002
+ pto.loop_unrolling = b
3003
+ self.assertEqual(pto.loop_unrolling, b)
3004
+
3005
+ def test_speed_level_constraints(self):
3006
+ pto = self.pto()
3007
+ with self.assertRaises(ValueError):
3008
+ pto.speed_level = 4
3009
+ with self.assertRaises(ValueError):
3010
+ pto.speed_level = -1
3011
+
3012
+ def test_size_level_constraints(self):
3013
+ pto = self.pto()
3014
+ with self.assertRaises(ValueError):
3015
+ pto.size_level = 3
3016
+ with self.assertRaises(ValueError):
3017
+ pto.speed_level = -1
3018
+ with self.assertRaises(ValueError):
3019
+ pto.speed_level = 3
3020
+ pto.size_level = 2
3021
+
3022
+
3023
+ class NewPassManagerMixin(object):
3024
+
3025
+ def pb(self, speed_level=0, size_level=0):
3026
+ tm = self.target_machine(jit=False)
3027
+ pto = llvm.create_pipeline_tuning_options(speed_level, size_level)
3028
+ pb = llvm.create_pass_builder(tm, pto)
3029
+ return pb
3030
+
3031
+
3032
+ class TestPassBuilder(BaseTest, NewPassManagerMixin):
3033
+
3034
+ def test_close(self):
3035
+ pb = self.pb()
3036
+ pb.close()
3037
+
3038
+ def test_pto(self):
3039
+ tm = self.target_machine(jit=False)
3040
+ pto = llvm.create_pipeline_tuning_options(3, 0)
3041
+ pto.inlining_threshold = 2
3042
+ pto.loop_interleaving = True
3043
+ pto.loop_vectorization = True
3044
+ pto.slp_vectorization = True
3045
+ pto.loop_unrolling = False
3046
+ pb = llvm.create_pass_builder(tm, pto)
3047
+ pb.close()
3048
+
3049
+ def test_get_module_pass_manager(self):
3050
+ pb = self.pb()
3051
+ mpm = pb.getModulePassManager()
3052
+ mpm.run(self.module(), pb)
3053
+ pb.close()
3054
+
3055
+ def test_get_function_pass_manager(self):
3056
+ pb = self.pb()
3057
+ fpm = pb.getFunctionPassManager()
3058
+ fpm.run(self.module().get_function("sum"), pb)
3059
+ pb.close()
3060
+
3061
+
3062
+ class TestNewModulePassManager(BaseTest, NewPassManagerMixin):
3063
+ def pm(self):
3064
+ return llvm.create_new_module_pass_manager()
3065
+
3066
+ def run_o_n(self, level):
3067
+ mod = self.module()
3068
+ orig_asm = str(mod)
3069
+ pb = self.pb(speed_level=level, size_level=0)
3070
+ mpm = pb.getModulePassManager()
3071
+ mpm.run(mod, pb)
3072
+ optimized_asm = str(mod)
3073
+ return orig_asm, optimized_asm
3074
+
3075
+ def test_close(self):
3076
+ mpm = self.pm()
3077
+ mpm.close()
3078
+
3079
+ def test_run_o3(self):
3080
+ orig_asm, optimized_asm = self.run_o_n(3)
3081
+ self.assertIn("%.4", orig_asm)
3082
+ self.assertNotIn("%.4", optimized_asm)
3083
+
3084
+ def test_run_o0(self):
3085
+ orig_asm, optimized_asm = self.run_o_n(0)
3086
+ self.assertIn("%.4", orig_asm)
3087
+ self.assertIn("%.4", optimized_asm)
3088
+
3089
+ def test_instcombine(self):
3090
+ pb = self.pb()
3091
+ mpm = self.pm()
3092
+ mpm.add_instruction_combine_pass()
3093
+ mod = self.module(asm_sum4)
3094
+ orig_asm = str(mod)
3095
+ mpm.run(mod, pb)
3096
+ optimized_asm = str(mod)
3097
+ self.assertIn("%.3", orig_asm)
3098
+ self.assertNotIn("%.3", optimized_asm)
3099
+
3100
+ def test_optnone(self):
3101
+ pb = self.pb(speed_level=3, size_level=0)
3102
+ orig_asm = str(asm_alloca_optnone.replace("optnone ", ""))
3103
+ mod = llvm.parse_assembly(orig_asm)
3104
+ mpm = pb.getModulePassManager()
3105
+ mpm.run(mod, pb)
3106
+ optimized_asm = str(mod)
3107
+ self.assertIn("alloca", orig_asm)
3108
+ self.assertNotIn("alloca", optimized_asm)
3109
+
3110
+ # Module shouldn't be optimized if the function has `optnone` attached
3111
+ orig_asm_optnone = str(asm_alloca_optnone)
3112
+ mpm = pb.getModulePassManager()
3113
+ mod = llvm.parse_assembly(orig_asm_optnone)
3114
+ mpm.run(mod, pb)
3115
+ optimized_asm_optnone = str(mod)
3116
+ self.assertIn("alloca", orig_asm_optnone)
3117
+ self.assertIn("alloca", optimized_asm_optnone)
3118
+
3119
+ def test_add_passes(self):
3120
+ mpm = self.pm()
3121
+ mpm.add_verifier()
3122
+ mpm.add_aa_eval_pass()
3123
+ mpm.add_simplify_cfg_pass()
3124
+ mpm.add_loop_unroll_pass()
3125
+ mpm.add_loop_rotate_pass()
3126
+ mpm.add_instruction_combine_pass()
3127
+ mpm.add_jump_threading_pass()
3128
+ mpm.add_refprune_pass()
3129
+
3130
+
3131
+ class TestNewFunctionPassManager(BaseTest, NewPassManagerMixin):
3132
+ def pm(self):
3133
+ return llvm.create_new_function_pass_manager()
3134
+
3135
+ def test_close(self):
3136
+ fpm = self.pm()
3137
+ fpm.close()
3138
+
3139
+ def run_o_n(self, level):
3140
+ mod = self.module()
3141
+ fun = mod.get_function("sum")
3142
+ orig_asm = str(fun)
3143
+ pb = self.pb(speed_level=level, size_level=0)
3144
+ fpm = pb.getFunctionPassManager()
3145
+ fpm.run(fun, pb)
3146
+ optimized_asm = str(fun)
3147
+ return orig_asm, optimized_asm
3148
+
3149
+ def test_run_o3(self):
3150
+ orig_asm, optimized_asm = self.run_o_n(3)
3151
+ self.assertIn("%.4", orig_asm)
3152
+ self.assertNotIn("%.4", optimized_asm)
3153
+
3154
+ def test_run_o0(self):
3155
+ orig_asm, optimized_asm = self.run_o_n(0)
3156
+ self.assertIn("%.4", orig_asm)
3157
+ self.assertIn("%.4", optimized_asm)
3158
+
3159
+ def test_optnone(self):
3160
+ pb = self.pb(speed_level=3, size_level=0)
3161
+ orig_asm = str(asm_alloca_optnone.replace("optnone ", ""))
3162
+ fun = llvm.parse_assembly(orig_asm).get_function("foo")
3163
+ fpm = pb.getFunctionPassManager()
3164
+ fpm.run(fun, pb)
3165
+ optimized_asm = str(fun)
3166
+ self.assertIn("alloca", orig_asm)
3167
+ self.assertNotIn("alloca", optimized_asm)
3168
+
3169
+ # Function shouldn't be optimized if the function has `optnone` attached
3170
+ orig_asm_optnone = str(asm_alloca_optnone)
3171
+ fun = llvm.parse_assembly(orig_asm_optnone).get_function("foo")
3172
+ fpm = pb.getFunctionPassManager()
3173
+ fpm.run(fun, pb)
3174
+ optimized_asm_optnone = str(fun)
3175
+ self.assertIn("alloca", orig_asm_optnone)
3176
+ self.assertIn("alloca", optimized_asm_optnone)
3177
+
3178
+ def test_instcombine(self):
3179
+ pb = self.pb()
3180
+ fpm = self.pm()
3181
+ fun = self.module(asm_sum4).get_function("sum")
3182
+ fpm.add_instruction_combine_pass()
3183
+ orig_asm = str(fun)
3184
+ fpm.run(fun, pb)
3185
+ optimized_asm = str(fun)
3186
+ self.assertIn("%.3", orig_asm)
3187
+ self.assertNotIn("%.3", optimized_asm)
3188
+
3189
+ # This should not crash
3190
+ def test_declarations(self):
3191
+ pb = self.pb(3)
3192
+ fpm = pb.getFunctionPassManager()
3193
+ for fun in llvm.parse_assembly(asm_declaration).functions:
3194
+ fpm.run(fun, pb)
3195
+
3196
+ def test_add_passes(self):
3197
+ fpm = self.pm()
3198
+ fpm.add_aa_eval_pass()
3199
+ fpm.add_simplify_cfg_pass()
3200
+ fpm.add_loop_unroll_pass()
3201
+ fpm.add_loop_rotate_pass()
3202
+ fpm.add_instruction_combine_pass()
3203
+ fpm.add_jump_threading_pass()
3204
+ fpm.add_refprune_pass()
3205
+
3206
+
3207
+ if __name__ == "__main__":
3208
+ unittest.main()