Skip to content

Stmt

ArgumentList dataclass

ArgumentList(node: NodeType, field: FieldType)

Bases: MutableSequenceView[tuple[SSAValue, ...], 'Statement', SSAValue], Printable

A View object that contains a list of Arguemnts of a Statement.

Description

This is a proxy object that provide safe API to manipulate the arguemnts of a statement.

Pretty Printing

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

get_slice

get_slice(name: str) -> slice

Get the slice of the arguments.

Parameters:

Name Type Description Default
name str

The name of the slice.

required

Returns:

Name Type Description
slice slice

The slice of the arguments.

Source code in src/kirin/ir/nodes/stmt.py
75
76
77
78
79
80
81
82
83
84
85
86
87
def get_slice(self, name: str) -> slice:
    """Get the slice of the arguments.

    Args:
        name (str): The name of the slice.

    Returns:
        slice: The slice of the arguments.
    """
    index = self.node._name_args_slice[name]
    if isinstance(index, int):
        return slice(index, index + 1)
    return index

insert

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

Insert the argument SSAValue at the specified index.

Parameters:

Name Type Description Default
idx int

The index to insert the value.

required
value SSAValue

The value to insert.

required
Source code in src/kirin/ir/nodes/stmt.py
62
63
64
65
66
67
68
69
70
71
72
73
def insert(self, idx: int, value: SSAValue) -> None:
    """Insert the argument SSAValue at the specified index.

    Args:
        idx (int): The index to insert the value.
        value (SSAValue): The value to insert.
    """
    args = self.field
    value.add_use(Use(self.node, idx))
    new_args = (*args[:idx], value, *args[idx:])
    self.node._args = new_args
    self.field = new_args

set_item

set_item(idx: int, value: SSAValue) -> None

Set the argument SSAVAlue at the specified index.

Parameters:

Name Type Description Default
idx int

The index of the item to set.

required
value SSAValue

The value to set.

required
Source code in src/kirin/ir/nodes/stmt.py
48
49
50
51
52
53
54
55
56
57
58
59
60
def set_item(self, idx: int, value: SSAValue) -> None:
    """Set the argument SSAVAlue at the specified index.

    Args:
        idx (int): The index of the item to set.
        value (SSAValue): The value to set.
    """
    args = self.field
    args[idx].remove_use(Use(self.node, idx))
    value.add_use(Use(self.node, idx))
    new_args = (*args[:idx], value, *args[idx + 1 :])
    self.node._args = new_args
    self.field = new_args

ResultList dataclass

ResultList(node: NodeType, field: FieldType)

Bases: MutableSequenceView[list[ResultValue], 'Statement', ResultValue]

A View object that contains a list of ResultValue of a Statement.

Description

This is a proxy object that provide safe API to manipulate the result values of a statement

Pretty Printing

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

types property

types: Sequence[TypeAttribute]

Get the result types of the Statement.

Returns:

Type Description
Sequence[TypeAttribute]

Sequence[TypeAttribute]: type of each result value.

Statement dataclass

Statement(
    *,
    args: Sequence[SSAValue] = (),
    regions: Sequence[Region] = (),
    successors: Sequence[Block] = (),
    attributes: Mapping[str, Attribute] = {},
    results: Sequence[ResultValue] = (),
    result_types: Sequence[TypeAttribute] = (),
    args_slice: Mapping[str, int | slice] = {},
    source: SourceInfo | None = None
)

Bases: IRNode['Block']

The Statment is an instruction in the IR

Pretty Printing

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

