Skip to content

Warning

This page is under construction. The content may be incomplete or incorrect. Submit an issue on GitHub if you need help or want to contribute.

Dialects for special Python functions

There are some special built-in Python functions that does not necessarily provide new data types when using them as Kirin dialects.

For example, the py.range dialect may not use a Python range type, the actual type can be decided by another dialect that implements the type inference method for Range statement, e.g ilist dialect provides an IList implementation for Range statement.

The reason for this is that in many cases, eDSLs are not interested in the actual data type of the result, but rather the semantics of the operation. For ilist dialect, the Range statement is just a syntax sugar for creating a list of integers. The compiler will decide what the actual implementation (such as the memory layout) of the list should be.

References

Iterable

kirin.dialects.py.iterable

This module provides access to Python iterables.

This is used to lower Python loops into cf dialect.

This module contains the common methods for the Python iterable:

  • The Iter statement class.
  • The Next statement class.
  • The lowering pass for the iterable.
  • The concrete implementation of the iterable.

This dialect maps iter() and next() calls to the Iter and Next statements.

PyRangeIterType module-attribute

PyRangeIterType = PyClass(type(iter(range(0))))

dialect module-attribute

dialect = Dialect('py.iterable')

Concrete dataclass

Concrete()

Bases: MethodTable

iter_

iter_(interp, frame: interp.Frame, stmt: Iter)
Source code in src/kirin/dialects/py/iterable.py
46
47
48
@interp.impl(Iter)
def iter_(self, interp, frame: interp.Frame, stmt: Iter):
    return (iter(frame.get(stmt.value)),)

next_

next_(interp, frame: interp.Frame, stmt: Next)
Source code in src/kirin/dialects/py/iterable.py
50
51
52
@interp.impl(Next)
def next_(self, interp, frame: interp.Frame, stmt: Next):
    return (next(frame.get(stmt.iter), None),)

Iter kirin-statement

Iter(value: ir.SSAValue)

Bases: Statement

This is equivalent to iter(value) in Python.

iter kirin-result

iter: ResultValue = result(Any)

traits class-attribute instance-attribute

traits = frozenset({Pure()})

value kirin-argument

value: SSAValue = argument(Any)

Lowering

Bases: FromPythonAST

lower_Call_iter

lower_Call_iter(
    state: lowering.LoweringState, node: Call
) -> lowering.Result
Source code in src/kirin/dialects/py/iterable.py
70
71
72
73
74
75
76
77
def lower_Call_iter(
    self, state: lowering.LoweringState, node: Call
) -> lowering.Result:
    if len(node.args) != 1:
        raise DialectLoweringError("iter() takes exactly 1 argument")
    return lowering.Result(
        state.append_stmt(Iter(state.visit(node.args[0]).expect_one()))
    )

lower_Call_next

lower_Call_next(
    state: lowering.LoweringState, node: Call
) -> lowering.Result
Source code in src/kirin/dialects/py/iterable.py
79
80
81
82
83
84
85
86
87
88
89
90
def lower_Call_next(
    self, state: lowering.LoweringState, node: Call
) -> lowering.Result:
    if len(node.args) == 2:
        raise DialectLoweringError(
            "next() does not throw StopIteration inside kernel"
        )
    if len(node.args) != 1:
        raise DialectLoweringError("next() takes exactly 1 argument")
    return lowering.Result(
        state.append_stmt(Next(state.visit(node.args[0]).expect_one()))
    )

Next kirin-statement

Next(iter: ir.SSAValue)

Bases: Statement

This is equivalent to next(iterable, None) in Python.

iter kirin-argument

iter: SSAValue = argument(Any)

value kirin-result

value: ResultValue = result(Any)

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

iter_

iter_(interp, frame: interp.Frame, stmt: Iter)
Source code in src/kirin/dialects/py/iterable.py
58
59
60
@interp.impl(Iter, types.PyClass(range))
def iter_(self, interp, frame: interp.Frame, stmt: Iter):
    return (PyRangeIterType,)

next_

next_(interp, frame: interp.Frame, stmt: Next)
Source code in src/kirin/dialects/py/iterable.py
62
63
64
@interp.impl(Next, PyRangeIterType)
def next_(self, interp, frame: interp.Frame, stmt: Next):
    return (types.Int,)

Len

kirin.dialects.py.len

The Len dialect.

This dialect maps the len() call to the Len statement:

  • The Len statement class.
  • The lowering pass for the len() call.
  • The concrete implementation of the len() call.

dialect module-attribute

dialect = Dialect('py.len')

Concrete dataclass

Concrete()

Bases: MethodTable

len

len(interp, frame: interp.Frame, stmt: Len)
Source code in src/kirin/dialects/py/len.py
30
31
32
@interp.impl(Len)
def len(self, interp, frame: interp.Frame, stmt: Len):
    return (len(frame.get(stmt.value)),)

ConstProp dataclass

ConstProp()

Bases: MethodTable

len

