kirin-toolchain 0.13.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (225) hide show
  1. kirin/__init__.py +7 -0
  2. kirin/analysis/__init__.py +24 -0
  3. kirin/analysis/callgraph.py +61 -0
  4. kirin/analysis/cfg.py +112 -0
  5. kirin/analysis/const/__init__.py +20 -0
  6. kirin/analysis/const/_visitor.py +2 -0
  7. kirin/analysis/const/_visitor.pyi +8 -0
  8. kirin/analysis/const/lattice.py +219 -0
  9. kirin/analysis/const/prop.py +116 -0
  10. kirin/analysis/forward.py +100 -0
  11. kirin/analysis/typeinfer/__init__.py +5 -0
  12. kirin/analysis/typeinfer/analysis.py +90 -0
  13. kirin/analysis/typeinfer/solve.py +141 -0
  14. kirin/decl/__init__.py +108 -0
  15. kirin/decl/base.py +65 -0
  16. kirin/decl/camel2snake.py +2 -0
  17. kirin/decl/emit/__init__.py +0 -0
  18. kirin/decl/emit/_create_fn.py +29 -0
  19. kirin/decl/emit/_set_new_attribute.py +22 -0
  20. kirin/decl/emit/dialect.py +8 -0
  21. kirin/decl/emit/init.py +277 -0
  22. kirin/decl/emit/name.py +10 -0
  23. kirin/decl/emit/property.py +182 -0
  24. kirin/decl/emit/repr.py +31 -0
  25. kirin/decl/emit/traits.py +13 -0
  26. kirin/decl/emit/typecheck.py +77 -0
  27. kirin/decl/emit/verify.py +51 -0
  28. kirin/decl/info.py +346 -0
  29. kirin/decl/scan_fields.py +157 -0
  30. kirin/decl/verify.py +69 -0
  31. kirin/dialects/__init__.py +14 -0
  32. kirin/dialects/_pprint_helper.py +53 -0
  33. kirin/dialects/cf/__init__.py +20 -0
  34. kirin/dialects/cf/constprop.py +51 -0
  35. kirin/dialects/cf/dialect.py +3 -0
  36. kirin/dialects/cf/emit.py +58 -0
  37. kirin/dialects/cf/interp.py +24 -0
  38. kirin/dialects/cf/stmts.py +68 -0
  39. kirin/dialects/cf/typeinfer.py +27 -0
  40. kirin/dialects/eltype.py +23 -0
  41. kirin/dialects/func/__init__.py +20 -0
  42. kirin/dialects/func/attrs.py +39 -0
  43. kirin/dialects/func/constprop.py +138 -0
  44. kirin/dialects/func/dialect.py +3 -0
  45. kirin/dialects/func/emit.py +80 -0
  46. kirin/dialects/func/interp.py +68 -0
  47. kirin/dialects/func/stmts.py +233 -0
  48. kirin/dialects/func/typeinfer.py +124 -0
  49. kirin/dialects/ilist/__init__.py +33 -0
  50. kirin/dialects/ilist/_dialect.py +3 -0
  51. kirin/dialects/ilist/_wrapper.py +51 -0
  52. kirin/dialects/ilist/interp.py +85 -0
  53. kirin/dialects/ilist/lowering.py +25 -0
  54. kirin/dialects/ilist/passes.py +32 -0
  55. kirin/dialects/ilist/rewrite/__init__.py +3 -0
  56. kirin/dialects/ilist/rewrite/const.py +45 -0
  57. kirin/dialects/ilist/rewrite/list.py +38 -0
  58. kirin/dialects/ilist/rewrite/unroll.py +131 -0
  59. kirin/dialects/ilist/runtime.py +63 -0
  60. kirin/dialects/ilist/stmts.py +102 -0
  61. kirin/dialects/ilist/typeinfer.py +120 -0
  62. kirin/dialects/lowering/__init__.py +7 -0
  63. kirin/dialects/lowering/call.py +48 -0
  64. kirin/dialects/lowering/cf.py +206 -0
  65. kirin/dialects/lowering/func.py +134 -0
  66. kirin/dialects/math/__init__.py +41 -0
  67. kirin/dialects/math/_gen.py +176 -0
  68. kirin/dialects/math/dialect.py +3 -0
  69. kirin/dialects/math/interp.py +190 -0
  70. kirin/dialects/math/stmts.py +369 -0
  71. kirin/dialects/module.py +139 -0
  72. kirin/dialects/py/__init__.py +40 -0
  73. kirin/dialects/py/assertion.py +91 -0
  74. kirin/dialects/py/assign.py +103 -0
  75. kirin/dialects/py/attr.py +59 -0
  76. kirin/dialects/py/base.py +34 -0
  77. kirin/dialects/py/binop/__init__.py +23 -0
  78. kirin/dialects/py/binop/_dialect.py +3 -0
  79. kirin/dialects/py/binop/interp.py +60 -0
  80. kirin/dialects/py/binop/julia.py +33 -0
  81. kirin/dialects/py/binop/lowering.py +22 -0
  82. kirin/dialects/py/binop/stmts.py +79 -0
  83. kirin/dialects/py/binop/typeinfer.py +108 -0
  84. kirin/dialects/py/boolop.py +84 -0
  85. kirin/dialects/py/builtin.py +78 -0
  86. kirin/dialects/py/cmp/__init__.py +16 -0
  87. kirin/dialects/py/cmp/_dialect.py +3 -0
  88. kirin/dialects/py/cmp/interp.py +48 -0
  89. kirin/dialects/py/cmp/julia.py +33 -0
  90. kirin/dialects/py/cmp/lowering.py +45 -0
  91. kirin/dialects/py/cmp/stmts.py +62 -0
  92. kirin/dialects/py/constant.py +79 -0
  93. kirin/dialects/py/indexing.py +251 -0
  94. kirin/dialects/py/iterable.py +90 -0
  95. kirin/dialects/py/len.py +57 -0
  96. kirin/dialects/py/list/__init__.py +15 -0
  97. kirin/dialects/py/list/_dialect.py +3 -0
  98. kirin/dialects/py/list/interp.py +21 -0
  99. kirin/dialects/py/list/lowering.py +25 -0
  100. kirin/dialects/py/list/stmts.py +22 -0
  101. kirin/dialects/py/list/typeinfer.py +54 -0
  102. kirin/dialects/py/range.py +76 -0
  103. kirin/dialects/py/slice.py +120 -0
  104. kirin/dialects/py/tuple.py +109 -0
  105. kirin/dialects/py/unary/__init__.py +24 -0
  106. kirin/dialects/py/unary/_dialect.py +3 -0
  107. kirin/dialects/py/unary/constprop.py +20 -0
  108. kirin/dialects/py/unary/interp.py +24 -0
  109. kirin/dialects/py/unary/julia.py +21 -0
  110. kirin/dialects/py/unary/lowering.py +22 -0
  111. kirin/dialects/py/unary/stmts.py +33 -0
  112. kirin/dialects/py/unary/typeinfer.py +23 -0
  113. kirin/dialects/py/unpack.py +90 -0
  114. kirin/dialects/scf/__init__.py +23 -0
  115. kirin/dialects/scf/_dialect.py +3 -0
  116. kirin/dialects/scf/absint.py +64 -0
  117. kirin/dialects/scf/constprop.py +140 -0
  118. kirin/dialects/scf/interp.py +35 -0
  119. kirin/dialects/scf/lowering.py +123 -0
  120. kirin/dialects/scf/stmts.py +250 -0
  121. kirin/dialects/scf/trim.py +36 -0
  122. kirin/dialects/scf/typeinfer.py +58 -0
  123. kirin/dialects/scf/unroll.py +92 -0
  124. kirin/emit/__init__.py +3 -0
  125. kirin/emit/abc.py +89 -0
  126. kirin/emit/abc.pyi +38 -0
  127. kirin/emit/exceptions.py +5 -0
  128. kirin/emit/julia.py +63 -0
  129. kirin/emit/str.py +51 -0
  130. kirin/exceptions.py +59 -0
  131. kirin/graph.py +34 -0
  132. kirin/idtable.py +57 -0
  133. kirin/interp/__init__.py +39 -0
  134. kirin/interp/abstract.py +253 -0
  135. kirin/interp/base.py +438 -0
  136. kirin/interp/concrete.py +62 -0
  137. kirin/interp/exceptions.py +26 -0
  138. kirin/interp/frame.py +151 -0
  139. kirin/interp/impl.py +197 -0
  140. kirin/interp/result.py +93 -0
  141. kirin/interp/state.py +71 -0
  142. kirin/interp/table.py +40 -0
  143. kirin/interp/value.py +73 -0
  144. kirin/ir/__init__.py +46 -0
  145. kirin/ir/attrs/__init__.py +20 -0
  146. kirin/ir/attrs/_types.py +8 -0
  147. kirin/ir/attrs/_types.pyi +13 -0
  148. kirin/ir/attrs/abc.py +46 -0
  149. kirin/ir/attrs/py.py +45 -0
  150. kirin/ir/attrs/types.py +522 -0
  151. kirin/ir/dialect.py +125 -0
  152. kirin/ir/group.py +249 -0
  153. kirin/ir/method.py +118 -0
  154. kirin/ir/nodes/__init__.py +7 -0
  155. kirin/ir/nodes/base.py +149 -0
  156. kirin/ir/nodes/block.py +458 -0
  157. kirin/ir/nodes/region.py +337 -0
  158. kirin/ir/nodes/stmt.py +713 -0
  159. kirin/ir/nodes/view.py +142 -0
  160. kirin/ir/ssa.py +204 -0
  161. kirin/ir/traits/__init__.py +36 -0
  162. kirin/ir/traits/abc.py +42 -0
  163. kirin/ir/traits/basic.py +78 -0
  164. kirin/ir/traits/callable.py +51 -0
  165. kirin/ir/traits/lowering/__init__.py +2 -0
  166. kirin/ir/traits/lowering/call.py +37 -0
  167. kirin/ir/traits/lowering/context.py +120 -0
  168. kirin/ir/traits/region/__init__.py +2 -0
  169. kirin/ir/traits/region/ssacfg.py +22 -0
  170. kirin/ir/traits/symbol.py +57 -0
  171. kirin/ir/use.py +17 -0
  172. kirin/lattice/__init__.py +13 -0
  173. kirin/lattice/abc.py +128 -0
  174. kirin/lattice/empty.py +25 -0
  175. kirin/lattice/mixin.py +51 -0
  176. kirin/lowering/__init__.py +7 -0
  177. kirin/lowering/binding.py +65 -0
  178. kirin/lowering/core.py +72 -0
  179. kirin/lowering/dialect.py +35 -0
  180. kirin/lowering/dialect.pyi +183 -0
  181. kirin/lowering/frame.py +171 -0
  182. kirin/lowering/result.py +68 -0
  183. kirin/lowering/state.py +441 -0
  184. kirin/lowering/stream.py +53 -0
  185. kirin/passes/__init__.py +3 -0
  186. kirin/passes/abc.py +44 -0
  187. kirin/passes/aggressive/__init__.py +1 -0
  188. kirin/passes/aggressive/fold.py +43 -0
  189. kirin/passes/fold.py +45 -0
  190. kirin/passes/inline.py +25 -0
  191. kirin/passes/typeinfer.py +25 -0
  192. kirin/prelude.py +197 -0
  193. kirin/print/__init__.py +15 -0
  194. kirin/print/printable.py +141 -0
  195. kirin/print/printer.py +415 -0
  196. kirin/py.typed +0 -0
  197. kirin/registry.py +105 -0
  198. kirin/registry.pyi +52 -0
  199. kirin/rewrite/__init__.py +14 -0
  200. kirin/rewrite/abc.py +43 -0
  201. kirin/rewrite/aggressive/__init__.py +1 -0
  202. kirin/rewrite/aggressive/fold.py +43 -0
  203. kirin/rewrite/alias.py +16 -0
  204. kirin/rewrite/apply_type.py +47 -0
  205. kirin/rewrite/call2invoke.py +34 -0
  206. kirin/rewrite/chain.py +39 -0
  207. kirin/rewrite/compactify.py +288 -0
  208. kirin/rewrite/cse.py +48 -0
  209. kirin/rewrite/dce.py +19 -0
  210. kirin/rewrite/fixpoint.py +34 -0
  211. kirin/rewrite/fold.py +57 -0
  212. kirin/rewrite/getfield.py +21 -0
  213. kirin/rewrite/getitem.py +37 -0
  214. kirin/rewrite/inline.py +143 -0
  215. kirin/rewrite/result.py +15 -0
  216. kirin/rewrite/walk.py +83 -0
  217. kirin/rewrite/wrap_const.py +55 -0
  218. kirin/source.py +21 -0
  219. kirin/symbol_table.py +27 -0
  220. kirin/types.py +34 -0
  221. kirin/worklist.py +30 -0
  222. kirin_toolchain-0.13.0.dist-info/METADATA +42 -0
  223. kirin_toolchain-0.13.0.dist-info/RECORD +225 -0
  224. kirin_toolchain-0.13.0.dist-info/WHEEL +4 -0
  225. kirin_toolchain-0.13.0.dist-info/licenses/LICENSE +234 -0
