Skip to content

Prop

Frame dataclass

Frame(
    code: Statement,
    worklist: WorkList[Successor[ResultType]] = WorkList(),
    visited: dict[
        ir.Block, set[Successor[ResultType]]
    ] = dict(),
    should_be_pure: set[ir.Statement] = set(),
    frame_is_not_pure: bool = False,
    *,
    parent: Self | None = None,
    has_parent_access: bool = False,
    lineno_offset: int = 0,
    entries: dict[SSAValue, ValueType] = dict()
)

Bases: ForwardFrame[Result]

frame_is_not_pure class-attribute instance-attribute

frame_is_not_pure: bool = False

If we hit any non-pure statement.

should_be_pure class-attribute instance-attribute

should_be_pure: set[Statement] = field(default_factory=set)

If any ir.MaybePure is actually pure.

Propagate dataclass

Propagate(
    dialects: ir.DialectGroup,
    *,
    max_depth: int = 800,
    max_python_recursion_depth: int = 131072,
    debug: bool = False
)

Bases: ForwardExtra[Frame, Result]

Forward dataflow analysis for constant propagation.

This analysis is a forward dataflow analysis that propagates constant values through the program. It uses the Result lattice to track the constant values and purity of the values.

The analysis is implemented as a forward dataflow analysis, where the eval_stmt method is overridden to handle the different types of statements in the IR. The analysis uses the interp.Interpreter to evaluate the statements and propagate the constant values.

When a statement is registered under the "constprop" key in the method table, the analysis will call the method to evaluate the statement instead of using the interpreter. This allows for custom handling of statements.

keys class-attribute instance-attribute

keys = ('constprop',)

The name of the interpreter to select from dialects by order. First matching key will be used.

lattice class-attribute instance-attribute

lattice = Result

lattice type for the abstract interpreter.

frame_eval

frame_eval(
    frame: Frame, node: ir.Statement
) -> interp.StatementResult[Result]

Run a statement within the current frame. This is the entry point of running a statement. It will look up the statement implementation in the dialect registry, or optionally call a fallback implementation.

Parameters:

Name Type Description Default
frame FrameType

the current frame

required
node Statement

the statement to run

required

Returns:

Name Type Description
StatementResult StatementResult[ValueType]

the result of running the statement

Source code in src/kirin/analysis/const/prop.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def frame_eval(
    self, frame: Frame, node: ir.Statement
) -> interp.StatementResult[Result]:
    method = self.lookup_registry(frame, node)
    if method is None:
        if node.has_trait(ir.ConstantLike):
            return self.try_eval_const_pure(frame, node, ())
        elif node.has_trait(ir.Pure):
            values = frame.get_values(node.args)
            if types.is_tuple_of(values, Value):
                return self.try_eval_const_pure(frame, node, values)

        if not node.has_trait(ir.Pure):
            # not pure, and no implementation, let's say it's not pure
            frame.frame_is_not_pure = True
        return tuple(Unknown() for _ in node._results)

    ret = method(self, frame, node)
    if node.has_trait(ir.IsTerminator) or node.has_trait(ir.Pure):
        return ret
    elif not node.has_trait(ir.MaybePure):  # cannot be pure at all
        frame.frame_is_not_pure = True
    elif (
        node not in frame.should_be_pure
    ):  # implementation cannot decide if it's pure
        frame.frame_is_not_pure = True
    return ret

initialize_frame

initialize_frame(
    node: ir.Statement, *, has_parent_access: bool = False
) -> Frame

Initialize a new call frame for the given callable node.

Source code in src/kirin/analysis/const/prop.py
56
57
58
59
def initialize_frame(
    self, node: ir.Statement, *, has_parent_access: bool = False
) -> Frame:
    return Frame(node, has_parent_access=has_parent_access)

method_self

method_self(method: ir.Method) -> Result

Return the self value for the given method.

Source code in src/kirin/analysis/const/prop.py
61
62
def method_self(self, method: ir.Method) -> Result:
    return Value(method)