提交 4e51e5fd 编写于 作者: R Ray Liu 提交者: GitHub

Merge branch 'develop' into develop

......@@ -16,7 +16,6 @@ limitations under the License. */
#pragma once
#include <vector>
#include "operators/math/conv_arm_int8.h"
#include "operators/math/conv_func.h"
#include "operators/math/depthwise_conv_3x3.h"
#include "operators/math/im2col.h"
......@@ -28,11 +27,12 @@ limitations under the License. */
namespace paddle_mobile {
namespace operators {
template <typename Dtype>
template <typename Itype, typename Otype>
inline void ConvBasic(const ConvParam<CPU> &param) {
const Tensor *input = param.Input();
Tensor filter = *param.Filter();
Tensor *output = param.Output();
output->mutable_data<Otype>();
int groups = param.Groups();
const std::vector<int> strides = param.Strides();
const std::vector<int> paddings = param.Paddings();
......@@ -60,7 +60,7 @@ inline void ConvBasic(const ConvParam<CPU> &param) {
Tensor col;
Tensor col_matrix;
if (is_expand) {
col.mutable_data<Dtype>(col_shape);
col.mutable_data<Itype>(col_shape);
col_matrix.ShareDataWith(col);
col_matrix.Resize(col_matrix_shape);
}
......@@ -79,8 +79,8 @@ inline void ConvBasic(const ConvParam<CPU> &param) {
int in_step = static_cast<int>(input->dims()[1]) / groups;
int out_step = static_cast<int>(output->dims()[1]) / groups;
math::Vol2ColFunctor<CPU, Dtype> vol2col;
math::Im2ColFunctor<math::ColFormat::kCFO, CPU, Dtype> im2col;
math::Vol2ColFunctor<CPU, Itype> vol2col;
math::Im2ColFunctor<math::ColFormat::kCFO, CPU, Itype> im2col;
for (int i = 0; i < batch_size; i++) {
Tensor in_batch = input->Slice(i, i + 1).Resize(input_shape);
......@@ -109,69 +109,18 @@ inline void ConvBasic(const ConvParam<CPU> &param) {
Tensor out_slice = out_batch.Slice(g * out_step, (g + 1) * out_step);
Tensor filter_slice = filter.Slice(g * out_step, (g + 1) * out_step);
math::matmul<Dtype>(filter_slice, false, col_matrix, false,
math::matmul<Itype>(filter_slice, false, col_matrix, false,
static_cast<float>(1), &out_slice,
static_cast<float>(0));
}
}
}
inline void ConvCompute_int8(const ConvParam<CPU> &param) {
typedef void (*ConvFunc)(const Tensor &input, const Tensor &kernel,
Tensor *output);
static ConvFunc conv_funcs_table[7][5] = {
{0, 0, 0, 0, 0}, // k = 1
{0, 0, 0, 0, 0}, {conv3x3s1_int8, 0, 0, 0, 0}, // k = 3
{0, 0, 0, 0, 0}, {conv5x5s1_int8, 0, 0, 0, 0}, // k = 5
{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, // k = 7
};
const Tensor *input = param.Input();
Tensor *filter = param.Filter();
Tensor *output = param.Output();
int groups = param.Groups();
const std::vector<int> &strides = param.Strides();
const std::vector<int> &paddings = param.Paddings();
const std::vector<int> &dilations = param.Dilations();
int kernel_h = filter->dims()[2];
int kernel_w = filter->dims()[3];
output->mutable_data<int32_t>();
ConvFunc conv_func = 0;
if (strides[1] == strides[0] && strides[1] < 6 && kernel_h == kernel_w &&
kernel_h < 8 && groups == 1 && dilations[0] == dilations[1] &&
dilations[1] == 1) {
conv_func = conv_funcs_table[kernel_h - 1][strides[0] - 1];
}
if (conv_func) {
int batch_size = input->dims()[0];
math::PadFunctor<CPU, int8_t> pad;
Tensor input_pad;
for (int i = 0; i < batch_size; ++i) {
Tensor in_batch = input->Slice(i, i + 1);
Tensor out_batch = output->Slice(i, i + 1);
if (paddings[0] == 0 && paddings[1] == 0) {
input_pad = in_batch;
} else {
framework::DDim pad_shape = in_batch.dims();
pad_shape[2] += 2 * paddings[0];
pad_shape[3] += 2 * paddings[1];
input_pad.mutable_data<int8_t>(pad_shape);
pad(in_batch, paddings[0], paddings[1], &input_pad);
}
conv_func(input_pad, *filter, &out_batch);
}
} else {
ConvBasic<int8_t>(param);
}
}
template <typename P>
void ConvCompute(const ConvParam<CPU> &param) {
if (param.Input()->type() == typeid(int8_t)) {
ConvCompute_int8(param);
ConvBasic<int8_t, int32_t>(param);
} else {
param.Output()->mutable_data<float>();
if (param.Groups() == param.Input()->dims()[1] &&
param.Input()->dims()[1] == param.Output()->dims()[1] &&
param.Filter()->dims()[2] == param.Filter()->dims()[3] &&
......@@ -185,7 +134,7 @@ void ConvCompute(const ConvParam<CPU> &param) {
math::DepthwiseConv3x3(param.Input(), param.Strides(), param.Paddings(),
param.Filter(), nullptr, param.Output(), false);
} else {
ConvBasic<float>(param);
ConvBasic<float, float>(param);
}
}
}
......
......@@ -44,7 +44,7 @@ void DepthwiseConvCompute(const ConvParam<CPU> &param) {
Bias, false);
} else {
ConvBasic<float>(param);
ConvBasic<float, float>(param);
}
}
......
/* Copyright (c) 2018 PaddlePaddle 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. */
#ifdef CONV_OP
#include "operators/math/conv_arm_int8.h"
namespace paddle_mobile {
namespace operators {
void conv3x3s1_int8(const framework::Tensor& input,
const framework::Tensor& weight,
framework::Tensor* output) {
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
const int8_t* in_data = input.data<int8_t>();
const int8_t* w_data = weight.data<int8_t>();
int32_t* out_data = output->mutable_data<int32_t>();
// make sure that batch size is 1
int input_c = input.dims()[1];
int input_h = input.dims()[2];
int input_w = input.dims()[3];
int output_c = output->dims()[1];
int output_h = output->dims()[2];
int output_w = output->dims()[3];
int image_size = input_h * input_w;
int out_image_size = output_h * output_w;
memset(out_data, 0, output_c * out_image_size * sizeof(int32_t));
#if __aarch64__
// TODO(hjchen2)
#else
int oc = 0;
#pragma omp parallel for
for (; oc < output_c - 1; oc += 2) {
for (int ic = 0; ic < input_c; ++ic) {
const int8_t* kernel0 = w_data + (oc * input_c + ic) * 9;
const int8_t* kernel1 = w_data + ((oc + 1) * input_c + ic) * 9;
int32_t* output0 = out_data + oc * out_image_size;
int32_t* output0n = output0 + output_w;
int32_t* output1 = out_data + (oc + 1) * out_image_size;
int32_t* output1n = output1 + output_w;
int oh = 0;
for (; oh < output_h - 1; oh += 2) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
const int8_t* r3 = r2 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"vld1.8 {d1}, [%[kernel1]] \n"
"ldr r6, [%[kernel1], #8] \n"
"0: \n"
"vld1.8 {d2-d3}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[0] \n"
"vdup.s8 d7, d0[1] \n"
"vdup.s8 d8, d0[2] \n"
"vdup.s8 d9, d1[0] \n"
"vdup.s8 d10, d1[1] \n"
"vdup.s8 d11, d1[2] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q12, d12, d14 \n"
"vaddl.s16 q13, d13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddl.s16 q14, d12, d14 \n"
"vaddl.s16 q15, d13, d15 \n"
"vld1.8 {d2-d3}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q8, d12, d14 \n"
"vaddl.s16 q9, d13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddl.s16 q10, d12, d14 \n"
"vaddl.s16 q11, d13, d15 \n"
"vdup.s8 d6, d0[3] \n"
"vdup.s8 d7, d0[4] \n"
"vdup.s8 d8, d0[5] \n"
"vdup.s8 d9, d1[3] \n"
"vdup.s8 d10, d1[4] \n"
"vdup.s8 d11, d1[5] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q14, q14, d12 \n"
"vaddw.s16 q15, q15, d13 \n"
"vaddw.s16 q14, q14, d14 \n"
"vaddw.s16 q15, q15, d15 \n"
"vld1.8 {d2-d3}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q8, q8, d12 \n"
"vaddw.s16 q8, q8, d14 \n"
"vaddw.s16 q9, q9, d13 \n"
"vaddw.s16 q9, q9, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q10, q10, d12 \n"
"vaddw.s16 q11, q11, d13 \n"
"vaddw.s16 q10, q10, d14 \n"
"vaddw.s16 q11, q11, d15 \n"
"vdup.s8 d6, d0[6] \n"
"vdup.s8 d7, d0[7] \n"
"vdup.s8 d8, r5 \n"
"vdup.s8 d9, d1[6] \n"
"vdup.s8 d10, d1[7] \n"
"vdup.s8 d11, r6 \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d15 \n"
"vld1.32 {d12-d15}, [%[output0]] \n"
"vadd.s32 q6, q6, q12 \n"
"vadd.s32 q7, q7, q13 \n"
"vst1.32 {d12-d15}, [%[output0]]! \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q14, q14, d12 \n"
"vaddw.s16 q15, q15, d13 \n"
"vaddw.s16 q14, q14, d14 \n"
"vaddw.s16 q15, q15, d15 \n"
"vld1.32 {d12-d15}, [%[output1]] \n"
"vadd.s32 q6, q6, q14 \n"
"vadd.s32 q7, q7, q15 \n"
"vst1.32 {d12-d15}, [%[output1]]! \n"
"vld1.8 {d2-d3}, [%[r3]] \n" // r3
"add %[r3], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q8, q8, d12 \n"
"vaddw.s16 q9, q9, d15 \n"
"vaddw.s16 q8, q8, d14 \n"
"vaddw.s16 q9, q9, d13 \n"
"vld1.32 {d12-d15}, [%[output0n]] \n"
"vadd.s32 q6, q6, q8 \n"
"vadd.s32 q7, q7, q9 \n"
"vst1.32 {d12-d15}, [%[output0n]]! \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q10, q10, d12 \n"
"vaddw.s16 q11, q11, d15 \n"
"vaddw.s16 q10, q10, d14 \n"
"vaddw.s16 q11, q11, d13 \n"
"vld1.32 {d12-d15}, [%[output1n]] \n"
"vadd.s32 q6, q6, q10 \n"
"vadd.s32 q7, q7, q11 \n"
"vst1.32 {d12-d15}, [%[output1n]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[ow] "+r"(ow), [output0] "+r"(output0), [output1] "+r"(output1),
[output0n] "+r"(output0n), [output1n] "+r"(output1n)
: [kernel0] "r"(kernel0), [kernel1] "r"(kernel1)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "r5",
"r6");
}
if (remain > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"vld1.8 {d1}, [%[kernel1]] \n"
"ldr r6, [%[kernel1], #8] \n"
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"vld1.8 d7, [%[r3]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"add %[r3], #1 \n"
"vdup.s8 d2, r5 \n"
"vdup.s8 d3, r6 \n"
"vext.8 d8, d0, d2, #3 \n"
"vext.8 d9, d0, d2, #6 \n"
"vext.8 d10, d1, d3, #3 \n"
"vext.8 d11, d1, d3, #6 \n"
"vmull.s8 q6, d4, d0 \n"
"vmull.s8 q7, d5, d8 \n"
"vmlal.s8 q6, d6, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"vmull.s8 q6, d4, d1 \n"
"vmull.s8 q7, d5, d10 \n"
"vmlal.s8 q6, d6, d11 \n"
"vaddl.s16 q13, d12, d14 \n"
"vdup.s32 d2, d26[1] \n"
"vadd.s32 d26, d26, d2 \n"
"vadd.s32 d26, d26, d27 \n"
"ldr r7, [%[output0]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0]]! \n"
"ldr r7, [%[output1]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d26 \n"
"vst1.32 d14[0], [%[output1]]! \n"
"vmull.s8 q6, d5, d0 \n"
"vmull.s8 q7, d6, d8 \n"
"vmlal.s8 q6, d7, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"vmull.s8 q6, d5, d1 \n"
"vmull.s8 q7, d6, d10 \n"
"vmlal.s8 q6, d7, d11 \n"
"vaddl.s16 q13, d12, d14 \n"
"vdup.s32 d2, d26[1] \n"
"vadd.s32 d26, d26, d2 \n"
"vadd.s32 d26, d26, d27 \n"
"ldr r7, [%[output0n]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0n]]! \n"
"ldr r7, [%[output1n]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d26 \n"
"vst1.32 d14[0], [%[output1n]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[remain] "+r"(remain), [output0] "+r"(output0),
[output1] "+r"(output1), [output0n] "+r"(output0n),
[output1n] "+r"(output1n)
: [kernel0] "r"(kernel0), [kernel1] "r"(kernel1)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r5", "r6", "r7");
}
output0 += output_w;
output1 += output_w;
output0n += output_w;
output1n += output_w;
}
// remain output height
for (; oh < output_h; ++oh) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
const int8_t* r3 = r2 + input_w;
const int8_t* r4 = r3 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"vld1.8 {d1}, [%[kernel1]] \n"
"ldr r6, [%[kernel1], #8] \n"
"0: \n"
"vld1.8 {d2-d3}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[0] \n"
"vdup.s8 d7, d0[1] \n"
"vdup.s8 d8, d0[2] \n"
"vdup.s8 d9, d1[0] \n"
"vdup.s8 d10, d1[1] \n"
"vdup.s8 d11, d1[2] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q12, d12, d14 \n"
"vaddl.s16 q13, d13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddl.s16 q14, d12, d14 \n"
"vaddl.s16 q15, d13, d15 \n"
"vld1.8 {d2-d3}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[3] \n"
"vdup.s8 d7, d0[4] \n"
"vdup.s8 d8, d0[5] \n"
"vdup.s8 d9, d1[3] \n"
"vdup.s8 d10, d1[4] \n"
"vdup.s8 d11, d1[5] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q14, q14, d12 \n"
"vaddw.s16 q14, q14, d14 \n"
"vaddw.s16 q15, q15, d13 \n"
"vaddw.s16 q15, q15, d15 \n"
"vld1.8 {d2-d3}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[6] \n"
"vdup.s8 d7, d0[7] \n"
"vdup.s8 d8, r5 \n"
"vdup.s8 d9, d1[6] \n"
"vdup.s8 d10, d1[7] \n"
"vdup.s8 d11, r6 \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vmull.s8 q6, d2, d9 \n"
"vmull.s8 q7, d4, d10 \n"
"vmlal.s8 q6, d5, d11 \n"
"vaddw.s16 q14, q14, d12 \n"
"vaddw.s16 q14, q14, d14 \n"
"vaddw.s16 q15, q15, d13 \n"
"vaddw.s16 q15, q15, d15 \n"
"vld1.32 {d12-d15}, [%[output0]] \n"
"vadd.s32 q6, q6, q12 \n"
"vadd.s32 q7, q7, q13 \n"
"vst1.32 {d12-d15}, [%[output0]]! \n"
"vld1.32 {d12-d15}, [%[output1]] \n"
"vadd.s32 q6, q6, q14 \n"
"vadd.s32 q7, q7, q15 \n"
"vst1.32 {d12-d15}, [%[output1]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [ow] "+r"(ow),
[output0] "+r"(output0), [output1] "+r"(output1)
: [kernel0] "r"(kernel0), [kernel1] "r"(kernel1)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "r5",
"r6");
}
if (remain > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"vld1.8 {d1}, [%[kernel1]] \n"
"ldr r6, [%[kernel1], #8] \n"
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"vdup.s8 d2, r5 \n"
"vdup.s8 d3, r6 \n"
"vext.8 d8, d0, d2, #3 \n"
"vext.8 d9, d0, d2, #6 \n"
"vext.8 d10, d1, d3, #3 \n"
"vext.8 d11, d1, d3, #6 \n"
"vmull.s8 q6, d4, d0 \n"
"vmull.s8 q7, d5, d8 \n"
"vmlal.s8 q6, d6, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"vmull.s8 q6, d4, d1 \n"
"vmull.s8 q7, d5, d10 \n"
"vmlal.s8 q6, d6, d11 \n"
"vaddl.s16 q13, d12, d14 \n"
"vdup.s32 d2, d26[1] \n"
"vadd.s32 d26, d26, d2 \n"
"vadd.s32 d26, d26, d27 \n"
"ldr r7, [%[output0]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0]]! \n"
"ldr r7, [%[output1]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d26 \n"
"vst1.32 d14[0], [%[output1]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2),
[remain] "+r"(remain), [output0] "+r"(output0),
[output1] "+r"(output1)
: [kernel0] "r"(kernel0), [kernel1] "r"(kernel1)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r5", "r6", "r7");
}
}
}
}
for (; oc < output_c; ++oc) {
for (int ic = 0; ic < input_c; ++ic) {
const int8_t* kernel0 = w_data + (oc * input_c + ic) * 9;
int32_t* output0 = out_data + oc * out_image_size;
int32_t* output0n = output0 + output_w;
int oh = 0;
for (; oh < output_h - 1; oh += 2) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
const int8_t* r3 = r2 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"0: \n"
"vld1.8 {d2-d3}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[0] \n"
"vdup.s8 d7, d0[1] \n"
"vdup.s8 d8, d0[2] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q12, d12, d14 \n"
"vaddl.s16 q13, d13, d15 \n"
"vld1.8 {d2-d3}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q8, d12, d14 \n"
"vaddl.s16 q9, d13, d15 \n"
"vdup.s8 d6, d0[3] \n"
"vdup.s8 d7, d0[4] \n"
"vdup.s8 d8, d0[5] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vld1.8 {d2-d3}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q8, q8, d12 \n"
"vaddw.s16 q8, q8, d14 \n"
"vaddw.s16 q9, q9, d13 \n"
"vaddw.s16 q9, q9, d15 \n"
"vdup.s8 d6, d0[6] \n"
"vdup.s8 d7, d0[7] \n"
"vdup.s8 d8, r5 \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vld1.32 {d12-d15}, [%[output0]] \n"
"vadd.s32 q6, q6, q12 \n"
"vadd.s32 q7, q7, q13 \n"
"vst1.32 {d12-d15}, [%[output0]]! \n"
"vld1.8 {d2-d3}, [%[r3]] \n" // r3
"add %[r3], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vmull.s8 q6, d2, d6 \n" // next row
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q8, q8, d12 \n"
"vaddw.s16 q8, q8, d14 \n"
"vaddw.s16 q9, q9, d13 \n"
"vaddw.s16 q9, q9, d15 \n"
"vld1.32 {d12-d15}, [%[output0n]] \n"
"vadd.s32 q6, q6, q8 \n"
"vadd.s32 q7, q7, q9 \n"
"vst1.32 {d12-d15}, [%[output0n]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[ow] "+r"(ow), [output0] "+r"(output0),
[output0n] "+r"(output0n)
: [kernel0] "r"(kernel0)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "r5");
}
if (remain > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"vld1.8 d7, [%[r3]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"add %[r3], #1 \n"
"vdup.s8 d2, r5 \n"
"vext.8 d8, d0, d2, #3 \n"
"vext.8 d9, d0, d2, #6 \n"
"vmull.s8 q6, d4, d0 \n"
"vmull.s8 q7, d5, d8 \n"
"vmlal.s8 q6, d6, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"ldr r7, [%[output0]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0]]! \n"
"vmull.s8 q6, d5, d0 \n"
"vmull.s8 q7, d6, d8 \n"
"vmlal.s8 q6, d7, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"ldr r7, [%[output0n]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0n]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[remain] "+r"(remain), [output0] "+r"(output0),
[output0n] "+r"(output0n)
: [kernel0] "r"(kernel0)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r5", "r7");
}
output0 += output_w;
output0n += output_w;
}
// remain output height
for (; oh < output_h; ++oh) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"0: \n"
"vld1.8 {d2-d3}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[0] \n"
"vdup.s8 d7, d0[1] \n"
"vdup.s8 d8, d0[2] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddl.s16 q12, d12, d14 \n"
"vaddl.s16 q13, d13, d15 \n"
"vld1.8 {d2-d3}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[3] \n"
"vdup.s8 d7, d0[4] \n"
"vdup.s8 d8, d0[5] \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vld1.8 {d2-d3}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d4, d2, d3, #1 \n"
"vext.8 d5, d2, d3, #2 \n"
"vdup.s8 d6, d0[6] \n"
"vdup.s8 d7, d0[7] \n"
"vdup.s8 d8, r5 \n"
"vmull.s8 q6, d2, d6 \n"
"vmull.s8 q7, d4, d7 \n"
"vmlal.s8 q6, d5, d8 \n"
"vaddw.s16 q12, q12, d12 \n"
"vaddw.s16 q12, q12, d14 \n"
"vaddw.s16 q13, q13, d13 \n"
"vaddw.s16 q13, q13, d15 \n"
"vld1.32 {d12-d15}, [%[output0]] \n"
"vadd.s32 q6, q6, q12 \n"
"vadd.s32 q7, q7, q13 \n"
"vst1.32 {d12-d15}, [%[output0]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [ow] "+r"(ow),
[output0] "+r"(output0)
: [kernel0] "r"(kernel0)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "r5");
}
if (remain > 0) {
asm volatile(
"vld1.8 {d0}, [%[kernel0]] \n"
"ldr r5, [%[kernel0], #8] \n"
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"vdup.s8 d2, r5 \n"
"vext.8 d8, d0, d2, #3 \n"
"vext.8 d9, d0, d2, #6 \n"
"vmull.s8 q6, d4, d0 \n"
"vmull.s8 q7, d5, d8 \n"
"vmlal.s8 q6, d6, d9 \n"
"vaddl.s16 q12, d12, d14 \n"
"vdup.s32 d2, d24[1] \n"
"vadd.s32 d24, d24, d2 \n"
"vadd.s32 d24, d24, d25 \n"
"ldr r7, [%[output0]] \n"
"vdup.s32 d14, r7 \n"
"vadd.s32 d14, d14, d24 \n"
"vst1.32 d14[0], [%[output0]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2),
[remain] "+r"(remain), [output0] "+r"(output0)
: [kernel0] "r"(kernel0)
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r5", "r7");
}
}
}
}
#endif
#else
// TODO(hjchen2)
#endif
}
} // namespace operators
} // namespace paddle_mobile
#endif
/* Copyright (c) 2018 PaddlePaddle 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. */
#ifdef CONV_OP
#include "operators/math/conv_arm_int8.h"
namespace paddle_mobile {
namespace operators {
void conv5x5s1_int8(const framework::Tensor& input,
const framework::Tensor& weight,
framework::Tensor* output) {
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
const int8_t* in_data = input.data<int8_t>();
const int8_t* w_data = weight.data<int8_t>();
int32_t* out_data = output->mutable_data<int32_t>();
// make sure that batch size is 1
int input_c = input.dims()[1];
int input_h = input.dims()[2];
int input_w = input.dims()[3];
int output_c = output->dims()[1];
int output_h = output->dims()[2];
int output_w = output->dims()[3];
int image_size = input_h * input_w;
int out_image_size = output_h * output_w;
memset(out_data, 0, output_c * out_image_size * sizeof(int32_t));
#if __aarch64__
// TODO(hjchen2)
#else
#pragma omp parallel for
for (int oc = 0; oc < output_c; ++oc) {
for (int ic = 0; ic < input_c; ++ic) {
const int8_t* kernel = w_data + (oc * input_c + ic) * 25;
int32_t* output0 = out_data + oc * out_image_size;
int32_t* output1 = output0 + output_w;
int oh = 0;
for (; oh < output_h - 1; oh += 2) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
const int8_t* r3 = r2 + input_w;
const int8_t* r4 = r3 + input_w;
const int8_t* r5 = r4 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile("vld1.8 {d0-d3}, [%[kernel]] \n"
: [kernel] "+r"(kernel)
:
: "cc", "memory", "q0", "q1");
asm volatile(
"0: \n"
"vld1.8 {d4-d5}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d0[0] \n"
"vdup.s8 d11, d0[1] \n"
"vdup.s8 d12, d0[2] \n"
"vdup.s8 d13, d0[3] \n"
"vdup.s8 d14, d0[4] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q14, d16, d18 \n"
"vaddl.s16 q15, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q14, q14, d16 \n"
"vaddw.s16 q15, q15, d17 \n"
"vld1.8 {d4-d5}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vmull.s8 q8, d4, d10 \n" // next row
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q10, d16, d18 \n"
"vaddl.s16 q11, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q10, q10, d16 \n"
"vaddw.s16 q11, q11, d17 \n"
"vdup.s8 d10, d0[5] \n"
"vdup.s8 d11, d0[6] \n"
"vdup.s8 d12, d0[7] \n"
"vdup.s8 d13, d1[0] \n"
"vdup.s8 d14, d1[1] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vmull.s8 q8, d4, d10 \n" // next row
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q10, q10, q12 \n"
"vadd.s32 q11, q11, q13 \n"
"vdup.s8 d10, d1[2] \n"
"vdup.s8 d11, d1[3] \n"
"vdup.s8 d12, d1[4] \n"
"vdup.s8 d13, d1[5] \n"
"vdup.s8 d14, d1[6] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r3]] \n" // r3
"add %[r3], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vmull.s8 q8, d4, d10 \n" // next row
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q10, q10, q12 \n"
"vadd.s32 q11, q11, q13 \n"
"vdup.s8 d10, d1[7] \n"
"vdup.s8 d11, d2[0] \n"
"vdup.s8 d12, d2[1] \n"
"vdup.s8 d13, d2[2] \n"
"vdup.s8 d14, d2[3] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r4]] \n" // r4
"add %[r4], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vmull.s8 q8, d4, d10 \n" // next row
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q10, q10, q12 \n"
"vadd.s32 q11, q11, q13 \n"
"vdup.s8 d10, d2[4] \n"
"vdup.s8 d11, d2[5] \n"
"vdup.s8 d12, d2[6] \n"
"vdup.s8 d13, d2[7] \n"
"vdup.s8 d14, d3[0] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.32 {d24-d27}, [%[output0]] \n"
"vadd.s32 q12, q12, q14 \n"
"vadd.s32 q13, q13, q15 \n"
"vst1.32 {d24-d27}, [%[output0]]! \n"
"vld1.8 {d4-d5}, [%[r5]] \n" // row 5
"add %[r5], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q10, q10, q12 \n"
"vadd.s32 q11, q11, q13 \n"
"vld1.32 {d24-d27}, [%[output1]] \n"
"vadd.s32 q12, q12, q10 \n"
"vadd.s32 q13, q13, q11 \n"
"vst1.32 {d24-d27}, [%[output1]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[r4] "+r"(r4), [r5] "+r"(r5), [ow] "+r"(ow),
[output0] "+r"(output0), [output1] "+r"(output1)
:
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15");
}
if (remain > 0) {
asm volatile("vld1.8 {d0-d3}, [%[kernel]] \n"
: [kernel] "+r"(kernel)
:
: "cc", "memory", "q0", "q1");
asm volatile(
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"vld1.8 d7, [%[r3]] \n"
"vld1.8 d8, [%[r4]] \n"
"vld1.8 d9, [%[r5]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"add %[r3], #1 \n"
"add %[r4], #1 \n"
"add %[r5], #1 \n"
"vext.8 d10, d0, d1, #5 \n"
"vext.8 d11, d1, d2, #2 \n"
"vext.8 d12, d1, d2, #7 \n"
"vext.8 d13, d2, d3, #4 \n"
"vmull.s8 q7, d4, d0 \n"
"vmull.s8 q8, d5, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q10, d14, d16 \n"
"vaddw.s16 q10, q10, d18 \n"
"vadd.s32 d4, d20, d21 \n"
"vaddl.s16 q10, d15, d17 \n"
"vaddw.s16 q10, q10, d19 \n"
"vdup.s32 d14, d4[0] \n"
"vdup.s32 d15, d4[1] \n"
"vadd.s32 d15, d15, d14 \n"
"vdup.s32 d14, d20[0] \n"
"vadd.s32 d15, d15, d14 \n"
"ldr r6, [%[output0]] \n"
"vdup.s32 d14, r6 \n"
"vadd.s32 d15, d15, d14 \n"
"vst1.32 d15[0], [%[output0]]! \n"
"vmull.s8 q7, d5, d0 \n"
"vmull.s8 q8, d6, d10 \n"
"vmull.s8 q9, d7, d11 \n"
"vmlal.s8 q8, d8, d12 \n"
"vmlal.s8 q9, d9, d13 \n"
"vaddl.s16 q10, d14, d16 \n"
"vaddw.s16 q10, q10, d18 \n"
"vadd.s32 d4, d20, d21 \n"
"vaddl.s16 q10, d15, d17 \n"
"vaddw.s16 q10, q10, d19 \n"
"vdup.s32 d14, d4[0] \n"
"vdup.s32 d15, d4[1] \n"
"vadd.s32 d15, d15, d14 \n"
"vdup.s32 d14, d20[0] \n"
"vadd.s32 d15, d15, d14 \n"
"ldr r6, [%[output1]] \n"
"vdup.s32 d14, r6 \n"
"vadd.s32 d15, d15, d14 \n"
"vst1.32 d15[0], [%[output1]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[r4] "+r"(r4), [r5] "+r"(r5), [remain] "+r"(remain),
[output0] "+r"(output0), [output1] "+r"(output1)
:
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r6");
}
output0 += output_w;
output1 += output_w;
}
// remain output height
for (; oh < output_h; ++oh) {
const int8_t* r0 = in_data + ic * image_size + oh * input_w;
const int8_t* r1 = r0 + input_w;
const int8_t* r2 = r1 + input_w;
const int8_t* r3 = r2 + input_w;
const int8_t* r4 = r3 + input_w;
int ow = output_w >> 3;
int remain = output_w & 0x7;
if (ow > 0) {
asm volatile("vld1.8 {d0-d3}, [%[kernel]] \n"
: [kernel] "+r"(kernel)
:
: "cc", "memory", "q0", "q1");
asm volatile(
"0: \n"
"vld1.8 {d4-d5}, [%[r0]] \n" // r0
"add %[r0], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d0[0] \n"
"vdup.s8 d11, d0[1] \n"
"vdup.s8 d12, d0[2] \n"
"vdup.s8 d13, d0[3] \n"
"vdup.s8 d14, d0[4] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q14, d16, d18 \n"
"vaddl.s16 q15, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q14, q14, d16 \n"
"vaddw.s16 q15, q15, d17 \n"
"vld1.8 {d4-d5}, [%[r1]] \n" // r1
"add %[r1], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d0[5] \n"
"vdup.s8 d11, d0[6] \n"
"vdup.s8 d12, d0[7] \n"
"vdup.s8 d13, d1[0] \n"
"vdup.s8 d14, d1[1] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r2]] \n" // r2
"add %[r2], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d1[2] \n"
"vdup.s8 d11, d1[3] \n"
"vdup.s8 d12, d1[4] \n"
"vdup.s8 d13, d1[5] \n"
"vdup.s8 d14, d1[6] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r3]] \n" // r3
"add %[r3], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d1[7] \n"
"vdup.s8 d11, d2[0] \n"
"vdup.s8 d12, d2[1] \n"
"vdup.s8 d13, d2[2] \n"
"vdup.s8 d14, d2[3] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.8 {d4-d5}, [%[r4]] \n" // r4
"add %[r4], #8 \n"
"vext.8 d6, d4, d5, #1 \n"
"vext.8 d7, d4, d5, #2 \n"
"vext.8 d8, d4, d5, #3 \n"
"vext.8 d9, d4, d5, #4 \n"
"vdup.s8 d10, d2[4] \n"
"vdup.s8 d11, d2[5] \n"
"vdup.s8 d12, d2[6] \n"
"vdup.s8 d13, d2[7] \n"
"vdup.s8 d14, d3[0] \n"
"vmull.s8 q8, d4, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q12, d16, d18 \n"
"vaddl.s16 q13, d17, d19 \n"
"vmull.s8 q8, d9, d14 \n"
"vaddw.s16 q12, q12, d16 \n"
"vaddw.s16 q13, q13, d17 \n"
"vadd.s32 q14, q14, q12 \n"
"vadd.s32 q15, q15, q13 \n"
"vld1.32 {d24-d27}, [%[output0]] \n"
"vadd.s32 q12, q12, q14 \n"
"vadd.s32 q13, q13, q15 \n"
"vst1.32 {d24-d27}, [%[output0]]! \n"
"subs %[ow], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[r4] "+r"(r4), [ow] "+r"(ow), [output0] "+r"(output0)
:
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15");
}
if (remain > 0) {
asm volatile("vld1.8 {d0-d3}, [%[kernel]] \n"
: [kernel] "+r"(kernel)
:
: "cc", "memory", "q0", "q1");
asm volatile(
"0: \n"
"vld1.8 d4, [%[r0]] \n"
"vld1.8 d5, [%[r1]] \n"
"vld1.8 d6, [%[r2]] \n"
"vld1.8 d7, [%[r3]] \n"
"vld1.8 d8, [%[r4]] \n"
"add %[r0], #1 \n"
"add %[r1], #1 \n"
"add %[r2], #1 \n"
"add %[r3], #1 \n"
"add %[r4], #1 \n"
"vext.8 d10, d0, d1, #5 \n"
"vext.8 d11, d1, d2, #2 \n"
"vext.8 d12, d1, d2, #7 \n"
"vext.8 d13, d2, d3, #4 \n"
"vmull.s8 q7, d4, d0 \n"
"vmull.s8 q8, d5, d10 \n"
"vmull.s8 q9, d6, d11 \n"
"vmlal.s8 q8, d7, d12 \n"
"vmlal.s8 q9, d8, d13 \n"
"vaddl.s16 q10, d14, d16 \n"
"vaddw.s16 q10, q10, d18 \n"
"vadd.s32 d4, d20, d21 \n"
"vaddl.s16 q10, d15, d17 \n"
"vaddw.s16 q10, q10, d19 \n"
"vdup.s32 d14, d4[0] \n"
"vdup.s32 d15, d4[1] \n"
"vadd.s32 d15, d15, d14 \n"
"vdup.s32 d14, d20[0] \n"
"vadd.s32 d15, d15, d14 \n"
"ldr r6, [%[output0]] \n"
"vdup.s32 d14, r6 \n"
"vadd.s32 d15, d15, d14 \n"
"vst1.32 d15[0], [%[output0]]! \n"
"subs %[remain], #1 \n"
"bne 0b \n"
: [r0] "+r"(r0), [r1] "+r"(r1), [r2] "+r"(r2), [r3] "+r"(r3),
[r4] "+r"(r4), [remain] "+r"(remain), [output0] "+r"(output0)
:
: "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "r6");
}
}
}
}
#endif
#else
// TODO(hjchen2)
#endif
}
} // namespace operators
} // namespace paddle_mobile
#endif
/* Copyright (c) 2018 PaddlePaddle 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. */
#ifdef CONV_OP
#pragma once
#include "framework/tensor.h"
namespace paddle_mobile {
namespace operators {
void conv3x3s1_int8(const framework::Tensor& input,
const framework::Tensor& weight, framework::Tensor* output);
void conv3x3s1_int8_4c(const framework::Tensor& input,
const framework::Tensor& weight,
framework::Tensor* output);
void conv5x5s1_int8(const framework::Tensor& input,
const framework::Tensor& weight, framework::Tensor* output);
} // namespace operators
} // namespace paddle_mobile
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册