Skip to content

Region

Region dataclass

Region(
    blocks: Block | Iterable[Block] = (),
    parent: Statement | None = None,
    *,
    source: SourceInfo | None = None
)

Bases: IRNode['Statement']


              flowchart TD
              kirin.ir.nodes.region.Region[Region]
              kirin.ir.nodes.base.IRNode[IRNode]
              kirin.print.printable.Printable[Printable]

                              kirin.ir.nodes.base.IRNode --> kirin.ir.nodes.region.Region
                                kirin.print.printable.Printable --> kirin.ir.nodes.base.IRNode
                



              click kirin.ir.nodes.region.Region href "" "kirin.ir.nodes.region.Region"
              click kirin.ir.nodes.base.IRNode href "" "kirin.ir.nodes.base.IRNode"
              click kirin.print.printable.Printable href "" "kirin.print.printable.Printable"
            

Region consist of a list of Blocks

Pretty Printing

This object is pretty printable via .print() method.

Parameters:

Name Type Description Default
blocks Block | Iterable[Block]

A single Block object or an iterable of Block objects. Defaults to ().

()
parent Statement | None

The parent Statement object. Defaults to None.

None
Source code in src/kirin/ir/nodes/region.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def __init__(
    self,
    blocks: Block | Iterable[Block] = (),
    parent: Statement | None = None,
    *,
    source: SourceInfo | None = None,
):
    """Initialize a Region object.

    Args:
        blocks (Block | Iterable[Block], optional): A single [`Block`][kirin.ir.Block] object or an iterable of Block objects. Defaults to ().
        parent (Statement | None, optional): The parent [`Statement`][kirin.ir.Statement] object. Defaults to None.
    """
    super().__init__()
    self.source = source
    self._blocks = []
    self._block_idx = {}
    self.parent_node = parent
    if isinstance(blocks, Block):
        blocks = (blocks,)
    for block in blocks:
        self.blocks.append(block)

blocks property

blocks: RegionBlocks

Get the Blocks in the region.

Returns:

Name Type Description
RegionBlocks RegionBlocks

The blocks View object of the region.

parent_node property writable

parent_node: Statement | None

Get the parent statement of the region.

region_index property

region_index: int

Get the index of the region within the parent scope.

Returns:

Name Type Description
int int

The index of the region within the parent scope.

__getitem__

__getitem__(block: Block) -> int

Get the index of a block within the region.

Parameters:

Name Type Description Default
block Block

The block to get the index of.

required

Raises:

Type Description
ValueError

If the block does not belong to the region.

Returns:

Name Type Description
int int

The index of the block within the region.

Source code in src/kirin/ir/nodes/region.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def __getitem__(self, block: Block) -> int:
    """Get the index of a block within the region.

    Args:
        block (Block): The block to get the index of.

    Raises:
        ValueError: If the block does not belong to the region.

    Returns:
        int: The index of the block within the region.
    """
    if block.parent is not self:
        raise ValueError("Block does not belong to the region")
    return self._block_idx[block]

clone

clone(
    ssamap: dict[SSAValue, SSAValue] | None = None,
) -> Region

Clone a region. This will clone all blocks and statements in the region. SSAValue defined outside the region will not be cloned unless provided in ssamap.

Note

Blocks must be in definition order (e.g. reverse post-order of the CFG) so that every statement result is cloned before it is referenced. Use :class:kirin.rewrite.SortBlocks to ensure this after passes that may reorder blocks.

Source code in src/kirin/ir/nodes/region.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def clone(self, ssamap: dict[SSAValue, SSAValue] | None = None) -> Region:
    """Clone a region. This will clone all blocks and statements in the region.
    `SSAValue` defined outside the region will not be cloned unless provided in `ssamap`.

    Note:
        Blocks must be in definition order (e.g. reverse post-order of the CFG)
        so that every statement result is cloned before it is referenced.
        Use :class:`kirin.rewrite.SortBlocks` to ensure this after passes
        that may reorder blocks.
    """
    ret = Region()
    successor_map: dict[Block, Block] = {}
    _ssamap = ssamap or {}

    # Collect all SSA values defined inside this region (statement results).
    # Block args are handled separately below.
    in_region_defs: set[SSAValue] = set()
    for block in self.blocks:
        for stmt in block.stmts:
            in_region_defs.update(stmt.results)

    # First pass: create cloned blocks and block args (order doesn't matter).
    for block in self.blocks:
        new_block = Block()
        ret.blocks.append(new_block)
        successor_map[block] = new_block
        for arg in block.args:
            new_arg = new_block.args.append_from(arg.type, arg.name)
            _ssamap[arg] = new_arg

    def _map_arg(arg: SSAValue) -> SSAValue:
        if arg in _ssamap:
            return _ssamap[arg]
        if arg in in_region_defs:
            raise ValueError(
                f"Region.clone: in-region SSA value {arg!r} used before "
                f"its defining statement was cloned. This indicates a "
                f"block ordering issue — run SortBlocks before cloning."
            )
        # Value defined outside the region — keep as-is.
        return arg

    # Second pass: clone statements in block-list order.
    for block in self.blocks:
        for stmt in block.stmts:
            new_stmt = stmt.from_stmt(
                stmt,
                args=[_map_arg(arg) for arg in stmt.args],
                regions=[region.clone(_ssamap) for region in stmt.regions],
                successors=[
                    successor_map[successor] for successor in stmt.successors
                ],
            )
            successor_map[block].stmts.append(new_stmt)
            for result, new_result in zip(stmt.results, new_stmt.results):
                _ssamap[result] = new_result
                new_result.name = result.name

    return ret