len(interp, frame: interp.Frame, stmt: Len)
Source code in src/kirin/dialects/py/len.py
38
39
40
41
42
43
44
45
46
@interp.impl(Len)
def len(self, interp, frame: interp.Frame, stmt: Len):
    value = frame.get(stmt.value)
    if isinstance(value, const.Value):
        return (const.Value(len(value.data)),)
    elif isinstance(value, const.PartialTuple):
        return (const.Value(len(value.data)),)
    else:
        return (const.Result.top(),)

Len kirin-statement

Len(value: ir.SSAValue)

Bases: Statement

name class-attribute instance-attribute

name = 'len'

result kirin-result

result: ResultValue = result(Int)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

value kirin-argument

value: SSAValue = argument(Any)

Lowering

Bases: FromPythonAST

lower_Call_len

lower_Call_len(
    state: lowering.LoweringState, node: ast.Call
) -> lowering.Result
Source code in src/kirin/dialects/py/len.py
52
53
54
55
56
57
def lower_Call_len(
    self, state: lowering.LoweringState, node: ast.Call
) -> lowering.Result:
    return lowering.Result(
        state.append_stmt(Len(value=state.visit(node.args[0]).expect_one()))
    )

Range

kirin.dialects.py.range

The range dialect for Python.

This dialect models the builtin range() function in Python.

The dialect includes: - The Range statement class. - The lowering pass for the range() function.

This dialect does not include a concrete implementation or type inference for the range() function. One needs to use other dialect for the concrete implementation and type inference, e.g., ilist dialect.

dialect module-attribute

dialect = Dialect('py.range')

Range kirin-statement

Range(
    start: ir.SSAValue, stop: ir.SSAValue, step: ir.SSAValue
)

Bases: Statement

name class-attribute instance-attribute

name = 'range'

result kirin-result

result: ResultValue = result(PyClass(range))

start kirin-argument

start: SSAValue = argument(Int)

step kirin-argument

step: SSAValue = argument(Int)

stop kirin-argument

stop: SSAValue = argument(Int)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonRangeLike()})

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

eltype_range

eltype_range(
    interp_, frame: interp.Frame, stmt: eltype.ElType
)
Source code in src/kirin/dialects/py/range.py
34
35
36
@interp.impl(eltype.ElType, types.PyClass(range))
def eltype_range(self, interp_, frame: interp.Frame, stmt: eltype.ElType):
    return (types.Int,)

Slice

kirin.dialects.py.slice

The slice dialect for Python.

This dialect provides a Slice statement that represents a slice object in Python:

  • The Slice statement class.
  • The lowering pass for the slice call.
  • The concrete implementation of the slice call.
  • The type inference implementation of the slice call.

T module-attribute

T = TypeVar('T')

dialect module-attribute

dialect = Dialect('py.slice')

Concrete dataclass

Concrete()

Bases: MethodTable

_slice

_slice(interp, frame: interp.Frame, stmt: Slice)
Source code in src/kirin/dialects/py/slice.py
68
69
70
71
72
73
74
75
76
@interp.impl(Slice)
def _slice(self, interp, frame: interp.Frame, stmt: Slice):
    start, stop, step = frame.get_values(stmt.args)
    if start is None and step is None:
        return (slice(stop),)
    elif step is None:
        return (slice(start, stop),)
    else:
        return (slice(start, stop, step),)

Lowering

Bases: FromPythonAST

lower_Call_slice

lower_Call_slice(
    state: lowering.LoweringState, node: ast.Call
) -> lowering.Result
Source code in src/kirin/dialects/py/slice.py
 98
 99
100
101
def lower_Call_slice(
    self, state: lowering.LoweringState, node: ast.Call
) -> lowering.Result:
    return _lower_slice(state, node)

lower_Slice

lower_Slice(
    state: lowering.LoweringState, node: ast.Slice
) -> lowering.Result
Source code in src/kirin/dialects/py/slice.py
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def lower_Slice(
    self, state: lowering.LoweringState, node: ast.Slice
) -> lowering.Result:
    def value_or_none(expr: ast.expr | None) -> ir.SSAValue:
        if expr is not None:
            return state.visit(expr).expect_one()
        else:
            return state.append_stmt(Constant(None)).result

    lower = value_or_none(node.lower)
    upper = value_or_none(node.upper)
    step = value_or_none(node.step)
    return lowering.Result(
        state.append_stmt(Slice(start=lower, stop=upper, step=step))
    )

Slice kirin-statement

Slice(
    start: ir.SSAValue, stop: ir.SSAValue, step: ir.SSAValue
)

Bases: Statement

Source code in src/kirin/dialects/py/slice.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def __init__(
    self, start: ir.SSAValue, stop: ir.SSAValue, step: ir.SSAValue
) -> None:
    if not (
        isinstance(stop.type, types.TypeAttribute)
        and isinstance(start.type, types.TypeAttribute)
    ):
        result_type = types.Bottom
    elif start.type.is_subseteq(types.NoneType):
        if stop.type.is_subseteq(types.NoneType):
            result_type = types.Bottom
        else:
            result_type = types.Slice[stop.type]
    else:
        result_type = types.Slice[start.type]

    super().__init__(
        args=(start, stop, step),
        result_types=[result_type],
        args_slice={"start": 0, "stop": 1, "step": 2},
    )

