You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4289 lines
128 KiB
4289 lines
128 KiB
// Copyright 2016 The Gemmlowp Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef GEMMLOWP_META_QUANTIZED_MUL_KERNELS_ARM_32_H_
|
|
#define GEMMLOWP_META_QUANTIZED_MUL_KERNELS_ARM_32_H_
|
|
|
|
#ifdef GEMMLOWP_NEON_32
|
|
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
|
|
namespace gemmlowp {
|
|
namespace meta {
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 1, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d2}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d3}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q2, d3, d2\n"
|
|
"vpadal.u16 q0, q2\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.8 {d0[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d8", "d9", "d10", "d11", "d12",
|
|
"d13", "d14", "d15", "d16", "d17", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 2, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d5, d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d5, d4\n"
|
|
"vmull.u8 q5, d6, d4\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10", "d11",
|
|
"d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 3, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d7, d8, d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d7, d6\n"
|
|
"vmull.u8 q6, d8, d6\n"
|
|
"vmull.u8 q7, d9, d6\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d0[2]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 4, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9, d10, d11, d12}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vmull.u8 q8, d10, d8\n"
|
|
"vmull.u8 q9, d11, d8\n"
|
|
"vmull.u8 q10, d12, d8\n"
|
|
"vpadal.u16 q0, q7\n"
|
|
"vpadal.u16 q1, q8\n"
|
|
"vpadal.u16 q2, q9\n"
|
|
"vpadal.u16 q3, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 5,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 5, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d10, d11, d12, d13}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d14}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vmull.u8 q9, d11, d14\n"
|
|
"vmull.u8 q10, d12, d14\n"
|
|
"vmull.u8 q11, d13, d14\n"
|
|
"vld1.32 {d10}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q8\n"
|
|
"vpadal.u16 q1, q9\n"
|
|
"vpadal.u16 q2, q10\n"
|
|
"vpadal.u16 q3, q11\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vpadal.u16 q4, q8\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d10, d11}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[multiplicative_offset]\n"
|
|
"vdup.32 q9, %[rounding_offset]\n"
|
|
"vdup.32 q10, %[shift]\n"
|
|
"vdup.32 q5, d10[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d8\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vmul.i32 q0, q0, q8\n"
|
|
"vmul.i32 q1, q1, q8\n"
|
|
"vadd.i32 q0, q0, q9\n"
|
|
"vadd.i32 q1, q1, q9\n"
|
|
"vshl.s32 q0, q0, q10\n"
|
|
"vshl.s32 q1, q1, q10\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d1, q1\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d0[4]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 6,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 6, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vmull.u8 q11, d14, d16\n"
|
|
"vmull.u8 q12, d15, d16\n"
|
|
"vld1.32 {d12, d13}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vpadal.u16 q4, q9\n"
|
|
"vpadal.u16 q5, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vdup.32 q9, %[multiplicative_offset]\n"
|
|
"vdup.32 q10, %[rounding_offset]\n"
|
|
"vdup.32 q11, %[shift]\n"
|
|
"vdup.32 q6, d12[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
"vmul.i32 q0, q0, q9\n"
|
|
"vmul.i32 q1, q1, q9\n"
|
|
"vadd.i32 q0, q0, q10\n"
|
|
"vadd.i32 q1, q1, q10\n"
|
|
"vshl.s32 q0, q0, q11\n"
|
|
"vshl.s32 q1, q1, q11\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d1, q1\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.16 {d0[2]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 7,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 7, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d18}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d17, d18\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q10\n"
|
|
"vpadal.u16 q1, q11\n"
|
|
"vpadal.u16 q2, q12\n"
|
|
"vpadal.u16 q3, q13\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vpadal.u16 q4, q10\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d14, d15}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d16, d17, d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q10, %[multiplicative_offset]\n"
|
|
"vdup.32 q11, %[rounding_offset]\n"
|
|
"vdup.32 q12, %[shift]\n"
|
|
"vdup.32 q7, d14[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d12\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q9\n"
|
|
"vmul.i32 q0, q0, q10\n"
|
|
"vmul.i32 q1, q1, q10\n"
|
|
"vadd.i32 q0, q0, q11\n"
|
|
"vadd.i32 q1, q1, q11\n"
|
|
"vshl.s32 q0, q0, q12\n"
|
|
"vshl.s32 q1, q1, q12\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d1, q1\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.16 {d0[2]}, [%[result]]!\n"
|
|
"vst1.8 {d0[6]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 1, 8,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 1, 8, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 1x8 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d17\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d16, d19\n"
|
|
"vmull.u8 q14, d16, d20\n"
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vpadal.u16 q3, q14\n"
|
|
"pld [%[rhs], #256]\n"
|
|
"vmull.u8 q15, d16, d17\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #32]\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19, d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q11, %[multiplicative_offset]\n"
|
|
"vdup.32 q12, %[rounding_offset]\n"
|
|
"vdup.32 q13, %[shift]\n"
|
|
"vdup.32 q8, d16[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d14\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q1, q1, q10\n"
|
|
"vmul.i32 q0, q0, q11\n"
|
|
"vmul.i32 q1, q1, q11\n"
|
|
"vadd.i32 q0, q0, q12\n"
|
|
"vadd.i32 q1, q1, q12\n"
|
|
"vshl.s32 q0, q0, q13\n"
|
|
"vshl.s32 q1, q1, q13\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d1, q1\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 2, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 2, 1, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4, d5}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d6, d4\n"
|
|
"vmull.u8 q5, d6, d5\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q2, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q2\n"
|
|
"vadd.s32 q1, q1, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vmul.i32 q1, q1, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vadd.i32 q1, q1, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vshl.s32 q1, q1, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d2, q1\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d2, q1\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.8 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d2[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 2, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 2, 2, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q6, d10, d8\n"
|
|
"vmull.u8 q7, d11, d8\n"
|
|
"vmull.u8 q8, d10, d9\n"
|
|
"vmull.u8 q9, d11, d9\n"
|
|
"vpadal.u16 q0, q6\n"
|
|
"vpadal.u16 q1, q7\n"
|
|
"vpadal.u16 q2, q8\n"
|
|
"vpadal.u16 q3, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q9, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vmul.i32 q2, q2, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vadd.i32 q2, q2, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vshl.s32 q2, q2, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d4, q2\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d4, q2\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
"vst1.16 {d4[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 2, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 2, 3, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d14, d12\n"
|
|
"vmull.u8 q10, d15, d12\n"
|
|
"vmull.u8 q11, d16, d12\n"
|
|
"vmull.u8 q12, d14, d13\n"
|
|
"vmull.u8 q13, d15, d13\n"
|
|
"vmull.u8 q14, d16, d13\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[multiplicative_offset]\n"
|
|
"vdup.32 q9, %[rounding_offset]\n"
|
|
"vdup.32 q10, %[shift]\n"
|
|
"vdup.32 q11, d12[0]\n"
|
|
"vdup.32 q6, d12[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q11\n"
|
|
"vadd.s32 q3, q3, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q3, q3, q7\n"
|
|
"vmul.i32 q0, q0, q8\n"
|
|
"vmul.i32 q3, q3, q8\n"
|
|
"vadd.i32 q0, q0, q9\n"
|
|
"vadd.i32 q3, q3, q9\n"
|
|
"vshl.s32 q0, q0, q10\n"
|
|
"vshl.s32 q3, q3, q10\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d6, q3\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d6, q3\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d0[2]}, [%[result]]!\n"
|
|
"vst1.16 {d6[0]}, [r0]!\n"
|
|
"vst1.8 {d6[2]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 2, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 2, 4, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 2x4 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d18, d19, d20, d21}, [%[rhs]:256]!\n"
|
|
"vld1.8 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vld1.8 {d17}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q14, d16, d21\n"
|
|
"vmull.u8 q15, d17, d18\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vmull.u8 q11, d17, d19\n"
|
|
"vmull.u8 q12, d17, d20\n"
|
|
"vmull.u8 q13, d17, d21\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q3, q14\n"
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q10, %[multiplicative_offset]\n"
|
|
"vdup.32 q11, %[rounding_offset]\n"
|
|
"vdup.32 q12, %[shift]\n"
|
|
"vdup.32 q13, d16[0]\n"
|
|
"vdup.32 q8, d16[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
"vpadd.u32 d9, d12, d14\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q13\n"
|
|
"vadd.s32 q4, q4, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q4, q4, q9\n"
|
|
"vmul.i32 q0, q0, q10\n"
|
|
"vmul.i32 q4, q4, q10\n"
|
|
"vadd.i32 q0, q0, q11\n"
|
|
"vadd.i32 q4, q4, q11\n"
|
|
"vshl.s32 q0, q0, q12\n"
|
|
"vshl.s32 q4, q4, q12\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d8, q4\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d8, q4\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.32 {d8[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 3, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 3, 1, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6, d7, d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d9, d6\n"
|
|
"vmull.u8 q6, d9, d7\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[multiplicative_offset]\n"
|
|
"vdup.32 q7, %[rounding_offset]\n"
|
|
"vdup.32 q8, %[shift]\n"
|
|
"vdup.32 q3, d8[0]\n"
|
|
"vdup.32 q9, d8[1]\n"
|
|
"vdup.32 q4, d9[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d4, d4, d4\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q3\n"
|
|
"vadd.s32 q1, q1, q9\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
"vmul.i32 q0, q0, q6\n"
|
|
"vmul.i32 q1, q1, q6\n"
|
|
"vmul.i32 q2, q2, q6\n"
|
|
"vadd.i32 q0, q0, q7\n"
|
|
"vadd.i32 q1, q1, q7\n"
|
|
"vadd.i32 q2, q2, q7\n"
|
|
"vshl.s32 q0, q0, q8\n"
|
|
"vshl.s32 q1, q1, q8\n"
|
|
"vshl.s32 q2, q2, q8\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d2, q1\n"
|
|
"vqmovn.s32 d4, q2\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d2, q1\n"
|
|
"vqmovun.s16 d4, q2\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.8 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d2[0]}, [r0]!\n"
|
|
"vst1.8 {d4[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 3, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 3, 2, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d15, d12\n"
|
|
"vmull.u8 q10, d16, d12\n"
|
|
"vmull.u8 q11, d15, d13\n"
|
|
"vmull.u8 q12, d16, d13\n"
|
|
"vmull.u8 q13, d15, d14\n"
|
|
"vmull.u8 q14, d16, d14\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[multiplicative_offset]\n"
|
|
"vdup.32 q9, %[rounding_offset]\n"
|
|
"vdup.32 q10, %[shift]\n"
|
|
"vdup.32 q11, d12[0]\n"
|
|
"vdup.32 q12, d12[1]\n"
|
|
"vdup.32 q6, d13[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q11\n"
|
|
"vadd.s32 q2, q2, q12\n"
|
|
"vadd.s32 q4, q4, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q2, q2, q7\n"
|
|
"vadd.s32 q4, q4, q7\n"
|
|
"vmul.i32 q0, q0, q8\n"
|
|
"vmul.i32 q2, q2, q8\n"
|
|
"vmul.i32 q4, q4, q8\n"
|
|
"vadd.i32 q0, q0, q9\n"
|
|
"vadd.i32 q2, q2, q9\n"
|
|
"vadd.i32 q4, q4, q9\n"
|
|
"vshl.s32 q0, q0, q10\n"
|
|
"vshl.s32 q2, q2, q10\n"
|
|
"vshl.s32 q4, q4, q10\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d4, q2\n"
|
|
"vqmovn.s32 d8, q4\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d4, q2\n"
|
|
"vqmovun.s16 d8, q4\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
"vst1.16 {d4[0]}, [r0]!\n"
|
|
"vst1.16 {d8[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void
|
|
MulKernel<uint8_t, uint8_t, QuantizedStaticPreprocessed, RowMajor, 3, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessed,
|
|
RowMajor>& params,
|
|
uint8_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedRowMajor<uint8_t, uint8_t, "
|
|
"QuantizedStaticPreprocessed, RowMajor, 3, 3, 8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
"vmov.i32 q8, q5\n"
|
|
|
|
// 3x3 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d21, d22, d23}, [%[rhs]:64]!\n"
|
|
"vld1.8 {d18}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d18, d21\n"
|
|
"vld1.8 {d19}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q13, d18, d22\n"
|
|
"vld1.8 {d20}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q14, d18, d23\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q15, d19, d21\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vpadal.u16 q0, q12\n"
|
|
"vpadal.u16 q1, q13\n"
|
|
"vpadal.u16 q2, q14\n"
|
|
"vpadal.u16 q3, q15\n"
|
|
"vmull.u8 q12, d19, d22\n"
|
|
"vmull.u8 q13, d19, d23\n"
|
|
"vmull.u8 q14, d20, d21\n"
|
|
"vmull.u8 q15, d20, d22\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vmull.u8 q9, d20, d23\n"
|
|
"vpadal.u16 q4, q12\n"
|
|
"vpadal.u16 q5, q13\n"
|
|
"vpadal.u16 q6, q14\n"
|
|
"vpadal.u16 q7, q15\n"
|
|
"vpadal.u16 q8, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantization::Prepare
|
|
"vld1.32 {d18, d19}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q11, %[multiplicative_offset]\n"
|
|
"vdup.32 q12, %[rounding_offset]\n"
|
|
"vdup.32 q13, %[shift]\n"
|
|
"vdup.32 q14, d18[0]\n"
|
|
"vdup.32 q15, d18[1]\n"
|
|
"vdup.32 q9, d19[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d16, d16, d17\n"
|
|
"vpadd.u32 d12, d12, d14\n"
|
|
"vpadd.u32 d13, d16, d16\n"
|
|
|
|
// StaticQuantization::Transform
|
|
"vadd.s32 q0, q0, q14\n"
|
|
"vadd.s32 q3, q3, q15\n"
|
|
"vadd.s32 q6, q6, q9\n"
|
|
"vadd.s32 q0, q0, q10\n"
|
|
"vadd.s32 q3, q3, q10\n"
|
|
"vadd.s32 q6, q6, q10\n"
|
|
"vmul.i32 q0, q0, q11\n"
|
|
"vmul.i32 q3, q3, q11\n"
|
|
"vmul.i32 q6, q6, q11\n"
|
|
"vadd.i32 q0, q0, q12\n"
|
|
"vadd.i32 q3, q3, q12\n"
|
|
"vadd.i32 q6, q6, q12\n"
|
|
"vshl.s32 q0, q0, q13\n"
|
|
"vshl.s32 q3, q3, q13\n"
|
|
"vshl.s32 q6, q6, q13\n"
|
|
"vqmovn.s32 d0, q0\n"
|
|
"vqmovn.s32 d6, q3\n"
|
|
"vqmovn.s32 d12, q6\n"
|
|
"vqmovun.s16 d0, q0\n"
|
|
"vqmovun.s16 d6, q3\n"
|
|
"vqmovun.s16 d12, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.16 {d0[0]}, [%[result]]!\n"
|
|
"vst1.8 {d0[2]}, [%[result]]!\n"
|
|
"vst1.16 {d6[0]}, [r0]!\n"
|
|
"vst1.8 {d6[2]}, [r0]!\n"
|
|
"vst1.16 {d12[0]}, [r1]!\n"
|
|
"vst1.8 {d12[2]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[multiplicative_offset] "r"(params.kernel.multiplicative_offset),
|
|
[shift] "r"(params.kernel.shift),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[rounding_offset] "r"(params.kernel.rounding_offset)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"d30", "d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d2}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d3}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q2, d3, d2\n"
|
|
"vpadal.u16 q0, q2\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d8", "d9", "d10", "d11", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d5, d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d5, d4\n"
|
|
"vmull.u8 q5, d6, d4\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10", "d11",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d7, d8, d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d7, d6\n"
|
|
"vmull.u8 q6, d8, d6\n"
|
|
"vmull.u8 q7, d9, d6\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 4, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9, d10, d11, d12}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vmull.u8 q8, d10, d8\n"
|
|
"vmull.u8 q9, d11, d8\n"
|
|
"vmull.u8 q10, d12, d8\n"
|
|
"vpadal.u16 q0, q7\n"
|
|
"vpadal.u16 q1, q8\n"
|
|
"vpadal.u16 q2, q9\n"
|
|
"vpadal.u16 q3, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 5,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 5, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d10, d11, d12, d13}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d14}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vmull.u8 q9, d11, d14\n"
|
|
"vmull.u8 q10, d12, d14\n"
|
|
"vmull.u8 q11, d13, d14\n"
|
|
"vld1.32 {d10}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q8\n"
|
|
"vpadal.u16 q1, q9\n"
|
|
"vpadal.u16 q2, q10\n"
|
|
"vpadal.u16 q3, q11\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vpadal.u16 q4, q8\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d10, d11}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q5, d10[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d8\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 6,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 6, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vmull.u8 q11, d14, d16\n"
|
|
"vmull.u8 q12, d15, d16\n"
|
|
"vld1.32 {d12, d13}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vpadal.u16 q4, q9\n"
|
|
"vpadal.u16 q5, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, d12[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 7,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 7, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d18}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d17, d18\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q10\n"
|
|
"vpadal.u16 q1, q11\n"
|
|
"vpadal.u16 q2, q12\n"
|
|
"vpadal.u16 q3, q13\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vpadal.u16 q4, q10\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d14, d15}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d16, d17, d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q7, d14[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d12\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q9\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2}, [%[result]]!\n"
|
|
"vst1.32 {d3[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 8,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 1, 8, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 1x8 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d17\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d16, d19\n"
|
|
"vmull.u8 q14, d16, d20\n"
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vpadal.u16 q3, q14\n"
|
|
"pld [%[rhs], #256]\n"
|
|
"vmull.u8 q15, d16, d17\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #32]\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19, d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, d16[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d14\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q1, q1, q10\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2, d3}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4, d5}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d6, d4\n"
|
|
"vmull.u8 q5, d6, d5\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q2, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q2\n"
|
|
"vadd.s32 q1, q1, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10",
|
|
"d11", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q6, d10, d8\n"
|
|
"vmull.u8 q7, d11, d8\n"
|
|
"vmull.u8 q8, d10, d9\n"
|
|
"vmull.u8 q9, d11, d9\n"
|
|
"vpadal.u16 q0, q6\n"
|
|
"vpadal.u16 q1, q7\n"
|
|
"vpadal.u16 q2, q8\n"
|
|
"vpadal.u16 q3, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d4}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d14, d12\n"
|
|
"vmull.u8 q10, d15, d12\n"
|
|
"vmull.u8 q11, d16, d12\n"
|
|
"vmull.u8 q12, d14, d13\n"
|
|
"vmull.u8 q13, d15, d13\n"
|
|
"vmull.u8 q14, d16, d13\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, d12[0]\n"
|
|
"vdup.32 q6, d12[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q3, q3, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q3, q3, q7\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
"vst1.32 {d6}, [r0]!\n"
|
|
"vst1.32 {d7[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 2, 4, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 2x4 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d18, d19, d20, d21}, [%[rhs]:256]!\n"
|
|
"vld1.8 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vld1.8 {d17}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q14, d16, d21\n"
|
|
"vmull.u8 q15, d17, d18\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vmull.u8 q11, d17, d19\n"
|
|
"vmull.u8 q12, d17, d20\n"
|
|
"vmull.u8 q13, d17, d21\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q3, q14\n"
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q10, d16[0]\n"
|
|
"vdup.32 q8, d16[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
"vpadd.u32 d9, d12, d14\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q10\n"
|
|
"vadd.s32 q4, q4, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q4, q4, q9\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
"vst1.32 {d8, d9}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6, d7, d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d9, d6\n"
|
|
"vmull.u8 q6, d9, d7\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q3, d8[0]\n"
|
|
"vdup.32 q6, d8[1]\n"
|
|
"vdup.32 q4, d9[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d4, d4, d4\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q3\n"
|
|
"vadd.s32 q1, q1, q6\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [r0]!\n"
|
|
"vst1.32 {d4[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d15, d12\n"
|
|
"vmull.u8 q10, d16, d12\n"
|
|
"vmull.u8 q11, d15, d13\n"
|
|
"vmull.u8 q12, d16, d13\n"
|
|
"vmull.u8 q13, d15, d14\n"
|
|
"vmull.u8 q14, d16, d14\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, d12[0]\n"
|
|
"vdup.32 q9, d12[1]\n"
|
|
"vdup.32 q6, d13[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q2, q2, q9\n"
|
|
"vadd.s32 q4, q4, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q2, q2, q7\n"
|
|
"vadd.s32 q4, q4, q7\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d4}, [r0]!\n"
|
|
"vst1.32 {d8}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, int32_t, QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsInt32,
|
|
RowMajor>& params,
|
|
int32_t* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsInt32RowMajor<uint8_t, int32_t, "
|
|
"QuantizedStaticPreprocessedAsInt32, RowMajor, 3, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
"vmov.i32 q8, q5\n"
|
|
|
|
// 3x3 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d21, d22, d23}, [%[rhs]:64]!\n"
|
|
"vld1.8 {d18}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d18, d21\n"
|
|
"vld1.8 {d19}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q13, d18, d22\n"
|
|
"vld1.8 {d20}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q14, d18, d23\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q15, d19, d21\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vpadal.u16 q0, q12\n"
|
|
"vpadal.u16 q1, q13\n"
|
|
"vpadal.u16 q2, q14\n"
|
|
"vpadal.u16 q3, q15\n"
|
|
"vmull.u8 q12, d19, d22\n"
|
|
"vmull.u8 q13, d19, d23\n"
|
|
"vmull.u8 q14, d20, d21\n"
|
|
"vmull.u8 q15, d20, d22\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vmull.u8 q9, d20, d23\n"
|
|
"vpadal.u16 q4, q12\n"
|
|
"vpadal.u16 q5, q13\n"
|
|
"vpadal.u16 q6, q14\n"
|
|
"vpadal.u16 q7, q15\n"
|
|
"vpadal.u16 q8, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationInt32::Prepare
|
|
"vld1.32 {d18, d19}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q11, d18[0]\n"
|
|
"vdup.32 q12, d18[1]\n"
|
|
"vdup.32 q9, d19[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d16, d16, d17\n"
|
|
"vpadd.u32 d12, d12, d14\n"
|
|
"vpadd.u32 d13, d16, d16\n"
|
|
|
|
// StaticQuantizationInt32::Transform
|
|
"vadd.s32 q0, q0, q11\n"
|
|
"vadd.s32 q3, q3, q12\n"
|
|
"vadd.s32 q6, q6, q9\n"
|
|
"vadd.s32 q0, q0, q10\n"
|
|
"vadd.s32 q3, q3, q10\n"
|
|
"vadd.s32 q6, q6, q10\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
"vst1.32 {d6}, [r0]!\n"
|
|
"vst1.32 {d7[0]}, [r0]!\n"
|
|
"vst1.32 {d12}, [r1]!\n"
|
|
"vst1.32 {d13[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"d30", "d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d2}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d3}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q2, d3, d2\n"
|
|
"vpadal.u16 q0, q2\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d8", "d9", "d10", "d11", "d12",
|
|
"d13", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d5, d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d5, d4\n"
|
|
"vmull.u8 q5, d6, d4\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10", "d11",
|
|
"d12", "d13", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d7, d8, d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d7, d6\n"
|
|
"vmull.u8 q6, d8, d6\n"
|
|
"vmull.u8 q7, d9, d6\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 4, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9, d10, d11, d12}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vmull.u8 q8, d10, d8\n"
|
|
"vmull.u8 q9, d11, d8\n"
|
|
"vmull.u8 q10, d12, d8\n"
|
|
"vpadal.u16 q0, q7\n"
|
|
"vpadal.u16 q1, q8\n"
|
|
"vpadal.u16 q2, q9\n"
|
|
"vpadal.u16 q3, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q4, d8[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 5,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 5, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d10, d11, d12, d13}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d14}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vmull.u8 q9, d11, d14\n"
|
|
"vmull.u8 q10, d12, d14\n"
|
|
"vmull.u8 q11, d13, d14\n"
|
|
"vld1.32 {d10}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q8\n"
|
|
"vpadal.u16 q1, q9\n"
|
|
"vpadal.u16 q2, q10\n"
|
|
"vpadal.u16 q3, q11\n"
|
|
"vmull.u8 q8, d10, d14\n"
|
|
"vpadal.u16 q4, q8\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d10, d11}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[scale]\n"
|
|
"vdup.32 q5, d10[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d8\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vmul.f32 q0, q0, q8\n"
|
|
"vmul.f32 q1, q1, q8\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 6,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 6, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14, d15}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vmull.u8 q11, d14, d16\n"
|
|
"vmull.u8 q12, d15, d16\n"
|
|
"vld1.32 {d12, d13}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vmull.u8 q9, d12, d16\n"
|
|
"vmull.u8 q10, d13, d16\n"
|
|
"vpadal.u16 q4, q9\n"
|
|
"vpadal.u16 q5, q10\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vdup.32 q9, %[scale]\n"
|
|
"vdup.32 q6, d12[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q6\n"
|
|
"vadd.s32 q1, q1, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vmul.f32 q0, q0, q9\n"
|
|
"vmul.f32 q1, q1, q9\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 7,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 7, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
|
|
// General 1xM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d14, d15, d16, d17}, [%[rhs]:64]!\n"
|
|
"vld1.32 {d18}, [%[lhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d17, d18\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[rhs], #128]\n"
|
|
"vpadal.u16 q0, q10\n"
|
|
"vpadal.u16 q1, q11\n"
|
|
"vpadal.u16 q2, q12\n"
|
|
"vpadal.u16 q3, q13\n"
|
|
"vmull.u8 q10, d14, d18\n"
|
|
"vmull.u8 q11, d15, d18\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vpadal.u16 q4, q10\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d14, d15}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d16, d17, d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q10, %[scale]\n"
|
|
"vdup.32 q7, d14[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d12\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q9\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vmul.f32 q0, q0, q10\n"
|
|
"vmul.f32 q1, q1, q10\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2}, [%[result]]!\n"
|
|
"vst1.32 {d3[0]}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 8,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 1, 8, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 1x8 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vld1.32 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d17\n"
|
|
"vmull.u8 q12, d16, d18\n"
|
|
"vmull.u8 q13, d16, d19\n"
|
|
"vmull.u8 q14, d16, d20\n"
|
|
"vld1.32 {d17, d18, d19, d20}, [%[rhs]:256]!\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vpadal.u16 q3, q14\n"
|
|
"pld [%[rhs], #256]\n"
|
|
"vmull.u8 q15, d16, d17\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #32]\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19, d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q11, %[scale]\n"
|
|
"vdup.32 q8, d16[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d2, d8, d10\n"
|
|
"vpadd.u32 d3, d12, d14\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q8\n"
|
|
"vadd.s32 q1, q1, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q1, q1, q10\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vmul.f32 q0, q0, q11\n"
|
|
"vmul.f32 q1, q1, q11\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1, d2, d3}, [%[result]]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d4, d5}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d6}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q4, d6, d4\n"
|
|
"vmull.u8 q5, d6, d5\n"
|
|
"vpadal.u16 q0, q4\n"
|
|
"vpadal.u16 q1, q5\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q2, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q2\n"
|
|
"vadd.s32 q1, q1, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
"vmul.f32 q1, q1, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q6, d10, d8\n"
|
|
"vmull.u8 q7, d11, d8\n"
|
|
"vmull.u8 q8, d10, d9\n"
|
|
"vmull.u8 q9, d11, d9\n"
|
|
"vpadal.u16 q0, q6\n"
|
|
"vpadal.u16 q1, q7\n"
|
|
"vpadal.u16 q2, q8\n"
|
|
"vpadal.u16 q3, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q7, d8[0]\n"
|
|
"vdup.32 q4, d8[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q2, q2\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
"vmul.f32 q2, q2, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d4}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d14, d12\n"
|
|
"vmull.u8 q10, d15, d12\n"
|
|
"vmull.u8 q11, d16, d12\n"
|
|
"vmull.u8 q12, d14, d13\n"
|
|
"vmull.u8 q13, d15, d13\n"
|
|
"vmull.u8 q14, d16, d13\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[scale]\n"
|
|
"vdup.32 q9, d12[0]\n"
|
|
"vdup.32 q6, d12[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q3, q3, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q3, q3, q7\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q3, q3\n"
|
|
"vmul.f32 q0, q0, q8\n"
|
|
"vmul.f32 q3, q3, q8\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
"vst1.32 {d6}, [r0]!\n"
|
|
"vst1.32 {d7[0]}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "cc",
|
|
"memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 4,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 2, 4, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
|
|
// 2x4 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d18, d19, d20, d21}, [%[rhs]:256]!\n"
|
|
"vld1.8 {d16}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q11, d16, d18\n"
|
|
"vld1.8 {d17}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d16, d19\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q13, d16, d20\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q14, d16, d21\n"
|
|
"vmull.u8 q15, d17, d18\n"
|
|
"vpadal.u16 q0, q11\n"
|
|
"vpadal.u16 q1, q12\n"
|
|
"vpadal.u16 q2, q13\n"
|
|
"vmull.u8 q11, d17, d19\n"
|
|
"vmull.u8 q12, d17, d20\n"
|
|
"vmull.u8 q13, d17, d21\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vpadal.u16 q3, q14\n"
|
|
"vpadal.u16 q4, q15\n"
|
|
"vpadal.u16 q5, q11\n"
|
|
"vpadal.u16 q6, q12\n"
|
|
"vpadal.u16 q7, q13\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d16, d17}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d18, d19}, [%[rhs]:64]!\n"
|
|
"vdup.32 q10, %[scale]\n"
|
|
"vdup.32 q11, d16[0]\n"
|
|
"vdup.32 q8, d16[1]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
"vpadd.u32 d9, d12, d14\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q11\n"
|
|
"vadd.s32 q4, q4, q8\n"
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q4, q4, q9\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q4, q4\n"
|
|
"vmul.f32 q0, q0, q10\n"
|
|
"vmul.f32 q4, q4, q10\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0, d1}, [%[result]]!\n"
|
|
"vst1.32 {d8, d9}, [r0]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
|
|
"d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
|
|
"d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
|
|
"d31", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 1,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 1, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d6, d7, d8}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d9}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q5, d9, d6\n"
|
|
"vmull.u8 q6, d9, d7\n"
|
|
"vmull.u8 q7, d9, d8\n"
|
|
"vpadal.u16 q0, q5\n"
|
|
"vpadal.u16 q1, q6\n"
|
|
"vpadal.u16 q2, q7\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d8, d9}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d10, d11}, [%[rhs]:64]!\n"
|
|
"vdup.32 q6, %[scale]\n"
|
|
"vdup.32 q3, d8[0]\n"
|
|
"vdup.32 q7, d8[1]\n"
|
|
"vdup.32 q4, d9[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d0, d0, d0\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d2, d2, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d4, d4, d4\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q3\n"
|
|
"vadd.s32 q1, q1, q7\n"
|
|
"vadd.s32 q2, q2, q4\n"
|
|
"vadd.s32 q0, q0, q5\n"
|
|
"vadd.s32 q1, q1, q5\n"
|
|
"vadd.s32 q2, q2, q5\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q1, q1\n"
|
|
"vcvt.f32.s32 q2, q2\n"
|
|
"vmul.f32 q0, q0, q6\n"
|
|
"vmul.f32 q1, q1, q6\n"
|
|
"vmul.f32 q2, q2, q6\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0[0]}, [%[result]]!\n"
|
|
"vst1.32 {d2[0]}, [r0]!\n"
|
|
"vst1.32 {d4[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 2,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 2, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
|
|
// General NxM lanes loop.
|
|
"1:"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vld1.32 {d12, d13, d14}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d15, d16}, [%[rhs]:64]!\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vmull.u8 q9, d15, d12\n"
|
|
"vmull.u8 q10, d16, d12\n"
|
|
"vmull.u8 q11, d15, d13\n"
|
|
"vmull.u8 q12, d16, d13\n"
|
|
"vmull.u8 q13, d15, d14\n"
|
|
"vmull.u8 q14, d16, d14\n"
|
|
"vpadal.u16 q0, q9\n"
|
|
"vpadal.u16 q1, q10\n"
|
|
"vpadal.u16 q2, q11\n"
|
|
"vpadal.u16 q3, q12\n"
|
|
"vpadal.u16 q4, q13\n"
|
|
"vpadal.u16 q5, q14\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d12, d13}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d14, d15}, [%[rhs]:64]!\n"
|
|
"vdup.32 q8, %[scale]\n"
|
|
"vdup.32 q9, d12[0]\n"
|
|
"vdup.32 q10, d12[1]\n"
|
|
"vdup.32 q6, d13[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d4, d4, d6\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d8, d8, d10\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q9\n"
|
|
"vadd.s32 q2, q2, q10\n"
|
|
"vadd.s32 q4, q4, q6\n"
|
|
"vadd.s32 q0, q0, q7\n"
|
|
"vadd.s32 q2, q2, q7\n"
|
|
"vadd.s32 q4, q4, q7\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q2, q2\n"
|
|
"vcvt.f32.s32 q4, q4\n"
|
|
"vmul.f32 q0, q0, q8\n"
|
|
"vmul.f32 q2, q2, q8\n"
|
|
"vmul.f32 q4, q4, q8\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d4}, [r0]!\n"
|
|
"vst1.32 {d8}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"cc", "memory");
|
|
}
|
|
|
|
template <>
|
|
inline void MulKernel<
|
|
uint8_t, float, QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 3,
|
|
8>::Multiply(const uint8_t* lhs, const uint8_t* rhs,
|
|
const FusedKernelParams<QuantizedStaticPreprocessedAsFloat,
|
|
RowMajor>& params,
|
|
float* result) {
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG_METAGEMM_VERBOSE
|
|
std::cout << __FILE__ << "(" << __LINE__
|
|
<< ") QuantizedStaticPreprocessedAsFloatRowMajor<uint8_t, float, "
|
|
"QuantizedStaticPreprocessedAsFloat, RowMajor, 3, 3, "
|
|
"8>::Multiply()"
|
|
<< std::endl
|
|
<< std::flush;
|
|
#endif
|
|
#endif
|
|
asm volatile(
|
|
"pld [%[lhs]]\n"
|
|
"pld [%[rhs]]\n"
|
|
|
|
// Clear aggregators.
|
|
"vmov.i32 q0, #0\n"
|
|
"vmov.i32 q1, #0\n"
|
|
"vmov.i32 q2, #0\n"
|
|
"vmov.i32 q3, q0\n"
|
|
"vmov.i32 q4, q1\n"
|
|
"vmov.i32 q5, q2\n"
|
|
"vmov.i32 q6, q3\n"
|
|
"vmov.i32 q7, q4\n"
|
|
"vmov.i32 q8, q5\n"
|
|
|
|
// 3x3 lanes loop.
|
|
"1:"
|
|
|
|
"vld1.8 {d21, d22, d23}, [%[rhs]:64]!\n"
|
|
"vld1.8 {d18}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q12, d18, d21\n"
|
|
"vld1.8 {d19}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q13, d18, d22\n"
|
|
"vld1.8 {d20}, [%[lhs]:64]!\n"
|
|
"vmull.u8 q14, d18, d23\n"
|
|
"pld [%[lhs], #64]\n"
|
|
"vmull.u8 q15, d19, d21\n"
|
|
"pld [%[rhs], #64]\n"
|
|
"vpadal.u16 q0, q12\n"
|
|
"vpadal.u16 q1, q13\n"
|
|
"vpadal.u16 q2, q14\n"
|
|
"vpadal.u16 q3, q15\n"
|
|
"vmull.u8 q12, d19, d22\n"
|
|
"vmull.u8 q13, d19, d23\n"
|
|
"vmull.u8 q14, d20, d21\n"
|
|
"vmull.u8 q15, d20, d22\n"
|
|
|
|
// Subtract counter.
|
|
"subs %[count], %[count], #8\n"
|
|
|
|
"vmull.u8 q9, d20, d23\n"
|
|
"vpadal.u16 q4, q12\n"
|
|
"vpadal.u16 q5, q13\n"
|
|
"vpadal.u16 q6, q14\n"
|
|
"vpadal.u16 q7, q15\n"
|
|
"vpadal.u16 q8, q9\n"
|
|
|
|
// Loop break.
|
|
"bgt 1b\n"
|
|
|
|
// StaticQuantizationFloat::Prepare
|
|
"vld1.32 {d18, d19}, [%[lhs]:64]!\n"
|
|
"vld1.32 {d20, d21}, [%[rhs]:64]!\n"
|
|
"vdup.32 q11, %[scale]\n"
|
|
"vdup.32 q12, d18[0]\n"
|
|
"vdup.32 q13, d18[1]\n"
|
|
"vdup.32 q9, d19[0]\n"
|
|
|
|
// RowMajorOutput::Prepare
|
|
"add r0, %[result], %[stride]\n"
|
|
"add r1, r0, %[stride]\n"
|
|
|
|
// Reduce aggregators.
|
|
"vpadd.u32 d0, d0, d1\n"
|
|
"vpadd.u32 d2, d2, d3\n"
|
|
"vpadd.u32 d4, d4, d5\n"
|
|
"vpadd.u32 d0, d0, d2\n"
|
|
"vpadd.u32 d1, d4, d4\n"
|
|
"vpadd.u32 d6, d6, d7\n"
|
|
"vpadd.u32 d8, d8, d9\n"
|
|
"vpadd.u32 d10, d10, d11\n"
|
|
"vpadd.u32 d6, d6, d8\n"
|
|
"vpadd.u32 d7, d10, d10\n"
|
|
"vpadd.u32 d12, d12, d13\n"
|
|
"vpadd.u32 d14, d14, d15\n"
|
|
"vpadd.u32 d16, d16, d17\n"
|
|
"vpadd.u32 d12, d12, d14\n"
|
|
"vpadd.u32 d13, d16, d16\n"
|
|
|
|
// StaticQuantizationFloat::Transform
|
|
"vadd.s32 q0, q0, q12\n"
|
|
"vadd.s32 q3, q3, q13\n"
|
|
"vadd.s32 q6, q6, q9\n"
|
|
"vadd.s32 q0, q0, q10\n"
|
|
"vadd.s32 q3, q3, q10\n"
|
|
"vadd.s32 q6, q6, q10\n"
|
|
"vcvt.f32.s32 q0, q0\n"
|
|
"vcvt.f32.s32 q3, q3\n"
|
|
"vcvt.f32.s32 q6, q6\n"
|
|
"vmul.f32 q0, q0, q11\n"
|
|
"vmul.f32 q3, q3, q11\n"
|
|
"vmul.f32 q6, q6, q11\n"
|
|
|
|
// RowMajorOutput::Output
|
|
"vst1.32 {d0}, [%[result]]!\n"
|
|
"vst1.32 {d1[0]}, [%[result]]!\n"
|
|
"vst1.32 {d6}, [r0]!\n"
|
|
"vst1.32 {d7[0]}, [r0]!\n"
|
|
"vst1.32 {d12}, [r1]!\n"
|
|
"vst1.32 {d13[0]}, [r1]!\n"
|
|
: [rhs] "+r"(rhs), [lhs] "+r"(lhs), [result] "+r"(result)
|
|
: [count] "r"(params.kernel.count),
|
|
[stride] "r"(params.output_stream.stride),
|
|
[scale] "r"(params.kernel.scale)
|
|
: "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
|
|
"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
|
|
"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
|
|
"d30", "d31", "cc", "memory");
|
|
}
|
|
|
|
} // namespace meta
|
|
} // namespace gemmlowp
|
|
|
|
#else
|
|
#warning "Meta gemm for arm32 requires: GEMMLOWP_NEON_32!"
|
|
#endif
|
|
|
|
#endif // GEMMLOWP_META_QUANTIZED_MUL_KERNELS_ARM_32_H_
|