2019-10-19 05:09:42 +08:00
// RUN: mlir-opt %s -convert-linalg-to-llvm | FileCheck %s
// RUN: mlir-opt %s -linalg-lower-to-loops -convert-linalg-to-llvm | FileCheck %s --check-prefix=LLVM-LOOPS
2019-10-01 20:22:54 +08:00
2019-05-03 02:36:52 +08:00
func @range ( %arg0 : index ) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%R = linalg. range %c0 : %arg0 : %c1 : ! linalg. range
return
}
2019-07-10 01:40:29 +08:00
// CHECK-LABEL: func @range(%{{.*}}: !llvm.i64) {
2019-09-04 00:10:24 +08:00
// CHECK: llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK-NEXT: llvm.mlir.undef : !llvm<"{ i64, i64, i64 }">
2019-08-20 01:21:15 +08:00
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ i64, i64, i64 }">
2019-05-03 02:36:52 +08:00
2019-11-07 22:32:39 +08:00
func @slice ( %arg0 : memref < ?x f32 , offset: ? , strides: [ 1 ] > , %arg1 : ! linalg. range) {
%1 = linalg. slice %arg0 [ %arg1 ] : memref < ?x f32 , offset: ? , strides: [ 1 ] > , ! linalg. range, memref < ?x f32 , offset: ? , strides: [ 1 ] >
2019-05-03 02:36:52 +08:00
return
}
2019-08-20 01:21:15 +08:00
// CHECK-LABEL: func @slice
2019-09-06 23:30:54 +08:00
// insert data ptr for slice op
2019-11-12 23:06:18 +08:00
// CHECK: llvm.extractvalue %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[2] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
2019-08-20 01:21:15 +08:00
// CHECK-NEXT: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64
// CHECK-NEXT: llvm.add %{{.*}}, %{{.*}} : !llvm.i64
2019-08-23 03:46:30 +08:00
// insert offset
2019-11-12 23:06:18 +08:00
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
2019-10-01 20:22:54 +08:00
// CHECK-NEXT: llvm.mlir.constant(0 : index)
2019-08-20 01:21:15 +08:00
// CHECK-NEXT: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[2] : !llvm<"{ i64, i64, i64 }">
2019-08-23 03:46:30 +08:00
// get size[0] from parent view
2019-11-12 23:06:18 +08:00
// CHECK-NEXT: llvm.extractvalue %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
2019-08-23 03:46:30 +08:00
// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64
// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64
// compute size[0] bounded by parent view's size[0]
2019-08-20 01:21:15 +08:00
// CHECK-NEXT: llvm.sub %{{.*}}, %{{.*}} : !llvm.i64
2019-08-23 03:46:30 +08:00
// bound below by 0
// CHECK-NEXT: llvm.icmp "slt" %{{.*}}, %{{.*}} : !llvm.i64
// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64
// compute stride[0] using bounded size
2019-08-20 01:21:15 +08:00
// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64
2019-08-23 03:46:30 +08:00
// insert size and stride
2019-11-12 23:06:18 +08:00
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }">
2019-05-03 02:36:52 +08:00
2019-10-04 03:33:47 +08:00
func @dot ( %arg0 : memref < ?x f32 , offset: ? , strides: [ 1 ] > , %arg1 : memref < ?x f32 , offset: ? , strides: [ 1 ] > , %arg2 : memref < f32 > ) {
linalg. dot( %arg0 , %arg1 , %arg2 ) : memref < ?x f32 , offset: ? , strides: [ 1 ] > , memref < ?x f32 , offset: ? , strides: [ 1 ] > , memref < f32 >
2019-05-03 02:36:52 +08:00
return
}
2019-11-12 23:06:18 +08:00
// CHECK-LABEL: func @dot(%{{.*}}: !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }*">, %{{.*}}: !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }*">, %{{.*}}: !llvm<"{ float*, float*, i64 }*">) {
2019-09-06 23:30:54 +08:00
// CHECK-COUNT-3: llvm.mlir.constant(1 : index){{.*[[:space:]].*}}llvm.alloca{{.*[[:space:]].*}}llvm.store
2019-11-12 23:06:18 +08:00
// CHECK-NEXT: llvm.call @linalg_dot_viewsxf32_viewsxf32_viewf32(%{{.*}}, %{{.*}}, %{{.*}}) : (!llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, float*, i64 }*">) -> ()
2019-05-14 05:59:55 +08:00
2019-11-14 04:09:40 +08:00
func @slice_with_range_and_index ( %arg0 : memref < ?x?x f64 , offset: ? , strides: [ ? , 1 ] > ) {
2019-08-14 00:20:06 +08:00
%c0 = constant 0 : index
%c1 = constant 1 : index
%R = linalg. range %c0 : %c1 : %c1 : ! linalg. range
loop. for %i0 = %c0 to %c1 step %c1 {
2019-10-04 03:33:47 +08:00
%1 = linalg. slice %arg0 [ %i0 , %R ] : memref < ?x?x f64 , offset: ? , strides: [ ? , 1 ] > , index , ! linalg. range, memref < ?x f64 , offset: ? , strides: [ 1 ] >
2019-08-14 00:20:06 +08:00
}
return
}
2019-11-14 04:09:40 +08:00
// CHECK-LABEL: func @slice_with_range_and_index
2019-09-06 23:30:54 +08:00
// loop-body.
2019-11-12 23:06:18 +08:00
// CHECK: llvm.mlir.undef : !llvm<"{ double*, double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[4, 0] : !llvm<"{ double*, double*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[4, 1] : !llvm<"{ double*, double*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[2] : !llvm<"{ double*, double*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ double*, double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}[2] : !llvm<"{ double*, double*, i64, [1 x i64], [1 x i64] }">
2019-08-14 00:20:06 +08:00
// CHECK: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i64, i64, i64 }">
2019-11-12 23:06:18 +08:00
// CHECK: llvm.insertvalue %{{.*}}[3, 0] : !llvm<"{ double*, double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}[4, 0] : !llvm<"{ double*, double*, i64, [1 x i64], [1 x i64] }">
2019-08-24 02:08:59 +08:00
2019-10-04 03:33:47 +08:00
func @copy ( %arg0 : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > , %arg1 : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > ) {
linalg. copy( %arg0 , %arg1 ) : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > , memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] >
2019-08-24 02:08:59 +08:00
return
}
// CHECK-LABEL: func @copy
2019-11-12 23:06:18 +08:00
// CHECK: llvm.call @linalg_copy_viewsxsxsxf32_viewsxsxsxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }*">) -> ()
2019-08-24 08:28:51 +08:00
2019-10-04 03:33:47 +08:00
func @transpose ( %arg0 : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > ) {
%0 = linalg. transpose %arg0 ( i, j, k) -> ( k, i, j) : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] >
2019-08-24 08:28:51 +08:00
return
}
// CHECK-LABEL: func @transpose
2019-11-12 23:06:18 +08:00
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
2019-08-24 08:44:55 +08:00
2019-10-04 03:33:47 +08:00
func @copy_transpose ( %arg0 : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > , %arg1 : memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > ) {
2019-08-24 08:44:55 +08:00
linalg. copy( %arg0 , %arg1 ) { inputPermutation = ( i, j, k) -> ( i, k, j) ,
outputPermutation = ( i, j, k) -> ( k, j, i) }
2019-10-04 03:33:47 +08:00
: memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] > , memref < ?x?x?x f32 , offset: ? , strides: [ ? , ? , 1 ] >
2019-08-24 08:44:55 +08:00
return
}
// CHECK-LABEL: func @copy
// Tranpose input
2019-11-12 23:06:18 +08:00
// CHECK: llvm.insertvalue {{.*}}[0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
2019-08-24 08:44:55 +08:00
// Transpose output
2019-11-12 23:06:18 +08:00
// CHECK: llvm.insertvalue {{.*}}[0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.extractvalue {{.*}}[3, 2] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }">
2019-09-06 23:30:54 +08:00
// Call external copy after promoting input and output structs to pointers
// CHECK-COUNT-2: llvm.mlir.constant(1 : index){{.*[[:space:]].*}}llvm.alloca{{.*[[:space:]].*}}llvm.store
2019-11-12 23:06:18 +08:00
// CHECK: llvm.call @linalg_copy_viewsxsxsxf32_viewsxsxsxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, float*, i64, [3 x i64], [3 x i64] }*">) -> ()
2019-10-14 22:48:29 +08:00
#matmul_accesses = [
( m, n, k) -> ( m, k) ,
( m, n, k) -> ( k, n) ,
( m, n, k) -> ( m, n)
]
#matmul_trait = {
n_views = [ 2 , 1 ] ,
n_loop_types = [ 2 , 1 , 0 ] ,
indexing_maps = #matmul_accesses ,
library_call = "some_external_function_name_for_vector_outerproduct_matmul"
}
! vector_type_A = type vector < 4x f32 >
! vector_type_B = type vector < 4x f32 >
! vector_type_C = type vector < 4x4x f32 >
! matrix_type_A = type memref < ?x?x ! vector _type_A>
! matrix_type_B = type memref < ?x?x ! vector _type_B>
! matrix_type_C = type memref < ?x?x ! vector _type_C>
func @matmul_vec_impl ( %A : ! matrix_type_A, %B : ! matrix_type_B, %C : ! matrix_type_C) {
linalg. generic #matmul_trait %A , %B , %C {
^bb0 ( %a : ! vector _type_A, %b : ! vector _type_B, %c : ! vector _type_C) :
%d = vector . outerproduct %a , %b , %c : ! vector _type_A, ! vector _type_B
linalg. yield %d : ! vector _type_C
} : ! matrix_type_A, ! matrix_type_B, ! matrix_type_C
return
}
// CHECK-LABEL: func @matmul_vec_impl(
2019-11-12 23:06:18 +08:00
// CHECK: llvm.call @some_external_function_name_for_vector_outerproduct_matmul(%{{.*}}) : (!llvm<"{ <4 x float>*, <4 x float>*, i64, [2 x i64], [2 x i64] }*">, !llvm<"{ <4 x float>*, <4 x float>*, i64, [2 x i64], [2 x i64] }*">, !llvm<"{ [4 x <4 x float>]*, [4 x <4 x float>]*, i64, [2 x i64], [2 x i64] }*">) -> ()
2019-10-14 22:48:29 +08:00
// LLVM-LOOPS-LABEL: func @matmul_vec_impl(
// LLVM-LOOPS: llvm.shufflevector {{.*}} [0 : i32, 0 : i32, 0 : i32, 0 : i32] : !llvm<"<4 x float>">, !llvm<"<4 x float>">
// LLVM-LOOPS: llvm.shufflevector {{.*}} [1 : i32, 1 : i32, 1 : i32, 1 : i32] : !llvm<"<4 x float>">, !llvm<"<4 x float>">
// LLVM-LOOPS: llvm.shufflevector {{.*}} [2 : i32, 2 : i32, 2 : i32, 2 : i32] : !llvm<"<4 x float>">, !llvm<"<4 x float>">
// LLVM-LOOPS: llvm.shufflevector {{.*}} [3 : i32, 3 : i32, 3 : i32, 3 : i32] : !llvm<"<4 x float>">, !llvm<"<4 x float>">
// LLVM-LOOPS-NEXT: llvm.extractvalue {{.*}}[3] : !llvm<"[4 x <4 x float>]">
// LLVM-LOOPS-NEXT: "llvm.intr.fmuladd"({{.*}}) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
// LLVM-LOOPS-NEXT: llvm.insertvalue {{.*}}, {{.*}}[3] : !llvm<"[4 x <4 x float>]">