delete

delete(safe: bool = True) -> None

Delete the Region completely from the IR graph.

Note

This method will detach + remove references of the Region.

Parameters:

Name Type Description Default
safe bool

If True, raise error if there is anything that still reference components in the Region. Defaults to True.

True
Source code in src/kirin/ir/nodes/region.py
266
267
268
269
270
271
272
273
274
275
276
def delete(self, safe: bool = True) -> None:
    """Delete the Region completely from the IR graph.

    Note:
        This method will detach + remove references of the Region.

    Args:
        safe (bool, optional): If True, raise error if there is anything that still reference components in the Region. Defaults to True.
    """
    self.detach()
    self.drop_all_references()

detach

detach(index: int | None = None) -> None

Detach this Region from the IR tree graph.

Note

Detach only detach the Region from the IR graph. It does not remove uses that reference the Region.

Source code in src/kirin/ir/nodes/region.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def detach(self, index: int | None = None) -> None:
    """Detach this Region from the IR tree graph.

    Note:
        Detach only detach the Region from the IR graph. It does not remove uses that reference the Region.
    """
    # already detached
    if self.parent_node is None:
        return

    if index is not None:
        region_idx = index
    else:
        region_idx = self.region_index

    del self.parent_node._regions[region_idx]
    self.parent_node = None

drop_all_references

drop_all_references() -> None

Remove all the dependency that reference/uses this Region.

Source code in src/kirin/ir/nodes/region.py
260
261
262
263
264
def drop_all_references(self) -> None:
    """Remove all the dependency that reference/uses this Region."""
    self.parent_node = None
    for block in self._blocks:
        block.drop_all_references()

is_structurally_equal

is_structurally_equal(
    other: IRNode,
    context: (
        dict[IRNode | SSAValue, IRNode | SSAValue] | None
    ) = None,
) -> bool

Check if the Region is structurally equal to another Region.

Parameters:

Name Type Description Default
other IRNode

The other node to compare with.

required
context dict[IRNode | SSAValue, IRNode | SSAValue] | None

A map of IRNode/SSAValue to hint that they are equivalent so the check will treat them as equivalent. Defaults to None.

None

Returns:

Name Type Description
bool bool

True if the Region is structurally equal to the other Region.

Source code in src/kirin/ir/nodes/region.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
def is_structurally_equal(
    self,
    other: IRNode,
    context: dict[IRNode | SSAValue, IRNode | SSAValue] | None = None,
) -> bool:
    """Check if the Region is structurally equal to another Region.

    Args:
        other (IRNode): The other node to compare with.
        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.

    Returns:
        bool: True if the Region is structurally equal to the other Region.
    """
    if not isinstance(other, Region):
        return False

    if context is None:
        context = {}
    context[self] = other
    if len(self.blocks) != len(other.blocks):
        return False

    for block, other_block in zip(self.blocks, other.blocks):
        context[block] = other_block

    if not all(
        block.is_structurally_equal(other_block, context)
        for block, other_block in zip(self.blocks, other.blocks)
    ):
        return False

    return True

stmts

stmts() -> Iterator[Statement]

Iterate over all the Statements in the Region. This does not walk into nested Regions.

Yields:

Type Description
Statement

Iterator[Statement]: An iterator that yield Statements of Blocks in the Region.

Source code in src/kirin/ir/nodes/region.py
327
328
329
330
331
332
333
334
def stmts(self) -> Iterator[Statement]:
    """Iterate over all the Statements in the Region. This does not walk into nested Regions.

    Yields:
        Iterator[Statement]: An iterator that yield Statements of Blocks in the Region.
    """
    for block in self.blocks:
        yield from block.stmts

verify

verify() -> None

Verify the correctness of the Region.

Raises:

Type Description
ValidationError

If the Region is not correct.

Source code in src/kirin/ir/nodes/region.py
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def verify(self) -> None:
    """Verify the correctness of the Region.

    Raises:
        ValidationError: If the Region is not correct.
    """
    from kirin.ir.nodes.stmt import Statement

    if not isinstance(self.parent_node, Statement):
        raise ValidationError(
            self, "expect Region to have a parent of type Statement"
        )

    for block in self.blocks:
        block.verify()

verify_type

verify_type() -> None

verify the type of the node.

Source code in src/kirin/ir/nodes/region.py
375
376
377
def verify_type(self) -> None:
    for block in self.blocks:
        block.verify_type()

walk

