@@ -94,22 +94,24 @@ layout, and the second one is a `memref` of 4-element vectors with a 2-strided,
94
94
affine_map<(m) -> (m)>,
95
95
affine_map<(m) -> (m)>
96
96
]
97
+
97
98
#attrs = {
98
- args_in = 1,
99
- args_out = 1,
100
99
indexing_maps = #accesses,
101
100
iterator_types = ["parallel"]
102
101
}
102
+
103
103
// memory layouts
104
104
#identity = affine_map<(d0) -> (d0)>
105
105
106
106
func @example(%A: memref<?xf32, #identity>,
107
107
%B: memref<?xvector<4xf32>, offset: 1, strides: [2]>) {
108
- linalg.generic #attrs %A, %B {
108
+ linalg.generic #attrs
109
+ ins(%A: memref<?xf32, #identity>)
110
+ outs(%B: memref<?xvector<4xf32>, offset: 1, strides: [2]>) {
109
111
^bb0(%a: f32, %b: vector<4xf32>):
110
112
%c = "some_compute"(%a, %b): (f32, vector<4xf32>) -> (vector<4xf32>)
111
113
linalg.yield %c: vector<4xf32>
112
- } : memref<?xf32, #identity>, memref<?xvector<4xf32>, offset: 1, strides: [2]>
114
+ }
113
115
return
114
116
}
115
117
```
@@ -173,34 +175,35 @@ Consider the following fully specified `linalg.generic` example. Here, the first
173
175
` memref ` is a 2-strided one on both of its dimensions, and the second ` memref `
174
176
uses an identity layout.
175
177
176
- ```
178
+ ``` mlir
177
179
// File name: example2.mlir
178
180
#indexing_maps = [
179
181
affine_map<(i, j) -> (j, i)>,
180
182
affine_map<(i, j) -> (j)>
181
183
]
184
+
182
185
#attrs = {
183
- args_in = 1,
184
- args_out = 1,
185
186
indexing_maps = #indexing_maps,
186
187
iterator_types = ["parallel", "parallel"]
187
188
}
188
189
189
190
func @example(%A: memref<8x?xf32, offset: 0, strides: [2, 2]>,
190
191
%B: memref<?xvector<4xf32>>) {
191
- linalg.generic #attrs %A, %B {
192
+ linalg.generic #attrs
193
+ ins(%A: memref<8x?xf32, offset: 0, strides: [2, 2]>)
194
+ outs(%B: memref<?xvector<4xf32>>) {
192
195
^bb0(%a: f32, %b: vector<4xf32>):
193
196
%c = "some_compute"(%a, %b): (f32, vector<4xf32>) -> (vector<4xf32>)
194
197
linalg.yield %c: vector<4xf32>
195
- }: memref<8x?xf32 , offset: 0, strides: [2, 2]>, memref<?xvector<4xf32>>
198
+ }
196
199
return
197
200
}
198
201
```
199
202
200
203
The property "* Reversible Mappings Between Control and Data Structures* " is
201
204
materialized by a lowering into a form that will resemble:
202
205
203
- ```
206
+ ``` mlir
204
207
// Run: mlir-opt example2.mlir -allow-unregistered-dialect -convert-linalg-to-loops
205
208
#map0 = affine_map<(d0, d1) -> (d0 * 2 + d1 * 2)>
206
209
@@ -298,25 +301,24 @@ Previous examples already elaborate compute payloads with an unregistered
298
301
function ` "some_compute" ` . The following code snippet shows what the result will
299
302
be when using a concrete operation ` addf ` :
300
303
301
- ```
304
+ ``` mlir
302
305
// File name: example3.mlir
303
- #indexing_maps = [
304
- affine_map<(i, j) -> (i, j)>,
305
- affine_map<(i, j) -> (i, j)>,
306
- affine_map<(i, j) -> (i, j)>
307
- ]
306
+ #map = affine_map<(i, j) -> (i, j)>
307
+
308
308
#attrs = {
309
- args_in = 2,
310
- args_out = 1,
311
- indexing_maps = #indexing_maps,
309
+ indexing_maps = [#map, #map, #map],
312
310
iterator_types = ["parallel", "parallel"]
313
311
}
312
+
314
313
func @example(%A: memref<?x?xf32>, %B: memref<?x?xf32>, %C: memref<?x?xf32>) {
315
- linalg.generic #attrs %A, %B, %C {
316
- ^bb0(%a: f32, %b: f32, %c: f32):
317
- %d = addf %a, %b : f32
318
- linalg.yield %d : f32
319
- }: memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
314
+ linalg.generic #attrs
315
+ ins(%A, %B: memref<?x?xf32>, memref<?x?xf32>)
316
+ outs(%C: memref<?x?xf32>) {
317
+ ^bb0(%a: f32, %b: f32, %c: f32):
318
+ %d = addf %a, %b : f32
319
+ linalg.yield %d : f32
320
+ }
321
+
320
322
return
321
323
}
322
324
```
@@ -327,25 +329,20 @@ stores the result into another one (`%C`).
327
329
The property "* The Compute Payload is Specified With a Region* " is materialized
328
330
by a lowering into a form that will resemble:
329
331
330
- ```
331
- // Run: mlir-opt example3.mlir -convert-linalg-to-loops
332
- #indexing_maps = [
333
- affine_map<(i, j) -> (i, j)>,
334
- affine_map<(i, j) -> (i, j)>,
335
- affine_map<(i, j) -> (i, j)>
336
- ]
337
- #attrs = {
338
- args_in = 2,
339
- args_out = 1,
340
- indexing_maps = #indexing_maps,
341
- iterator_types = ["parallel", "parallel"]
342
- }
343
- func @example(%A: memref<?x?xf32>, %B: memref<?x?xf32>, %C: memref<?x?xf32>) {
344
- linalg.generic #attrs %A, %B, %C {
345
- ^bb0(%a: f32, %b: f32, %c: f32):
346
- %d = addf %a, %b : f32
347
- linalg.yield %d : f32
348
- }: memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
332
+ ``` mlir
333
+ func @example(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>, %arg2: memref<?x?xf32>) {
334
+ %c0 = constant 0 : index
335
+ %c1 = constant 1 : index
336
+ %0 = dim %arg0, %c0 : memref<?x?xf32>
337
+ %1 = dim %arg0, %c1 : memref<?x?xf32>
338
+ scf.for %arg3 = %c0 to %0 step %c1 {
339
+ scf.for %arg4 = %c0 to %1 step %c1 {
340
+ %2 = load %arg0[%arg3, %arg4] : memref<?x?xf32>
341
+ %3 = load %arg1[%arg3, %arg4] : memref<?x?xf32>
342
+ %4 = addf %2, %3 : f32
343
+ store %4, %arg2[%arg3, %arg4] : memref<?x?xf32>
344
+ }
345
+ }
349
346
return
350
347
}
351
348
```
@@ -372,34 +369,36 @@ Consider the following example that adds an additional attribute
372
369
` library_call="pointwise_add" ` that specifies the name of an external library
373
370
call we intend to use:
374
371
375
- ```
372
+ ``` mlir
376
373
// File name: example4.mlir
377
374
#indexing_maps = [
378
375
affine_map<(i, j) -> (i, j)>,
379
376
affine_map<(i, j) -> (i, j)>,
380
377
affine_map<(i, j) -> (i, j)>
381
378
]
379
+
382
380
#attrs = {
383
- args_in = 2,
384
- args_out = 1,
385
381
indexing_maps = #indexing_maps,
386
382
iterator_types = ["parallel", "parallel"],
387
383
library_call = "pointwise_add"
388
384
}
385
+
389
386
func @example(%A: memref<?x?xf32>, %B: memref<?x?xf32>, %C: memref<?x?xf32>) {
390
- linalg.generic #attrs %A, %B, %C {
387
+ linalg.generic #attrs
388
+ ins(%A, %B: memref<?x?xf32>, memref<?x?xf32>)
389
+ outs(%C: memref<?x?xf32>) {
391
390
^bb0(%a: f32, %b: f32, %c: f32):
392
391
%d = addf %a, %b : f32
393
392
linalg.yield %d : f32
394
- }: memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
393
+ }
395
394
return
396
395
}
397
396
```
398
397
399
398
The property "* Map To an External Library Call* " is materialized by a lowering
400
399
into a form that will resemble:
401
400
402
- ```
401
+ ``` mlir
403
402
// Run: mlir-opt example4.mlir -convert-linalg-to-std
404
403
// Note that we lower the Linalg dialect directly to the Standard dialect.
405
404
// See this doc: https://mlir.llvm.org/docs/Dialects/Standard/
@@ -418,7 +417,7 @@ func @pointwise_add(memref<?x?xf32, #map0>, memref<?x?xf32, #map0>, memref<?x?xf
418
417
419
418
Which, after lowering to LLVM resembles:
420
419
421
- ```
420
+ ``` mlir
422
421
// Run: mlir-opt example4.mlir -convert-linalg-to-std | mlir-opt -convert-std-to-llvm
423
422
// Some generated code are omitted here.
424
423
func @example(%arg0: !llvm<"float*">, ...) {
0 commit comments