annotate mlir/docs/EDSC.md @ 194:f2ef29ba5fe2

try to remove setjmp.h start
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 22 Mar 2021 18:10:23 +0900 (2021-03-22)
parents 0572611fdcc8
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 # Background: declarative builders API
anatofuz
parents:
diff changeset
2
anatofuz
parents:
diff changeset
3 The main purpose of the declarative builders API is to provide an intuitive way
anatofuz
parents:
diff changeset
4 of constructing MLIR programmatically. In the majority of cases, the IR we wish
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
5 to construct exhibits structured control-flow. The Declarative builders in the
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
6 `EDSC` library (Embedded Domain Specific Constructs) provide an API to make MLIR
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
7 construction and manipulation very idiomatic, for the structured control-flow
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
8 case, in C++.
150
anatofuz
parents:
diff changeset
9
anatofuz
parents:
diff changeset
10 ## ScopedContext
anatofuz
parents:
diff changeset
11
anatofuz
parents:
diff changeset
12 `mlir::edsc::ScopedContext` provides an implicit thread-local context,
anatofuz
parents:
diff changeset
13 supporting a simple declarative API with globally accessible builders. These
anatofuz
parents:
diff changeset
14 declarative builders are available within the lifetime of a `ScopedContext`.
anatofuz
parents:
diff changeset
15
anatofuz
parents:
diff changeset
16 ## Intrinsics
anatofuz
parents:
diff changeset
17
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
18 `mlir::ValueBuilder` is a generic wrapper for the `mlir::OpBuilder::create`
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
19 method that operates on `Value` objects and return a single Value. For
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
20 instructions that return no values or that return multiple values, the
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
21 `mlir::edsc::OperationBuilder` can be used. Named intrinsics are provided as
150
anatofuz
parents:
diff changeset
22 syntactic sugar to further reduce boilerplate.
anatofuz
parents:
diff changeset
23
anatofuz
parents:
diff changeset
24 ```c++
anatofuz
parents:
diff changeset
25 using load = ValueBuilder<LoadOp>;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
26 using store = OperationBuilder<StoreOp>;
150
anatofuz
parents:
diff changeset
27 ```
anatofuz
parents:
diff changeset
28
anatofuz
parents:
diff changeset
29 ## LoopBuilder and AffineLoopNestBuilder
anatofuz
parents:
diff changeset
30
anatofuz
parents:
diff changeset
31 `mlir::edsc::AffineLoopNestBuilder` provides an interface to allow writing
anatofuz
parents:
diff changeset
32 concise and structured loop nests.
anatofuz
parents:
diff changeset
33
anatofuz
parents:
diff changeset
34 ```c++
anatofuz
parents:
diff changeset
35 ScopedContext scope(f.get());
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
36 Value i, j, lb(f->getArgument(0)), ub(f->getArgument(1));
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
37 Value f7(std_constant_float(llvm::APFloat(7.0f), f32Type)),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
38 f13(std_constant_float(llvm::APFloat(13.0f), f32Type)),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
39 i7(constant_int(7, 32)),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
40 i13(constant_int(13, 32));
150
anatofuz
parents:
diff changeset
41 AffineLoopNestBuilder(&i, lb, ub, 3)([&]{
anatofuz
parents:
diff changeset
42 lb * index_type(3) + ub;
anatofuz
parents:
diff changeset
43 lb + index_type(3);
anatofuz
parents:
diff changeset
44 AffineLoopNestBuilder(&j, lb, ub, 2)([&]{
anatofuz
parents:
diff changeset
45 ceilDiv(index_type(31) * floorDiv(i + j * index_type(3), index_type(32)),
anatofuz
parents:
diff changeset
46 index_type(32));
anatofuz
parents:
diff changeset
47 ((f7 + f13) / f7) % f13 - f7 * f13;
anatofuz
parents:
diff changeset
48 ((i7 + i13) / i7) % i13 - i7 * i13;
anatofuz
parents:
diff changeset
49 });
anatofuz
parents:
diff changeset
50 });
anatofuz
parents:
diff changeset
51 ```
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 ## IndexedValue
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 `mlir::edsc::IndexedValue` provides an index notation around load and store
anatofuz
parents:
diff changeset
56 operations on abstract data types by overloading the C++ assignment and
anatofuz
parents:
diff changeset
57 parenthesis operators. The relevant loads and stores are emitted as appropriate.
anatofuz
parents:
diff changeset
58
anatofuz
parents:
diff changeset
59 ## Putting it all together
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 With declarative builders, it becomes fairly concise to build rank and
anatofuz
parents:
diff changeset
62 type-agnostic custom operations even though MLIR does not yet have generic
anatofuz
parents:
diff changeset
63 types. Here is what a definition of a general pointwise add looks in
anatofuz
parents:
diff changeset
64 Tablegen with declarative builders.
anatofuz
parents:
diff changeset
65
anatofuz
parents:
diff changeset
66 ```c++
anatofuz
parents:
diff changeset
67 def AddOp : Op<"x.add">,
anatofuz
parents:
diff changeset
68 Arguments<(ins Tensor:$A, Tensor:$B)>,
anatofuz
parents:
diff changeset
69 Results<(outs Tensor: $C)> {
anatofuz
parents:
diff changeset
70 code referenceImplementation = [{
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
71 SmallVector<Value, 4> ivs(view_A.rank());
150
anatofuz
parents:
diff changeset
72 IndexedValue A(arg_A), B(arg_B), C(arg_C);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
73 AffineLoopNestBuilder(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
74 ivs, view_A.getLbs(), view_A.getUbs(), view_A.getSteps())([&]{
150
anatofuz
parents:
diff changeset
75 C(ivs) = A(ivs) + B(ivs)
anatofuz
parents:
diff changeset
76 });
anatofuz
parents:
diff changeset
77 }];
anatofuz
parents:
diff changeset
78 }
anatofuz
parents:
diff changeset
79 ```
anatofuz
parents:
diff changeset
80
anatofuz
parents:
diff changeset
81 Depending on the function signature on which this emitter is called, the
anatofuz
parents:
diff changeset
82 generated IR resembles the following, for a 4-D memref of `vector<4xi8>`:
anatofuz
parents:
diff changeset
83
anatofuz
parents:
diff changeset
84 ```
anatofuz
parents:
diff changeset
85 // CHECK-LABEL: func @t1(%lhs: memref<3x4x5x6xvector<4xi8>>, %rhs: memref<3x4x5x6xvector<4xi8>>, %result: memref<3x4x5x6xvector<4xi8>>) -> () {
anatofuz
parents:
diff changeset
86 // CHECK: affine.for {{.*}} = 0 to 3 {
anatofuz
parents:
diff changeset
87 // CHECK: affine.for {{.*}} = 0 to 4 {
anatofuz
parents:
diff changeset
88 // CHECK: affine.for {{.*}} = 0 to 5 {
anatofuz
parents:
diff changeset
89 // CHECK: affine.for {{.*}}= 0 to 6 {
anatofuz
parents:
diff changeset
90 // CHECK: {{.*}} = load %arg1[{{.*}}] : memref<3x4x5x6xvector<4xi8>>
anatofuz
parents:
diff changeset
91 // CHECK: {{.*}} = load %arg0[{{.*}}] : memref<3x4x5x6xvector<4xi8>>
anatofuz
parents:
diff changeset
92 // CHECK: {{.*}} = addi {{.*}} : vector<4xi8>
anatofuz
parents:
diff changeset
93 // CHECK: store {{.*}}, %arg2[{{.*}}] : memref<3x4x5x6xvector<4xi8>>
anatofuz
parents:
diff changeset
94 ```
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 or the following, for a 0-D `memref<f32>`:
anatofuz
parents:
diff changeset
97
anatofuz
parents:
diff changeset
98 ```
anatofuz
parents:
diff changeset
99 // CHECK-LABEL: func @t3(%lhs: memref<f32>, %rhs: memref<f32>, %result: memref<f32>) -> () {
anatofuz
parents:
diff changeset
100 // CHECK: {{.*}} = load %arg1[] : memref<f32>
anatofuz
parents:
diff changeset
101 // CHECK: {{.*}} = load %arg0[] : memref<f32>
anatofuz
parents:
diff changeset
102 // CHECK: {{.*}} = addf {{.*}}, {{.*}} : f32
anatofuz
parents:
diff changeset
103 // CHECK: store {{.*}}, %arg2[] : memref<f32>
anatofuz
parents:
diff changeset
104 ```
anatofuz
parents:
diff changeset
105
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
106 Similar APIs are provided to emit the lower-level `scf.for` op with
150
anatofuz
parents:
diff changeset
107 `LoopNestBuilder`. See the `builder-api-test.cpp` test for more usage examples.
anatofuz
parents:
diff changeset
108
anatofuz
parents:
diff changeset
109 Since the implementation of declarative builders is in C++, it is also available
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
110 to program the IR with an embedded-DSL flavor directly integrated in MLIR.