Source code in src/kirin/ir/nodes/stmt.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
def __init__(
    self,
    *,
    args: Sequence[SSAValue] = (),
    regions: Sequence[Region] = (),
    successors: Sequence[Block] = (),
    attributes: Mapping[str, Attribute] = {},
    results: Sequence[ResultValue] = (),
    result_types: Sequence[TypeAttribute] = (),
    args_slice: Mapping[str, int | slice] = {},
    source: SourceInfo | None = None,
) -> None:
    super().__init__()
    """Initialize the Statement.

    Args:
        arsg (Sequence[SSAValue], optional): The arguments of the Statement. Defaults to ().
        regions (Sequence[Region], optional): The regions where the Statement belong to. Defaults to ().
        successors (Sequence[Block], optional): The successors of the Statement. Defaults to ().
        attributes (Mapping[str, Attribute], optional): The attributes of the Statement. Defaults to {}.
        results (Sequence[ResultValue], optional): The result values of the Statement. Defaults to ().
        result_types (Sequence[TypeAttribute], optional): The result types of the Statement. Defaults to ().
        args_slice (Mapping[str, int | slice], optional): The arguments slice of the Statement. Defaults to {}.
        source (SourceInfo | None, optional): The source information of the Statement for debugging/stacktracing. Defaults to None.

    """
    self._args = ()
    self._regions = []
    self._name_args_slice = dict(args_slice)
    self.source = source
    self.args = args

    if results:
        self._results = list(results)
        assert (
            len(result_types) == 0
        ), "expect either results or result_types specified, got both"

    if result_types:
        self._results = [
            ResultValue(self, idx, type=type)
            for idx, type in enumerate(result_types)
        ]

    if not results and not result_types:
        self._results = list(results)

    self.successors = list(successors)
    self.attributes = dict(attributes)
    self.regions = list(regions)

    self.parent = None
    self._next_stmt = None
    self._prev_stmt = None
    self.__post_init__()

args instance-attribute property writable

args: ArgumentList = args

Get the arguments of the Statement.

Returns:

Name Type Description
ArgumentList ArgumentList

The arguments View of the Statement.

next_stmt property writable

next_stmt: Statement | None

Get the next statement.

parent_block property

parent_block: Block | None

Get the parent Block.

Returns:

Type Description
Block | None

Block | None: The parent Block.

parent_node property writable

parent_node: Block | None

Get the parent node.

Returns:

Type Description
Block | None

Block | None: The parent node.

parent_region property

parent_region: Region | None

Get the parent Region. Returns: Region | None: The parent Region.

parent_stmt property

parent_stmt: Statement | None

Get the parent statement.

Returns:

Type Description
Statement | None

Statement | None: The parent statement.

prev_stmt property writable

prev_stmt: Statement | None

Get the previous statement.

regions instance-attribute property writable

regions: list[Region] = list(regions)

Get a list of regions of the Statement.

Returns:

Type Description
list[Region]

list[Region]: The list of regions of the Statement.

results property

results: ResultList

Get the result values of the Statement.

Returns:

Name Type Description
ResultList ResultList

The result values View of the Statement.

source class-attribute instance-attribute

source: SourceInfo | None = source

The source information of the Statement for debugging/stacktracing.

check

check() -> None

Check the statement. Raises Exception if the statement is not correct. This method is called by the verify method, which will detect the source of the error in the IR. One should always call the verify method to verify the IR.

The difference between check and check_type is that check is called at any time to check the structure of the IR by verify, while check_type is called after the type inference to check the types of the IR.

Source code in src/kirin/ir/nodes/stmt.py
727
728
729
730
731
732
733
734
735
736
737
def check(self) -> None:
    """Check the statement. Raises `Exception` if the statement is not correct.
    This method is called by the `verify` method, which will detect the source
    of the error in the IR. One should always call the `verify` method to verify
    the IR.

    The difference between `check` and `check_type` is that `check` is called
    at any time to check the structure of the IR by `verify`, while `check_type`
    is called after the type inference to check the types of the IR.
    """
    return

check_type

check_type() -> None

Check the types of the Block. Raises Exception if the types are not correct. This method is called by the verify_type method, which will detect the source of the error in the IR. One should always call the verify_type method to verify the types of the IR.

Note

This method is generated by the @statement decorator. But can be overridden if needed.

Source code in src/kirin/ir/nodes/stmt.py
712
713
714
715
716
717
718
719
720
721
722
723
724
725
def check_type(self) -> None:
    """Check the types of the Block. Raises `Exception` if the types are not correct.
    This method is called by the `verify_type` method, which will detect the source
    of the error in the IR. One should always call the `verify_type` method to verify
    the types of the IR.

    Note:
        This method is generated by the `@statement` decorator. But can be overridden
        if needed.
    """
    raise NotImplementedError(
        "check_type should be implemented in the "
        "statement or generated by the @statement decorator"
    )

delete

delete(safe: bool = True) -> None

Delete the Statement completely from the IR graph.

Note

This method will detach + remove references of the Statement.

