Skip to content

Commit ad20611

Browse files
authored
sketch some big sections for documentation (#160)
1 parent a8a1d6d commit ad20611

File tree

21 files changed

+605
-24
lines changed

21 files changed

+605
-24
lines changed

docs/101.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.
5+
6+
17
# Compiler 101 for scientists
28

39
In this section, we cover some common compiler concepts that are useful to know when working with Kirin.

docs/analysis.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.
5+
6+
# Analysis
7+
8+
Kirin provides a framework for performing dataflow analysis on the IR. This is done via
9+
10+
- IR walking
11+
- Abstract interpretation
12+
13+
## Lattice
14+
15+
A lattice is a set of values that are partially ordered. In Kirin IR, a lattice is a subclass of the [`Lattice`][kirin.lattice.abc.Lattice] ABC class. A lattice can be used to represent the result of a statement that has multiple possible results.

docs/codegen.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

docs/comparison.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

docs/contrib.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
Please see [Installation](install.md) for instructions on how to set up your development environment.
44

5+
## Pre-commit hooks
6+
7+
We use `pre-commit` to run the linter checks before you commit your changes. The pre-commit hooks are installed as part of the development dependencies. You can setup `pre-commit` using the following command:
8+
9+
```bash
10+
pre-commit install
11+
```
12+
13+
This will run the linter checks before you commit your changes. If the checks fail, the commit will be
14+
rejected. Most of the following sections can be checked by the pre-commit hooks.
15+
516
## Running the tests
617

718
We use `pytest` for testing. To run the tests, simply run:
@@ -26,7 +37,7 @@ good-to-have practices:
2637
### Naming
2738

2839
- try not to use abbreviation as names, unless it's a common abbreviation like `idx` for `index`
29-
- try not create a lot of duplicated name prefix, e.g `ConstantInt` and `ConstantFloat`, instead use a new module to group them.
40+
- try not create a lot of duplicated name prefix unless the extra information is necessary when accessing the class object.
3041
- try to use `snake_case` for naming variables and functions, and `CamelCase` for classes.
3142

3243
### Comments

docs/cookbook/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

docs/def.md

Lines changed: 282 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,300 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.
5+
16
# Understanding Kirin IR Declarations
27

38
In this section, we will learn about the terminology used in Kirin IR. This will help you understand the structure of the IR and how to write your own compiler using Kirin.
49

5-
## SSA Values
10+
!!! note
11+
The examples in this section will also contain the equivalent MLIR and xDSL code to help you understand the differences between them if you are already familiar with MLIR or xDSL.
12+
13+
## Dialect
14+
15+
The [`Dialect`][kirin.ir.Dialect] object is the main registry of all the statements and attributes that are available in the IR. You can create a dialect by just following:
16+
17+
```python
18+
from kirin import ir
19+
dialect = ir.Dialect("my_dialect") # (1)!
20+
```
21+
22+
1. The [`Dialect`][kirin.ir.Dialect] object is created with the name `my_dialect`.
23+
24+
## Dialect Groups
25+
26+
A dialect group is a collection of dialects that can be used as a decorator for Python frontend. It is used to group multiple dialects together and define the passes, compiler options, and other configurations for the dialects.
27+
28+
```python
29+
from kirin.ir import Method, dialect_group
30+
31+
@dialect_group(
32+
[
33+
base,
34+
binop,
35+
cmp,
36+
unary,
37+
assign,
38+
attr,
39+
boolop,
40+
constant,
41+
indexing,
42+
func,
43+
]
44+
) # (1)!
45+
def python_basic(self): # (2)!
46+
def run_pass(mt: Method) -> None: # (3)!
47+
pass # (4)!
48+
return run_pass
49+
```
50+
51+
1. The [`dialect_group`][kirin.ir.dialect_group] decorator is used to create a dialect group with the specified dialects. In this case, we construct a basic Python dialect that allows some basic operations.
52+
2. The `python_basic` function is the entry point of the dialect group. It takes a `self` argument, which is the [`DialectGroup`][kirin.ir.group.DialectGroup] object. This argument is used to access the definition of the dialect group and optionally update the dialect group.
53+
3. The `run_pass` function is the function that will be called when the dialect group is applied to a given Python function. This is where you can define the passes that will be applied to the method. See the next example.
54+
55+
!!! note
56+
Unlike MLIR/LLVM, because Kirin focuses on kernel functions, the minimal unit of compilation is a function. Therefore, the compiler pass always passes a [`ir.Method`][kirin.ir.Method] object which contains a function-like statement (a statement has [`ir.traits.CallableStmtInterface`][kirin.ir.traits.CallableStmtInterface]).
57+
58+
The above dialect group `python_basic` allows you to use it as following:
59+
60+
```python
61+
@python_basic
62+
def my_function():
63+
pass
64+
```
65+
66+
However, if we want to run some compilation passes on the function, we need to define some passes in the `run_pass` function.
67+
68+
```python
69+
from kirin.passes.fold import Fold
70+
71+
@dialect_group(python_basic) # (1)!
72+
def python(self):
73+
fold_pass = Fold(self) # (2)!
74+
75+
def run_pass(mt: Method, *, verify: bool = True, fold: bool = True) -> None: # (3)!
76+
if verify: # (4)!
77+
mt.verify()
78+
79+
if fold: # (5)!
80+
fold_pass(mt)
81+
return run_pass
82+
```
83+
84+
1. The [`dialect_group`][kirin.ir.dialect_group] decorator can also take a dialect group as an argument. This will use the dialects defined in the given dialect group with different passes.
85+
2. The `Fold` pass is created when initializing the dialect group. This pass is used later when running the `run_pass` function.
86+
3. The `run_pass` function is the function that will be called when the dialect group is applied to a given Python function. This function takes a `mt` argument, which is the [`ir.Method`][kirin.ir.Method] object, and optional arguments `verify`, `fold`, and `aggressive`.
87+
4. If the `verify` argument is `True`, the method will be verified.
88+
5. If the `fold` argument is `True`, the `Fold` pass will be applied to the method.
89+
90+
The above dialect group `python` allows you to use it as following:
91+
92+
```python
93+
@python(fold=True) # (1)!
94+
def my_function():
95+
pass
96+
```
97+
98+
1. The `fold` argument here is passed to the `run_pass` function defined in the dialect group. Looks complicated? Don't worry, the `@dialect_group` decorator will handle everything including the type hints!
99+
100+
## Statement
101+
102+
In Kirin IR, a statement describes an operation that can be executed. Statements are the building blocks that contain the semantics of the program.
103+
104+
### Defining a Statement
105+
106+
While a statement can be hand-written by inheriting [`ir.Statement`][kirin.ir.Statement],
107+
we provide a python-`dataclass`-like decorator [`statement`][kirin.decl.statement] and in combine
108+
with the [`info.argument`][kirin.decl.info.argument],[`info.result`][kirin.decl.info.result],[`info.region`][kirin.decl.info.region], [`info.block`][kirin.decl.info.block] field specifier to make it easier to define a statement.
109+
110+
=== "Kirin"
111+
112+
```python
113+
from kirin import ir
114+
from kirin.decl import statement, info
115+
116+
@statement # (1)!
117+
class MyStatement(ir.Statement): # (2)!
118+
name = "awesome" # (3)!
119+
traits = frozenset({ir.Pure()}) # (4)!
120+
# blabla, we will talk about this later
121+
```
122+
123+
1. the decorator [`@statement`][kirin.decl.statement] is used to generate implementations for the `MyStatement` class based on the fields defined in the class.
124+
2. The `MyStatement` class inherits from [`ir.Statement`][kirin.ir.Statement].
125+
3. The `name` field is the name of the statement, if your desired name is just `my_statement`, you can omit this field, [`@statement`][kirin.decl.statement] will automatically generate the name by converting the class name to snake case. The name is what will be used in text/pretty printing.
126+
4. The `traits` field is used to specify the traits of the statement. In this case, the statement is pure.
127+
128+
=== "MLIR"
129+
130+
```mlir
131+
```
132+
133+
=== "xDSL"
134+
135+
```python
136+
```
137+
138+
Like a function, a statement can have multiple inputs and outputs.
139+
140+
=== "Kirin"
141+
142+
```python
143+
@statement # (1)!
144+
class Add(ir.Statement):
145+
traits = frozenset({ir.Pure()}) # (2)!
146+
lhs: ir.SSAValue = info.argument(ir.types.Int) # (3)!
147+
rhs: ir.SSAValue = info.argument(ir.types.Int) # (4)!
148+
output: ir.ResultValue = info.result(ir.types.Int) # (5)!
149+
```
150+
151+
1. the decorator [`@statement`][kirin.decl.statement] is used to generate implementations for the `MyStatement` class based on the fields defined in the class.
152+
2. The `traits` field is used to specify the traits of the statement. In this case, the statement is pure.
153+
3. The `lhs` field is the left-hand side input value of the statement. The field descriptor [`info.argument`][kirin.decl.info.argument] is used to specify the type of the input value.
154+
4. The `rhs` field is the right-hand side input value of the statement. The field descriptor [`info.argument`][kirin.decl.info.argument] is used to specify the type of the input value.
155+
5. The `output` field is the output value of the statement. The field descriptor [`info.result`][kirin.decl.info.result] is used to specify the type of the output value.
156+
157+
=== "MLIR"
158+
159+
```mlir
160+
```
161+
162+
=== "xDSL"
163+
164+
```python
165+
```
166+
167+
A statement can have blocks as successors, which describe the control flow of the program.
168+
169+
=== "Kirin"
170+
171+
```python
172+
@statement
173+
class Branch(Statement):
174+
name = "br"
175+
traits = frozenset({IsTerminator()}) # (1)!
176+
177+
arguments: tuple[SSAValue, ...] # (2)!
178+
successor: Block = info.block() # (3)!
179+
```
180+
181+
1. The `traits` field is used to specify the traits of the statement. In this case, the statement is a [terminator](/101.md/#terminator).
182+
2. The `arguments` field is the input values of the statement. Branch can take multiple arguments, `tuple[SSAValue, ...]` is used to specify that the field is a tuple of `SSAValue`. Note that only `...` is supported because if the number of arguments is known, we recommend specifying them explicitly.
183+
3. The `successor` field is the block that the statement will go to after execution. The field descriptor [`info.block`][kirin.decl.info.block] is used to specify the type of the field.
184+
185+
=== "MLIR"
186+
187+
```mlir
188+
```
189+
190+
=== "xDSL"
191+
192+
```python
193+
```
194+
195+
It can also have a region that contains other statements, for example, a function statement
196+
197+
=== "Kirin"
198+
199+
```python
200+
@statement
201+
class Function(ir.Statement):
202+
name = "func"
203+
traits = frozenset({SSACFGRegion()}) # (1)!
204+
sym_name: str = info.attribute(property=True) # (2)!
205+
body: Region = info.region(multi=True) # (3)!
206+
```
207+
208+
1. The `traits` field contains the `SSACFGRegion` trait, which indicates that the region in the statement is a standard control-flow graph.
209+
2. The `sym_name` field is the name of the function. In the [`@statement`][kirin.decl.statement] decorator, if a field annotated with normal Python types (not an IR node, e.g [`ir.SSAValue`][kirin.ir.SSAValue], [`ir.Block`][kirin.ir.Block], [`ir.Region`][kirin.ir.Region]), it will be treated as a [`PyAttr`][kirin.ir.PyAttr] attribute.
210+
3. The `body` field is the region that contains the statements of the function. The field descriptor [`info.region`][kirin.decl.info.region] is used to specify this region can contain multiple blocks.
211+
212+
213+
=== "MLIR"
214+
215+
```mlir
216+
```
217+
218+
=== "xDSL"
219+
220+
```python
221+
```
222+
223+
### Constructing a Statement
224+
225+
Statements can be constructed in similar ways to constructing a normal Python `dataclass`. Taking the previous
226+
definitions as an example:
227+
228+
```python
229+
from kirin.dialects.py.constant import Constant
230+
231+
lhs, rhs = Constant(1), Constant(2) # (1)!
232+
add = Add(lhs.result, rhs=rhs.result) # (2)!
233+
```
234+
235+
1. Two [`Constant`][kirin.dialect.py.constant.Constant] statements are created with the value `1` and `2`.
236+
2. An [`Add`][kirin.decl.statement] statement is created with the `lhs` and `rhs` fields set to the results of the `lhs` and `rhs` statements. Like `@dataclass` unless specified by `kw_only=True`, the fields are positional.
237+
238+
## Block
239+
240+
A block is a sequence of statements that are executed in order. Optionally, a block can have arguments that are passed from the predecessor block and terminates with a terminator statement. Unlike [`ir.Statement`][kirin.ir.Statement], the [`ir.Block`][kirin.ir.Block] class is final and cannot be extended.
241+
242+
### Constructing a Block
243+
244+
`Block` takes a `Sequence` of statements as an argument, e.g a list of statements.
245+
246+
```python
247+
from kirin import ir
248+
ir.Block() # Block(_args=())
249+
ir.Block([stmt_a, stmt_b])
250+
```
251+
252+
continue the example from [Constructing a Statement](#constructing-a-statement), we can construct
253+
a block like following:
6254

7-
::: kirin.ir.SSAValue
255+
```python
256+
block = ir.Block()
257+
arg_x = block.args.append_from(ir.types.Any)
258+
arg_y = block.args.append_from(ir.types.Any)
259+
block.stmts.append(Add(arg_x, arg_y))
260+
```
8261

9-
## Dialects
262+
!!! note
263+
Every IR node in Kirin has a pretty printer that can be used to print the node in a human-readable format. Just call [`.print`][kirin.print.Printable.print] method. In the above example, we have
10264

11-
::: kirin.ir.Dialect
265+
```mlir
266+
^0(%0, %1):
267+
%2 = add(lhs=%0, rhs=%1) : !py.int
268+
```
269+
which is the pretty-printed version of the block. You may notice this is similar to MLIR text format, which is intentional.
12270

13-
## Statements
271+
## Region
14272

15-
::: kirin.ir.Statement
273+
A region is a sequence of blocks that are connected by control flow. A region can contain multiple blocks and can be nested within another region via statements that contain a region field. Unlike [`ir.Statement`][kirin.ir.Statement], the [`ir.Region`][kirin.ir.Region] class is final and cannot be extended.
16274

17-
## Attributes
275+
### Constructing a Region
18276

19-
::: kirin.ir.Attribute
277+
Continuing the example from [Constructing a Block](#constructing-a-block), we can construct a region like following:
20278

21-
::: kirin.ir.types.TypeAttribute
279+
```python
280+
region = ir.Region([block])
281+
```
22282

23-
## Traits
283+
pretty printing the region will give you
24284

25-
::: kirin.ir.StmtTrait
285+
```mlir
286+
{
287+
^0(%1, %2):
288+
│ %0 = add(lhs=%1, rhs=%2) : !py.int
289+
}
290+
```
26291

27-
## Blocks
292+
## SSA Value
28293

29-
::: kirin.ir.Block
294+
An SSA value is a value that is assigned only once in the program. In Kirin IR, an SSA value is represented by the [`ir.SSAValue`][kirin.ir.SSAValue] class. Most of the time, one does not need to construct the SSA value directly, as it is automatically created when constructing a statement.
30295

31-
## Regions
296+
There are 3 types of SSA values:
32297

33-
::: kirin.ir.Region
298+
- [`ir.SSAValue`][kirin.ir.SSAValue]: the base class of SSA values.
299+
- [`ir.ResultValue`][kirin.ir.ResultValue]: SSA values that are the result of a statement, this object allows you to access the parent statement via [`result.owner`][kirin.ir.SSAValue.owner] property.
300+
- [`ir.BlockArgument`][kirin.ir.BlockArgument]: SSA values that are the arguments of a block.

docs/dialects/cf.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

docs/dialects/func.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

docs/dialects/ilist.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!!! warning
2+
This page is under construction. The content may be incomplete or incorrect. Submit an issue
3+
on [GitHub](https://github.com/QuEraComputing/kirin/issues/new) if you need help or want to
4+
contribute.

0 commit comments

Comments
 (0)