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.

Files changed (45) hide show
  1. llvmlite/__init__.py +11 -0
  2. llvmlite/_version.py +11 -0
  3. llvmlite/binding/__init__.py +18 -0
  4. llvmlite/binding/analysis.py +69 -0
  5. llvmlite/binding/common.py +34 -0
  6. llvmlite/binding/config.py +143 -0
  7. llvmlite/binding/context.py +31 -0
  8. llvmlite/binding/dylib.py +45 -0
  9. llvmlite/binding/executionengine.py +330 -0
  10. llvmlite/binding/ffi.py +395 -0
  11. llvmlite/binding/initfini.py +85 -0
  12. llvmlite/binding/libllvmlite.so +0 -0
  13. llvmlite/binding/linker.py +20 -0
  14. llvmlite/binding/module.py +349 -0
  15. llvmlite/binding/newpassmanagers.py +1049 -0
  16. llvmlite/binding/object_file.py +82 -0
  17. llvmlite/binding/options.py +17 -0
  18. llvmlite/binding/orcjit.py +342 -0
  19. llvmlite/binding/targets.py +462 -0
  20. llvmlite/binding/typeref.py +267 -0
  21. llvmlite/binding/value.py +632 -0
  22. llvmlite/ir/__init__.py +11 -0
  23. llvmlite/ir/_utils.py +80 -0
  24. llvmlite/ir/builder.py +1120 -0
  25. llvmlite/ir/context.py +20 -0
  26. llvmlite/ir/instructions.py +920 -0
  27. llvmlite/ir/module.py +256 -0
  28. llvmlite/ir/transforms.py +64 -0
  29. llvmlite/ir/types.py +730 -0
  30. llvmlite/ir/values.py +1217 -0
  31. llvmlite/tests/__init__.py +57 -0
  32. llvmlite/tests/__main__.py +3 -0
  33. llvmlite/tests/customize.py +407 -0
  34. llvmlite/tests/refprune_proto.py +330 -0
  35. llvmlite/tests/test_binding.py +3155 -0
  36. llvmlite/tests/test_ir.py +3095 -0
  37. llvmlite/tests/test_refprune.py +574 -0
  38. llvmlite/tests/test_valuerepr.py +60 -0
  39. llvmlite/utils.py +29 -0
  40. llvmlite-0.46.0b1.dist-info/METADATA +145 -0
  41. llvmlite-0.46.0b1.dist-info/RECORD +45 -0
  42. llvmlite-0.46.0b1.dist-info/WHEEL +6 -0
  43. llvmlite-0.46.0b1.dist-info/licenses/LICENSE +24 -0
  44. llvmlite-0.46.0b1.dist-info/licenses/LICENSE.thirdparty +225 -0
  45. llvmlite-0.46.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,330 @@
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
+ "entry:": ["A"],
107
+ "A": ["B", "C"],
108
+ "B": ["C"],
109
+ "C": [],
110
+ }
111
+ nodes = defaultdict(list)
112
+ nodes["A"] = ["incref"]
113
+ nodes["C"] = ["decref"]
114
+ expected = {"A": {"C"}}
115
+ return nodes, edges, expected
116
+
117
+
118
+ def case9():
119
+ nodes, edges, _ = case8()
120
+ # adds back edge
121
+ edges["C"].append("B")
122
+ expected = {"A": None}
123
+ return nodes, edges, expected
124
+
125
+
126
+ def case10():
127
+ nodes, edges, _ = case8()
128
+ # adds back edge to A
129
+ edges["C"].append("A")
130
+ expected = {"A": {"C"}}
131
+ return nodes, edges, expected
132
+
133
+
134
+ def case11():
135
+ nodes, edges, _ = case8()
136
+ edges["C"].append("D")
137
+ edges["D"] = []
138
+ expected = {"A": {"C"}}
139
+ return nodes, edges, expected
140
+
141
+
142
+ def case12():
143
+ nodes, edges, _ = case8()
144
+ edges["C"].append("D")
145
+ edges["D"] = ["A"]
146
+ expected = {"A": {"C"}}
147
+ return nodes, edges, expected
148
+
149
+
150
+ def case13():
151
+ nodes, edges, _ = case8()
152
+ edges["C"].append("D")
153
+ edges["D"] = ["B"]
154
+ expected = {"A": None}
155
+ return nodes, edges, expected
156
+
157
+
158
+ def make_predecessor_map(edges):
159
+ d = defaultdict(set)
160
+ for src, outgoings in edges.items():
161
+ for dst in outgoings:
162
+ d[dst].add(src)
163
+ return d
164
+
165
+
166
+ class FanoutAlgorithm:
167
+ def __init__(self, nodes, edges, verbose=False):
168
+ self.nodes = nodes
169
+ self.edges = edges
170
+ self.rev_edges = make_predecessor_map(edges)
171
+ self.print = print if verbose else self._null_print
172
+
173
+ def run(self):
174
+ return self.find_fanout_in_function()
175
+
176
+ def _null_print(self, *args, **kwargs):
177
+ pass
178
+
179
+ def find_fanout_in_function(self):
180
+ got = {}
181
+ for cur_node in self.edges:
182
+ for incref in (x for x in self.nodes[cur_node] if x == "incref"):
183
+ decref_blocks = self.find_fanout(cur_node)
184
+ self.print(">>", cur_node, "===", decref_blocks)
185
+ got[cur_node] = decref_blocks
186
+ return got
187
+
188
+ def find_fanout(self, head_node):
189
+ decref_blocks = self.find_decref_candidates(head_node)
190
+ self.print("candidates", decref_blocks)
191
+ if not decref_blocks:
192
+ return None
193
+ if not self.verify_non_overlapping(
194
+ head_node, decref_blocks, entry=ENTRY
195
+ ):
196
+ return None
197
+ return set(decref_blocks)
198
+
199
+ def verify_non_overlapping(self, head_node, decref_blocks, entry):
200
+ self.print("verify_non_overlapping".center(80, "-"))
201
+ # reverse walk for each decref_blocks
202
+ # they should end at head_node
203
+ todo = list(decref_blocks)
204
+ while todo:
205
+ cur_node = todo.pop()
206
+ visited = set()
207
+
208
+ workstack = [cur_node]
209
+ del cur_node
210
+ while workstack:
211
+ cur_node = workstack.pop()
212
+ self.print("cur_node", cur_node, "|", workstack)
213
+ if cur_node in visited:
214
+ continue # skip
215
+ if cur_node == entry:
216
+ # Entry node
217
+ self.print(
218
+ "!! failed because we arrived at entry", cur_node
219
+ )
220
+ return False
221
+ visited.add(cur_node)
222
+ # check all predecessors
223
+ self.print(
224
+ f" {cur_node} preds {self.get_predecessors(cur_node)}"
225
+ )
226
+ for pred in self.get_predecessors(cur_node):
227
+ if pred in decref_blocks:
228
+ # reject because there's a predecessor in decref_blocks
229
+ self.print(
230
+ "!! reject because predecessor in decref_blocks"
231
+ )
232
+ return False
233
+ if pred != head_node:
234
+
235
+ workstack.append(pred)
236
+
237
+ return True
238
+
239
+ def get_successors(self, node):
240
+ return tuple(self.edges[node])
241
+
242
+ def get_predecessors(self, node):
243
+ return tuple(self.rev_edges[node])
244
+
245
+ def has_decref(self, node):
246
+ return "decref" in self.nodes[node]
247
+
248
+ def walk_child_for_decref(
249
+ self, cur_node, path_stack, decref_blocks, depth=10
250
+ ):
251
+ indent = " " * len(path_stack)
252
+ self.print(indent, "walk", path_stack, cur_node)
253
+ if depth <= 0:
254
+ return False # missing
255
+ if cur_node in path_stack:
256
+ if cur_node == path_stack[0]:
257
+ return False # reject interior node backedge
258
+ return True # skip
259
+ if self.has_decref(cur_node):
260
+ decref_blocks.add(cur_node)
261
+ self.print(indent, "found decref")
262
+ return True
263
+
264
+ depth -= 1
265
+ path_stack += (cur_node,)
266
+ found = False
267
+ for child in self.get_successors(cur_node):
268
+ if not self.walk_child_for_decref(
269
+ child, path_stack, decref_blocks
270
+ ):
271
+ found = False
272
+ break
273
+ else:
274
+ found = True
275
+
276
+ self.print(indent, f"ret {found}")
277
+ return found
278
+
279
+ def find_decref_candidates(self, cur_node):
280
+ # Forward pass
281
+ self.print("find_decref_candidates".center(80, "-"))
282
+ path_stack = (cur_node,)
283
+ found = False
284
+ decref_blocks = set()
285
+ for child in self.get_successors(cur_node):
286
+ if not self.walk_child_for_decref(
287
+ child, path_stack, decref_blocks
288
+ ):
289
+ found = False
290
+ break
291
+ else:
292
+ found = True
293
+ if not found:
294
+ return set()
295
+ else:
296
+ return decref_blocks
297
+
298
+
299
+ def check_once():
300
+ nodes, edges, expected = case13()
301
+
302
+ # Render graph
303
+ G = Digraph()
304
+ for node in edges:
305
+ G.node(node, shape="rect", label=f"{node}\n" + r"\l".join(nodes[node]))
306
+ for node, children in edges.items():
307
+ for child in children:
308
+ G.edge(node, child)
309
+
310
+ G.view()
311
+
312
+ algo = FanoutAlgorithm(nodes, edges, verbose=True)
313
+ got = algo.run()
314
+ assert expected == got
315
+
316
+
317
+ def check_all():
318
+ for k, fn in list(globals().items()):
319
+ if k.startswith("case"):
320
+ print(f"{fn}".center(80, "-"))
321
+ nodes, edges, expected = fn()
322
+ algo = FanoutAlgorithm(nodes, edges)
323
+ got = algo.run()
324
+ assert expected == got
325
+ print("ALL PASSED")
326
+
327
+
328
+ if __name__ == "__main__":
329
+ # check_once()
330
+ check_all()