llvmlite 0.44.0__cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl

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

Potentially problematic release.


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

Files changed (46) hide show
  1. llvmlite/__init__.py +10 -0
  2. llvmlite/_version.py +11 -0
  3. llvmlite/binding/__init__.py +19 -0
  4. llvmlite/binding/analysis.py +69 -0
  5. llvmlite/binding/common.py +34 -0
  6. llvmlite/binding/context.py +39 -0
  7. llvmlite/binding/dylib.py +45 -0
  8. llvmlite/binding/executionengine.py +330 -0
  9. llvmlite/binding/ffi.py +395 -0
  10. llvmlite/binding/initfini.py +73 -0
  11. llvmlite/binding/libllvmlite.so +0 -0
  12. llvmlite/binding/linker.py +20 -0
  13. llvmlite/binding/module.py +349 -0
  14. llvmlite/binding/newpassmanagers.py +357 -0
  15. llvmlite/binding/object_file.py +82 -0
  16. llvmlite/binding/options.py +17 -0
  17. llvmlite/binding/orcjit.py +342 -0
  18. llvmlite/binding/passmanagers.py +946 -0
  19. llvmlite/binding/targets.py +520 -0
  20. llvmlite/binding/transforms.py +151 -0
  21. llvmlite/binding/typeref.py +285 -0
  22. llvmlite/binding/value.py +632 -0
  23. llvmlite/ir/__init__.py +11 -0
  24. llvmlite/ir/_utils.py +80 -0
  25. llvmlite/ir/builder.py +1120 -0
  26. llvmlite/ir/context.py +20 -0
  27. llvmlite/ir/instructions.py +920 -0
  28. llvmlite/ir/module.py +246 -0
  29. llvmlite/ir/transforms.py +64 -0
  30. llvmlite/ir/types.py +734 -0
  31. llvmlite/ir/values.py +1217 -0
  32. llvmlite/tests/__init__.py +57 -0
  33. llvmlite/tests/__main__.py +3 -0
  34. llvmlite/tests/customize.py +407 -0
  35. llvmlite/tests/refprune_proto.py +329 -0
  36. llvmlite/tests/test_binding.py +3208 -0
  37. llvmlite/tests/test_ir.py +2994 -0
  38. llvmlite/tests/test_refprune.py +730 -0
  39. llvmlite/tests/test_valuerepr.py +60 -0
  40. llvmlite/utils.py +29 -0
  41. llvmlite-0.44.0.dist-info/LICENSE +24 -0
  42. llvmlite-0.44.0.dist-info/LICENSE.thirdparty +225 -0
  43. llvmlite-0.44.0.dist-info/METADATA +145 -0
  44. llvmlite-0.44.0.dist-info/RECORD +46 -0
  45. llvmlite-0.44.0.dist-info/WHEEL +6 -0
  46. llvmlite-0.44.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,329 @@
