Skip to content

Commit ef05a98

Browse files
authored
add some docstrings for interp interface (#167)
1 parent baeb6f2 commit ef05a98

File tree

10 files changed

+258
-17
lines changed

10 files changed

+258
-17
lines changed

src/kirin/interp/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
"""Interpreter module for Kirin.
2+
3+
This module contains the interpreter framework for Kirin. The interpreter
4+
framework is used to implement concrete and abstract interpreters for the
5+
IR. The interpreter framework provides a set of classes and interfaces to
6+
implement interpreters for the IR.
7+
8+
The interpreter framework is designed to be extensible and customizable. It
9+
provides a set of base classes and interfaces for implementing concrete and
10+
abstract interpreters:
11+
12+
- [`BaseInterpreter`][kirin.interp.BaseInterpreter]: Base class for implementing concrete interpreters.
13+
- [`AbstractInterpreter`][kirin.interp.AbstractInterpreter]: Base class for implementing abstract interpreters.
14+
- [`Frame`][kirin.interp.Frame]: Base class for interpreter frame.
15+
- [`MethodTable`][kirin.interp.MethodTable]: Method table for registering implementations of statements.
16+
"""
17+
118
from . import result as result
219
from .base import BaseInterpreter as BaseInterpreter
320
from .impl import ImplDef as ImplDef, Signature as Signature, impl as impl

src/kirin/interp/abstract.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515

1616
@dataclass
1717
class AbstractFrame(Frame[ResultType]):
18+
"""Interpreter frame for abstract interpreter.
19+
20+
This frame is used to store the state of the abstract interpreter.
21+
It contains the worklist of successors to be processed.
22+
"""
23+
1824
worklist: WorkList[Successor[ResultType]] = field(default_factory=WorkList)
1925

2026

@@ -34,6 +40,29 @@ class AbstractInterpreter(
3440
ABC,
3541
metaclass=AbstractInterpreterMeta,
3642
):
43+
"""Abstract interpreter for the IR.
44+
45+
This is a base class for implementing abstract interpreters for the IR.
46+
It provides a framework for implementing abstract interpreters given a
47+
bounded lattice type.
48+
49+
The abstract interpreter is a forward dataflow analysis that computes
50+
the abstract values for each SSA value in the IR. The abstract values
51+
are computed by evaluating the statements in the IR using the abstract
52+
lattice operations.
53+
54+
The abstract interpreter is implemented as a worklist algorithm. The
55+
worklist contains the successors of the current block to be processed.
56+
The abstract interpreter processes each successor by evaluating the
57+
statements in the block and updating the abstract values in the frame.
58+
59+
The abstract interpreter provides hooks for customizing the behavior of
60+
the interpreter.
61+
The [`prehook_succ`][kirin.interp.abstract.AbstractInterpreter.prehook_succ] and
62+
[`posthook_succ`][kirin.interp.abstract.AbstractInterpreter.posthook_succ] methods
63+
can be used to perform custom actions before and after processing a successor.
64+
"""
65+
3766
lattice: type[BoundedLattice[ResultType]] = field(init=False)
3867
"""lattice type for the abstract interpreter.
3968
"""
@@ -50,12 +79,46 @@ def __init_subclass__(cls) -> None:
5079
super().__init_subclass__()
5180

5281
def prehook_succ(self, frame: AbstractFrameType, succ: Successor):
82+
"""Hook called before processing a successor.
83+
84+
This method can be used to perform custom actions before processing
85+
a successor. It is called before evaluating the statements in the block.
86+
87+
Args:
88+
frame: The current frame of the interpreter.
89+
succ: The successor to be processed.
90+
"""
5391
return
5492

5593
def posthook_succ(self, frame: AbstractFrameType, succ: Successor):
94+
"""Hook called after processing a successor.
95+
96+
This method can be used to perform custom actions after processing
97+
a successor. It is called after evaluating the statements in the block.
98+
99+
Args:
100+
frame: The current frame of the interpreter.
101+
succ: The successor that was processed.
102+
"""
56103
return
57104

58-
def should_exec_stmt(self, stmt: Statement):
105+
def should_exec_stmt(self, stmt: Statement) -> bool:
106+
"""This method can be used to control which statements are executed
107+
during the abstract interpretation. By default, all statements are
108+
executed.
109+
110+
This method is useful when one wants to skip certain statements
111+
during the abstract interpretation and is certain that the skipped
112+
statements do not affect the final result. This would allow saving
113+
computation time and memory by not evaluating the skipped statements
114+
and their results.
115+
116+
Args:
117+
stmt: The statement to be executed.
118+
119+
Returns:
120+
True if the statement should be executed, False otherwise.
121+
"""
59122
return True
60123

61124
def set_values(
@@ -64,6 +127,12 @@ def set_values(
64127
ssa: Iterable[SSAValue],
65128
results: Iterable[ResultType],
66129
):
130+
"""Set the abstract values for the given SSA values in the frame.
131+
132+
This method is used to customize how the abstract values are set in
133+
the frame. By default, the abstract values are set directly in the
134+
frame.
135+
"""
67136
frame.set_values(ssa, results)
68137

69138
def eval_recursion_limit(self, frame: AbstractFrameType) -> ResultType:

src/kirin/interp/base.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525

2626
class InterpreterMeta(ABCMeta):
27+
"""A metaclass for interpreters."""
28+
2729
pass
2830

2931

@@ -35,8 +37,8 @@ class BaseInterpreter(ABC, Generic[FrameType, ValueType], metaclass=InterpreterM
3537
designed to be subclassed to provide the actual implementation of
3638
the interpreter.
3739
38-
When subclassing, if the bases contains `ABC` no checks will be
39-
performed on the subclass. If the subclass does not contain `ABC`,
40+
### Required Overrides
41+
When subclassing, if the subclass does not contain `ABC`,
4042
the subclass must define the following attributes:
4143
4244
- `keys`: a list of strings that defines the order of dialects to select from.
@@ -83,12 +85,13 @@ def __post_init__(self) -> None:
8385
self.registry = self.dialects.registry.interpreter(keys=self.keys)
8486

8587
def initialize(self) -> Self:
86-
"""Initialize the interpreter global states.
87-
88-
This method is called before calling `eval` to initialize the
88+
"""Initialize the interpreter global states. This method is called before
89+
calling [`run`][kirin.interp.base.BaseInterpreter.run] to initialize the
8990
interpreter global states.
9091
91-
Override this method to add custom global states.
92+
!!! note "Default Implementation"
93+
This method provides default behavior but may be overridden by subclasses
94+
to customize or extend functionality.
9295
"""
9396
self.symbol_table: dict[str, Statement] = {}
9497
self.state: InterpreterState[FrameType] = InterpreterState()
@@ -119,7 +122,16 @@ def run(
119122
args: tuple[ValueType, ...],
120123
kwargs: dict[str, ValueType] | None = None,
121124
) -> Result[ValueType]:
122-
"""Run a method."""
125+
"""Run a method. This is the main entry point of the interpreter.
126+
127+
Args:
128+
mt (Method): the method to run.
129+
args (tuple[ValueType]): the arguments to the method, does not include self.
130+
kwargs (dict[str, ValueType], optional): the keyword arguments to the method.
131+
132+
Returns:
133+
Result[ValueType]: the result of the method.
134+
"""
123135
if self._eval_lock:
124136
raise InterpreterError(
125137
"recursive eval is not allowed, use run_method instead"
@@ -340,6 +352,15 @@ def build_signature(self, frame: FrameType, stmt: Statement) -> "Signature":
340352
def lookup_registry(
341353
self, frame: FrameType, stmt: Statement
342354
) -> Optional["StatementImpl[Self, FrameType]"]:
355+
"""Lookup the statement implementation in the registry.
356+
357+
Args:
358+
frame: the current frame
359+
stmt: the statement to run
360+
361+
Returns:
362+
Optional[StatementImpl]: the statement implementation if found, None otherwise.
363+
"""
343364
sig = self.build_signature(frame, stmt)
344365
if sig in self.registry.statements:
345366
return self.registry.statements[sig]
@@ -348,7 +369,17 @@ def lookup_registry(
348369
return
349370

350371
@abstractmethod
351-
def run_ssacfg_region(self, frame: FrameType, region: Region) -> ValueType: ...
372+
def run_ssacfg_region(self, frame: FrameType, region: Region) -> ValueType:
373+
"""This implements how to run a region with MLIR SSA CFG convention.
374+
375+
Args:
376+
frame: the current frame.
377+
region: the region to run.
378+
379+
Returns:
380+
ValueType: the result of running the region.
381+
"""
382+
...
352383

353384
class FuelResult(Enum):
354385
Stop = 0

src/kirin/interp/concrete.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111

1212

1313
class Interpreter(BaseInterpreter[Frame[Any], Any]):
14+
"""Concrete interpreter for the IR.
15+
16+
This is a concrete interpreter for the IR. It evaluates the IR by
17+
executing the statements in the IR using a simple stack-based
18+
interpreter.
19+
"""
20+
1421
keys = ["main"]
1522
void = None
1623

src/kirin/interp/exceptions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@
33

44
# errors
55
class InterpreterError(Exception):
6+
"""Generic interpreter error.
7+
8+
This is the base class for all interpreter errors. Interpreter
9+
errors will be catched by the interpreter and handled appropriately
10+
as an error with stack trace (of Kirin, not Python) from the interpreter.
11+
"""
12+
613
pass
714

815

916
@dataclass
1017
class WrapException(InterpreterError):
18+
"""A special interpreter error that wraps a Python exception."""
19+
1120
exception: Exception
1221

1322

1423
class FuelExhaustedError(InterpreterError):
24+
"""An error raised when the interpreter runs out of fuel."""
25+
1526
pass

src/kirin/interp/frame.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
@dataclass
1515
class FrameABC(ABC, Generic[ValueType]):
16+
"""Abstract base class for interpreter frame."""
17+
1618
code: Statement
1719
"""func statement being interpreted.
1820
"""
@@ -24,17 +26,49 @@ def from_func_like(cls, code: Statement) -> Self:
2426
...
2527

2628
@abstractmethod
27-
def get(self, key: SSAValue) -> ValueType: ...
29+
def get(self, key: SSAValue) -> ValueType:
30+
"""Get the value for the given [`SSAValue`][kirin.ir.SSAValue] key.
31+
See also [`get_values`][kirin.interp.frame.Frame.get_values].
32+
33+
Args:
34+
key(SSAValue): The key to get the value for.
35+
36+
Returns:
37+
ValueType: The value.
38+
"""
39+
...
2840

2941
@abstractmethod
30-
def set(self, key: SSAValue, value: ValueType) -> None: ...
42+
def set(self, key: SSAValue, value: ValueType) -> None:
43+
"""Set the value for the given [`SSAValue`][kirin.ir.SSAValue] key.
44+
See also [`set_values`][kirin.interp.frame.Frame.set_values].
45+
46+
Args:
47+
key(SSAValue): The key to set the value for.
48+
value(ValueType): The value.
49+
"""
50+
...
3151

3252
def get_values(self, keys: Iterable[SSAValue]) -> tuple[ValueType, ...]:
33-
"""Get the values of the given `SSAValue` keys."""
53+
"""Get the values of the given [`SSAValue`][kirin.ir.SSAValue] keys.
54+
See also [`get`][kirin.interp.frame.Frame.get].
55+
56+
Args:
57+
keys(Iterable[SSAValue]): The keys to get the values for.
58+
59+
Returns:
60+
tuple[ValueType, ...]: The values.
61+
"""
3462
return tuple(self.get(key) for key in keys)
3563

3664
def set_values(self, keys: Iterable[SSAValue], values: Iterable[ValueType]) -> None:
37-
"""Set the values of the given `SSAValue` keys."""
65+
"""Set the values of the given [`SSAValue`][kirin.ir.SSAValue] keys.
66+
This is a convenience method to set multiple values at once.
67+
68+
Args:
69+
keys(Iterable[SSAValue]): The keys to set the values for.
70+
values(Iterable[ValueType]): The values.
71+
"""
3872
for key, value in zip(keys, values):
3973
self.set(key, value)
4074

@@ -46,6 +80,8 @@ def set_stmt(self, stmt: Statement) -> Self:
4680

4781
@dataclass
4882
class Frame(FrameABC[ValueType]):
83+
"""Interpreter frame."""
84+
4985
lino: int = 0
5086
stmt: Statement | None = None
5187
"""statement being interpreted.
@@ -65,6 +101,7 @@ class Frame(FrameABC[ValueType]):
65101

66102
@classmethod
67103
def from_func_like(cls, code: Statement) -> Self:
104+
"""Create a new frame for the given statement."""
68105
return cls(code=code)
69106

70107
def get(self, key: SSAValue) -> ValueType:

0 commit comments

Comments
 (0)