From 7485d5a62685cb745ab50e970adb722cb71557ac Mon Sep 17 00:00:00 2001 From: Vidhya Sudhan Loganathan Date: Wed, 4 Jul 2018 09:34:00 +0100 Subject: COMPMID-970 : Remove QS8 / QS16 support Removed fixed point related code. Change-Id: I487acf138dace3b0450e0d72ca7071eaec254566 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/137678 Tested-by: Jenkins Reviewed-by: Anthony Barbier --- .../NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp | 654 +-------------------- 1 file changed, 1 insertion(+), 653 deletions(-) (limited to 'src/core/NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp') diff --git a/src/core/NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp b/src/core/NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp index 69b052a9bd..196398a2de 100644 --- a/src/core/NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp +++ b/src/core/NEON/kernels/NEGEMMMatrixMultiplyKernel.cpp @@ -355,263 +355,6 @@ void vector_matrix_multiply_f32(const ITensor *input0, const ITensor *input1, IT ina, inb, out); } -template -void vector_matrix_multiply_qs8(const ITensor *input0, const ITensor *input1, ITensor *output, const Window &window, const ThreadInfo &info, float alpha) -{ - const auto width_matrix_b = static_cast(output->info()->dimension(0)); - const auto in_b_stride = static_cast(input1->info()->strides_in_bytes()[1] / data_size_from_type(input1->info()->data_type())); - const auto num_elems_vec_a = static_cast(input0->info()->dimension(0)); - const int fixed_point_position = input0->info()->fixed_point_position(); - - // The implementation computes 32 elements per iteration - const int window_start_x = 32 * info.thread_id; - const int window_step_x = 32 * info.num_threads; - // Make sure (window_end_x - window_start_x) is a multiple of window_step_x - const int window_end_x = ceil_to_multiple(width_matrix_b - window_start_x, window_step_x) + window_start_x; - - Window win_out(window); - win_out.set(Window::DimX, Window::Dimension(window_start_x, window_end_x, window_step_x)); - win_out.set(Window::DimY, Window::Dimension(0, 1, 1)); - - Window win_a(window); - win_a.set(Window::DimX, Window::Dimension(0, 0, 0)); - win_a.set(Window::DimY, Window::Dimension(0, 0, 0)); - - Window win_b; - // Don't slice matrix B along the z dimension if matrix B has just 2 dimensions and matrix A more than 2 - // This scenario can happen when the the matrix multiplication is used to perform a convolution operation - if(input1->info()->num_dimensions() >= 3) - { - win_b = window; - } - win_b.set(Window::DimX, Window::Dimension(window_start_x, window_end_x, window_step_x)); - win_b.set(Window::DimY, Window::Dimension(0, 1, 1)); - - Iterator ina(input0, win_a); - Iterator inb(input1, win_b); - Iterator out(output, win_out); - - execute_window_loop(win_out, [&](const Coordinates & id) - { - if(id.x() > width_matrix_b) - { - return; - } - - // Reset accumulators - qint16x8_t acc00_qs16 = vdupq_n_qs16(0); - qint16x8_t acc01_qs16 = vdupq_n_qs16(0); - qint16x8_t acc02_qs16 = vdupq_n_qs16(0); - qint16x8_t acc03_qs16 = vdupq_n_qs16(0); - - auto vec_a = reinterpret_cast(ina.ptr()); - auto matrix_b = reinterpret_cast(inb.ptr()); - - auto vec_a_end_addr = vec_a + num_elems_vec_a; - for(; vec_a <= (vec_a_end_addr - 2);) - { - const qint8x8_t a0 = vld1_dup_qs8(vec_a + 0); - const qint8x8_t a1 = vld1_dup_qs8(vec_a + 1); - - const qint8x8_t b00 = vld1_qs8(matrix_b + 0 + 0 * in_b_stride); - const qint8x8_t b01 = vld1_qs8(matrix_b + 8 + 0 * in_b_stride); - const qint8x8_t b02 = vld1_qs8(matrix_b + 16 + 0 * in_b_stride); - const qint8x8_t b03 = vld1_qs8(matrix_b + 24 + 0 * in_b_stride); - const qint8x8_t b10 = vld1_qs8(matrix_b + 0 + 1 * in_b_stride); - const qint8x8_t b11 = vld1_qs8(matrix_b + 8 + 1 * in_b_stride); - const qint8x8_t b12 = vld1_qs8(matrix_b + 16 + 1 * in_b_stride); - const qint8x8_t b13 = vld1_qs8(matrix_b + 24 + 1 * in_b_stride); - - // First accumulation - acc00_qs16 = vqmlal_qs8(acc00_qs16, b00, a0, fixed_point_position); - acc01_qs16 = vqmlal_qs8(acc01_qs16, b01, a0, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b02, a0, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b03, a0, fixed_point_position); - - // Second accumulation - acc00_qs16 = vqmlal_qs8(acc00_qs16, b10, a1, fixed_point_position); - acc01_qs16 = vqmlal_qs8(acc01_qs16, b11, a1, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b12, a1, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b13, a1, fixed_point_position); - - vec_a += 2; - matrix_b += 2 * in_b_stride; - } - - for(; vec_a < vec_a_end_addr;) - { - const qint8x8_t a0 = vld1_dup_qs8(vec_a); - - const qint8x8_t b00 = vld1_qs8(matrix_b + 0); - const qint8x8_t b01 = vld1_qs8(matrix_b + 8); - const qint8x8_t b02 = vld1_qs8(matrix_b + 16); - const qint8x8_t b03 = vld1_qs8(matrix_b + 24); - - acc00_qs16 = vqmlal_qs8(acc00_qs16, b00, a0, fixed_point_position); - acc01_qs16 = vqmlal_qs8(acc01_qs16, b01, a0, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b02, a0, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b03, a0, fixed_point_position); - - vec_a += 1; - matrix_b += in_b_stride; - } - - // Convert back to qint8x8_t and saturate - qint8x8_t acc00_qs8 = vqmovn_qs16(acc00_qs16); - qint8x8_t acc01_qs8 = vqmovn_qs16(acc01_qs16); - qint8x8_t acc02_qs8 = vqmovn_qs16(acc02_qs16); - qint8x8_t acc03_qs8 = vqmovn_qs16(acc03_qs16); - - // Multiply by the weight of the matrix product (alpha) - if(multiply_alpha) - { - const qint8x8_t alpha_qs8 = vdup_n_qs8(sqcvt_qs8_f32(alpha, fixed_point_position)); - acc00_qs8 = vqmul_qs8(acc00_qs8, alpha_qs8, fixed_point_position); - acc01_qs8 = vqmul_qs8(acc01_qs8, alpha_qs8, fixed_point_position); - acc02_qs8 = vqmul_qs8(acc02_qs8, alpha_qs8, fixed_point_position); - acc03_qs8 = vqmul_qs8(acc03_qs8, alpha_qs8, fixed_point_position); - } - - const auto mtx_out0 = reinterpret_cast(out.ptr()); - - // Store 8x4 output elements - vst1_qs8(mtx_out0 + 0, acc00_qs8); - vst1_qs8(mtx_out0 + 8, acc01_qs8); - vst1_qs8(mtx_out0 + 16, acc02_qs8); - vst1_qs8(mtx_out0 + 24, acc03_qs8); - }, - ina, inb, out); -} - -template -void vector_matrix_multiply_qs16(const ITensor *input0, const ITensor *input1, ITensor *output, const Window &window, const ThreadInfo &info, float alpha) -{ - const auto width_matrix_b = static_cast(output->info()->dimension(0)); - const auto in_b_stride = static_cast(input1->info()->strides_in_bytes()[1] / data_size_from_type(input1->info()->data_type())); - const auto num_elems_vec_a = static_cast(input0->info()->dimension(0)); - const int fixed_point_position = input0->info()->fixed_point_position(); - - // The implementation computes 16 elements per iteration - const int window_start_x = 16 * info.thread_id; - const int window_step_x = 16 * info.num_threads; - // Make sure (window_end_x - window_start_x) is a multiple of window_step_x - const int window_end_x = ceil_to_multiple(width_matrix_b - window_start_x, window_step_x) + window_start_x; - ARM_COMPUTE_ERROR_ON_MSG((window_end_x - window_start_x) % window_step_x, " (window_end_x - window_start_x) must be multiple of window_step_x"); - - Window win_out(window); - win_out.set(Window::DimX, Window::Dimension(window_start_x, window_end_x, window_step_x)); - win_out.set(Window::DimY, Window::Dimension(0, 1, 1)); - - Window win_a(window); - win_a.set(Window::DimX, Window::Dimension(0, 0, 0)); - win_a.set(Window::DimY, Window::Dimension(0, 0, 0)); - - Window win_b; - // Don't slice matrix B along the z dimension if matrix B has just 2 dimensions and matrix A more than 2 - // This scenario can happen when the the matrix multiplication is used to perform a convolution operation - if(input1->info()->num_dimensions() >= 3) - { - win_b = window; - } - win_b.set(Window::DimX, Window::Dimension(window_start_x, window_end_x, window_step_x)); - win_b.set(Window::DimY, Window::Dimension(0, 1, 1)); - - Iterator ina(input0, win_a); - Iterator inb(input1, win_b); - Iterator out(output, win_out); - - execute_window_loop(win_out, [&](const Coordinates & id) - { - if(id.x() > width_matrix_b) - { - return; - } - - // Reset accumulators - qint32x4_t acc00_qs32 = vdupq_n_qs32(0); - qint32x4_t acc01_qs32 = vdupq_n_qs32(0); - qint32x4_t acc02_qs32 = vdupq_n_qs32(0); - qint32x4_t acc03_qs32 = vdupq_n_qs32(0); - - auto vec_a = reinterpret_cast(ina.ptr()); - auto matrix_b = reinterpret_cast(inb.ptr()); - - auto vec_a_end_addr = vec_a + num_elems_vec_a; - for(; vec_a <= (vec_a_end_addr - 2);) - { - const qint16x4_t a0 = vld1_dup_qs16(vec_a + 0); - const qint16x4_t a1 = vld1_dup_qs16(vec_a + 1); - - const qint16x4_t b00 = vld1_qs16(matrix_b + 0 + 0 * in_b_stride); - const qint16x4_t b01 = vld1_qs16(matrix_b + 4 + 0 * in_b_stride); - const qint16x4_t b02 = vld1_qs16(matrix_b + 8 + 0 * in_b_stride); - const qint16x4_t b03 = vld1_qs16(matrix_b + 12 + 0 * in_b_stride); - const qint16x4_t b10 = vld1_qs16(matrix_b + 0 + 1 * in_b_stride); - const qint16x4_t b11 = vld1_qs16(matrix_b + 4 + 1 * in_b_stride); - const qint16x4_t b12 = vld1_qs16(matrix_b + 8 + 1 * in_b_stride); - const qint16x4_t b13 = vld1_qs16(matrix_b + 12 + 1 * in_b_stride); - - // First accumulation - acc00_qs32 = vqmlal_qs16(acc00_qs32, b00, a0, fixed_point_position); - acc01_qs32 = vqmlal_qs16(acc01_qs32, b01, a0, fixed_point_position); - acc02_qs32 = vqmlal_qs16(acc02_qs32, b02, a0, fixed_point_position); - acc03_qs32 = vqmlal_qs16(acc03_qs32, b03, a0, fixed_point_position); - - // Second accumulation - acc00_qs32 = vqmlal_qs16(acc00_qs32, b10, a1, fixed_point_position); - acc01_qs32 = vqmlal_qs16(acc01_qs32, b11, a1, fixed_point_position); - acc02_qs32 = vqmlal_qs16(acc02_qs32, b12, a1, fixed_point_position); - acc03_qs32 = vqmlal_qs16(acc03_qs32, b13, a1, fixed_point_position); - - vec_a += 2; - matrix_b += 2 * in_b_stride; - } - - for(; vec_a < vec_a_end_addr;) - { - const qint16x4_t a0 = vld1_dup_qs16(vec_a); - - const qint16x4_t b00 = vld1_qs16(matrix_b + 0); - const qint16x4_t b01 = vld1_qs16(matrix_b + 4); - const qint16x4_t b02 = vld1_qs16(matrix_b + 8); - const qint16x4_t b03 = vld1_qs16(matrix_b + 12); - - acc00_qs32 = vqmlal_qs16(acc00_qs32, b00, a0, fixed_point_position); - acc01_qs32 = vqmlal_qs16(acc01_qs32, b01, a0, fixed_point_position); - acc02_qs32 = vqmlal_qs16(acc02_qs32, b02, a0, fixed_point_position); - acc03_qs32 = vqmlal_qs16(acc03_qs32, b03, a0, fixed_point_position); - - vec_a += 1; - matrix_b += in_b_stride; - } - - // Convert back to qint16x4_t and saturate - qint16x4_t acc00_qs16 = vqmovn_qs32(acc00_qs32); - qint16x4_t acc01_qs16 = vqmovn_qs32(acc01_qs32); - qint16x4_t acc02_qs16 = vqmovn_qs32(acc02_qs32); - qint16x4_t acc03_qs16 = vqmovn_qs32(acc03_qs32); - - // Multiply by the weight of the matrix product (alpha) - if(multiply_alpha) - { - const qint16x4_t alpha_qs16 = vdup_n_qs16(sqcvt_qs16_f32(alpha, fixed_point_position)); - acc00_qs16 = vqmul_qs16(acc00_qs16, alpha_qs16, fixed_point_position); - acc01_qs16 = vqmul_qs16(acc01_qs16, alpha_qs16, fixed_point_position); - acc02_qs16 = vqmul_qs16(acc02_qs16, alpha_qs16, fixed_point_position); - acc03_qs16 = vqmul_qs16(acc03_qs16, alpha_qs16, fixed_point_position); - } - - const auto mtx_out0 = reinterpret_cast(out.ptr()); - - // Store 16x4 output elements - vst1_qs16(mtx_out0 + 0, acc00_qs16); - vst1_qs16(mtx_out0 + 4, acc01_qs16); - vst1_qs16(mtx_out0 + 8, acc02_qs16); - vst1_qs16(mtx_out0 + 12, acc03_qs16); - }, - ina, inb, out); -} - template void matrix_matrix_multiply_f32(const ITensor *input0, const ITensor *input1, ITensor *output, const Window &window, float alpha) { @@ -1063,361 +806,12 @@ void matrix_matrix_multiply_f16(const ITensor *input0, const ITensor *input1, IT #endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */ } -template -void matrix_matrix_multiply_qs8(const ITensor *input0, const ITensor *input1, ITensor *output, const Window &window, float alpha) -{ - const size_t in_b_stride = input1->info()->strides_in_bytes()[1] / data_size_from_type(input1->info()->data_type()); - const size_t out_stride1 = output->info()->strides_in_bytes()[1] / data_size_from_type(output->info()->data_type()); - const size_t out_stride2 = out_stride1 * 2; - const size_t out_stride3 = out_stride1 * 3; - const int num_elems_matrix_b_x = input1->info()->dimension(0); - const int fixed_point_position = input0->info()->fixed_point_position(); - const qint8x8_t alpha_qs8 = vdup_n_qs8(sqcvt_qs8_f32(alpha, fixed_point_position)); - ARM_COMPUTE_UNUSED(alpha_qs8); - - // Set step_x and step_y for matrix A. Scale by a factor of 4 the Y range as the input interleaved matrix A has 4 times less the rows of the output matrix - Window win_a(window); - win_a.set(Window::DimX, Window::Dimension(0, 0, 0)); - win_a.set(Window::DimY, Window::Dimension(window.y().start() / 4, std::max(window.y().end() / 4, 1), 1)); - - Window win_b; - // Don't slice matrix B along the z dimension if matrix B has just 2 dimensions and matrix A more than 2 - // This scenario can happen when the the matrix multiplication is used to perform a convolution operation - if(input1->info()->num_dimensions() >= 3) - { - win_b = window; - } - // Set step_x and step_y for matrix B. Scale by a factor of 16 the X range as the input transposed matrix A has 16 times less the cols of the output matrix - // The step along the x direction is 2 times the in_b_stride because for each iteration we compute 2 blocks of size 16x4 - win_b.set(Window::DimX, Window::Dimension(window.x().start() / 16, window.x().end() / 16, 2 * in_b_stride)); - win_b.set(Window::DimY, Window::Dimension(0, 0, 0)); - - Iterator ina(input0, win_a); - Iterator inb(input1, win_b); - Iterator out(output, window); - - // The implementation assumes that the matrix A and Matrix B have been reshaped respectively with NEGEMMInterleave4x4 and NEGEMMTranspose1xW - // The reshaping of the matrices helps to have a cache friendly implementation and helps to avoid the data re-arrangements needed for computing 16x4 elements per iteration - // All the values needed for computing a single 32x4 block will be read from consecutive memory positions - execute_window_loop(window, [&](const Coordinates & id) - { - auto mtx_a0 = reinterpret_cast(ina.ptr()); - auto mtx_b0 = reinterpret_cast(inb.ptr()); - auto mtx_b1 = mtx_b0 + in_b_stride; - - qint16x8_t acc00_qs16 = vdupq_n_qs16(0); - qint16x8_t acc10_qs16 = vdupq_n_qs16(0); - qint16x8_t acc20_qs16 = vdupq_n_qs16(0); - qint16x8_t acc30_qs16 = vdupq_n_qs16(0); - - qint16x8_t acc01_qs16 = vdupq_n_qs16(0); - qint16x8_t acc11_qs16 = vdupq_n_qs16(0); - qint16x8_t acc21_qs16 = vdupq_n_qs16(0); - qint16x8_t acc31_qs16 = vdupq_n_qs16(0); - - qint16x8_t acc02_qs16 = vdupq_n_qs16(0); - qint16x8_t acc12_qs16 = vdupq_n_qs16(0); - qint16x8_t acc22_qs16 = vdupq_n_qs16(0); - qint16x8_t acc32_qs16 = vdupq_n_qs16(0); - - qint16x8_t acc03_qs16 = vdupq_n_qs16(0); - qint16x8_t acc13_qs16 = vdupq_n_qs16(0); - qint16x8_t acc23_qs16 = vdupq_n_qs16(0); - qint16x8_t acc33_qs16 = vdupq_n_qs16(0); - - int k = 0; - // This for loop performs 2 accumulations - for(; k <= (num_elems_matrix_b_x - 32); k += 32) - { - const qint8x8_t a0 = vld1_dup_qs8(mtx_a0 + 0); - const qint8x8_t a1 = vld1_dup_qs8(mtx_a0 + 1); - const qint8x8_t a2 = vld1_dup_qs8(mtx_a0 + 2); - const qint8x8_t a3 = vld1_dup_qs8(mtx_a0 + 3); - const qint8x8_t a4 = vld1_dup_qs8(mtx_a0 + 4); - const qint8x8_t a5 = vld1_dup_qs8(mtx_a0 + 5); - const qint8x8_t a6 = vld1_dup_qs8(mtx_a0 + 6); - const qint8x8_t a7 = vld1_dup_qs8(mtx_a0 + 7); - - const qint8x8_t b00 = vld1_qs8(mtx_b0 + 0); - const qint8x8_t b01 = vld1_qs8(mtx_b0 + 8); - const qint8x8_t b10 = vld1_qs8(mtx_b1 + 0); - const qint8x8_t b11 = vld1_qs8(mtx_b1 + 8); - - // First accumulation - acc00_qs16 = vqmlal_qs8(acc00_qs16, b00, a0, fixed_point_position); - acc10_qs16 = vqmlal_qs8(acc10_qs16, b00, a1, fixed_point_position); - acc20_qs16 = vqmlal_qs8(acc20_qs16, b00, a2, fixed_point_position); - acc30_qs16 = vqmlal_qs8(acc30_qs16, b00, a3, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b10, a0, fixed_point_position); - acc12_qs16 = vqmlal_qs8(acc12_qs16, b10, a1, fixed_point_position); - acc22_qs16 = vqmlal_qs8(acc22_qs16, b10, a2, fixed_point_position); - acc32_qs16 = vqmlal_qs8(acc32_qs16, b10, a3, fixed_point_position); - - const qint8x8_t b02 = vld1_qs8(mtx_b0 + 16); - const qint8x8_t b03 = vld1_qs8(mtx_b0 + 24); - const qint8x8_t b12 = vld1_qs8(mtx_b1 + 16); - const qint8x8_t b13 = vld1_qs8(mtx_b1 + 24); - - acc01_qs16 = vqmlal_qs8(acc01_qs16, b01, a0, fixed_point_position); - acc11_qs16 = vqmlal_qs8(acc11_qs16, b01, a1, fixed_point_position); - acc21_qs16 = vqmlal_qs8(acc21_qs16, b01, a2, fixed_point_position); - acc31_qs16 = vqmlal_qs8(acc31_qs16, b01, a3, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b11, a0, fixed_point_position); - acc13_qs16 = vqmlal_qs8(acc13_qs16, b11, a1, fixed_point_position); - acc23_qs16 = vqmlal_qs8(acc23_qs16, b11, a2, fixed_point_position); - acc33_qs16 = vqmlal_qs8(acc33_qs16, b11, a3, fixed_point_position); - -#if __arm__ - asm volatile("PLD [%0, #128*2]" ::"r"(reinterpret_cast(mtx_a0))); - asm volatile("PLD [%0, #128*2]" ::"r"(reinterpret_cast(mtx_b0))); - asm volatile("PLD [%0, #128*2]" ::"r"(reinterpret_cast(mtx_b1))); -#endif /* __arm__ */ - - // Second accumulation - acc00_qs16 = vqmlal_qs8(acc00_qs16, b02, a4, fixed_point_position); - acc10_qs16 = vqmlal_qs8(acc10_qs16, b02, a5, fixed_point_position); - acc20_qs16 = vqmlal_qs8(acc20_qs16, b02, a6, fixed_point_position); - acc30_qs16 = vqmlal_qs8(acc30_qs16, b02, a7, fixed_point_position); - acc01_qs16 = vqmlal_qs8(acc01_qs16, b03, a4, fixed_point_position); - acc11_qs16 = vqmlal_qs8(acc11_qs16, b03, a5, fixed_point_position); - acc21_qs16 = vqmlal_qs8(acc21_qs16, b03, a6, fixed_point_position); - acc31_qs16 = vqmlal_qs8(acc31_qs16, b03, a7, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b12, a4, fixed_point_position); - acc12_qs16 = vqmlal_qs8(acc12_qs16, b12, a5, fixed_point_position); - acc22_qs16 = vqmlal_qs8(acc22_qs16, b12, a6, fixed_point_position); - acc32_qs16 = vqmlal_qs8(acc32_qs16, b12, a7, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b13, a4, fixed_point_position); - acc13_qs16 = vqmlal_qs8(acc13_qs16, b13, a5, fixed_point_position); - acc23_qs16 = vqmlal_qs8(acc23_qs16, b13, a6, fixed_point_position); - acc33_qs16 = vqmlal_qs8(acc33_qs16, b13, a7, fixed_point_position); - - mtx_a0 += 8; - mtx_b0 += 32; - mtx_b1 += 32; - } - - // This for loop performs the left over accumulations - for(; k < num_elems_matrix_b_x; k += 16) - { - const qint8x8_t a0 = vld1_dup_qs8(mtx_a0 + 0); - const qint8x8_t a1 = vld1_dup_qs8(mtx_a0 + 1); - const qint8x8_t a2 = vld1_dup_qs8(mtx_a0 + 2); - const qint8x8_t a3 = vld1_dup_qs8(mtx_a0 + 3); - - const qint8x8_t b00 = vld1_qs8(mtx_b0 + 0); - const qint8x8_t b01 = vld1_qs8(mtx_b0 + 8); - const qint8x8_t b10 = vld1_qs8(mtx_b1 + 0); - const qint8x8_t b11 = vld1_qs8(mtx_b1 + 8); - - acc00_qs16 = vqmlal_qs8(acc00_qs16, b00, a0, fixed_point_position); - acc10_qs16 = vqmlal_qs8(acc10_qs16, b00, a1, fixed_point_position); - acc20_qs16 = vqmlal_qs8(acc20_qs16, b00, a2, fixed_point_position); - acc30_qs16 = vqmlal_qs8(acc30_qs16, b00, a3, fixed_point_position); - acc01_qs16 = vqmlal_qs8(acc01_qs16, b01, a0, fixed_point_position); - acc11_qs16 = vqmlal_qs8(acc11_qs16, b01, a1, fixed_point_position); - acc21_qs16 = vqmlal_qs8(acc21_qs16, b01, a2, fixed_point_position); - acc31_qs16 = vqmlal_qs8(acc31_qs16, b01, a3, fixed_point_position); - acc02_qs16 = vqmlal_qs8(acc02_qs16, b10, a0, fixed_point_position); - acc12_qs16 = vqmlal_qs8(acc12_qs16, b10, a1, fixed_point_position); - acc22_qs16 = vqmlal_qs8(acc22_qs16, b10, a2, fixed_point_position); - acc32_qs16 = vqmlal_qs8(acc32_qs16, b10, a3, fixed_point_position); - acc03_qs16 = vqmlal_qs8(acc03_qs16, b11, a0, fixed_point_position); - acc13_qs16 = vqmlal_qs8(acc13_qs16, b11, a1, fixed_point_position); - acc23_qs16 = vqmlal_qs8(acc23_qs16, b11, a2, fixed_point_position); - acc33_qs16 = vqmlal_qs8(acc33_qs16, b11, a3, fixed_point_position); - - mtx_a0 += 4; - mtx_b0 += 16; - mtx_b1 += 16; - } - - // Convert back to qint8x8_t and saturate - qint8x8_t acc00_qs8 = vqmovn_qs16(acc00_qs16); - qint8x8_t acc10_qs8 = vqmovn_qs16(acc10_qs16); - qint8x8_t acc20_qs8 = vqmovn_qs16(acc20_qs16); - qint8x8_t acc30_qs8 = vqmovn_qs16(acc30_qs16); - - qint8x8_t acc01_qs8 = vqmovn_qs16(acc01_qs16); - qint8x8_t acc11_qs8 = vqmovn_qs16(acc11_qs16); - qint8x8_t acc21_qs8 = vqmovn_qs16(acc21_qs16); - qint8x8_t acc31_qs8 = vqmovn_qs16(acc31_qs16); - - qint8x8_t acc02_qs8 = vqmovn_qs16(acc02_qs16); - qint8x8_t acc12_qs8 = vqmovn_qs16(acc12_qs16); - qint8x8_t acc22_qs8 = vqmovn_qs16(acc22_qs16); - qint8x8_t acc32_qs8 = vqmovn_qs16(acc32_qs16); - - qint8x8_t acc03_qs8 = vqmovn_qs16(acc03_qs16); - qint8x8_t acc13_qs8 = vqmovn_qs16(acc13_qs16); - qint8x8_t acc23_qs8 = vqmovn_qs16(acc23_qs16); - qint8x8_t acc33_qs8 = vqmovn_qs16(acc33_qs16); - - // Multiply by the weight of the matrix product (alpha) - if(multiply_alpha) - { - acc00_qs8 = vqmul_qs8(acc00_qs8, alpha_qs8, fixed_point_position); - acc10_qs8 = vqmul_qs8(acc10_qs8, alpha_qs8, fixed_point_position); - acc20_qs8 = vqmul_qs8(acc20_qs8, alpha_qs8, fixed_point_position); - acc30_qs8 = vqmul_qs8(acc30_qs8, alpha_qs8, fixed_point_position); - acc01_qs8 = vqmul_qs8(acc01_qs8, alpha_qs8, fixed_point_position); - acc11_qs8 = vqmul_qs8(acc11_qs8, alpha_qs8, fixed_point_position); - acc21_qs8 = vqmul_qs8(acc21_qs8, alpha_qs8, fixed_point_position); - acc31_qs8 = vqmul_qs8(acc31_qs8, alpha_qs8, fixed_point_position); - acc02_qs8 = vqmul_qs8(acc02_qs8, alpha_qs8, fixed_point_position); - acc12_qs8 = vqmul_qs8(acc12_qs8, alpha_qs8, fixed_point_position); - acc22_qs8 = vqmul_qs8(acc22_qs8, alpha_qs8, fixed_point_position); - acc32_qs8 = vqmul_qs8(acc32_qs8, alpha_qs8, fixed_point_position); - acc03_qs8 = vqmul_qs8(acc03_qs8, alpha_qs8, fixed_point_position); - acc13_qs8 = vqmul_qs8(acc13_qs8, alpha_qs8, fixed_point_position); - acc23_qs8 = vqmul_qs8(acc23_qs8, alpha_qs8, fixed_point_position); - acc33_qs8 = vqmul_qs8(acc33_qs8, alpha_qs8, fixed_point_position); - } - - const auto mtx_out0 = reinterpret_cast(out.ptr()); - - // Store 32x4 output elements - vst1_qs8(mtx_out0 + 0, acc00_qs8); - vst1_qs8(mtx_out0 + 8, acc01_qs8); - vst1_qs8(mtx_out0 + 16, acc02_qs8); - vst1_qs8(mtx_out0 + 24, acc03_qs8); - vst1_qs8(mtx_out0 + out_stride1 + 0, acc10_qs8); - vst1_qs8(mtx_out0 + out_stride1 + 8, acc11_qs8); - vst1_qs8(mtx_out0 + out_stride1 + 16, acc12_qs8); - vst1_qs8(mtx_out0 + out_stride1 + 24, acc13_qs8); - vst1_qs8(mtx_out0 + out_stride2 + 0, acc20_qs8); - vst1_qs8(mtx_out0 + out_stride2 + 8, acc21_qs8); - vst1_qs8(mtx_out0 + out_stride2 + 16, acc22_qs8); - vst1_qs8(mtx_out0 + out_stride2 + 24, acc23_qs8); - vst1_qs8(mtx_out0 + out_stride3 + 0, acc30_qs8); - vst1_qs8(mtx_out0 + out_stride3 + 8, acc31_qs8); - vst1_qs8(mtx_out0 + out_stride3 + 16, acc32_qs8); - vst1_qs8(mtx_out0 + out_stride3 + 24, acc33_qs8); - }, - ina, inb, out); -} - -template -void matrix_matrix_multiply_qs16(const ITensor *input0, const ITensor *input1, ITensor *output, const Window &window, float alpha) -{ - const size_t in_b_stride = input1->info()->strides_in_bytes()[1] / data_size_from_type(input1->info()->data_type()); - const size_t out_stride1 = output->info()->strides_in_bytes()[1] / data_size_from_type(output->info()->data_type()); - const size_t out_stride2 = out_stride1 * 2; - const size_t out_stride3 = out_stride1 * 3; - const int num_elems_matrix_b_x = input1->info()->dimension(0); - const int fixed_point_position = input0->info()->fixed_point_position(); - const qint16x4_t alpha_qs16 = vdup_n_qs16(sqcvt_qs16_f32(alpha, fixed_point_position)); - ARM_COMPUTE_UNUSED(alpha_qs16); - - // Set step_x and step_y for matrix A. Scale by a factor of 4 the Y range as the input interleaved matrix A has 4 times less the rows of the output matrix - Window win_a(window); - win_a.set(Window::DimX, Window::Dimension(0, 0, 0)); - win_a.set(Window::DimY, Window::Dimension(window.y().start() / 4, std::max(window.y().end() / 4, 1), 1)); - - Window win_b; - // Don't slice matrix B along the z dimension if matrix B has just 2 dimensions and matrix A more than 2 - // This scenario can happen when the the matrix multiplication is used to perform a convolution operation - if(input1->info()->num_dimensions() >= 3) - { - win_b = window; - } - // Set step_x and step_y for matrix B. Scale by a factor of 16 the X range as the input transposed matrix A has 16 times less the cols of the output matrix - win_b.set(Window::DimX, Window::Dimension(window.x().start() / 8, window.x().end() / 8, in_b_stride)); - win_b.set(Window::DimY, Window::Dimension(0, 0, 0)); - - Iterator ina(input0, win_a); - Iterator inb(input1, win_b); - Iterator out(output, window); - - // The implementation assumes that the matrix A and Matrix B have been reshaped respectively with NEGEMMInterleave4x4 and NEGEMMTranspose1xW - // The reshaping of the matrices helps to have a cache friendly implementation and helps to avoid the data re-arrangements needed for computing 8x4 elements per iteration - // All the values needed for computing a single 8x4 block will be read from consecutive memory positions - execute_window_loop(window, [&](const Coordinates & id) - { - auto mtx_a0 = reinterpret_cast(ina.ptr()); - auto mtx_b0 = reinterpret_cast(inb.ptr()); - auto mtx_b1 = mtx_b0 + in_b_stride; - - qint32x4_t acc00_qs32 = vdupq_n_qs32(0); - qint32x4_t acc10_qs32 = vdupq_n_qs32(0); - qint32x4_t acc20_qs32 = vdupq_n_qs32(0); - qint32x4_t acc30_qs32 = vdupq_n_qs32(0); - - qint32x4_t acc01_qs32 = vdupq_n_qs32(0); - qint32x4_t acc11_qs32 = vdupq_n_qs32(0); - qint32x4_t acc21_qs32 = vdupq_n_qs32(0); - qint32x4_t acc31_qs32 = vdupq_n_qs32(0); - - // This for loop performs 1 accumulation - for(int k = 0; k <= (num_elems_matrix_b_x - 8); k += 8) - { - const qint16x4_t a0 = vld1_dup_qs16(mtx_a0 + 0); - const qint16x4_t a1 = vld1_dup_qs16(mtx_a0 + 1); - const qint16x4_t a2 = vld1_dup_qs16(mtx_a0 + 2); - const qint16x4_t a3 = vld1_dup_qs16(mtx_a0 + 3); - - const qint16x4_t b00 = vld1_qs16(mtx_b0 + 0); - const qint16x4_t b01 = vld1_qs16(mtx_b0 + 4); - - acc00_qs32 = vqmlal_qs16(acc00_qs32, b00, a0, fixed_point_position); - acc10_qs32 = vqmlal_qs16(acc10_qs32, b00, a1, fixed_point_position); - acc20_qs32 = vqmlal_qs16(acc20_qs32, b00, a2, fixed_point_position); - acc30_qs32 = vqmlal_qs16(acc30_qs32, b00, a3, fixed_point_position); - acc01_qs32 = vqmlal_qs16(acc01_qs32, b01, a0, fixed_point_position); - acc11_qs32 = vqmlal_qs16(acc11_qs32, b01, a1, fixed_point_position); - acc21_qs32 = vqmlal_qs16(acc21_qs32, b01, a2, fixed_point_position); - acc31_qs32 = vqmlal_qs16(acc31_qs32, b01, a3, fixed_point_position); - - mtx_a0 += 4; - mtx_b0 += 8; - mtx_b1 += 8; - } - - // Convert back to qint16x4_t and saturate - qint16x4_t acc00_qs16 = vqmovn_qs32(acc00_qs32); - qint16x4_t acc10_qs16 = vqmovn_qs32(acc10_qs32); - qint16x4_t acc20_qs16 = vqmovn_qs32(acc20_qs32); - qint16x4_t acc30_qs16 = vqmovn_qs32(acc30_qs32); - - qint16x4_t acc01_qs16 = vqmovn_qs32(acc01_qs32); - qint16x4_t acc11_qs16 = vqmovn_qs32(acc11_qs32); - qint16x4_t acc21_qs16 = vqmovn_qs32(acc21_qs32); - qint16x4_t acc31_qs16 = vqmovn_qs32(acc31_qs32); - - // Multiply by the weight of the matrix product (alpha) - if(multiply_alpha) - { - acc00_qs16 = vqmul_qs16(acc00_qs16, alpha_qs16, fixed_point_position); - acc10_qs16 = vqmul_qs16(acc10_qs16, alpha_qs16, fixed_point_position); - acc20_qs16 = vqmul_qs16(acc20_qs16, alpha_qs16, fixed_point_position); - acc30_qs16 = vqmul_qs16(acc30_qs16, alpha_qs16, fixed_point_position); - acc01_qs16 = vqmul_qs16(acc01_qs16, alpha_qs16, fixed_point_position); - acc11_qs16 = vqmul_qs16(acc11_qs16, alpha_qs16, fixed_point_position); - acc21_qs16 = vqmul_qs16(acc21_qs16, alpha_qs16, fixed_point_position); - acc31_qs16 = vqmul_qs16(acc31_qs16, alpha_qs16, fixed_point_position); - } - - const auto mtx_out0 = reinterpret_cast(out.ptr()); - - // Store 8x4 output elements - vst1_qs16(mtx_out0 + 0, acc00_qs16); - vst1_qs16(mtx_out0 + 4, acc01_qs16); - vst1_qs16(mtx_out0 + out_stride1 + 0, acc10_qs16); - vst1_qs16(mtx_out0 + out_stride1 + 4, acc11_qs16); - vst1_qs16(mtx_out0 + out_stride2 + 0, acc20_qs16); - vst1_qs16(mtx_out0 + out_stride2 + 4, acc21_qs16); - vst1_qs16(mtx_out0 + out_stride3 + 0, acc30_qs16); - vst1_qs16(mtx_out0 + out_stride3 + 4, acc31_qs16); - }, - ina, inb, out); -} - inline Status validate_arguments(const ITensorInfo *input0, const ITensorInfo *input1, const ITensorInfo *output, float alpha, bool is_interleaved, const GEMMReshapeInfo &reshape_info) { ARM_COMPUTE_UNUSED(alpha); - ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input0, 1, DataType::F16, DataType::F32, DataType::QS8, DataType::QS16); + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input0, 1, DataType::F16, DataType::F32); ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input0, input1, output); - ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_FIXED_POINT(input0, input1, output); if(!is_interleaved) { @@ -1428,7 +822,6 @@ inline Status validate_arguments(const ITensorInfo *input0, const ITensorInfo *i ARM_COMPUTE_RETURN_ERROR_ON(input1->dimension(0) != output->dimension(0)); ARM_COMPUTE_RETURN_ERROR_ON(input0->dimension(1) != output->dimension(1)); ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input0, output); - ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_FIXED_POINT(input0, output); } } else @@ -1467,7 +860,6 @@ inline Status validate_arguments(const ITensorInfo *input0, const ITensorInfo *i } ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(1) != static_cast(m)); ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input0, output); - ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_FIXED_POINT(input0, output); } } @@ -1492,16 +884,6 @@ inline std::pair validate_and_configure_window(ITensorInfo *inpu num_elems_processed_per_iteration_x = 16; break; } - case DataType::QS8: - { - num_elems_processed_per_iteration_x = 32; - break; - } - case DataType::QS16: - { - num_elems_processed_per_iteration_x = 16; - break; - } #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC case DataType::F16: { @@ -1539,16 +921,6 @@ inline std::pair validate_and_configure_window(ITensorInfo *inpu num_elems_processed_per_iteration_x = 8; break; } - case DataType::QS8: - { - num_elems_processed_per_iteration_x = 32; - break; - } - case DataType::QS16: - { - num_elems_processed_per_iteration_x = 8; - break; - } #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC case DataType::F16: { @@ -1638,18 +1010,6 @@ void NEGEMMMatrixMultiplyKernel::run(const Window &window, const ThreadInfo &inf vector_matrix_multiply_f32(_input0, _input1, _output, window, info, _alpha); break; } - case DataType::QS8: - { - multiply_alpha ? vector_matrix_multiply_qs8(_input0, _input1, _output, window, info, _alpha) : - vector_matrix_multiply_qs8(_input0, _input1, _output, window, info, _alpha); - break; - } - case DataType::QS16: - { - multiply_alpha ? vector_matrix_multiply_qs16(_input0, _input1, _output, window, info, _alpha) : - vector_matrix_multiply_qs16(_input0, _input1, _output, window, info, _alpha); - break; - } #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC case DataType::F16: { @@ -1675,18 +1035,6 @@ void NEGEMMMatrixMultiplyKernel::run(const Window &window, const ThreadInfo &inf matrix_matrix_multiply_f32(_input0, _input1, _output, window, _alpha); break; } - case DataType::QS8: - { - multiply_alpha ? matrix_matrix_multiply_qs8(_input0, _input1, _output, window, _alpha) : - matrix_matrix_multiply_qs8(_input0, _input1, _output, window, _alpha); - break; - } - case DataType::QS16: - { - multiply_alpha ? matrix_matrix_multiply_qs16(_input0, _input1, _output, window, _alpha) : - matrix_matrix_multiply_qs16(_input0, _input1, _output, window, _alpha); - break; - } #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC case DataType::F16: { -- cgit v1.2.1