1
+ """
2
+ Contains tests and a prototype implementation for the fanout algorithm in
3
+ the LLVM refprune pass.
4
+ """
5
+
6
+ try:
7
+ from graphviz import Digraph
8
+ except ImportError:
9
+ pass
10
+ from collections import defaultdict
11
+
12
+ # The entry block. It's always the same.
13
+ ENTRY = "A"
14
+
15
+
16
+ # The following caseNN() functions returns a 3-tuple of
17
+ # (nodes, edges, expected).
18
+ # `nodes` maps BB nodes to incref/decref inside the block.
19
+ # `edges` maps BB nodes to their successor BB.
20
+ # `expected` maps BB-node with incref to a set of BB-nodes with the decrefs, or
21
+ # the value can be None, indicating invalid prune.
22
+
23
+ def case1():
24
+ edges = {
25
+ "A": ["B"],
26
+ "B": ["C", "D"],
27
+ "C": [],
28
+ "D": ["E", "F"],
29
+ "E": ["G"],
30
+ "F": [],
31
+ "G": ["H", "I"],
32
+ "I": ["G", "F"],
33
+ "H": ["J", "K"],
34
+ "J": ["L", "M"],
35
+ "K": [],
36
+ "L": ["Z"],
37
+ "M": ["Z", "O", "P"],
38
+ "O": ["Z"],
39
+ "P": ["Z"],
40
+ "Z": [],
41
+ }
42
+ nodes = defaultdict(list)
43
+ nodes["D"] = ["incref"]
44
+ nodes["H"] = ["decref"]
45
+ nodes["F"] = ["decref", "decref"]
46
+ expected = {"D": {"H", "F"}}
47
+ return nodes, edges, expected
48
+
49
+
50
+ def case2():
51
+ edges = {
52
+ "A": ["B", "C"],
53
+ "B": ["C"],
54
+ "C": [],
55
+ }
56
+ nodes = defaultdict(list)
57
+ nodes["A"] = ["incref"]
58
+ nodes["B"] = ["decref"]
59
+ nodes["C"] = ["decref"]
60
+ expected = {"A": None}
61
+ return nodes, edges, expected
62
+
63
+
64
+ def case3():
65
+ nodes, edges, _ = case1()
66
+ # adds an invalid edge
67
+ edges["H"].append("F")
68
+ expected = {"D": None}
69
+ return nodes, edges, expected
70
+
71
+
72
+ def case4():
73
+ nodes, edges, _ = case1()
74
+ # adds an invalid edge
75
+ edges["H"].append("E")
76
+ expected = {"D": None}
77
+ return nodes, edges, expected
78
+
79
+
80
+ def case5():
81
+ nodes, edges, _ = case1()
82
+ # adds backedge to go before incref
83
+ edges["B"].append("I")
84
+ expected = {"D": None}
85
+ return nodes, edges, expected
86
+
87
+
88
+ def case6():
89
+ nodes, edges, _ = case1()
90
+ # adds backedge to go before incref
91
+ edges["I"].append("B")
92
+ expected = {"D": None}
93
+ return nodes, edges, expected
94
+
95
+
96
+ def case7():
97
+ nodes, edges, _ = case1()
98
+ # adds forward jump outside
99
+ edges["I"].append("M")
100
+ expected = {"D": None}
101
+ return nodes, edges, expected
102
+
103
+
104
+ def case8():
105
+ edges = {
106
+ "A": ["B", "C"],
107
+ "B": ["C"],
108
+ "C": [],
109
+ }
110
+ nodes = defaultdict(list)
111
+ nodes["A"] = ["incref"]
112
+ nodes["C"] = ["decref"]
113
+ expected = {"A": {"C"}}
114
+ return nodes, edges, expected
115
+
116
+
117
+ def case9():
118
+ nodes, edges, _ = case8()
119
+ # adds back edge
120
+ edges["C"].append("B")
121
+ expected = {"A": None}
122
+ return nodes, edges, expected
123
+
124
+
125
+ def case10():
126
+ nodes, edges, _ = case8()
127
+ # adds back edge to A
128
+ edges["C"].append("A")
129
+ expected = {"A": {"C"}}
130
+ return nodes, edges, expected
131
+
132
+
133
+ def case11():
134
+ nodes, edges, _ = case8()
135
+ edges["C"].append("D")
136
+ edges["D"] = []
137
+ expected = {"A": {"C"}}
138
+ return nodes, edges, expected
139
+
140
+
141
+ def case12():
142
+ nodes, edges, _ = case8()
143
+ edges["C"].append("D")
144
+ edges["D"] = ["A"]
145
+ expected = {"A": {"C"}}
146
+ return nodes, edges, expected
147
+
148
+
149
+ def case13():
150
+ nodes, edges, _ = case8()
151
+ edges["C"].append("D")
152
+ edges["D"] = ["B"]
153
+ expected = {"A": None}
154
+ return nodes, edges, expected
155
+
156
+
157
+ def make_predecessor_map(edges):
158
+ d = defaultdict(set)
159
+ for src, outgoings in edges.items():
160
+ for dst in outgoings:
161
+ d[dst].add(src)
162
+ return d
163
+
164
+
165
+ class FanoutAlgorithm:
166
+ def __init__(self, nodes, edges, verbose=False):
167
+ self.nodes = nodes
168
+ self.edges = edges
169
+ self.rev_edges = make_predecessor_map(edges)
170
+ self.print = print if verbose else self._null_print
171
+
172
+ def run(self):
173
+ return self.find_fanout_in_function()
174
+
175
+ def _null_print(self, *args, **kwargs):
176
+ pass
177
+
178
+ def find_fanout_in_function(self):
179
+ got = {}
180
+ for cur_node in self.edges:
181
+ for incref in (x for x in self.nodes[cur_node] if x == "incref"):
182
+ decref_blocks = self.find_fanout(cur_node)
183
+ self.print(">>", cur_node, "===", decref_blocks)
184
+ got[cur_node] = decref_blocks
185
+ return got
186
+
187
+ def find_fanout(self, head_node):
188
+ decref_blocks = self.find_decref_candidates(head_node)
189
+ self.print("candidates", decref_blocks)
190
+ if not decref_blocks:
191
+ return None
192
+ if not self.verify_non_overlapping(
193
+ head_node, decref_blocks, entry=ENTRY
194
+ ):
195
+ return None
196
+ return set(decref_blocks)
197
+
198
+ def verify_non_overlapping(self, head_node, decref_blocks, entry):
199
+ self.print("verify_non_overlapping".center(80, "-"))
200
+ # reverse walk for each decref_blocks
201
+ # they should end at head_node
202
+ todo = list(decref_blocks)
203
+ while todo:
204
+ cur_node = todo.pop()
205
+ visited = set()
206
+
207
+ workstack = [cur_node]
208
+ del cur_node
209
+ while workstack:
210
+ cur_node = workstack.pop()
211
+ self.print("cur_node", cur_node, "|", workstack)
212
+ if cur_node in visited:
213
+ continue # skip
214
+ if cur_node == entry:
215
+ # Entry node
216
+ self.print(
217
+ "!! failed because we arrived at entry", cur_node
218
+ )
219
+ return False
220
+ visited.add(cur_node)
221
+ # check all predecessors
222
+ self.print(
223
+ f" {cur_node} preds {self.get_predecessors(cur_node)}"
224
+ )
225
+ for pred in self.get_predecessors(cur_node):
226
+ if pred in decref_blocks:
227
+ # reject because there's a predecessor in decref_blocks
228
+ self.print(
229
+ "!! reject because predecessor in decref_blocks"
230
+ )
231
+ return False
232
+ if pred != head_node:
233
+
234
+ workstack.append(pred)
235
+
236
+ return True
237
+
238
+ def get_successors(self, node):
239
+ return tuple(self.edges[node])
240
+
241
+ def get_predecessors(self, node):
242
+ return tuple(self.rev_edges[node])
243
+
244
+ def has_decref(self, node):
245
+ return "decref" in self.nodes[node]
246
+
247
+ def walk_child_for_decref(
248
+ self, cur_node, path_stack, decref_blocks, depth=10
249
+ ):
250
+ indent = " " * len(path_stack)
251
+ self.print(indent, "walk", path_stack, cur_node)
252
+ if depth <= 0:
253
+ return False # missing
254
+ if cur_node in path_stack:
255
+ if cur_node == path_stack[0]:
256
+ return False # reject interior node backedge
257
+ return True # skip
258
+ if self.has_decref(cur_node):
259
+ decref_blocks.add(cur_node)
260
+ self.print(indent, "found decref")
261
+ return True
262
+
263
+ depth -= 1
264
+ path_stack += (cur_node,)
265
+ found = False
266
+ for child in self.get_successors(cur_node):
267
+ if not self.walk_child_for_decref(
268
+ child, path_stack, decref_blocks
269
+ ):
270
+ found = False
271
+ break
272
+ else:
273
+ found = True
274
+
275
+ self.print(indent, f"ret {found}")
276
+ return found
277
+
278
+ def find_decref_candidates(self, cur_node):
279
+ # Forward pass
280
+ self.print("find_decref_candidates".center(80, "-"))
281
+ path_stack = (cur_node,)
282
+ found = False
283
+ decref_blocks = set()
284
+ for child in self.get_successors(cur_node):
285
+ if not self.walk_child_for_decref(
286
+ child, path_stack, decref_blocks
287
+ ):
288
+ found = False
289
+ break
290
+ else:
291
+ found = True
292
+ if not found:
293
+ return set()
294
+ else:
295
+ return decref_blocks
296
+
297
+
298
+ def check_once():
299
+ nodes, edges, expected = case13()
300
+
301
+ # Render graph
302
+ G = Digraph()
303
+ for node in edges:
304
+ G.node(node, shape="rect", label=f"{node}\n" + r"\l".join(nodes[node]))
305
+ for node, children in edges.items():
306
+ for child in children:
307
+ G.edge(node, child)
308
+
309
+ G.view()
310
+
311
+ algo = FanoutAlgorithm(nodes, edges, verbose=True)
312
+ got = algo.run()
313
+ assert expected == got
314
+
315
+
316
+ def check_all():
317
+ for k, fn in list(globals().items()):
318
+ if k.startswith("case"):
319
+ print(f"{fn}".center(80, "-"))
320
+ nodes, edges, expected = fn()
321
+ algo = FanoutAlgorithm(nodes, edges)
322
+ got = algo.run()
323
+ assert expected == got
324
+ print("ALL PASSED")
325
+
326
+
327
+ if __name__ == "__main__":
328
+ # check_once()
329
+ check_all()