llvmlite 0.44.0rc1__cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of llvmlite might be problematic. Click here for more details.

Files changed (46) hide show
  1. llvmlite/__init__.py +10 -0
  2. llvmlite/_version.py +11 -0
  3. llvmlite/binding/__init__.py +19 -0
  4. llvmlite/binding/analysis.py +69 -0
  5. llvmlite/binding/common.py +34 -0
  6. llvmlite/binding/context.py +39 -0
  7. llvmlite/binding/dylib.py +45 -0
  8. llvmlite/binding/executionengine.py +330 -0
  9. llvmlite/binding/ffi.py +395 -0
  10. llvmlite/binding/initfini.py +73 -0
  11. llvmlite/binding/libllvmlite.so +0 -0
  12. llvmlite/binding/linker.py +20 -0
  13. llvmlite/binding/module.py +349 -0
  14. llvmlite/binding/newpassmanagers.py +357 -0
  15. llvmlite/binding/object_file.py +82 -0
  16. llvmlite/binding/options.py +17 -0
  17. llvmlite/binding/orcjit.py +342 -0
  18. llvmlite/binding/passmanagers.py +946 -0
  19. llvmlite/binding/targets.py +520 -0
  20. llvmlite/binding/transforms.py +151 -0
  21. llvmlite/binding/typeref.py +285 -0
  22. llvmlite/binding/value.py +632 -0
  23. llvmlite/ir/__init__.py +11 -0
  24. llvmlite/ir/_utils.py +80 -0
  25. llvmlite/ir/builder.py +1120 -0
  26. llvmlite/ir/context.py +20 -0
  27. llvmlite/ir/instructions.py +920 -0
  28. llvmlite/ir/module.py +246 -0
  29. llvmlite/ir/transforms.py +64 -0
  30. llvmlite/ir/types.py +734 -0
  31. llvmlite/ir/values.py +1217 -0
  32. llvmlite/tests/__init__.py +57 -0
  33. llvmlite/tests/__main__.py +3 -0
  34. llvmlite/tests/customize.py +407 -0
  35. llvmlite/tests/refprune_proto.py +329 -0
  36. llvmlite/tests/test_binding.py +3208 -0
  37. llvmlite/tests/test_ir.py +2986 -0
  38. llvmlite/tests/test_refprune.py +730 -0
  39. llvmlite/tests/test_valuerepr.py +60 -0
  40. llvmlite/utils.py +29 -0
  41. llvmlite-0.44.0rc1.dist-info/LICENSE +24 -0
  42. llvmlite-0.44.0rc1.dist-info/LICENSE.thirdparty +225 -0
  43. llvmlite-0.44.0rc1.dist-info/METADATA +138 -0
  44. llvmlite-0.44.0rc1.dist-info/RECORD +46 -0
  45. llvmlite-0.44.0rc1.dist-info/WHEEL +6 -0
  46. llvmlite-0.44.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,730 @@
