blob: 5bbb7ee51f6f7bc9f98d16ee910b76eed93d407c [file]
// RUN: iree-opt -pass-pipeline="hal.executable(hal.executable.variant(iree-llvmcpu-lower-executable-target{use-lowering-pipeline='builtin.func(iree-llvmcpu-vectorization)'}))" -split-input-file %s | IreeFileCheck %s
// RUN: iree-opt -pass-pipeline="hal.executable(hal.executable.variant(iree-llvmcpu-lower-executable-target{use-lowering-pipeline='builtin.func(iree-llvmcpu-vectorization{promote-workgroup-to-full-tiles}),cse'}))" -split-input-file %s | IreeFileCheck %s -check-prefix=CHECK-PROMOTED
#config = {nativeVectorSize = [4, 4, 4], tileSizes = [[64, 64], [32, 32, 32], [4, 4, 4]]}
hal.executable @dynamic_matmul attributes {sym_visibility = "private"} {
hal.interface @io {
hal.interface.binding @arg0, set=0, binding=0, type="StorageBuffer", access="Read"
hal.interface.binding @arg1, set=0, binding=1, type="StorageBuffer", access="Read"
hal.interface.binding @ret0, set=0, binding=2, type="StorageBuffer", access="Write|Discard"
}
hal.executable.variant @llvm, target = #hal.executable.target<"llvm", "embedded-elf-x86_64"> {
hal.executable.entry_point @matmul_128x128x128 attributes {
interface = @io,
ordinal = 0 : index
}
builtin.module {
func @matmul_128x128x128() {
%c0 = constant 0 : index
%c128 = constant 128 : index
%0 = hal.interface.binding.subspan @io::@arg0[%c0] : memref<128x128xf32>
%1 = hal.interface.binding.subspan @io::@arg1[%c0] : memref<128x128xf32>
%2 = hal.interface.binding.subspan @io::@ret0[%c0] : memref<128x128xf32>
%workgroup_id_x = hal.interface.workgroup.id[0] : index
%workgroup_count_x = hal.interface.workgroup.count[0] : index
%workgroup_id_y = hal.interface.workgroup.id[1] : index
%workgroup_count_y = hal.interface.workgroup.count[1] : index
%3 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_id_y]
%4 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_count_y]
scf.for %arg0 = %3 to %c128 step %4 {
%5 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_id_x]
%6 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_count_x]
scf.for %arg1 = %5 to %c128 step %6 {
%7 = memref.subview %0[%arg0, 0] [64, 128] [1, 1] : memref<128x128xf32> to memref<64x128xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
%8 = memref.subview %1[0, %arg1] [128, 64] [1, 1] : memref<128x128xf32> to memref<128x64xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
%9 = memref.subview %2[%arg0, %arg1] [64, 64] [1, 1] : memref<128x128xf32> to memref<64x64xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
linalg.matmul {__internal_linalg_transform__ = "workgroup", lowering.config = #config} ins(%7, %8 : memref<64x128xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>, memref<128x64xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>) outs(%9 : memref<64x64xf32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>)
}
}
return
}
}
}
}
// CHECK-LABEL: func @matmul_128x128x128
// CHECK-DAG: %[[ARG0:.+]] = hal.interface.binding.subspan @io::@arg0
// CHECK-DAG: %[[ARG1:.+]] = hal.interface.binding.subspan @io::@arg1
// CHECK-DAG: %[[RET0:.+]] = hal.interface.binding.subspan @io::@ret0
// CHECK-DAG: %[[START:.+]] = constant 0 : index
// CHECK-DAG: %[[WORGKROUP_SIZE:.+]] = constant 64
// CHECK-DAG: %[[VECTOR_SIZE:.+]] = constant 4
// CHECK-DAG: %[[L1_SIZE:.+]] = constant 32
// CHECK-DAG: %[[KDIM_SIZE:.+]] = constant 128
// CHECK: scf.for
// CHECK: scf.for
// CHECK: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[KDIM_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK: %[[VEC_C_0:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_1:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_2:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_3:.+]] = vector.transfer_read %[[RET0]]
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]]
// CHECK: %[[VEC_A_0:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_1:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_2:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_3:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_B_0:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_b_1:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_B_2:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_B_3:.+]] = vector.transfer_read %[[ARG1]]
// CHECK-PROMOTED: #[[MAP0:.+]] = affine_map<()[s0] -> (s0 * 64)>
// CHECK-PROMOTED: #[[MAP1:.+]] = affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>
// CHECK-PROMOTED: func @matmul_128x128x128
// CHECK-PROMOTED-DAG: %[[KDIM_SIZE:.+]] = constant 128 : index
// CHECK-PROMOTED-DAG: %[[WORGKROUP_SIZE:.+]] = constant 64 : index
// CHECK-PROMOTED-DAG: %[[VECTOR_SIZE:.+]] = constant 4 : index
// CHECK-PROMOTED-DAG: %[[L1_SIZE:.+]] = constant 32 : index
// CHECK-PROMOTED-DAG: %[[START:.+]] = constant 0 : index
// CHECK-PROMOTED-DAG: %[[C1:.+]] = constant 1 : index
// CHECK-PROMOTED-DAG: %[[C1:.+]] = constant 2 : index
// CHECK-PROMOTED-DAG: %[[C1:.+]] = constant 3 : index
// CHECK-PROMOTED-DAG: %[[C_PROMOTED_TILE:.+]] = memref.alloca() : memref<64x64xf32>
// CHECK-PROMOTED-DAG: %[[B_PROMOTED_TILE:.+]] = memref.alloca() : memref<128x64xf32>
// CHECK-PROMOTED-DAG: %[[A_PROMOTED_TILE:.+]] = memref.alloca() : memref<64x128xf32>
// CHECK-PROMOTED-DAG: %[[ARG0:.+]] = hal.interface.binding.subspan @io::@arg0
// CHECK-PROMOTED-DAG: %[[ARG1:.+]] = hal.interface.binding.subspan @io::@arg1
// CHECK-PROMOTED-DAG: %[[RET0:.+]] = hal.interface.binding.subspan @io::@ret0
// CHECK-PROMOTED: scf.for %[[IV0:.+]] =
// CHECK-PROMOTED: scf.for %[[IV1:.+]] =
// CHECK-PROMOTED-DAG: %[[A_TILE:.+]] = memref.subview %[[ARG0]][%[[IV0]], 0] [64, 128]
// CHECK-PROMOTED-DAG: %[[B_TILE:.+]] = memref.subview %[[ARG1]][0, %[[IV1]]] [128, 64]
// CHECK-PROMOTED-DAG: %[[C_TILE:.+]] = memref.subview %[[RET0]][%[[IV0]], %[[IV1]]] [64, 64]
// CHECK-PROMOTED-DAG: %[[A_PROMOTED_TILE_VIEW:.+]] = memref.subview %[[A_PROMOTED_TILE]][0, 0] [64, 128]
// CHECK-PROMOTED_DAG: linalg.fill(%{{.+}}, %[[A_PROMOTED_TILE]])
// CHECK-PROMOTED-DAG: %[[B_PROMOTED_TILE_VIEW:.+]] = memref.subview %[[B_PROMOTED_TILE]][0, 0] [128, 64]
// CHECK-PROMOTED_DAG: linalg.fill(%{{.+}}, %[[B_PROMOTED_TILE]])
// CHECK-PROMOTED-DAG: %[[C_PROMOTED_TILE_VIEW:.+]] = memref.subview %[[C_PROMOTED_TILE]][0, 0] [64, 64]
// CHECK-PROMOTED_DAG: linalg.fill(%{{.+}}, %[[C_PROMOTED_TILE]])
// CHECK-PROMOTED: linalg.copy(%[[A_TILE]], %[[A_PROMOTED_TILE_VIEW]])
// CHECK-PROMOTED: linalg.copy(%[[B_TILE]], %[[B_PROMOTED_TILE_VIEW]])
// CHECK-PROMOTED: linalg.copy(%[[C_TILE]], %[[C_PROMOTED_TILE_VIEW]])
// CHECK-PROMOTED: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK-PROMOTED: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK-PROMOTED: scf.for {{.*}} = %[[START]] to %[[KDIM_SIZE]] step %[[L1_SIZE]] {
// CHECK-PROMOTED: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK-PROMOTED: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK-PROMOTED: %[[VEC_C_0:.+]] = vector.transfer_read %[[C_PROMOTED_TILE]]
// CHECK-PROMOTED: %[[VEC_C_1:.+]] = vector.transfer_read %[[C_PROMOTED_TILE]]
// CHECK-PROMOTED: %[[VEC_C_2:.+]] = vector.transfer_read %[[C_PROMOTED_TILE]]
// CHECK-PROMOTED: %[[VEC_C_3:.+]] = vector.transfer_read %[[C_PROMOTED_TILE]]
// -----
#config = {nativeVectorSize = [4, 4, 4], tileSizes = [[64, 64], [32, 32, 32], [4, 4, 4]]}
hal.executable @matmul_i8_i8_i32 attributes {sym_visibility = "private"} {
hal.interface @io {
hal.interface.binding @arg0, set=0, binding=0, type="StorageBuffer", access="Read"
hal.interface.binding @arg1, set=0, binding=1, type="StorageBuffer", access="Read"
hal.interface.binding @ret0, set=0, binding=2, type="StorageBuffer", access="Write|Discard"
}
hal.executable.variant @llvm, target = #hal.executable.target<"llvm", "embedded-elf-x86_64"> {
hal.executable.entry_point @matmul_i8_i8_i32_128x128x128 attributes {
interface = @io,
ordinal = 0 : index
}
builtin.module {
func @matmul_i8_i8_i32_128x128x128() {
%c0 = constant 0 : index
%c128 = constant 128 : index
%0 = hal.interface.binding.subspan @io::@arg0[%c0] : memref<128x128xi8>
%1 = hal.interface.binding.subspan @io::@arg1[%c0] : memref<128x128xi8>
%2 = hal.interface.binding.subspan @io::@ret0[%c0] : memref<128x128xi32>
%workgroup_id_x = hal.interface.workgroup.id[0] : index
%workgroup_count_x = hal.interface.workgroup.count[0] : index
%workgroup_id_y = hal.interface.workgroup.id[1] : index
%workgroup_count_y = hal.interface.workgroup.count[1] : index
%3 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_id_y]
%4 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_count_y]
scf.for %arg0 = %3 to %c128 step %4 {
%5 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_id_x]
%6 = affine.apply affine_map<()[s0] -> (s0 * 64)>()[%workgroup_count_x]
scf.for %arg1 = %5 to %c128 step %6 {
%7 = memref.subview %0[%arg0, 0] [64, 128] [1, 1] : memref<128x128xi8> to memref<64x128xi8, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
%8 = memref.subview %1[0, %arg1] [128, 64] [1, 1] : memref<128x128xi8> to memref<128x64xi8, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
%9 = memref.subview %2[%arg0, %arg1] [64, 64] [1, 1] : memref<128x128xi32> to memref<64x64xi32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>
linalg.matmul_i8_i8_i32 {__internal_linalg_transform__ = "workgroup", lowering.config = #config} ins(%7, %8 : memref<64x128xi8, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>, memref<128x64xi8, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>) outs(%9 : memref<64x64xi32, affine_map<(d0, d1)[s0] -> (d0 * 128 + s0 + d1)>>)
}
}
return
}
}
}
}
// CHECK-LABEL: func @matmul_i8_i8_i32_128x128x128
// CHECK-DAG: %[[ARG0:.+]] = hal.interface.binding.subspan @io::@arg0
// CHECK-DAG: %[[ARG1:.+]] = hal.interface.binding.subspan @io::@arg1
// CHECK-DAG: %[[RET0:.+]] = hal.interface.binding.subspan @io::@ret0
// CHECK-DAG: %[[START:.+]] = constant 0 : index
// CHECK-DAG: %[[WORGKROUP_SIZE:.+]] = constant 64
// CHECK-DAG: %[[VECTOR_SIZE:.+]] = constant 4
// CHECK-DAG: %[[L1_SIZE:.+]] = constant 32
// CHECK-DAG: %[[KDIM_SIZE:.+]] = constant 128
// CHECK: scf.for
// CHECK: scf.for
// CHECK: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[WORGKROUP_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[KDIM_SIZE]] step %[[L1_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]] {
// CHECK: %[[VEC_C_0:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_1:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_2:.+]] = vector.transfer_read %[[RET0]]
// CHECK: %[[VEC_C_3:.+]] = vector.transfer_read %[[RET0]]
// CHECK: scf.for {{.*}} = %[[START]] to %[[L1_SIZE]] step %[[VECTOR_SIZE]]
// CHECK: %[[VEC_A_0:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_1:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_2:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_A_3:.+]] = vector.transfer_read %[[ARG0]]
// CHECK: %[[VEC_B_0:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_b_1:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_B_2:.+]] = vector.transfer_read %[[ARG1]]
// CHECK: %[[VEC_B_3:.+]] = vector.transfer_read %[[ARG1]]