@@ -0,0 +1,337 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Iterable, Iterator
4
+ from dataclasses import field, dataclass
5
+
6
+ from typing_extensions import Self
7
+
8
+ from kirin.ir.ssa import SSAValue
9
+ from kirin.exceptions import VerificationError
10
+ from kirin.ir.nodes.base import IRNode
11
+ from kirin.ir.nodes.view import MutableSequenceView
12
+ from kirin.ir.nodes.block import Block
13
+
14
+ if TYPE_CHECKING:
15
+ from kirin.print import Printer
16
+ from kirin.ir.nodes.stmt import Statement
17
+
18
+
19
+ @dataclass
20
+ class RegionBlocks(MutableSequenceView[list[Block], "Region", Block]):
21
+ """A View object that contains a list of Blocks of a Region.
22
+
23
+ Description:
24
+ This is a proxy object that provide safe API to manipulate the Blocks of a Region.
25
+
26
+ """
27
+
28
+ def __setitem__(
29
+ self, idx: int | slice, block_or_blocks: Block | Iterable[Block]
30
+ ) -> None:
31
+ """Replace/Set the Blocks of the Region.
32
+
33
+ Args:
34
+ idx (int | slice): The index or slice to replace the [`Blocks`][kirin.ir.Block].
35
+ block_or_blocks (Block | Iterable[Block]): The Block or Blocks to replace the Blocks.
36
+
37
+ """
38
+ if isinstance(idx, int) and isinstance(block_or_blocks, Block):
39
+ self.field[idx].detach()
40
+ block_or_blocks.attach(self.node)
41
+ self.field[idx] = block_or_blocks
42
+ self.node._block_idx[block_or_blocks] = idx
43
+ elif isinstance(idx, slice) and isinstance(block_or_blocks, Iterable):
44
+ for block in block_or_blocks:
45
+ block.attach(self.node)
46
+ self.field[idx] = block_or_blocks
47
+ self.node._block_idx = {
48
+ block: i for i, block in enumerate(self.field)
49
+ } # reindex
50
+ else:
51
+ raise ValueError("Invalid assignment")
52
+
53
+ def __delitem__(self, idx: int) -> None:
54
+ self.field[idx].delete()
55
+
56
+ def pop(self, idx: int = -1) -> Block:
57
+ item = self.field[idx]
58
+ self[idx].detach()
59
+ return item
60
+
61
+ def insert(self, idx: int, value: Block) -> None:
62
+ """Inserts a Block at the specified index.
63
+
64
+ Args:
65
+ idx (int): The index at which to insert the block.
66
+ value (Block): The block to be inserted.
67
+ """
68
+ value.attach(self.node)
69
+ self.field.insert(idx, value)
70
+ for i, value in enumerate(self.field[idx:], idx):
71
+ self.node._block_idx[value] = i
72
+
73
+ def append(self, value: Block) -> None:
74
+ """Append a Block to the Region.
75
+
76
+ Args:
77
+ value (Block): The block to be appended.
78
+ """
79
+ value.attach(self.node)
80
+ self.node._block_idx[value] = len(self.field)
81
+ self.field.append(value)
82
+
83
+
84
+ @dataclass
85
+ class Region(IRNode["Statement"]):
86
+ """Region consist of a list of Blocks
87
+
88
+ !!! note "Pretty Printing"
89
+ This object is pretty printable via
90
+ [`.print()`][kirin.print.printable.Printable.print] method.
91
+ """
92
+
93
+ _blocks: list[Block] = field(default_factory=list, repr=False)
94
+ _block_idx: dict[Block, int] = field(default_factory=dict, repr=False)
95
+ _parent: Statement | None = field(default=None, repr=False)
96
+
97
+ def __init__(
98
+ self,
99
+ blocks: Block | Iterable[Block] = (),
100
+ parent: Statement | None = None,
101
+ ):
102
+ """Initialize a Region object.
103
+
104
+ Args:
105
+ blocks (Block | Iterable[Block], optional): A single [`Block`][kirin.ir.Block] object or an iterable of Block objects. Defaults to ().
106
+ parent (Statement | None, optional): The parent [`Statement`][kirin.ir.Statement] object. Defaults to None.
107
+ """
108
+ self._blocks = []
109
+ self._block_idx = {}
110
+ self.parent_node = parent
111
+ if isinstance(blocks, Block):
112
+ blocks = (blocks,)
113
+ for block in blocks:
114
+ self.blocks.append(block)
115
+
116
+ def __getitem__(self, block: Block) -> int:
117
+ """Get the index of a block within the region.
118
+
119
+ Args:
120
+ block (Block): The block to get the index of.
121
+
122
+ Raises:
123
+ ValueError: If the block does not belong to the region.
124
+
125
+ Returns:
126
+ int: The index of the block within the region.
127
+ """
128
+ if block.parent is not self:
129
+ raise ValueError("Block does not belong to the region")
130
+ return self._block_idx[block]
131
+
132
+ def __hash__(self) -> int:
133
+ return id(self)
134
+
135
+ def clone(self, ssamap: dict[SSAValue, SSAValue] | None = None) -> Region:
136
+ """Clone a region. This will clone all blocks and statements in the region.
137
+ `SSAValue` defined outside the region will not be cloned unless provided in `ssamap`.
138
+ """
139
+ ret = Region()
140
+ successor_map: dict[Block, Block] = {}
141
+ _ssamap = ssamap or {}
142
+ for block in self.blocks:
143
+ new_block = Block()
144
+ ret.blocks.append(new_block)
145
+ successor_map[block] = new_block
146
+ for arg in block.args:
147
+ new_arg = new_block.args.append_from(arg.type, arg.name)
148
+ _ssamap[arg] = new_arg
149
+
150
+ # update statements
151
+ for block in self.blocks:
152
+ for stmt in block.stmts:
153
+ new_stmt = stmt.from_stmt(
154
+ stmt,
155
+ args=[_ssamap.get(arg, arg) for arg in stmt.args],
156
+ regions=[region.clone(_ssamap) for region in stmt.regions],
157
+ successors=[
158
+ successor_map[successor] for successor in stmt.successors
159
+ ],
160
+ )
161
+ successor_map[block].stmts.append(new_stmt)
162
+ for result, new_result in zip(stmt.results, new_stmt.results):
163
+ _ssamap[result] = new_result
164
+ new_result.name = result.name
165
+
166
+ return ret
167
+
168
+ @property
169
+ def parent_node(self) -> Statement | None:
170
+ """Get the parent statement of the region."""
171
+ return self._parent
172
+
173
+ @parent_node.setter
174
+ def parent_node(self, parent: Statement | None) -> None:
175
+ """Set the parent statement of the region."""
176
+ from kirin.ir.nodes.stmt import Statement
177
+
178
+ self.assert_parent(Statement, parent)
179
+ self._parent = parent
180
+
181
+ @property
182
+ def blocks(self) -> RegionBlocks:
183
+ """Get the Blocks in the region.
184
+
185
+ Returns:
186
+ RegionBlocks: The blocks View object of the region.
187
+ """
188
+ return RegionBlocks(self, self._blocks)
189
+
190
+ @property
191
+ def region_index(self) -> int:
192
+ """Get the index of the region within the parent scope.
193
+
194
+ Returns:
195
+ int: The index of the region within the parent scope.
196
+ """
197
+ if self.parent_node is None:
198
+ raise ValueError("Region has no parent")
199
+ for idx, region in enumerate(self.parent_node.regions):
200
+ if region is self:
201
+ return idx
202
+ raise ValueError("Region not found in parent")
203
+
204
+ def detach(self, index: int | None = None) -> None:
205
+ """Detach this Region from the IR tree graph.
206
+
207
+ Note:
208
+ Detach only detach the Region from the IR graph. It does not remove uses that reference the Region.
209
+ """
210
+ # already detached
211
+ if self.parent_node is None:
212
+ return
213
+
214
+ if index is not None:
215
+ region_idx = index
216
+ else:
217
+ region_idx = self.region_index
218
+
219
+ del self.parent_node._regions[region_idx]
220
+ self.parent_node = None
221
+
222
+ def drop_all_references(self) -> None:
223
+ """Remove all the dependency that reference/uses this Region."""
224
+ self.parent_node = None
225
+ for block in self._blocks:
226
+ block.drop_all_references()
227
+
228
+ def delete(self, safe: bool = True) -> None:
229
+ """Delete the Region completely from the IR graph.
230
+
231
+ Note:
232
+ This method will detach + remove references of the Region.
233
+
234
+ Args:
235
+ safe (bool, optional): If True, raise error if there is anything that still reference components in the Region. Defaults to True.
236
+ """
237
+ self.detach()
238
+ self.drop_all_references()
239
+
240
+ def is_structurally_equal(
241
+ self,
242
+ other: Self,
243
+ context: dict[IRNode | SSAValue, IRNode | SSAValue] | None = None,
244
+ ) -> bool:
245
+ """Check if the Region is structurally equal to another Region.
246
+
247
+ Args:
248
+ other (Self): The other Region to compare with.
249
+ context (dict[IRNode | SSAValue, IRNode | SSAValue] | None, optional): A map of IRNode/SSAValue to hint that they are equivalent so the check will treat them as equivalent. Defaults to None.
250
+
251
+ Returns:
252
+ bool: True if the Region is structurally equal to the other Region.
253
+ """
254
+ if context is None:
255
+ context = {}
256
+
257
+ if len(self.blocks) != len(other.blocks):
258
+ return False
259
+
260
+ for block, other_block in zip(self.blocks, other.blocks):
261
+ context[block] = other_block
262
+
263
+ if not all(
264
+ block.is_structurally_equal(other_block, context)
265
+ for block, other_block in zip(self.blocks, other.blocks)
266
+ ):
267
+ return False
268
+
269
+ return True
270
+
271
+ def walk(
272
+ self, *, reverse: bool = False, region_first: bool = False
273
+ ) -> Iterator[Statement]:
274
+ """Traversal the Statements of Blocks in the Region.
275
+
276
+ Args:
277
+ reverse (bool, optional): If walk in the reversed manner. Defaults to False.
278
+ region_first (bool, optional): If the walk should go through the Statement first or the Region of a Statement first. Defaults to False.
279
+
280
+ Yields:
281
+ Iterator[Statement]: An iterator that yield Statements of Blocks in the Region, in the specified order.
282
+ """
283
+ for block in reversed(self.blocks) if reverse else self.blocks:
284
+ yield from block.walk(reverse=reverse, region_first=region_first)
285
+
286
+ def stmts(self) -> Iterator[Statement]:
287
+ """Iterate over all the Statements in the Region. This does not walk into nested Regions.
288
+
289
+ Yields:
290
+ Iterator[Statement]: An iterator that yield Statements of Blocks in the Region.
291
+ """
292
+ for block in self.blocks:
293
+ yield from block.stmts
294
+
295
+ def print_impl(self, printer: Printer) -> None:
296
+ # populate block ids
297
+ for block in self.blocks:
298
+ printer.state.block_id[block]
299
+
300
+ printer.plain_print("{")
301
+ if len(self.blocks) == 0:
302
+ printer.print_newline()
303
+ printer.plain_print("}")
304
+ return
305
+
306
+ with printer.align(printer.result_width(self.stmts())):
307
+ with printer.indent(increase=2, mark=True):
308
+ printer.print_newline()
309
+ for idx, bb in enumerate(self.blocks):
310
+ printer.print(bb)
311
+
312
+ if idx != len(self.blocks) - 1:
313
+ printer.print_newline()
314
+
315
+ printer.print_newline()
316
+ printer.plain_print("}")
317
+
318
+ def typecheck(self) -> None:
319
+ """Checking the types of the Statments of Blocks in the Region."""
320
+ for block in self.blocks:
321
+ block.typecheck()
322
+
323
+ def verify(self) -> None:
324
+ """Verify the correctness of the Region.
325
+
326
+ Raises:
327
+ VerificationError: If the Region is not correct.
328
+ """
329
+ from kirin.ir.nodes.stmt import Statement
330
+
331
+ if not isinstance(self.parent_node, Statement):
332
+ raise VerificationError(
333
+ self, "expect Region to have a parent of type Statement"
334
+ )
335
+
336
+ for block in self.blocks:
337
+ block.verify()