Skip to content

Region

Region dataclass

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

Bases: IRNode['Statement']

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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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.

Source code in src/kirin/ir/nodes/region.py
140
141
142
143
144
145
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
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`.
    """
    ret = Region()
    successor_map: dict[Block, Block] = {}
    _ssamap = ssamap or {}
    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

    # update statements
    for block in self.blocks:
        for stmt in block.stmts:
            new_stmt = stmt.from_stmt(
                stmt,
                args=[_ssamap.get(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
233
234
235
236
237
238
239
240
241
242
243
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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
227
228
229
230
231
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: Self,
    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 Self

The other Region 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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def is_structurally_equal(
    self,
    other: Self,
    context: dict[IRNode | SSAValue, IRNode | SSAValue] | None = None,
) -> bool:
    """Check if the Region is structurally equal to another Region.

    Args:
        other (Self): The other Region 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 context is None:
        context = {}

    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
291
292
293
294
295
296
297
298
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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
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
339
340
341
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
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]

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 | Iterable[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 | Iterable[Block]

The Block or Blocks to replace the Blocks.

required
Source code in src/kirin/ir/nodes/region.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def __setitem__(
    self, idx: int | slice, block_or_blocks: Block | Iterable[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 | Iterable[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 isinstance(block_or_blocks, Iterable):
        for block in block_or_blocks:
            block.attach(self.node)
        self.field[idx] = block_or_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
74
75
76
77
78
79
80
81
82
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
62
63
64
65
66
67
68
69
70
71
72
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