walk(
    *, reverse: bool = False, region_first: bool = False
) -> Iterator[Statement]

Traversal the Statements of Blocks in the Region.

Parameters:

Name Type Description Default
reverse bool

If walk in the reversed manner. Defaults to False.

False
region_first bool

If the walk should go through the Statement first or the Region of a Statement first. Defaults to False.

False

Yields:

Type Description
Statement

Iterator[Statement]: An iterator that yield Statements of Blocks in the Region, in the specified order.

Source code in src/kirin/ir/nodes/region.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def walk(
    self, *, reverse: bool = False, region_first: bool = False
) -> Iterator[Statement]:
    """Traversal the Statements of Blocks in the Region.

    Args:
        reverse (bool, optional): If walk in the reversed manner. Defaults to False.
        region_first (bool, optional): If the walk should go through the Statement first or the Region of a Statement first. Defaults to False.

    Yields:
        Iterator[Statement]: An iterator that yield Statements of Blocks in the Region, in the specified order.
    """
    for block in reversed(self.blocks) if reverse else self.blocks:
        yield from block.walk(reverse=reverse, region_first=region_first)

RegionBlocks dataclass

RegionBlocks(node: NodeType, field: FieldType)

Bases: MutableSequenceView[list[Block], 'Region', Block]


              flowchart TD
              kirin.ir.nodes.region.RegionBlocks[RegionBlocks]
              kirin.ir.nodes.view.MutableSequenceView[MutableSequenceView]
              kirin.ir.nodes.view.SequenceView[SequenceView]
              kirin.ir.nodes.view.View[View]

                              kirin.ir.nodes.view.MutableSequenceView --> kirin.ir.nodes.region.RegionBlocks
                                kirin.ir.nodes.view.SequenceView --> kirin.ir.nodes.view.MutableSequenceView
                                kirin.ir.nodes.view.View --> kirin.ir.nodes.view.SequenceView
                




              click kirin.ir.nodes.region.RegionBlocks href "" "kirin.ir.nodes.region.RegionBlocks"
              click kirin.ir.nodes.view.MutableSequenceView href "" "kirin.ir.nodes.view.MutableSequenceView"
              click kirin.ir.nodes.view.SequenceView href "" "kirin.ir.nodes.view.SequenceView"
              click kirin.ir.nodes.view.View href "" "kirin.ir.nodes.view.View"
            

A View object that contains a list of Blocks of a Region.

Description

This is a proxy object that provide safe API to manipulate the Blocks of a Region.

__setitem__

__setitem__(
    idx: int | slice,
    block_or_blocks: Block | Sequence[Block],
) -> None

Replace/Set the Blocks of the Region.

Parameters:

Name Type Description Default
idx int | slice

The index or slice to replace the Blocks.

required
block_or_blocks Block | Sequence[Block]

The Block or Blocks to replace the Blocks.

required
Source code in src/kirin/ir/nodes/region.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def __setitem__(  # ty: ignore[invalid-method-override]  # generic TypeVar resolution
    self, idx: int | slice, block_or_blocks: Block | Sequence[Block]
) -> None:
    """Replace/Set the Blocks of the Region.

    Args:
        idx (int | slice): The index or slice to replace the [`Blocks`][kirin.ir.Block].
        block_or_blocks (Block | Sequence[Block]): The Block or Blocks to replace the Blocks.

    """
    if isinstance(idx, int) and isinstance(block_or_blocks, Block):
        self.field[idx].detach()
        block_or_blocks.attach(self.node)
        self.field[idx] = block_or_blocks
        self.node._block_idx[block_or_blocks] = idx
    elif isinstance(idx, slice) and not isinstance(block_or_blocks, Block):
        blocks = list(block_or_blocks)
        for block in blocks:
            block.attach(self.node)
        self.field[idx] = blocks
        self.node._block_idx = {
            block: i for i, block in enumerate(self.field)
        }  # reindex
    else:
        raise ValueError("Invalid assignment")

append

append(value: Block) -> None

Append a Block to the Region.

Parameters:

Name Type Description Default
value Block

The block to be appended.

required
Source code in src/kirin/ir/nodes/region.py
78
79
80
81
82
83
84
85
86
def append(self, value: Block) -> None:
    """Append a Block to the Region.

    Args:
        value (Block): The block to be appended.
    """
    value.attach(self.node)
    self.node._block_idx[value] = len(self.field)
    self.field.append(value)

insert

insert(idx: int, value: Block) -> None

Inserts a Block at the specified index.

Parameters:

Name Type Description Default
idx int

The index at which to insert the block.

required
value Block

The block to be inserted.

required
Source code in src/kirin/ir/nodes/region.py
66
67
68
69
70
71
72
73
74
75
76
def insert(self, idx: int, value: Block) -> None:
    """Inserts a Block at the specified index.

    Args:
        idx (int): The index at which to insert the block.
        value (Block): The block to be inserted.
    """
    value.attach(self.node)
    self.field.insert(idx, value)
    for i, value in enumerate(self.field[idx:], idx):
        self.node._block_idx[value] = i