1
+ import unittest
2
+ from llvmlite import ir
3
+ from llvmlite import binding as llvm
4
+ from llvmlite.tests import TestCase
5
+
6
+ import llvmlite.tests.refprune_proto as proto
7
+
8
+ # TODO:: Get rid of Legacy tests once completely transitioned to NewPassManager
9
+
10
+ # FIXME: Remove me once typed pointers are no longer supported.
11
+ from llvmlite import opaque_pointers_enabled
12
+
13
+
14
+ def _iterate_cases(generate_test):
15
+ def wrap(fn):
16
+ def wrapped(self):
17
+ return generate_test(self, fn)
18
+ wrapped.__doc__ = f"generated test for {fn.__module__}.{fn.__name__}"
19
+ return wrapped
20
+
21
+ for k, case_fn in proto.__dict__.items():
22
+ if k.startswith('case'):
23
+ yield f'test_{k}', wrap(case_fn)
24
+
25
+
26
+ class PassManagerMixin():
27
+
28
+ def pb(self):
29
+ llvm.initialize_native_target()
30
+ tm = llvm.Target.from_default_triple().create_target_machine()
31
+ pto = llvm.create_pipeline_tuning_options(speed_level=0, size_level=0)
32
+ return llvm.create_pass_builder(tm, pto)
33
+
34
+
35
+ class TestRefPrunePrototype(TestCase):
36
+ """
37
+ Test that the prototype is working.
38
+ """
39
+ def generate_test(self, case_gen):
40
+ nodes, edges, expected = case_gen()
41
+ got = proto.FanoutAlgorithm(nodes, edges).run()
42
+ self.assertEqual(expected, got)
43
+
44
+ # Generate tests
45
+ for name, case in _iterate_cases(generate_test):
46
+ locals()[name] = case
47
+
48
+
49
+ ptr_ty = ir.IntType(8).as_pointer()
50
+
51
+
52
+ class TestRefPrunePass(TestCase, PassManagerMixin):
53
+ """
54
+ Test that the C++ implementation matches the expected behavior as for
55
+ the prototype.
56
+
57
+ This generates a LLVM module for each test case, runs the pruner and checks
58
+ that the expected results are achieved.
59
+ """
60
+
61
+ def make_incref(self, m):
62
+ fnty = ir.FunctionType(ir.VoidType(), [ptr_ty])
63
+ return ir.Function(m, fnty, name='NRT_incref')
64
+
65
+ def make_decref(self, m):
66
+ fnty = ir.FunctionType(ir.VoidType(), [ptr_ty])
67
+ return ir.Function(m, fnty, name='NRT_decref')
68
+
69
+ def make_switcher(self, m):
70
+ fnty = ir.FunctionType(ir.IntType(32), ())
71
+ return ir.Function(m, fnty, name='switcher')
72
+
73
+ def make_brancher(self, m):
74
+ fnty = ir.FunctionType(ir.IntType(1), ())
75
+ return ir.Function(m, fnty, name='brancher')
76
+
77
+ def generate_ir(self, nodes, edges):
78
+ # Build LLVM module for the CFG
79
+ m = ir.Module()
80
+
81
+ incref_fn = self.make_incref(m)
82
+ decref_fn = self.make_decref(m)
83
+ switcher_fn = self.make_switcher(m)
84
+ brancher_fn = self.make_brancher(m)
85
+
86
+ fnty = ir.FunctionType(ir.VoidType(), [ptr_ty])
87
+ fn = ir.Function(m, fnty, name='main')
88
+ [ptr] = fn.args
89
+ ptr.name = 'mem'
90
+ # populate the BB nodes
91
+ bbmap = {}
92
+ for bb in edges:
93
+ bbmap[bb] = fn.append_basic_block(bb)
94
+ # populate the BB
95
+ builder = ir.IRBuilder()
96
+ for bb, jump_targets in edges.items():
97
+ builder.position_at_end(bbmap[bb])
98
+ # Insert increfs and decrefs
99
+ for action in nodes[bb]:
100
+ if action == 'incref':
101
+ builder.call(incref_fn, [ptr])
102
+ elif action == 'decref':
103
+ builder.call(decref_fn, [ptr])
104
+ else:
105
+ raise AssertionError('unreachable')
106
+
107
+ # Insert the terminator.
108
+ # Switch base on the number of jump targets.
109
+ n_targets = len(jump_targets)
110
+ if n_targets == 0:
111
+ builder.ret_void()
112
+ elif n_targets == 1:
113
+ [dst] = jump_targets
114
+ builder.branch(bbmap[dst])
115
+ elif n_targets == 2:
116
+ [left, right] = jump_targets
117
+ sel = builder.call(brancher_fn, ())
118
+ builder.cbranch(sel, bbmap[left], bbmap[right])
119
+ elif n_targets > 2:
120
+ sel = builder.call(switcher_fn, ())
121
+ [head, *tail] = jump_targets
122
+
123
+ sw = builder.switch(sel, default=bbmap[head])
124
+ for i, dst in enumerate(tail):
125
+ sw.add_case(sel.type(i), bbmap[dst])
126
+ else:
127
+ raise AssertionError('unreachable')
128
+
129
+ return m
130
+
131
+ def apply_refprune(self, irmod):
132
+ mod = llvm.parse_assembly(str(irmod))
133
+ pb = self.pb()
134
+ pm = pb.getModulePassManager()
135
+ pm.add_refprune_pass()
136
+ pm.run(mod, pb)
137
+ return mod
138
+
139
+ def apply_refprune_legacy(self, irmod):
140
+ mod = llvm.parse_assembly(str(irmod))
141
+ pm = llvm.ModulePassManager()
142
+ pm.add_refprune_pass()
143
+ pm.run(mod)
144
+ return mod
145
+
146
+ def check(self, mod, expected, nodes):
147
+ # preprocess incref/decref locations
148
+ d = {}
149
+ for k, vs in nodes.items():
150
+ n_incref = vs.count('incref')
151
+ n_decref = vs.count('decref')
152
+ d[k] = {'incref': n_incref, 'decref': n_decref}
153
+ for k, stats in d.items():
154
+ if expected.get(k):
155
+ stats['incref'] -= 1
156
+ for dec_bb in expected[k]:
157
+ d[dec_bb]['decref'] -= 1
158
+
159
+ # find the main function
160
+ for f in mod.functions:
161
+ if f.name == 'main':
162
+ break
163
+ # check each BB
164
+ for bb in f.blocks:
165
+ stats = d[bb.name]
166
+ text = str(bb)
167
+ n_incref = text.count('NRT_incref')
168
+ n_decref = text.count('NRT_decref')
169
+ self.assertEqual(stats['incref'], n_incref, msg=f'BB {bb}')
170
+ self.assertEqual(stats['decref'], n_decref, msg=f'BB {bb}')
171
+
172
+ def generate_test(self, case_gen):
173
+ nodes, edges, expected = case_gen()
174
+ irmod = self.generate_ir(nodes, edges)
175
+ outmod = self.apply_refprune(irmod)
176
+ self.check(outmod, expected, nodes)
177
+
178
+ def generate_test_legacy(self, case_gen):
179
+ nodes, edges, expected = case_gen()
180
+ irmod = self.generate_ir(nodes, edges)
181
+ outmod = self.apply_refprune_legacy(irmod)
182
+ self.check(outmod, expected, nodes)
183
+
184
+ # Generate tests
185
+ for name, case in _iterate_cases(generate_test):
186
+ locals()[name] = case
187
+
188
+ for name, case in _iterate_cases(generate_test_legacy):
189
+ locals()[name + "_legacy"] = case
190
+
191
+
192
+ class BaseTestByIR(TestCase, PassManagerMixin):
193
+ refprune_bitmask = 0
194
+
195
+ prologue = r"""
196
+ declare void @NRT_incref(i8* %ptr)
197
+ declare void @NRT_decref(i8* %ptr)
198
+ """
199
+
200
+ def check(self, irmod, subgraph_limit=None):
201
+ mod = llvm.parse_assembly(f"{self.prologue}\n{irmod}")
202
+ pb = self.pb()
203
+ pm = pb.getModulePassManager()
204
+ if subgraph_limit is None:
205
+ pm.add_refprune_pass(self.refprune_bitmask)
206
+ else:
207
+ pm.add_refprune_pass(self.refprune_bitmask,
208
+ subgraph_limit=subgraph_limit)
209
+ before = llvm.dump_refprune_stats()
210
+ pm.run(mod, pb)
211
+ after = llvm.dump_refprune_stats()
212
+ return mod, after - before
213
+
214
+ def check_legacy(self, irmod, subgraph_limit=None):
215
+ mod = llvm.parse_assembly(f"{self.prologue}\n{irmod}")
216
+ pm = llvm.ModulePassManager()
217
+ if subgraph_limit is None:
218
+ pm.add_refprune_pass(self.refprune_bitmask)
219
+ else:
220
+ pm.add_refprune_pass(self.refprune_bitmask,
221
+ subgraph_limit=subgraph_limit)
222
+ before = llvm.dump_refprune_stats()
223
+ pm.run(mod)
224
+ after = llvm.dump_refprune_stats()
225
+ return mod, after - before
226
+
227
+
228
+ class TestPerBB(BaseTestByIR):
229
+ refprune_bitmask = llvm.RefPruneSubpasses.PER_BB
230
+
231
+ per_bb_ir_1 = r"""
232
+ define void @main(i8* %ptr) {
233
+ call void @NRT_incref(i8* %ptr)
234
+ call void @NRT_decref(i8* %ptr)
235
+ ret void
236
+ }
237
+ """
238
+
239
+ def test_per_bb_1(self):
240
+ mod, stats = self.check(self.per_bb_ir_1)
241
+ self.assertEqual(stats.basicblock, 2)
242
+
243
+ def test_per_bb_1_legacy(self):
244
+ mod, stats = self.check_legacy(self.per_bb_ir_1)
245
+ self.assertEqual(stats.basicblock, 2)
246
+
247
+ per_bb_ir_2 = r"""
248
+ define void @main(i8* %ptr) {
249
+ call void @NRT_incref(i8* %ptr)
250
+ call void @NRT_incref(i8* %ptr)
251
+ call void @NRT_incref(i8* %ptr)
252
+ call void @NRT_decref(i8* %ptr)
253
+ call void @NRT_decref(i8* %ptr)
254
+ ret void
255
+ }
256
+ """
257
+
258
+ def test_per_bb_2(self):
259
+ mod, stats = self.check(self.per_bb_ir_2)
260
+ self.assertEqual(stats.basicblock, 4)
261
+ # not pruned
262
+ # FIXME: Remove `else' once TP are no longer supported.
263
+ if opaque_pointers_enabled:
264
+ self.assertIn("call void @NRT_incref(ptr %ptr)", str(mod))
265
+ else:
266
+ self.assertIn("call void @NRT_incref(i8* %ptr)", str(mod))
267
+
268
+ def test_per_bb_2_legacy(self):
269
+ mod, stats = self.check_legacy(self.per_bb_ir_2)
270
+ self.assertEqual(stats.basicblock, 4)
271
+ # not pruned
272
+ # FIXME: Remove `else' once TP are no longer supported.
273
+ if opaque_pointers_enabled:
274
+ self.assertIn("call void @NRT_incref(ptr %ptr)", str(mod))
275
+ else:
276
+ self.assertIn("call void @NRT_incref(i8* %ptr)", str(mod))
277
+
278
+ per_bb_ir_3 = r"""
279
+ define void @main(ptr %ptr, ptr %other) {
280
+ call void @NRT_incref(ptr %ptr)
281
+ call void @NRT_incref(ptr %ptr)
282
+ call void @NRT_decref(ptr %ptr)
283
+ call void @NRT_decref(ptr %other)
284
+ ret void
285
+ }
286
+ """ if opaque_pointers_enabled else r"""
287
+ define void @main(i8* %ptr, i8* %other) {
288
+ call void @NRT_incref(i8* %ptr)
289
+ call void @NRT_incref(i8* %ptr)
290
+ call void @NRT_decref(i8* %ptr)
291
+ call void @NRT_decref(i8* %other)
292
+ ret void
293
+ }
294
+ """
295
+
296
+ def test_per_bb_3(self):
297
+ mod, stats = self.check(self.per_bb_ir_3)
298
+ self.assertEqual(stats.basicblock, 2)
299
+ # not pruned
300
+ # FIXME: Remove `else' once TP are no longer supported.
301
+ if opaque_pointers_enabled:
302
+ self.assertIn("call void @NRT_decref(ptr %other)", str(mod))
303
+ else:
304
+ self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
305
+
306
+ def test_per_bb_3_legacy(self):
307
+ mod, stats = self.check_legacy(self.per_bb_ir_3)
308
+ self.assertEqual(stats.basicblock, 2)
309
+ # not pruned
310
+ # FIXME: Remove `else' once TP are no longer supported.
311
+ if opaque_pointers_enabled:
312
+ self.assertIn("call void @NRT_decref(ptr %other)", str(mod))
313
+ else:
314
+ self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
315
+
316
+ per_bb_ir_4 = r"""
317
+ ; reordered
318
+ define void @main(ptr %ptr, ptr %other) {
319
+ call void @NRT_incref(ptr %ptr)
320
+ call void @NRT_decref(ptr %ptr)
321
+ call void @NRT_decref(ptr %ptr)
322
+ call void @NRT_decref(ptr %other)
323
+ call void @NRT_incref(ptr %ptr)
324
+ ret void
325
+ }
326
+ """ if opaque_pointers_enabled else r"""
327
+ ; reordered
328
+ define void @main(i8* %ptr, i8* %other) {
329
+ call void @NRT_incref(i8* %ptr)
330
+ call void @NRT_decref(i8* %ptr)
331
+ call void @NRT_decref(i8* %ptr)
332
+ call void @NRT_decref(i8* %other)
333
+ call void @NRT_incref(i8* %ptr)
334
+ ret void
335
+ }
336
+ """
337
+
338
+ def test_per_bb_4(self):
339
+ mod, stats = self.check(self.per_bb_ir_4)
340
+ self.assertEqual(stats.basicblock, 4)
341
+ # not pruned
342
+ # FIXME: Remove `else' once TP are no longer supported.
343
+ if opaque_pointers_enabled:
344
+ self.assertIn("call void @NRT_decref(ptr %other)", str(mod))
345
+ else:
346
+ self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
347
+
348
+ def test_per_bb_4_legacy(self):
349
+ mod, stats = self.check_legacy(self.per_bb_ir_4)
350
+ self.assertEqual(stats.basicblock, 4)
351
+ # not pruned
352
+ # FIXME: Remove `else' once TP are no longer supported.
353
+ if opaque_pointers_enabled:
354
+ self.assertIn("call void @NRT_decref(ptr %other)", str(mod))
355
+ else:
356
+ self.assertIn("call void @NRT_decref(i8* %other)", str(mod))
357
+
358
+
359
+ class TestDiamond(BaseTestByIR):
360
+ refprune_bitmask = llvm.RefPruneSubpasses.DIAMOND
361
+
362
+ per_diamond_1 = r"""
363
+ define void @main(i8* %ptr) {
364
+ bb_A:
365
+ call void @NRT_incref(i8* %ptr)
366
+ br label %bb_B
367
+ bb_B:
368
+ call void @NRT_decref(i8* %ptr)
369
+ ret void
370
+ }
371
+ """
372
+
373
+ def test_per_diamond_1(self):
374
+ mod, stats = self.check(self.per_diamond_1)
375
+ self.assertEqual(stats.diamond, 2)
376
+
377
+ def test_per_diamond_1_legacy(self):
378
+ mod, stats = self.check_legacy(self.per_diamond_1)
379
+ self.assertEqual(stats.diamond, 2)
380
+
381
+ per_diamond_2 = r"""
382
+ define void @main(i8* %ptr, i1 %cond) {
383
+ bb_A:
384
+ call void @NRT_incref(i8* %ptr)
385
+ br i1 %cond, label %bb_B, label %bb_C
386
+ bb_B:
387
+ br label %bb_D
388
+ bb_C:
389
+ br label %bb_D
390
+ bb_D:
391
+ call void @NRT_decref(i8* %ptr)
392
+ ret void
393
+ }
394
+ """
395
+
396
+ def test_per_diamond_2(self):
397
+ mod, stats = self.check(self.per_diamond_2)
398
+ self.assertEqual(stats.diamond, 2)
399
+
400
+ def test_per_diamond_2_legacy(self):
401
+ mod, stats = self.check_legacy(self.per_diamond_2)
402
+ self.assertEqual(stats.diamond, 2)
403
+
404
+ per_diamond_3 = r"""
405
+ define void @main(i8* %ptr, i1 %cond) {
406
+ bb_A:
407
+ call void @NRT_incref(i8* %ptr)
408
+ br i1 %cond, label %bb_B, label %bb_C
409
+ bb_B:
410
+ br label %bb_D
411
+ bb_C:
412
+ call void @NRT_decref(i8* %ptr) ; reject because of decref in diamond
413
+ br label %bb_D
414
+ bb_D:
415
+ call void @NRT_decref(i8* %ptr)
416
+ ret void
417
+ }
418
+ """
419
+
420
+ def test_per_diamond_3(self):
421
+ mod, stats = self.check(self.per_diamond_3)
422
+ self.assertEqual(stats.diamond, 0)
423
+
424
+ def test_per_diamond_3_legacy(self):
425
+ mod, stats = self.check_legacy(self.per_diamond_3)
426
+ self.assertEqual(stats.diamond, 0)
427
+
428
+ per_diamond_4 = r"""
429
+ define void @main(i8* %ptr, i1 %cond) {
430
+ bb_A:
431
+ call void @NRT_incref(i8* %ptr)
432
+ br i1 %cond, label %bb_B, label %bb_C
433
+ bb_B:
434
+ call void @NRT_incref(i8* %ptr) ; extra incref will not affect prune
435
+ br label %bb_D
436
+ bb_C:
437
+ br label %bb_D
438
+ bb_D:
439
+ call void @NRT_decref(i8* %ptr)
440
+ ret void
441
+ }
442
+ """
443
+
444
+ def test_per_diamond_4(self):
445
+ mod, stats = self.check(self.per_diamond_4)
446
+ self.assertEqual(stats.diamond, 2)
447
+
448
+ def test_per_diamond_4_legacy(self):
449
+ mod, stats = self.check_legacy(self.per_diamond_4)
450
+ self.assertEqual(stats.diamond, 2)
451
+
452
+ per_diamond_5 = r"""
453
+ define void @main(i8* %ptr, i1 %cond) {
454
+ bb_A:
455
+ call void @NRT_incref(i8* %ptr)
456
+ call void @NRT_incref(i8* %ptr)
457
+ br i1 %cond, label %bb_B, label %bb_C
458
+ bb_B:
459
+ br label %bb_D
460
+ bb_C:
461
+ br label %bb_D
462
+ bb_D:
463
+ call void @NRT_decref(i8* %ptr)
464
+ call void @NRT_decref(i8* %ptr)
465
+ ret void
466
+ }
467
+ """
468
+
469
+ def test_per_diamond_5(self):
470
+ mod, stats = self.check(self.per_diamond_5)
471
+ self.assertEqual(stats.diamond, 4)
472
+
473
+ def test_per_diamond_5_legacy(self):
474
+ mod, stats = self.check_legacy(self.per_diamond_5)
475
+ self.assertEqual(stats.diamond, 4)
476
+
477
+
478
+ class TestFanout(BaseTestByIR):
479
+ """More complex cases are tested in TestRefPrunePass
480
+ """
481
+
482
+ refprune_bitmask = llvm.RefPruneSubpasses.FANOUT
483
+
484
+ fanout_1 = r"""
485
+ define void @main(i8* %ptr, i1 %cond) {
486
+ bb_A:
487
+ call void @NRT_incref(i8* %ptr)
488
+ br i1 %cond, label %bb_B, label %bb_C
489
+ bb_B:
490
+ call void @NRT_decref(i8* %ptr)
491
+ ret void
492
+ bb_C:
493
+ call void @NRT_decref(i8* %ptr)
494
+ ret void
495
+ }
496
+ """
497
+
498
+ def test_fanout_1(self):
499
+ mod, stats = self.check(self.fanout_1)
500
+ self.assertEqual(stats.fanout, 3)
501
+
502
+ def test_fanout_1_legacy(self):
503
+ mod, stats = self.check_legacy(self.fanout_1)
504
+ self.assertEqual(stats.fanout, 3)
505
+
506
+ fanout_2 = r"""
507
+ define void @main(i8* %ptr, i1 %cond, i8** %excinfo) {
508
+ bb_A:
509
+ call void @NRT_incref(i8* %ptr)
510
+ br i1 %cond, label %bb_B, label %bb_C
511
+ bb_B:
512
+ call void @NRT_decref(i8* %ptr)
513
+ ret void
514
+ bb_C:
515
+ call void @NRT_decref(i8* %ptr)
516
+ br label %bb_B ; illegal jump to other decref
517
+ }
518
+ """
519
+
520
+ def test_fanout_2(self):
521
+ mod, stats = self.check(self.fanout_2)
522
+ self.assertEqual(stats.fanout, 0)
523
+
524
+ def test_fanout_2_legacy(self):
525
+ mod, stats = self.check_legacy(self.fanout_2)
526
+ self.assertEqual(stats.fanout, 0)
527
+
528
+ fanout_3 = r"""
529
+ define void @main(i8* %ptr, i1 %cond) {
530
+ bb_A:
531
+ call void @NRT_incref(i8* %ptr)
532
+ call void @NRT_incref(i8* %ptr)
533
+ br i1 %cond, label %bb_B, label %bb_C
534
+ bb_B:
535
+ call void @NRT_decref(i8* %ptr)
536
+ call void @NRT_decref(i8* %ptr)
537
+ call void @NRT_decref(i8* %ptr)
538
+ ret void
539
+ bb_C:
540
+ call void @NRT_decref(i8* %ptr)
541
+ call void @NRT_decref(i8* %ptr)
542
+ ret void
543
+ }
544
+ """
545
+
546
+ def test_fanout_3(self):
547
+ mod, stats = self.check(self.fanout_3)
548
+ self.assertEqual(stats.fanout, 6)
549
+
550
+ def test_fanout_3_limited(self):
551
+ # With subgraph limit at 1, it is essentially turning off the fanout
552
+ # pruner.
553
+ mod, stats = self.check(self.fanout_3, subgraph_limit=1)
554
+ self.assertEqual(stats.fanout, 0)
555
+
556
+ def test_fanout_3_legacy(self):
557
+ mod, stats = self.check_legacy(self.fanout_3)
558
+ self.assertEqual(stats.fanout, 6)
559
+
560
+ def test_fanout_3_limited_legacy(self):
561
+ # With subgraph limit at 1, it is essentially turning off the fanout
562
+ # pruner.
563
+ mod, stats = self.check_legacy(self.fanout_3, subgraph_limit=1)
564
+ self.assertEqual(stats.fanout, 0)
565
+
566
+
567
+ class TestFanoutRaise(BaseTestByIR):
568
+ refprune_bitmask = llvm.RefPruneSubpasses.FANOUT_RAISE
569
+
570
+ fanout_raise_1 = r"""
571
+ define i32 @main(i8* %ptr, i1 %cond, i8** %excinfo) {
572
+ bb_A:
573
+ call void @NRT_incref(i8* %ptr)
574
+ br i1 %cond, label %bb_B, label %bb_C
575
+ bb_B:
576
+ call void @NRT_decref(i8* %ptr)
577
+ ret i32 0
578
+ bb_C:
579
+ store i8* null, i8** %excinfo, !numba_exception_output !0
580
+ ret i32 1
581
+ }
582
+ !0 = !{i1 true}
583
+ """
584
+
585
+ def test_fanout_raise_1(self):
586
+ mod, stats = self.check(self.fanout_raise_1)
587
+ self.assertEqual(stats.fanout_raise, 2)
588
+
589
+ def test_fanout_raise_1_legacy(self):
590
+ mod, stats = self.check_legacy(self.fanout_raise_1)
591
+ self.assertEqual(stats.fanout_raise, 2)
592
+
593
+ fanout_raise_2 = r"""
594
+ define i32 @main(i8* %ptr, i1 %cond, i8** %excinfo) {
595
+ bb_A:
596
+ call void @NRT_incref(i8* %ptr)
597
+ br i1 %cond, label %bb_B, label %bb_C
598
+ bb_B:
599
+ call void @NRT_decref(i8* %ptr)
600
+ ret i32 0
601
+ bb_C:
602
+ store i8* null, i8** %excinfo, !numba_exception_typo !0 ; bad metadata
603
+ ret i32 1
604
+ }
605
+
606
+ !0 = !{i1 true}
607
+ """
608
+
609
+ def test_fanout_raise_2(self):
610
+ # This is ensuring that fanout_raise is not pruning when the metadata
611
+ # is incorrectly named.
612
+ mod, stats = self.check(self.fanout_raise_2)
613
+ self.assertEqual(stats.fanout_raise, 0)
614
+
615
+ def test_fanout_raise_2_legacy(self):
616
+ # This is ensuring that fanout_raise is not pruning when the metadata
617
+ # is incorrectly named.
618
+ mod, stats = self.check_legacy(self.fanout_raise_2)
619
+ self.assertEqual(stats.fanout_raise, 0)
620
+
621
+ fanout_raise_3 = r"""
622
+ define i32 @main(i8* %ptr, i1 %cond, i8** %excinfo) {
623
+ bb_A:
624
+ call void @NRT_incref(i8* %ptr)
625
+ br i1 %cond, label %bb_B, label %bb_C
626
+ bb_B:
627
+ call void @NRT_decref(i8* %ptr)
628
+ ret i32 0
629
+ bb_C:
630
+ store i8* null, i8** %excinfo, !numba_exception_output !0
631
+ ret i32 1
632
+ }
633
+
634
+ !0 = !{i32 1} ; ok; use i32
635
+ """
636
+
637
+ def test_fanout_raise_3(self):
638
+ mod, stats = self.check(self.fanout_raise_3)
639
+ self.assertEqual(stats.fanout_raise, 2)
640
+
641
+ def test_fanout_raise_3_legacy(self):
642
+ mod, stats = self.check_legacy(self.fanout_raise_3)
643
+ self.assertEqual(stats.fanout_raise, 2)
644
+
645
+ fanout_raise_4 = r"""
646
+ define i32 @main(i8* %ptr, i1 %cond, i8** %excinfo) {
647
+ bb_A:
648
+ call void @NRT_incref(i8* %ptr)
649
+ br i1 %cond, label %bb_B, label %bb_C
650
+ bb_B:
651
+ ret i32 1 ; BAD; all tails are raising without decref
652
+ bb_C:
653
+ ret i32 1 ; BAD; all tails are raising without decref
654
+ }
655
+
656
+ !0 = !{i1 1}
657
+ """
658
+
659
+ def test_fanout_raise_4(self):
660
+ mod, stats = self.check(self.fanout_raise_4)
661
+ self.assertEqual(stats.fanout_raise, 0)
662
+
663
+ def test_fanout_raise_4_legacy(self):
664
+ mod, stats = self.check_legacy(self.fanout_raise_4)
665
+ self.assertEqual(stats.fanout_raise, 0)
666
+
667
+ fanout_raise_5 = r"""
668
+ define i32 @main(i8* %ptr, i1 %cond, i8** %excinfo) {
669
+ bb_A:
670
+ call void @NRT_incref(i8* %ptr)
671
+ br i1 %cond, label %bb_B, label %bb_C
672
+ bb_B:
673
+ call void @NRT_decref(i8* %ptr)
674
+ br label %common.ret
675
+ bb_C:
676
+ store i8* null, i8** %excinfo, !numba_exception_output !0
677
+ br label %common.ret
678
+ common.ret:
679
+ %common.ret.op = phi i32 [ 0, %bb_B ], [ 1, %bb_C ]
680
+ ret i32 %common.ret.op
681
+ }
682
+ !0 = !{i1 1}
683
+ """
684
+
685
+ def test_fanout_raise_5(self):
686
+ mod, stats = self.check(self.fanout_raise_5)
687
+ self.assertEqual(stats.fanout_raise, 2)
688
+
689
+ def test_fanout_raise_5_legacy(self):
690
+ mod, stats = self.check_legacy(self.fanout_raise_5)
691
+ self.assertEqual(stats.fanout_raise, 2)
692
+
693
+ # test case 6 is from https://github.com/numba/llvmlite/issues/1023
694
+ fanout_raise_6 = r"""
695
+ define i32 @main(i8* %ptr, i1 %cond1, i1 %cond2, i1 %cond3, i8** %excinfo) {
696
+ bb_A:
697
+ call void @NRT_incref(i8* %ptr)
698
+ call void @NRT_incref(i8* %ptr)
699
+ br i1 %cond1, label %bb_B, label %bb_C
700
+ bb_B:
701
+ call void @NRT_decref(i8* %ptr)
702
+ br i1 %cond2, label %bb_D, label %bb_E
703
+ bb_C:
704
+ store i8* null, i8** %excinfo, !numba_exception_output !0
705
+ ret i32 1
706
+ bb_D:
707
+ call void @NRT_decref(i8* %ptr)
708
+ ret i32 0
709
+ bb_E:
710
+ call void @NRT_incref(i8* %ptr)
711
+ br i1 %cond3, label %bb_F, label %bb_C
712
+ bb_F:
713
+ call void @NRT_decref(i8* %ptr)
714
+ call void @NRT_decref(i8* %ptr)
715
+ ret i32 0
716
+ }
717
+ !0 = !{i1 1}
718
+ """
719
+
720
+ def test_fanout_raise_6(self):
721
+ mod, stats = self.check(self.fanout_raise_6)
722
+ self.assertEqual(stats.fanout_raise, 7)
723
+
724
+ def test_fanout_raise_6_legacy(self):
725
+ mod, stats = self.check_legacy(self.fanout_raise_6)
726
+ self.assertEqual(stats.fanout_raise, 7)
727
+
728
+
729
+ if __name__ == '__main__':
730
+ unittest.main()