read the source · mlir-linalg/01_indexing_maps.mlir
#id2 = affine_map<(i, j) -> (i, j)>
#transp = affine_map<(i, j) -> (j, i)>
#row = affine_map<(i, j) -> (i)>
#col = affine_map<(i, j) -> (j)>
#mA = affine_map<(m, n, k) -> (m, k)>
#mB = affine_map<(m, n, k) -> (k, n)>
#mC = affine_map<(m, n, k) -> (m, n)>
// (1) elementwise add: every map is identity, every loop parallel
func.func @add(%a: tensor<2x3xf32>, %b: tensor<2x3xf32>) -> tensor<2x3xf32> {
%e = tensor.empty() : tensor<2x3xf32>
%r = linalg.generic {indexing_maps = [#id2, #id2, #id2], iterator_types = ["parallel", "parallel"]}
ins(%a, %b : tensor<2x3xf32>, tensor<2x3xf32>) outs(%e : tensor<2x3xf32>) {
^bb0(%x: f32, %y: f32, %o: f32):
%s = arith.addf %x, %y : f32
linalg.yield %s : f32
} -> tensor<2x3xf32>
return %r : tensor<2x3xf32>
}
// (2) transpose: the INPUT map is permuted; loop space is the output's shape
func.func @transpose(%a: tensor<2x3xf32>) -> tensor<3x2xf32> {
%e = tensor.empty() : tensor<3x2xf32>
%r = linalg.generic {indexing_maps = [#transp, #id2], iterator_types = ["parallel", "parallel"]}
ins(%a : tensor<2x3xf32>) outs(%e : tensor<3x2xf32>) {
^bb0(%x: f32, %o: f32):
linalg.yield %x : f32
} -> tensor<3x2xf32>
return %r : tensor<3x2xf32>
}
// (3) row sum: j is a REDUCTION dim, the output map drops it
func.func @rowsum(%a: tensor<2x3xf32>) -> tensor<2xf32> {
%z = arith.constant 0.0 : f32
%e = tensor.empty() : tensor<2xf32>
%init = linalg.fill ins(%z : f32) outs(%e : tensor<2xf32>) -> tensor<2xf32>
%r = linalg.generic {indexing_maps = [#id2, #row], iterator_types = ["parallel", "reduction"]}
ins(%a : tensor<2x3xf32>) outs(%init : tensor<2xf32>) {
^bb0(%x: f32, %acc: f32):
%s = arith.addf %acc, %x : f32
linalg.yield %s : f32
} -> tensor<2xf32>
return %r : tensor<2xf32>
}
// (4) bias add = BROADCAST: the bias map drops i
func.func @bias(%a: tensor<2x3xf32>, %b: tensor<3xf32>) -> tensor<2x3xf32> {
%e = tensor.empty() : tensor<2x3xf32>
%r = linalg.generic {indexing_maps = [#id2, #col, #id2], iterator_types = ["parallel", "parallel"]}
ins(%a, %b : tensor<2x3xf32>, tensor<3xf32>) outs(%e : tensor<2x3xf32>) {
^bb0(%x: f32, %y: f32, %o: f32):
%s = arith.addf %x, %y : f32
linalg.yield %s : f32
} -> tensor<2x3xf32>
return %r : tensor<2x3xf32>
}
// (5) matmul written as a generic: 3 loops (m, n parallel; k reduction)
func.func @matmul_generic(%a: tensor<2x3xf32>, %b: tensor<3x2xf32>) -> tensor<2x2xf32> {
%z = arith.constant 0.0 : f32
%e = tensor.empty() : tensor<2x2xf32>
%init = linalg.fill ins(%z : f32) outs(%e : tensor<2x2xf32>) -> tensor<2x2xf32>
%r = linalg.generic {indexing_maps = [#mA, #mB, #mC], iterator_types = ["parallel", "parallel", "reduction"]}
ins(%a, %b : tensor<2x3xf32>, tensor<3x2xf32>) outs(%init : tensor<2x2xf32>) {
^bb0(%x: f32, %y: f32, %acc: f32):
%m = arith.mulf %x, %y : f32
%s = arith.addf %acc, %m : f32
linalg.yield %s : f32
} -> tensor<2x2xf32>
return %r : tensor<2x2xf32>
}
func.func private @printMemrefF32(tensor<*xf32>)
func.func @main() {
%a = arith.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf32>
%b = arith.constant dense<[10.0, 20.0, 30.0]> : tensor<3xf32>
%r1 = call @add(%a, %a) : (tensor<2x3xf32>, tensor<2x3xf32>) -> tensor<2x3xf32>
%r2 = call @transpose(%a) : (tensor<2x3xf32>) -> tensor<3x2xf32>
%r3 = call @rowsum(%a) : (tensor<2x3xf32>) -> tensor<2xf32>
%r4 = call @bias(%a, %b) : (tensor<2x3xf32>, tensor<3xf32>) -> tensor<2x3xf32>
%r5 = call @matmul_generic(%a, %r2) : (tensor<2x3xf32>, tensor<3x2xf32>) -> tensor<2x2xf32>
%u1 = tensor.cast %r1 : tensor<2x3xf32> to tensor<*xf32>
%u2 = tensor.cast %r2 : tensor<3x2xf32> to tensor<*xf32>
%u3 = tensor.cast %r3 : tensor<2xf32> to tensor<*xf32>
%u4 = tensor.cast %r4 : tensor<2x3xf32> to tensor<*xf32>
%u5 = tensor.cast %r5 : tensor<2x2xf32> to tensor<*xf32>
call @printMemrefF32(%u1) : (tensor<*xf32>) -> ()
call @printMemrefF32(%u2) : (tensor<*xf32>) -> ()
call @printMemrefF32(%u3) : (tensor<*xf32>) -> ()
call @printMemrefF32(%u4) : (tensor<*xf32>) -> ()
call @printMemrefF32(%u5) : (tensor<*xf32>) -> ()
return
}