diff --git a/mlir/docs/Dialects/Linalg.md b/mlir/docs/Dialects/Linalg.md --- a/mlir/docs/Dialects/Linalg.md +++ b/mlir/docs/Dialects/Linalg.md @@ -94,22 +94,24 @@ affine_map<(m) -> (m)>, affine_map<(m) -> (m)> ] + #attrs = { - args_in = 1, - args_out = 1, indexing_maps = #accesses, iterator_types = ["parallel"] } + // memory layouts #identity = affine_map<(d0) -> (d0)> func @example(%A: memref, %B: memref, offset: 1, strides: [2]>) { - linalg.generic #attrs %A, %B { + linalg.generic #attrs + ins(%A: memref) + outs(%B: memref, offset: 1, strides: [2]>) { ^bb0(%a: f32, %b: vector<4xf32>): %c = "some_compute"(%a, %b): (f32, vector<4xf32>) -> (vector<4xf32>) linalg.yield %c: vector<4xf32> - } : memref, memref, offset: 1, strides: [2]> + } return } ``` @@ -173,26 +175,27 @@ `memref` is a 2-strided one on both of its dimensions, and the second `memref` uses an identity layout. -``` +```mlir // File name: example2.mlir #indexing_maps = [ affine_map<(i, j) -> (j, i)>, affine_map<(i, j) -> (j)> ] + #attrs = { - args_in = 1, - args_out = 1, indexing_maps = #indexing_maps, iterator_types = ["parallel", "parallel"] } func @example(%A: memref<8x?xf32, offset: 0, strides: [2, 2]>, %B: memref>) { - linalg.generic #attrs %A, %B { + linalg.generic #attrs + ins(%A: memref<8x?xf32, offset: 0, strides: [2, 2]>) + outs(%B: memref>) { ^bb0(%a: f32, %b: vector<4xf32>): %c = "some_compute"(%a, %b): (f32, vector<4xf32>) -> (vector<4xf32>) linalg.yield %c: vector<4xf32> - }: memref<8x?xf32 , offset: 0, strides: [2, 2]>, memref> + } return } ``` @@ -200,7 +203,7 @@ The property "*Reversible Mappings Between Control and Data Structures*" is materialized by a lowering into a form that will resemble: -``` +```mlir // Run: mlir-opt example2.mlir -allow-unregistered-dialect -convert-linalg-to-loops #map0 = affine_map<(d0, d1) -> (d0 * 2 + d1 * 2)> @@ -298,25 +301,24 @@ function `"some_compute"`. The following code snippet shows what the result will be when using a concrete operation `addf`: -``` +```mlir // File name: example3.mlir -#indexing_maps = [ - affine_map<(i, j) -> (i, j)>, - affine_map<(i, j) -> (i, j)>, - affine_map<(i, j) -> (i, j)> -] +#map = affine_map<(i, j) -> (i, j)> + #attrs = { - args_in = 2, - args_out = 1, - indexing_maps = #indexing_maps, + indexing_maps = [#map, #map, #map], iterator_types = ["parallel", "parallel"] } + func @example(%A: memref, %B: memref, %C: memref) { - linalg.generic #attrs %A, %B, %C { - ^bb0(%a: f32, %b: f32, %c: f32): - %d = addf %a, %b : f32 - linalg.yield %d : f32 - }: memref, memref, memref + linalg.generic #attrs + ins(%A, %B: memref, memref) + outs(%C: memref) { + ^bb0(%a: f32, %b: f32, %c: f32): + %d = addf %a, %b : f32 + linalg.yield %d : f32 + } + return } ``` @@ -327,25 +329,20 @@ The property "*The Compute Payload is Specified With a Region*" is materialized by a lowering into a form that will resemble: -``` -// Run: mlir-opt example3.mlir -convert-linalg-to-loops -#indexing_maps = [ - affine_map<(i, j) -> (i, j)>, - affine_map<(i, j) -> (i, j)>, - affine_map<(i, j) -> (i, j)> -] -#attrs = { - args_in = 2, - args_out = 1, - indexing_maps = #indexing_maps, - iterator_types = ["parallel", "parallel"] -} -func @example(%A: memref, %B: memref, %C: memref) { - linalg.generic #attrs %A, %B, %C { - ^bb0(%a: f32, %b: f32, %c: f32): - %d = addf %a, %b : f32 - linalg.yield %d : f32 - }: memref, memref, memref +```mlir +func @example(%arg0: memref, %arg1: memref, %arg2: memref) { + %c0 = constant 0 : index + %c1 = constant 1 : index + %0 = dim %arg0, %c0 : memref + %1 = dim %arg0, %c1 : memref + scf.for %arg3 = %c0 to %0 step %c1 { + scf.for %arg4 = %c0 to %1 step %c1 { + %2 = load %arg0[%arg3, %arg4] : memref + %3 = load %arg1[%arg3, %arg4] : memref + %4 = addf %2, %3 : f32 + store %4, %arg2[%arg3, %arg4] : memref + } + } return } ``` @@ -372,26 +369,28 @@ `library_call="pointwise_add"` that specifies the name of an external library call we intend to use: -``` +```mlir // File name: example4.mlir #indexing_maps = [ affine_map<(i, j) -> (i, j)>, affine_map<(i, j) -> (i, j)>, affine_map<(i, j) -> (i, j)> ] + #attrs = { - args_in = 2, - args_out = 1, indexing_maps = #indexing_maps, iterator_types = ["parallel", "parallel"], library_call = "pointwise_add" } + func @example(%A: memref, %B: memref, %C: memref) { - linalg.generic #attrs %A, %B, %C { + linalg.generic #attrs + ins(%A, %B: memref, memref) + outs(%C: memref) { ^bb0(%a: f32, %b: f32, %c: f32): %d = addf %a, %b : f32 linalg.yield %d : f32 - }: memref, memref, memref + } return } ``` @@ -399,7 +398,7 @@ The property "*Map To an External Library Call*" is materialized by a lowering into a form that will resemble: -``` +```mlir // Run: mlir-opt example4.mlir -convert-linalg-to-std // Note that we lower the Linalg dialect directly to the Standard dialect. // See this doc: https://mlir.llvm.org/docs/Dialects/Standard/ @@ -418,7 +417,7 @@ Which, after lowering to LLVM resembles: -``` +```mlir // Run: mlir-opt example4.mlir -convert-linalg-to-std | mlir-opt -convert-std-to-llvm // Some generated code are omitted here. func @example(%arg0: !llvm<"float*">, ...) {