Skip to content

Forward Dataflow

Forward dataclass

Forward(
    dialects: DialectGroup,
    *,
    fuel: int | None = None,
    debug: bool = False,
    max_depth: int = 128,
    max_python_recursion_depth: int = 8192
)

Bases: ForwardExtra[ForwardFrame[LatticeElemType], LatticeElemType], ABC

Forward dataflow analysis.

This is the base class for forward dataflow analysis. If your analysis requires extra information per frame, you should subclass ForwardExtra instead.

initialize_frame

initialize_frame(
    code: ir.Statement, *, has_parent_access: bool = False
) -> ForwardFrame[LatticeElemType]

Create a new frame for the given method.

Source code in src/kirin/analysis/forward.py
106
107
108
109
def initialize_frame(
    self, code: ir.Statement, *, has_parent_access: bool = False
) -> ForwardFrame[LatticeElemType]:
    return ForwardFrame(code, has_parent_access=has_parent_access)

ForwardExtra dataclass

ForwardExtra(
    dialects: DialectGroup,
    *,
    fuel: int | None = None,
    debug: bool = False,
    max_depth: int = 128,
    max_python_recursion_depth: int = 8192
)

Bases: AbstractInterpreter[ForwardFrameType, LatticeElemType], ABC

Abstract interpreter but record results for each SSA value.

Parameters:

Name Type Description Default
LatticeElemType

The lattice element type.

required
ExtraType

The type of extra information to be stored in the frame.

required

run_analysis

run_analysis(
    method: ir.Method,
    args: tuple[LatticeElemType, ...] | None = None,
    *,
    no_raise: bool = True
) -> tuple[ForwardFrameType, LatticeElemType]

Run the forward dataflow analysis.

Parameters:

Name Type Description Default
method(ir.Method)

The method to analyze.

required
args(tuple[LatticeElemType])

The arguments to the method. Defaults to tuple of top values.

required

Other Parameters:

Name Type Description
no_raise(bool)

If True, return bottom values if the analysis fails. Defaults to True.

Returns:

Name Type Description
ForwardFrameType ForwardFrameType

The results of the analysis contained in the frame.

LatticeElemType LatticeElemType

The result of the analysis for the method return value.

Source code in src/kirin/analysis/forward.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def run_analysis(
    self,
    method: ir.Method,
    args: tuple[LatticeElemType, ...] | None = None,
    *,
    no_raise: bool = True,
) -> tuple[ForwardFrameType, LatticeElemType]:
    """Run the forward dataflow analysis.

    Args:
        method(ir.Method): The method to analyze.
        args(tuple[LatticeElemType]): The arguments to the method. Defaults to tuple of top values.

    Keyword Args:
        no_raise(bool): If True, return bottom values if the analysis fails. Defaults to True.

    Returns:
        ForwardFrameType: The results of the analysis contained in the frame.
        LatticeElemType: The result of the analysis for the method return value.
    """
    args = args or tuple(self.lattice.top() for _ in method.args)

    if self._eval_lock:
        raise interp.InterpreterError(
            "recursive eval is not allowed, use run_method instead"
        )

    self._eval_lock = True
    self.initialize()
    current_recursion_limit = sys.getrecursionlimit()
    sys.setrecursionlimit(self.max_python_recursion_depth)
    try:
        frame, ret = self.run_method(method, args)
    except Exception as e:
        # NOTE: initialize will create new State
        # so we don't need to copy the frames.
        if not no_raise:
            raise e
        return self.state.current_frame, self.lattice.bottom()
    finally:
        self._eval_lock = False
        sys.setrecursionlimit(current_recursion_limit)
    return frame, ret

set_values

set_values(
    frame: AbstractFrame[LatticeElemType],
    ssa: Iterable[ir.SSAValue],
    results: Iterable[LatticeElemType],
)

Set the abstract values for the given SSA values in the frame.

This method is used to customize how the abstract values are set in the frame. By default, the abstract values are set directly in the frame. This method is overridden to join the results if the SSA value already exists in the frame.

Source code in src/kirin/analysis/forward.py
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def set_values(
    self,
    frame: AbstractFrame[LatticeElemType],
    ssa: Iterable[ir.SSAValue],
    results: Iterable[LatticeElemType],
):
    """Set the abstract values for the given SSA values in the frame.

    This method is used to customize how the abstract values are set in
    the frame. By default, the abstract values are set directly in the
    frame. This method is overridden to join the results if the SSA value
    already exists in the frame.
    """
    for ssa_value, result in zip(ssa, results):
        if ssa_value in frame.entries:
            frame.entries[ssa_value] = frame.entries[ssa_value].join(result)
        else:
            frame.entries[ssa_value] = result