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