Parameters:

Name Type Description Default
safe bool

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

True
Source code in src/kirin/ir/nodes/stmt.py
380
381
382
383
384
385
386
387
388
389
390
391
392
def delete(self, safe: bool = True) -> None:
    """Delete the Statement completely from the IR graph.

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

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

detach

detach() -> None

detach the statement from its parent block.

Source code in src/kirin/ir/nodes/stmt.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
def detach(self) -> None:
    """detach the statement from its parent block."""
    if self.parent is None:
        return

    parent: Block = self.parent
    prev_stmt = self.prev_stmt
    next_stmt = self.next_stmt

    if prev_stmt is not None:
        prev_stmt._next_stmt = next_stmt
        self._prev_stmt = None
    else:
        assert (
            parent._first_stmt is self
        ), "Invalid statement, has no prev_stmt but not first_stmt"
        parent._first_stmt = next_stmt

    if next_stmt is not None:
        next_stmt._prev_stmt = prev_stmt
        self._next_stmt = None
    else:
        assert (
            parent._last_stmt is self
        ), "Invalid statement, has no next_stmt but not last_stmt"
        parent._last_stmt = prev_stmt

    self.parent = None
    parent._stmt_len -= 1
    return

drop_all_references

drop_all_references() -> None

Remove all the dependency that reference/uses this Statement.

Source code in src/kirin/ir/nodes/stmt.py
372
373
374
375
376
377
378
def drop_all_references(self) -> None:
    """Remove all the dependency that reference/uses this Statement."""
    self.parent = None
    for idx, arg in enumerate(self._args):
        arg.remove_use(Use(self, idx))
    for region in self._regions:
        region.drop_all_references()

expect_one_result

expect_one_result() -> ResultValue

Check if the statement contain only one result, and return it

Source code in src/kirin/ir/nodes/stmt.py
706
707
708
709
710
def expect_one_result(self) -> ResultValue:
    """Check if the statement contain only one result, and return it"""
    if len(self._results) != 1:
        raise ValueError(f"expected one result, got {len(self._results)}")
    return self._results[0]

from_stmt classmethod

from_stmt(
    other: Statement,
    args: Sequence[SSAValue] | None = None,
    regions: list[Region] | None = None,
    successors: list[Block] | None = None,
    attributes: dict[str, Attribute] | None = None,
) -> Self

Create a similar Statement with new ResultValue and without attaching to any parent block. This still references to the old successor and regions.

Source code in src/kirin/ir/nodes/stmt.py
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
@classmethod
def from_stmt(
    cls,
    other: Statement,
    args: Sequence[SSAValue] | None = None,
    regions: list[Region] | None = None,
    successors: list[Block] | None = None,
    attributes: dict[str, Attribute] | None = None,
) -> Self:
    """Create a similar Statement with new `ResultValue` and without
    attaching to any parent block. This still references to the old successor
    and regions.
    """
    obj = cls.__new__(cls)
    Statement.__init__(
        obj,
        args=args or other._args,
        regions=regions or other._regions,
        successors=successors or other.successors,
        attributes=attributes or other.attributes,
        result_types=[result.type for result in other._results],
        args_slice=other._name_args_slice,
    )
    # inherit the hint:
    for result, other_result in zip(obj._results, other._results):
        result.hints = dict(other_result.hints)

    return obj

get_attribute

get_attribute(
    key: str, default: Attribute | None = None
) -> Attribute | None

Get the attribute or property of the Statement.

Parameters:

Name Type Description Default
key str

The key of the attribute or property.

required

Returns:

Type Description
Attribute | None

Attribute | None: The attribute or property of the Statement.

Source code in src/kirin/ir/nodes/stmt.py
659
660
661
662
663
664
665
666
667
668
669
670
def get_attribute(
    self, key: str, default: Attribute | None = None
) -> Attribute | None:
    """Get the attribute or property of the Statement.

    Args:
        key (str): The key of the attribute or property.

    Returns:
        Attribute | None: The attribute or property of the Statement.
    """
    return self.attributes.get(key, default)

get_present_trait classmethod

get_present_trait(trait: type[TraitType]) -> TraitType

Just like get_trait, but expects the trait to be there. Useful for linter checks, when you know the trait is present.

Source code in src/kirin/ir/nodes/stmt.py
697
698
699
700
701
702
703
704
@classmethod
def get_present_trait(cls, trait: type[TraitType]) -> TraitType:
    """Just like get_trait, but expects the trait to be there.
    Useful for linter checks, when you know the trait is present."""
    for t in cls.traits:
        if isinstance(t, trait):
            return t
    raise ValueError(f"Trait {trait} not present in statement {cls}")

get_trait classmethod

get_trait(trait: type[TraitType]) -> TraitType | None

Get the trait of the Statement.

Source code in src/kirin/ir/nodes/stmt.py
689
690
691
692
693
694
695
@classmethod
def get_trait(cls, trait: type[TraitType]) -> TraitType | None:
    """Get the trait of the Statement."""
    for t in cls.traits:
        if isinstance(t, trait):
            return t
    return None

has_trait classmethod

has_trait(trait_type: type[Trait['Statement']]) -> bool

Check if the Statement has a specific trait.

Parameters:

Name Type Description Default
trait_type type[StmtTrait]

The type of trait to check for.

required

Returns:

Name Type Description
bool bool

True if the class has the specified trait, False otherwise.

Source code in src/kirin/ir/nodes/stmt.py
672
673
674
675
676
677
678
679
680
681
682
683
684
685
@classmethod
def has_trait(cls, trait_type: type[Trait["Statement"]]) -> bool:
    """Check if the Statement has a specific trait.

    Args:
        trait_type (type[StmtTrait]): The type of trait to check for.

    Returns:
        bool: True if the class has the specified trait, False otherwise.
    """
    for trait in cls.traits:
        if isinstance(trait, trait_type):
            return True
    return False

insert_after

insert_after(stmt: Statement) -> None

Insert the current Statement after the input Statement.

Parameters:

Name Type Description Default
stmt Statement

Input Statement.

required
Example

The following example demonstrates how to insert a Statement after another Statement. After insert_after is called, stmt1 will be inserted after stmt2, which appears in IR in the order (stmt2 -> stmt1)

stmt1 = Statement()
stmt2 = Statement()
stmt1.insert_after(stmt2)

Source code in src/kirin/ir/nodes/stmt.py
239
240
241
242
243
244
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
def insert_after(self, stmt: Statement) -> None:
    """Insert the current Statement after the input Statement.

    Args:
        stmt (Statement): Input Statement.

    Example:
        The following example demonstrates how to insert a Statement after another Statement.
        After `insert_after` is called, `stmt1` will be inserted after `stmt2`, which appears in IR in the order (stmt2 -> stmt1)
        ```python
        stmt1 = Statement()
        stmt2 = Statement()
        stmt1.insert_after(stmt2)
        ```
    """
    if self._next_stmt is not None and self._prev_stmt is not None:
        raise ValueError(
            f"Cannot insert before a statement that is already in a block: {self.name}"
        )

    if stmt._next_stmt is not None:
        stmt._next_stmt._prev_stmt = self

    self._prev_stmt = stmt
    self._next_stmt = stmt._next_stmt

    self.parent = stmt.parent
    stmt._next_stmt = self

    if self.parent:
        self.parent._stmt_len += 1

        if self._next_stmt is None:
            self.parent._last_stmt = self

insert_before

insert_before(stmt: Statement) -> None

Insert the current Statement before the input Statement.

Parameters:

Name Type Description Default
stmt Statement

Input Statement.

required
Example

The following example demonstrates how to insert a Statement before another Statement. After insert_before is called, stmt1 will be inserted before stmt2, which appears in IR in the order (stmt1 -> stmt2)

stmt1 = Statement()
stmt2 = Statement()
stmt1.insert_before(stmt2)

Source code in src/kirin/ir/nodes/stmt.py
274
275
276
277
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
def insert_before(self, stmt: Statement) -> None:
    """Insert the current Statement before the input Statement.

    Args:
        stmt (Statement): Input Statement.

    Example:
        The following example demonstrates how to insert a Statement before another Statement.
        After `insert_before` is called, `stmt1` will be inserted before `stmt2`, which appears in IR in the order (stmt1 -> stmt2)
        ```python
        stmt1 = Statement()
        stmt2 = Statement()
        stmt1.insert_before(stmt2)
        ```
    """
    if self._next_stmt is not None and self._prev_stmt is not None:
        raise ValueError(
            f"Cannot insert before a statement that is already in a block: {self.name}"
        )

    if stmt._prev_stmt is not None:
        stmt._prev_stmt._next_stmt = self

    self._next_stmt = stmt
    self._prev_stmt = stmt._prev_stmt

    self.parent = stmt.parent
    stmt._prev_stmt = self

    if self.parent:
        self.parent._stmt_len += 1

        if self._prev_stmt is None:
            self.parent._first_stmt = self

is_structurally_equal

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

Check if the Statement is structurally equal to another Statement.

Parameters:

Name Type Description Default
other Self

The other Statelemt 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 IRNode is structurally equal to the other.

Source code in src/kirin/ir/nodes/stmt.py
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
def is_structurally_equal(
    self,
    other: Self,
    context: dict[IRNode | SSAValue, IRNode | SSAValue] | None = None,
) -> bool:
    """Check if the Statement is structurally equal to another Statement.

    Args:
        other (Self): The other Statelemt 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 IRNode is structurally equal to the other.
    """
    if context is None:
        context = {}

    if self.name != other.name:
        return False

    if (
        len(self.args) != len(other.args)
        or len(self.regions) != len(other.regions)
        or len(self.successors) != len(other.successors)
        or self.attributes != other.attributes
    ):
        return False

    if (
        self.parent is not None
        and other.parent is not None
        and context.get(self.parent) != other.parent
    ):
        return False

    if not all(
        context.get(arg, arg) == other_arg
        for arg, other_arg in zip(self.args, other.args)
    ):
        return False

    if not all(
        context.get(successor, successor) == other_successor
        for successor, other_successor in zip(self.successors, other.successors)
    ):
        return False

    if not all(
        region.is_structurally_equal(other_region, context)
        for region, other_region in zip(self.regions, other.regions)
    ):
        return False

    for result, other_result in zip(self._results, other._results):
        context[result] = other_result

    return True

replace_by

replace_by(stmt: Statement) -> None

Replace the current Statement by the input Statement.

Parameters:

Name Type Description Default
stmt Statement

Input Statement.

required
Source code in src/kirin/ir/nodes/stmt.py
309
310
311
312
313
314
315
316
317
318
319
320
def replace_by(self, stmt: Statement) -> None:
    """Replace the current Statement by the input Statement.

    Args:
        stmt (Statement): Input Statement.
    """
    stmt.insert_before(self)
    for result, old_result in zip(stmt._results, self._results):
        old_result.replace_by(result)
        if old_result.name:
            result.name = old_result.name
    self.delete()

verify

verify() -> None

run mandatory validation checks. This is not same as verify_type, which may be optional.

Source code in src/kirin/ir/nodes/stmt.py
739
740
741
742
743
744
745
def verify(self) -> None:
    try:
        self.check()
    except ValidationError as e:
        raise e
    except Exception as e:
        raise ValidationError(self, *e.args) from e

verify_type

verify_type() -> None

Verify the type of the statement.

Note

This API should be called after all the types are figured out (by typeinfer)

Source code in src/kirin/ir/nodes/stmt.py
747
748
749
750
751
752
753
754
755
756
757
758
def verify_type(self) -> None:
    """Verify the type of the statement.

    Note:
        This API should be called after all the types are figured out (by typeinfer)
    """
    try:
        self.check_type()
    except TypeCheckError as e:
        raise e
    except Exception as e:
        raise TypeCheckError(self, *e.args) from e

walk

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

Traversal the Statements of Regions.

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
include_self bool

If the walk should include the Statement itself. Defaults to True.

True

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/stmt.py
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
def walk(
    self,
    *,
    reverse: bool = False,
    region_first: bool = False,
    include_self: bool = True,
) -> Iterator[Statement]:
    """Traversal the Statements of Regions.

    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.
        include_self (bool, optional): If the walk should include the Statement itself. Defaults to True.

    Yields:
        Iterator[Statement]: An iterator that yield Statements of Blocks in the Region, in the specified order.
    """
    if include_self and not region_first:
        yield self

    for region in reversed(self.regions) if reverse else self.regions:
        yield from region.walk(reverse=reverse, region_first=region_first)

    if include_self and region_first:
        yield self