name class-attribute instance-attribute

name = 'slice'

result kirin-result

result: ResultValue = result(Slice[T])

start kirin-argument

start: SSAValue = argument(T | NoneType)

step kirin-argument

step: SSAValue = argument(T | NoneType)

stop kirin-argument

stop: SSAValue = argument(T | NoneType)

traits class-attribute instance-attribute

traits = frozenset({Pure(), SliceLowering()})

SliceLowering dataclass

SliceLowering()

Bases: FromPythonCall['Slice']

lower

lower(
    stmt: type[Slice],
    state: lowering.LoweringState,
    node: ast.Call,
) -> lowering.Result
Source code in src/kirin/dialects/py/slice.py
24
25
26
27
def lower(
    self, stmt: type["Slice"], state: lowering.LoweringState, node: ast.Call
) -> lowering.Result:
    return _lower_slice(state, node)

_lower_slice

_lower_slice(
    state: lowering.LoweringState, node: ast.Call
) -> lowering.Result
Source code in src/kirin/dialects/py/slice.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def _lower_slice(state: lowering.LoweringState, node: ast.Call) -> lowering.Result:
    if len(node.args) == 1:
        start = state.visit(ast.Constant(None)).expect_one()
        stop = state.visit(node.args[0]).expect_one()
        step = state.visit(ast.Constant(None)).expect_one()
    elif len(node.args) == 2:
        start = state.visit(node.args[0]).expect_one()
        stop = state.visit(node.args[1]).expect_one()
        step = state.visit(ast.Constant(None)).expect_one()
    elif len(node.args) == 3:
        start = state.visit(node.args[0]).expect_one()
        stop = state.visit(node.args[1]).expect_one()
        step = state.visit(node.args[2]).expect_one()
    else:
        raise exceptions.DialectLoweringError("slice() takes 1-3 arguments")

    return lowering.Result(state.append_stmt(Slice(start, stop, step)))

Built-in Function

kirin.dialects.py.builtin

builtin dialect for python builtins

This dialect provides implementations for builtin functions like abs and sum.

  • Statements: Abs, Sum.
  • The lowering pass for the builtin functions.
  • The concrete implementation of the builtin functions.
  • The type inference implementation of the builtin functions.

This dialect maps ast.Call nodes of builtin functions to the Abs and Sum statements.

T module-attribute

T = TypeVar('T', bound=Int | Float)

dialect module-attribute

dialect = Dialect('py.builtin')

Abs kirin-statement

Abs(value: ir.SSAValue)

Bases: Statement

name class-attribute instance-attribute

name = 'abs'

result kirin-result

result: ResultValue = result(T)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

value kirin-argument

value: SSAValue = argument(T, print=False)

Concrete dataclass

Concrete()

Bases: MethodTable

_sum

_sum(interp, frame: interp.Frame, stmt: Sum)
Source code in src/kirin/dialects/py/builtin.py
64
65
66
@interp.impl(Sum)
def _sum(self, interp, frame: interp.Frame, stmt: Sum):
    return (sum(frame.get(stmt.value)),)

abs

abs(interp, frame: interp.Frame, stmt: Abs)
Source code in src/kirin/dialects/py/builtin.py
60
61
62
@interp.impl(Abs)
def abs(self, interp, frame: interp.Frame, stmt: Abs):
    return (abs(frame.get(stmt.value)),)

Lowering

Bases: FromPythonAST

lower_Call_abs

lower_Call_abs(
    state: lowering.LoweringState, node: Call
) -> lowering.Result
Source code in src/kirin/dialects/py/builtin.py
42
43
44
45
46
47
def lower_Call_abs(
    self, state: lowering.LoweringState, node: Call
) -> lowering.Result:
    return lowering.Result(
        state.append_stmt(Abs(state.visit(node.args[0]).expect_one()))
    )

lower_Call_sum

lower_Call_sum(
    state: lowering.LoweringState, node: Call
) -> lowering.Result
Source code in src/kirin/dialects/py/builtin.py
49
50
51
52
53
54
def lower_Call_sum(
    self, state: lowering.LoweringState, node: Call
) -> lowering.Result:
    return lowering.Result(
        state.append_stmt(Sum(state.visit(node.args[0]).expect_one()))
    )

Sum kirin-statement

Sum(value: ir.SSAValue)

Bases: Statement

name class-attribute instance-attribute

name = 'sum'

result kirin-result

result: ResultValue = result(Any)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

value kirin-argument

value: SSAValue = argument(Any, print=False)

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

absf

absf(interp, frame, stmt)
Source code in src/kirin/dialects/py/builtin.py
76
77
78
@interp.impl(Abs, types.Float)
def absf(self, interp, frame, stmt):
    return (types.Float,)

absi

absi(interp, frame, stmt)
Source code in src/kirin/dialects/py/builtin.py
72
73
74
@interp.impl(Abs, types.Int)
def absi(self, interp, frame, stmt):
    return (types.Int,)