Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle-Lite
提交
2d300f69
P
Paddle-Lite
项目概览
PaddlePaddle
/
Paddle-Lite
通知
331
Star
4
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
271
列表
看板
标记
里程碑
合并请求
78
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle-Lite
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
271
Issue
271
列表
看板
标记
里程碑
合并请求
78
合并请求
78
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
2d300f69
编写于
10月 17, 2018
作者:
H
hjchen2
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Refine 3x3 int8 conv implementation
上级
7080e22b
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
701 addition
and
1087 deletion
+701
-1087
src/operators/kernel/central-arm-func/conv3x3_arm_int8.cpp
src/operators/kernel/central-arm-func/conv3x3_arm_int8.cpp
+691
-1081
test/CMakeLists.txt
test/CMakeLists.txt
+4
-0
test/operators/test_int8_conv_op.cpp
test/operators/test_int8_conv_op.cpp
+6
-6
未找到文件。
src/operators/kernel/central-arm-func/conv3x3_arm_int8.cpp
浏览文件 @
2d300f69
...
@@ -14,1129 +14,739 @@ limitations under the License. */
...
@@ -14,1129 +14,739 @@ limitations under the License. */
#ifdef CONV_OP
#ifdef CONV_OP
#if __ARM_NEON
#include <arm_neon.h>
#endif
#include "operators/kernel/central-arm-func/conv_arm_int8.h"
#include "operators/kernel/central-arm-func/conv_arm_int8.h"
namespace
paddle_mobile
{
namespace
paddle_mobile
{
namespace
operators
{
namespace
operators
{
void
transform_kernel3x3_s1_int8
(
const
framework
::
Tensor
*
filter
,
framework
::
Tensor
*
filter_tm
,
int
inch
,
int
outch
)
{
filter_tm
->
mutable_data
<
int8_t
>
(
framework
::
make_ddim
({
outch
/
4
+
outch
%
4
,
inch
,
4
*
9
}));
const
int8_t
*
filter_data
=
filter
->
data
<
int8_t
>
();
int
p
=
0
;
for
(;
p
+
3
<
outch
;
p
+=
4
)
{
const
int8_t
*
k0
=
filter_data
+
(
p
+
0
)
*
inch
*
9
;
const
int8_t
*
k1
=
filter_data
+
(
p
+
1
)
*
inch
*
9
;
const
int8_t
*
k2
=
filter_data
+
(
p
+
2
)
*
inch
*
9
;
const
int8_t
*
k3
=
filter_data
+
(
p
+
3
)
*
inch
*
9
;
int8_t
*
filter_tmp
=
filter_tm
->
Slice
(
p
/
4
,
p
/
4
+
1
).
data
<
int8_t
>
();
for
(
int
q
=
0
;
q
<
inch
;
q
++
)
{
asm
volatile
(
"vld1.s8 {d0-d1}, [%[k0]]
\n
"
"add %[k0], #9
\n
"
"vld1.s8 {d2-d3}, [%[k1]]
\n
"
"add %[k1], #9
\n
"
"vld1.s8 {d4-d5}, [%[k2]]
\n
"
"add %[k2], #9
\n
"
"vld1.s8 {d6-d7}, [%[k3]]
\n
"
"add %[k3], #9
\n
"
"vst4.s8 {d0, d2, d4, d6}, [%[filter_tmp]]!
\n
"
"vst4.s8 {d1, d3, d5, d7}, [%[filter_tmp]]
\n
"
"add %[filter_tmp], #4
\n
"
:
[
k0
]
"+r"
(
k0
),
[
k1
]
"+r"
(
k1
),
[
k2
]
"+r"
(
k2
),
[
k3
]
"+r"
(
k3
),
[
filter_tmp
]
"+r"
(
filter_tmp
)
:
:
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
);
}
}
for
(;
p
<
outch
;
p
++
)
{
const
int8_t
*
k0
=
filter_data
+
(
p
+
0
)
*
inch
*
9
;
int8_t
*
filter_tmp
=
filter_tm
->
Slice
(
p
/
4
+
p
%
4
,
p
/
4
+
p
%
4
+
1
).
data
<
int8_t
>
();
for
(
int
q
=
0
;
q
<
inch
;
q
++
)
{
asm
volatile
(
"vld1.s8 {d0-d1}, [%[k0]]
\n
"
"add %[k0], #9
\n
"
"vst1.s8 {d0-d1}, [%[filter_tmp]]
\n
"
"add %[filter_tmp], #9
\n
"
:
[
k0
]
"+r"
(
k0
),
[
filter_tmp
]
"+r"
(
filter_tmp
)
:
:
"memory"
,
"q0"
);
}
}
}
void
conv3x3s1_int8
(
const
framework
::
Tensor
&
input
,
void
conv3x3s1_int8
(
const
framework
::
Tensor
&
input
,
const
framework
::
Tensor
&
weight
,
const
framework
::
Tensor
&
weight
,
framework
::
Tensor
*
output
)
{
framework
::
Tensor
*
output
)
{
int64_t
inch
=
input
.
dims
()[
1
];
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
int64_t
h
=
input
.
dims
()[
2
];
int64_t
w
=
input
.
dims
()[
3
];
int64_t
outch
=
output
->
dims
()[
1
];
int64_t
outh
=
output
->
dims
()[
2
];
int64_t
outw
=
output
->
dims
()[
3
];
const
int8_t
*
in_data
=
input
.
data
<
int8_t
>
();
const
int8_t
*
in_data
=
input
.
data
<
int8_t
>
();
const
int8_t
*
w_data
=
weight
.
data
<
int8_t
>
();
const
int8_t
*
w_data
=
weight
.
data
<
int8_t
>
();
int32_t
*
out_data
=
output
->
mutable_data
<
int32_t
>
();
int32_t
*
out_data
=
output
->
mutable_data
<
int32_t
>
();
memset
(
out_data
,
0
,
output
->
numel
()
*
sizeof
(
int32_t
));
// make sure that batch size is 1
int
input_c
=
input
.
dims
()[
1
];
int64_t
nn_outch
=
outch
>>
2
;
int
input_h
=
input
.
dims
()[
2
];
int64_t
remain_outch_start
=
nn_outch
<<
2
;
int
input_w
=
input
.
dims
()[
3
];
int
output_c
=
output
->
dims
()[
1
];
framework
::
Tensor
weight_tm
;
int
output_h
=
output
->
dims
()[
2
];
transform_kernel3x3_s1_int8
(
&
weight
,
&
weight_tm
,
weight
.
dims
()[
1
],
int
output_w
=
output
->
dims
()[
3
];
weight
.
dims
()[
0
]);
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
));
int
oc
=
0
;
#pragma omp parallel for
#pragma omp parallel for
for
(
int
pp
=
0
;
pp
<
nn_outch
;
pp
++
)
{
for
(;
oc
<
output_c
-
1
;
oc
+=
2
)
{
int
p
=
pp
*
4
;
for
(
int
ic
=
0
;
ic
<
input_c
;
++
ic
)
{
const
int8_t
*
ktmp
=
weight_tm
.
Slice
(
p
/
4
,
p
/
4
+
1
).
data
<
int8_t
>
();
const
int8_t
*
kernel0
=
w_data
+
(
oc
*
input_c
+
ic
)
*
9
;
const
int8_t
*
kernel1
=
w_data
+
((
oc
+
1
)
*
input_c
+
ic
)
*
9
;
for
(
int
q
=
0
;
q
<
inch
;
q
++
)
{
int32_t
*
output0
=
out_data
+
oc
*
out_image_size
;
int32_t
*
outptr0
=
out_data
+
p
*
outh
*
outw
;
int32_t
*
output0n
=
output0
+
output_w
;
int32_t
*
outptr1
=
outptr0
+
outh
*
outw
;
int32_t
*
output1
=
out_data
+
(
oc
+
1
)
*
out_image_size
;
int32_t
*
outptr2
=
outptr0
+
outh
*
outw
*
2
;
int32_t
*
output1n
=
output1
+
output_w
;
int32_t
*
outptr3
=
outptr0
+
outh
*
outw
*
3
;
int
oh
=
0
;
const
int8_t
*
img0
=
in_data
+
q
*
h
*
w
;
for
(;
oh
<
output_h
-
1
;
oh
+=
2
)
{
const
int8_t
*
r0
=
img0
;
const
int8_t
*
r0
=
in_data
+
ic
*
image_size
+
oh
*
input_w
;
const
int8_t
*
r1
=
img0
+
w
;
const
int8_t
*
r1
=
r0
+
input_w
;
const
int8_t
*
r2
=
img0
+
w
*
2
;
const
int8_t
*
r2
=
r1
+
input_w
;
const
int8_t
*
r3
=
img0
+
w
*
3
;
const
int8_t
*
r3
=
r2
+
input_w
;
int
i
=
0
;
int
ow
=
output_w
>>
3
;
for
(;
i
+
1
<
outh
;
i
+=
2
)
{
// 每次计算两行的输出
int
remain
=
output_w
&
0x7
;
int
nn
=
outw
>>
3
;
if
(
ow
>
0
)
{
int
remain
=
outw
&
7
;
if
(
nn
>
0
)
{
asm
volatile
(
asm
volatile
(
"0:
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
// "pld [%[ktmp], #256] \n"
"ldr r5, [%[kernel0], #8]
\n
"
"vld1.s8 {d0-d3}, [%[ktmp]]!
\n
"
// d0=k00
"vld1.8 {d1}, [%[kernel1]]
\n
"
// k01(四个通道的k00和k01,8个数字,8*8=64bit)
"ldr r6, [%[kernel1], #8]
\n
"
// d1=k02 k10 d2=k11
// k12 d3=k20 k21
"0:
\n
"
"vld1.8 {d2-d3}, [%[r0]]
\n
"
// r0
"pld [%[r0], #128]
\n
"
"add %[r0], #8
\n
"
"vld1.s8 {d4-d5}, [%[r0]]
\n
"
// d4=r00 d5=r00n
"vext.8 d4, d2, d3, #1
\n
"
"add %[r0], #8
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d6, d0[0]
\n
"
"vdup.s8 d8, d0[0]
\n
"
// d8中每个8bit元素的值均为d0[0],d8内容为第1个通道的第1个值重复8次
"vdup.s8 d7, d0[1]
\n
"
"vdup.s8 d9, d0[1]
\n
"
// d9中每个8bit元素的值均为d0[1],d9内容为第2个通道的第1个值重复8次
"vdup.s8 d8, d0[2]
\n
"
"vdup.s8 d9, d1[0]
\n
"
"pld [%[r1], #128]
\n
"
"vdup.s8 d10, d1[1]
\n
"
"vld1.s8 {d6-d7}, [%[r1]]
\n
"
// d6=r10 d7=r10n
"vdup.s8 d11, d1[2]
\n
"
"add %[r1], #8
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vdup.s8 d10, d0[2]
\n
"
// d10中每个8bit元素的值均为d0[2],d10内容为第3个通道的第1个值重复8次
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d11, d0[3]
\n
"
// d11中每个8bit元素的值均为d0[3],d11内容为第4个通道的第1个值重复8次
"vaddl.s16 q12, d12, d14
\n
"
"vaddl.s16 q13, d13, d15
\n
"
"vmull.s8 q8, d4, d8
\n
"
// 将第1行的前8个元素与第1个通道的第1个值相乘,结果q8
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q9, d4, d9
\n
"
// 将第1行的前8个元素与第2个通道的第1个值相乘,结果q9
"vmull.s8 q7, d4, d10
\n
"
"vmlal.s8 q6, d5, d11
\n
"
"vdup.s8 d12, d0[4]
\n
"
// d12内容为第1个通道的第2个值重复8次
"vaddl.s16 q14, d12, d14
\n
"
"vdup.s8 d13, d0[5]
\n
"
// d13内容为第2个通道的第2个值重复8次
"vaddl.s16 q15, d13, d15
\n
"
"vmull.s8 q10, d4, d10
\n
"
// 将第1行的前8个元素与第3个通道的第1个值相乘,结果q10
"vld1.8 {d2-d3}, [%[r1]]
\n
"
// r1
"vmull.s8 q11, d4, d11
\n
"
// 将第1行的前8个元素与第4个通道的第1个值相乘,结果q11
"add %[r1], #8
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vdup.s8 d14, d0[6]
\n
"
// d14内容为第3个通道的第2个值重复8次
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d15, d0[7]
\n
"
// d15内容为第4个通道的第2个值重复8次
"vmull.s8 q6, d2, d6
\n
"
// next row
"vmull.s8 q12, d6, d8
\n
"
// 将第2行的前8个元素与第1个通道的第1个值相乘,结果q12
"vmull.s8 q7, d4, d7
\n
"
"vmull.s8 q13, d6, d9
\n
"
// 将第2行的前8个元素与第2个通道的第1个值相乘,结果q13
"vmlal.s8 q6, d5, d8
\n
"
"vaddl.s16 q8, d12, d14
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r01,循环右移一位(每位为8bit元素),第1行第2个值
"vaddl.s16 q9, d13, d15
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q14, d6, d10
\n
"
// 将第2行的前8个元素与第3个通道的第1个值相乘,结果q14
"vmull.s8 q7, d4, d10
\n
"
"vmull.s8 q15, d6, d11
\n
"
// 将第2行的前8个元素与第4个通道的第1个值相乘,结果q14
"vmlal.s8 q6, d5, d11
\n
"
"vaddl.s16 q10, d12, d14
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r11,第2行第2个值
"vaddl.s16 q11, d13, d15
\n
"
"vmlal.s8 q8, d4, d12
\n
"
// 第1行第1个通道:加乘上第2个值
"vdup.s8 d6, d0[3]
\n
"
"vmlal.s8 q9, d4, d13
\n
"
// 第1行第2个通道:加乘上第2个值
"vdup.s8 d7, d0[4]
\n
"
"vdup.s8 d8, d0[5]
\n
"
"vdup.s8 d8, d1[0]
\n
"
// d8内容为第1个通道的第3个值重复8次
"vdup.s8 d9, d1[3]
\n
"
"vdup.s8 d9, d1[1]
\n
"
// d9内容为第2个通道的第3个值重复8次
"vdup.s8 d10, d1[4]
\n
"
"vdup.s8 d11, d1[5]
\n
"
"vmlal.s8 q10, d4, d14
\n
"
// 第1行第3个通道:加乘上第2个值
"vmull.s8 q6, d2, d6
\n
"
"vmlal.s8 q11, d4, d15
\n
"
// 第1行第4个通道:加乘上第2个值
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d10, d1[2]
\n
"
// d10内容为第3个通道的第3个值重复8次
"vaddw.s16 q12, q12, d12
\n
"
"vdup.s8 d11, d1[3]
\n
"
// d10内容为第4个通道的第3个值重复8次
"vaddw.s16 q12, q12, d14
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vmlal.s8 q12, d6, d12
\n
"
// 第2行第1个通道:加乘上第2个值
"vaddw.s16 q13, q13, d15
\n
"
"vmlal.s8 q13, d6, d13
\n
"
// 第2行第2个通道:加乘上第2个值
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q7, d4, d10
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r02,第1行第3个值
"vmlal.s8 q6, d5, d11
\n
"
"vaddw.s16 q14, q14, d12
\n
"
"vmlal.s8 q14, d6, d14
\n
"
// 第2行第3个通道:加乘上第2个值
"vaddw.s16 q14, q14, d14
\n
"
"vmlal.s8 q15, d6, d15
\n
"
// 第2行第3个通道:加乘上第2个值
"vaddw.s16 q15, q15, d13
\n
"
"vaddw.s16 q15, q15, d15
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r12,第2行第3个值
"vld1.8 {d2-d3}, [%[r2]]
\n
"
// r2
"vmlal.s8 q8, d4, d8
\n
"
// 第1行第1个通道:加乘上第3个值
"add %[r2], #8
\n
"
"vmlal.s8 q9, d4, d9
\n
"
// 第1行第2个通道:加乘上第3个值
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d12, d1[4]
\n
"
// d12内容为第1个通道的第4个值重复8次
"vdup.s8 d13, d1[5]
\n
"
// d13内容为第2个通道的第4个值重复8次
"vmull.s8 q6, d2, d6
\n
"
// next row
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q10, d4, d10
\n
"
// 第1行第3个通道:加乘上第3个值
"vmlal.s8 q6, d5, d8
\n
"
"vmlal.s8 q11, d4, d11
\n
"
// 第1行第4个通道:加乘上第3个值
"vaddw.s16 q8, q8, d12
\n
"
"vaddw.s16 q8, q8, d14
\n
"
"vdup.s8 d14, d1[6]
\n
"
// d14内容为第3个通道的第4个值重复8次
"vaddw.s16 q9, q9, d13
\n
"
"vdup.s8 d15, d1[7]
\n
"
// d15内容为第4个通道的第4个值重复8次
"vaddw.s16 q9, q9, d15
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vmlal.s8 q12, d6, d8
\n
"
// 第2行第1个通道:加乘上第3个值
"vmull.s8 q7, d4, d10
\n
"
"vmlal.s8 q13, d6, d9
\n
"
// 第2行第2个通道:加乘上第3个值
"vmlal.s8 q6, d5, d11
\n
"
"vaddw.s16 q10, q10, d12
\n
"
"pld [%[r2], #128]
\n
"
"vaddw.s16 q10, q10, d14
\n
"
"vld1.s8 {d4-d5}, [%[r2]]
\n
"
// d4=r20 d5=r20n
"vaddw.s16 q11, q11, d13
\n
"
"add %[r2], #8
\n
"
"vaddw.s16 q11, q11, d15
\n
"
"vmlal.s8 q14, d6, d10
\n
"
// 第2行第3个通道:加乘上第3个值
"vdup.s8 d6, d0[6]
\n
"
"vmlal.s8 q15, d6, d11
\n
"
// 第2行第4个通道:加乘上第3个值
"vdup.s8 d7, d0[7]
\n
"
"vdup.s8 d8, r5
\n
"
///
"vdup.s8 d9, d1[6]
\n
"
"vext.s8 q3, q3, q3, #14
\n
"
// d6=r10,输入的第4个值
"vdup.s8 d10, d1[7]
\n
"
"vdup.s8 d11, r6
\n
"
"vmlal.s8 q8, d6, d12
\n
"
// 第1行第1个通道:加乘上第4个值
"vmull.s8 q6, d2, d6
\n
"
"vmlal.s8 q9, d6, d13
\n
"
// 第1行第2个通道:加乘上第4个值
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d8, d2[0]
\n
"
// d8内容为第1个通道的第5个值重复8次
"vaddw.s16 q12, q12, d12
\n
"
"vdup.s8 d9, d2[1]
\n
"
// d9内容为第2个通道的第5个值重复8次
"vaddw.s16 q12, q12, d14
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vmlal.s8 q10, d6, d14
\n
"
// 第1行第3个通道:加乘上第4个值
"vaddw.s16 q13, q13, d15
\n
"
"vmlal.s8 q11, d6, d15
\n
"
// 第1行第4个通道:加乘上第4个值
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q7, d4, d10
\n
"
"vdup.s8 d10, d2[2]
\n
"
// d10内容为第3个通道的第5个值重复8次
"vmlal.s8 q6, d5, d11
\n
"
"vdup.s8 d11, d2[3]
\n
"
// d11内容为第4个通道的第5个值重复8次
"vaddw.s16 q14, q14, d12
\n
"
"vaddw.s16 q14, q14, d14
\n
"
"vmlal.s8 q12, d4, d12
\n
"
// 第2行第1个通道:加乘上第4个值
"vaddw.s16 q15, q15, d13
\n
"
"vmlal.s8 q13, d4, d13
\n
"
// 第2行第2个通道:加乘上第4个值
"vaddw.s16 q15, q15, d15
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r11,输入的第5个值
"vld1.32 {d12-d15}, [%[output0]]
\n
"
"vadd.s32 q6, q6, q12
\n
"
"vmlal.s8 q14, d4, d14
\n
"
// 第2行第3个通道:加乘上第4个值
"vadd.s32 q7, q7, q13
\n
"
"vmlal.s8 q15, d4, d15
\n
"
// 第2行第4个通道:加乘上第4个值
"vst1.32 {d12-d15}, [%[output0]]!
\n
"
"vld1.32 {d12-d15}, [%[output1]]
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r21
"vadd.s32 q6, q6, q14
\n
"
"vadd.s32 q7, q7, q15
\n
"
"vmlal.s8 q8, d6, d8
\n
"
"vst1.32 {d12-d15}, [%[output1]]!
\n
"
"vmlal.s8 q9, d6, d9
\n
"
"vld1.8 {d2-d3}, [%[r3]]
\n
"
// r3
"vdup.s8 d12, d2[4]
\n
"
// d12内容为第1个通道的第6个值重复8次
"add %[r3], #8
\n
"
"vdup.s8 d13, d2[5]
\n
"
// d13内容为第2个通道的第6个值重复8次
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vmlal.s8 q10, d6, d10
\n
"
"vmlal.s8 q11, d6, d11
\n
"
"vmull.s8 q6, d2, d6
\n
"
// next row
"vmull.s8 q7, d4, d7
\n
"
"vdup.s8 d14, d2[6]
\n
"
// d14内容为第3个通道的第6个值重复8次
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d15, d2[7]
\n
"
// d15内容为第4个通道的第6个值重复8次
"vaddw.s16 q8, q8, d12
\n
"
"vaddw.s16 q8, q8, d14
\n
"
"vmlal.s8 q12, d4, d8
\n
"
"vaddw.s16 q9, q9, d13
\n
"
"vmlal.s8 q13, d4, d9
\n
"
"vaddw.s16 q9, q9, d15
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r12
"vmull.s8 q7, d4, d10
\n
"
"vmlal.s8 q6, d5, d11
\n
"
"vmlal.s8 q14, d4, d10
\n
"
"vaddw.s16 q10, q10, d12
\n
"
"vmlal.s8 q15, d4, d11
\n
"
"vaddw.s16 q10, q10, d14
\n
"
"vaddw.s16 q11, q11, d13
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r22
"vaddw.s16 q11, q11, d15
\n
"
"vmlal.s8 q8, d6, d12
\n
"
"vld1.32 {d12-d15}, [%[output0n]]
\n
"
"vmlal.s8 q9, d6, d13
\n
"
"vadd.s32 q6, q6, q8
\n
"
"vadd.s32 q7, q7, q9
\n
"
"vdup.s8 d8, d3[0]
\n
"
"vst1.32 {d12-d15}, [%[output0n]]!
\n
"
"vdup.s8 d9, d3[1]
\n
"
"vld1.32 {d12-d15}, [%[output1n]]
\n
"
"vadd.s32 q6, q6, q10
\n
"
"vmlal.s8 q10, d6, d14
\n
"
"vadd.s32 q7, q7, q11
\n
"
"vmlal.s8 q11, d6, d15
\n
"
"vst1.32 {d12-d15}, [%[output1n]]!
\n
"
"vdup.s8 d10, d3[2]
\n
"
"subs %[ow], #1
\n
"
"vdup.s8 d11, d3[3]
\n
"
"bne 0b
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
"vmlal.s8 q12, d4, d12
\n
"
[
ow
]
"+r"
(
ow
),
[
output0
]
"+r"
(
output0
),
[
output1
]
"+r"
(
output1
),
"vmlal.s8 q13, d4, d13
\n
"
[
output0n
]
"+r"
(
output0n
),
[
output1n
]
"+r"
(
output1n
)
:
[
kernel0
]
"r"
(
kernel0
),
[
kernel1
]
"r"
(
kernel1
)
"pld [%[r3], #128]
\n
"
"vld1.s8 {d6-d7}, [%[r3]]
\n
"
// d6=r30 d6=r30n
"add %[r3], #8
\n
"
"vmlal.s8 q14, d4, d14
\n
"
"vmlal.s8 q15, d4, d15
\n
"
///
"vext.s8 q2, q2, q2, #14
\n
"
// d4=r20
"vmlal.s8 q8, d4, d8
\n
"
"vmlal.s8 q9, d4, d9
\n
"
"vdup.s8 d12, d3[4]
\n
"
"vdup.s8 d13, d3[5]
\n
"
"vmlal.s8 q10, d4, d10
\n
"
"vmlal.s8 q11, d4, d11
\n
"
"vdup.s8 d14, d3[6]
\n
"
"vdup.s8 d15, d3[7]
\n
"
"vmlal.s8 q12, d6, d8
\n
"
"vmlal.s8 q13, d6, d9
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r21
"vmlal.s8 q14, d6, d10
\n
"
"vmlal.s8 q15, d6, d11
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r31
// "pld [%[ktmp], #128] \n"
"vld1.s8 {d0}, [%[ktmp]]
\n
"
"add %[ktmp], #4
\n
"
"vmlal.s8 q8, d4, d12
\n
"
"vmlal.s8 q9, d4, d13
\n
"
"vdup.s8 d8, d0[0]
\n
"
"vdup.s8 d9, d0[1]
\n
"
"vmlal.s8 q10, d4, d14
\n
"
"vmlal.s8 q11, d4, d15
\n
"
"vdup.s8 d10, d0[2]
\n
"
"vdup.s8 d11, d0[3]
\n
"
"vmlal.s8 q12, d6, d12
\n
"
"vmlal.s8 q13, d6, d13
\n
"
"vext.s8 q2, q2, q2, #1
\n
"
// d4=r22
"vmlal.s8 q14, d6, d14
\n
"
"vmlal.s8 q15, d6, d15
\n
"
"vext.s8 q3, q3, q3, #1
\n
"
// d6=r32
"vmlal.s8 q8, d4, d8
\n
"
"vmlal.s8 q9, d4, d9
\n
"
"pld [%[outptr0], #256]
\n
"
"vld1.s32 {d12-d15}, [%[outptr0]]
\n
"
"vmlal.s8 q10, d4, d10
\n
"
"vmlal.s8 q11, d4, d11
\n
"
"pld [%[outptr1], #256]
\n
"
"vld1.s32 {d0-d3}, [%[outptr1]]
\n
"
"vaddw.s16 q6, q6, d16
\n
"
"vaddw.s16 q7, q7, d17
\n
"
"vaddw.s16 q0, q0, d18
\n
"
"vaddw.s16 q1, q1, d19
\n
"
"pld [%[outptr2], #256]
\n
"
"vld1.s32 {d16-d19}, [%[outptr2]]
\n
"
"vmlal.s8 q12, d6, d8
\n
"
"vmlal.s8 q13, d6, d9
\n
"
"vst1.s32 {d12-d15}, [%[outptr0]]
\n
"
"add %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"vmlal.s8 q14, d6, d10
\n
"
"vmlal.s8 q15, d6, d11
\n
"
"pld [%[outptr3], #256]
\n
"
"vld1.s32 {d4-d7}, [%[outptr3]]
\n
"
"vst1.s32 {d0-d3}, [%[outptr1]]
\n
"
"add %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
"vaddw.s16 q8, q8, d20
\n
"
"vaddw.s16 q9, q9, d21
\n
"
"pld [%[outptr0], #256]
\n
"
"vld1.s32 {d12-d15}, [%[outptr0]]
\n
"
"vaddw.s16 q2, q2, d22
\n
"
"vaddw.s16 q3, q3, d23
\n
"
///
"pld [%[outptr1], #256]
\n
"
"vld1.s32 {d0-d3}, [%[outptr1]]
\n
"
"vaddw.s16 q6, q6, d24
\n
"
"vst1.s32 {d16-d19}, [%[outptr2]]
\n
"
"add %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"vaddw.s16 q7, q7, d25
\n
"
"pld [%[outptr2], #256]
\n
"
"vld1.s32 {d8-d11}, [%[outptr2]]
\n
"
"vaddw.s16 q0, q0, d26
\n
"
"vst1.s32 {d4-d7}, [%[outptr3]]
\n
"
"add %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
///
"vaddw.s16 q1, q1, d27
\n
"
"pld [%[outptr3], #256]
\n
"
"vld1.s32 {d4-d7}, [%[outptr3]]
\n
"
"vaddw.s16 q4, q4, d28
\n
"
"vst1.s32 {d12-d15}, [%[outptr0]]!
\n
"
"vaddw.s16 q5, q5, d29
\n
"
"vst1.s32 {d0-d3}, [%[outptr1]]!
\n
"
"vaddw.s16 q2, q2, d30
\n
"
"vst1.s32 {d8-d11}, [%[outptr2]]!
\n
"
"vaddw.s16 q3, q3, d31
\n
"
"sub %[ktmp], #36
\n
"
"subs %[nn], #1
\n
"
"sub %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"sub %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
"sub %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"vst1.s32 {d4-d7}, [%[outptr3]]!
\n
"
"sub %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
"bne 0b
\n
"
:
[
nn
]
"+r"
(
nn
),
[
outptr0
]
"+r"
(
outptr0
),
[
outptr1
]
"+r"
(
outptr1
),
[
outptr2
]
"+r"
(
outptr2
),
[
outptr3
]
"+r"
(
outptr3
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
[
ktmp
]
"+r"
(
ktmp
)
:
[
outw
]
"r"
(
outw
)
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
);
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
"r5"
,
"r6"
);
}
}
if
(
remain
>
0
)
{
for
(;
remain
>
0
;
remain
--
)
{
asm
volatile
(
asm
volatile
(
"vld1.s8 {d0[]}, [%[r0]]!
\n
"
// d0 = 00 00
"vld1.8 {d0}, [%[kernel0]]
\n
"
"vld1.s8 {d1[]}, [%[r0]]!
\n
"
// d1 = 01 01
"ldr r5, [%[kernel0], #8]
\n
"
"vld1.s8 {d2[]}, [%[r0]]
\n
"
// d2 = 02 02
"vld1.8 {d1}, [%[kernel1]]
\n
"
"sub %[r0], %[r0], #2
\n
"
"ldr r6, [%[kernel1], #8]
\n
"
"vld1.s8 {d3[]}, [%[r1]]!
\n
"
// d3 = 10 10
"0:
\n
"
"vld1.s8 {d4[]}, [%[r1]]!
\n
"
// d4 = 11 11
"vld1.8 d4, [%[r0]]
\n
"
"vld1.s8 {d5[]}, [%[r1]]
\n
"
// d5 = 12 12
"vld1.8 d5, [%[r1]]
\n
"
"sub %[r1], %[r1], #2
\n
"
"vld1.8 d6, [%[r2]]
\n
"
"vld1.8 d7, [%[r3]]
\n
"
"vld1.s8 {d6[]}, [%[r2]]!
\n
"
// d6 = 20 20
"add %[r0], #1
\n
"
"vld1.s8 {d7[]}, [%[r2]]!
\n
"
// d7 = 21 21
"add %[r1], #1
\n
"
"vld1.s8 {d8[]}, [%[r2]]
\n
"
// d8 = 22 22
"add %[r2], #1
\n
"
"sub %[r2], %[r2], #2
\n
"
"add %[r3], #1
\n
"
"vdup.s8 d2, r5
\n
"
"vld1.s8 {d9[]}, [%[r3]]!
\n
"
// d9 = 30 30
"vdup.s8 d3, r6
\n
"
"vld1.s8 {d10[]}, [%[r3]]!
\n
"
// d10 = 31 31
"vext.8 d8, d0, d2, #3
\n
"
"vld1.s8 {d11[]}, [%[r3]]
\n
"
// d11 = 32 32
"vext.8 d9, d0, d2, #6
\n
"
"sub %[r3], %[r3], #2
\n
"
"vext.8 d10, d1, d3, #3
\n
"
"vext.8 d11, d1, d3, #6
\n
"
"vld1.s8 {d12-d15}, [%[ktmp]]!
\n
"
// d12 d13 d14 d15 = 0~7
"vmull.s8 q6, d4, d0
\n
"
"vsli.64 d0, d1, #32
\n
"
// d0 = 00 01
"vmull.s8 q7, d5, d8
\n
"
"vmlal.s8 q6, d6, d9
\n
"
"vsli.64 d3, d4, #32
\n
"
// d3 = 10 11
"vaddl.s16 q12, d12, d14
\n
"
"vdup.s32 d2, d24[1]
\n
"
"vmull.s8 q8, d0, d12
\n
"
"vadd.s32 d24, d24, d2
\n
"
"vadd.s32 d24, d24, d25
\n
"
"vsli.64 d2, d3, #32
\n
"
// d2 = 02 10
"vmull.s8 q6, d4, d1
\n
"
"vmull.s8 q7, d5, d10
\n
"
"vmull.s8 q9, d3, d12
\n
"
"vmlal.s8 q6, d6, d11
\n
"
"vaddl.s16 q13, d12, d14
\n
"
"vsli.64 d5, d6, #32
\n
"
// d5 = 12 20
"vdup.s32 d2, d26[1]
\n
"
"vadd.s32 d26, d26, d2
\n
"
"vmlal.s8 q8, d2, d13
\n
"
"vadd.s32 d26, d26, d27
\n
"
"vsli.64 d4, d5, #32
\n
"
// d4 = 11 12
"ldr r7, [%[output0]]
\n
"
"vdup.s32 d14, r7
\n
"
"vmlal.s8 q9, d5, d13
\n
"
"vadd.s32 d14, d14, d24
\n
"
"vst1.32 d14[0], [%[output0]]!
\n
"
"vsli.64 d7, d8, #32
\n
"
// d7 = 21 22
"ldr r7, [%[output1]]
\n
"
"vdup.s32 d14, r7
\n
"
"vmlal.s8 q8, d4, d14
\n
"
"vadd.s32 d14, d14, d26
\n
"
"vst1.32 d14[0], [%[output1]]!
\n
"
"vsli.64 d6, d7, #32
\n
"
// d6 = 20 21
"vmull.s8 q6, d5, d0
\n
"
"vmlal.s8 q9, d7, d14
\n
"
"vmull.s8 q7, d6, d8
\n
"
"vmlal.s8 q6, d7, d9
\n
"
"vsli.64 d9, d10, #32
\n
"
// d9 = 30 31
"vaddl.s16 q12, d12, d14
\n
"
"vdup.s32 d2, d24[1]
\n
"
"vld1.s32 {d20[0]}, [%[outptr0]]
\n
"
"vadd.s32 d24, d24, d2
\n
"
"vld1.s32 {d20[1]}, [%[outptr1]]
\n
"
"vadd.s32 d24, d24, d25
\n
"
"vmull.s8 q6, d5, d1
\n
"
"add %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"vmull.s8 q7, d6, d10
\n
"
"add %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
"vmlal.s8 q6, d7, d11
\n
"
"vaddl.s16 q13, d12, d14
\n
"
"vmlal.s8 q8, d6, d15
\n
"
"vdup.s32 d2, d26[1]
\n
"
"vadd.s32 d26, d26, d2
\n
"
"vsli.64 d8, d11, #32
\n
"
// d8 = 22 32
"vadd.s32 d26, d26, d27
\n
"
"vmlal.s8 q9, d9, d15
\n
"
"ldr r7, [%[output0n]]
\n
"
"vdup.s32 d14, r7
\n
"
"vld1.s8 {d14}, [%[ktmp]]
\n
"
"vadd.s32 d14, d14, d24
\n
"
"add %[ktmp], #4
\n
"
"vst1.32 d14[0], [%[output0n]]!
\n
"
"ldr r7, [%[output1n]]
\n
"
"vld1.s32 {d21[0]}, [%[outptr2]]
\n
"
"vdup.s32 d14, r7
\n
"
"vld1.s32 {d21[1]}, [%[outptr3]]
\n
"
"vadd.s32 d14, d14, d26
\n
"
"vst1.32 d14[0], [%[output1n]]!
\n
"
"add %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"add %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
"subs %[remain], #1
\n
"
"bne 0b
\n
"
"vadd.s16 d12, d16, d17
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
[
remain
]
"+r"
(
remain
),
[
output0
]
"+r"
(
output0
),
"vadd.s16 d13, d18, d19
\n
"
// q6 = sum0123 sum0123n
[
output1
]
"+r"
(
output1
),
[
output0n
]
"+r"
(
output0n
),
[
output1n
]
"+r"
(
output1n
)
"vsli.64 d14, d14, #32
\n
"
// d14 = 0~3 0~3
:
[
kernel0
]
"r"
(
kernel0
),
[
kernel1
]
"r"
(
kernel1
)
"vld1.s32 {d22[0]}, [%[outptr0]]
\n
"
"vld1.s32 {d22[1]}, [%[outptr1]]
\n
"
"vmlal.s8 q6, d8, d14
\n
"
"sub %[ktmp], #36
\n
"
///
"vld1.s32 {d23[0]}, [%[outptr2]]
\n
"
"vld1.s32 {d23[1]}, [%[outptr3]]
\n
"
"sub %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"sub %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
// addw
"vaddw.s16 q10, q10, d12
\n
"
"vaddw.s16 q11, q11, d13
\n
"
"sub %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"sub %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
"vst1.s32 {d20[0]}, [%[outptr0]]
\n
"
"vst1.s32 {d20[1]}, [%[outptr1]]
\n
"
"add %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"add %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
"vst1.s32 {d21[0]}, [%[outptr2]]
\n
"
"vst1.s32 {d21[1]}, [%[outptr3]]
\n
"
"add %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"add %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
"vst1.s32 {d22[0]}, [%[outptr0]]!
\n
"
"vst1.s32 {d22[1]}, [%[outptr1]]!
\n
"
"sub %[outptr0], %[outptr0], %[outw], lsl #2
\n
"
"sub %[outptr1], %[outptr1], %[outw], lsl #2
\n
"
"vst1.s32 {d23[0]}, [%[outptr2]]!
\n
"
"vst1.s32 {d23[1]}, [%[outptr3]]!
\n
"
"sub %[outptr2], %[outptr2], %[outw], lsl #2
\n
"
"sub %[outptr3], %[outptr3], %[outw], lsl #2
\n
"
:
[
outptr0
]
"+r"
(
outptr0
),
[
outptr1
]
"+r"
(
outptr1
),
[
outptr2
]
"+r"
(
outptr2
),
[
outptr3
]
"+r"
(
outptr3
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
[
ktmp
]
"+r"
(
ktmp
)
:
[
outw
]
"r"
(
outw
)
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"q8"
,
"q9"
,
"q10"
,
"q11"
);
"q8"
,
"q9"
,
"q10"
,
"r5"
,
"r6"
,
"r7"
);
r0
++
;
r1
++
;
r2
++
;
r3
++
;
}
}
output0
+=
output_w
;
r0
+=
2
+
w
;
output1
+=
output_w
;
r1
+=
2
+
w
;
output0n
+=
output_w
;
r2
+=
2
+
w
;
output1n
+=
output_w
;
r3
+=
2
+
w
;
outptr0
+=
outw
;
outptr1
+=
outw
;
outptr2
+=
outw
;
outptr3
+=
outw
;
}
}
// remain output height
for
(;
i
<
outh
;
i
++
)
{
for
(;
oh
<
output_h
;
++
oh
)
{
int
nn
=
outw
>>
3
;
const
int8_t
*
r0
=
in_data
+
ic
*
image_size
+
oh
*
input_w
;
int
remain
=
outw
&
7
;
const
int8_t
*
r1
=
r0
+
input_w
;
if
(
nn
>
0
)
{
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
(
asm
volatile
(
"0:
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
// "pld [%[ktmp], #256] \n"
"ldr r5, [%[kernel0], #8]
\n
"
"vld1.s8 {d0-d3}, [%[ktmp]]!
\n
"
// d0=k00 k01 d1=k02 k10
"vld1.8 {d1}, [%[kernel1]]
\n
"
// d2=k11
"ldr r6, [%[kernel1], #8]
\n
"
// k12 d3=k20 k21
"0:
\n
"
"pld [%[r0], #128]
\n
"
"vld1.8 {d2-d3}, [%[r0]]
\n
"
// r0
"vld1.s8 {d4-d5}, [%[r0]]
\n
"
// d4=r00 d5=r00n
"add %[r0], #8
\n
"
"add %[r0], #8
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d8, d0[0]
\n
"
"vdup.s8 d6, d0[0]
\n
"
"vdup.s8 d9, d0[1]
\n
"
"vdup.s8 d7, d0[1]
\n
"
"vdup.s8 d10, d0[2]
\n
"
"vdup.s8 d8, d0[2]
\n
"
"vdup.s8 d11, d0[3]
\n
"
"vdup.s8 d9, d1[0]
\n
"
"vdup.s8 d10, d1[1]
\n
"
"vmull.s8 q8, d4, d8
\n
"
"vdup.s8 d11, d1[2]
\n
"
"vmull.s8 q9, d4, d9
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vext.s8 d24, d4, d5, #1
\n
"
// d24=r01
"vmlal.s8 q6, d5, d8
\n
"
"vaddl.s16 q12, d12, d14
\n
"
"vdup.s8 d12, d0[4]
\n
"
"vaddl.s16 q13, d13, d15
\n
"
"vdup.s8 d13, d0[5]
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q7, d4, d10
\n
"
"vmull.s8 q10, d4, d10
\n
"
"vmlal.s8 q6, d5, d11
\n
"
"vmull.s8 q11, d4, d11
\n
"
"vaddl.s16 q14, d12, d14
\n
"
"vaddl.s16 q15, d13, d15
\n
"
"vdup.s8 d14, d0[6]
\n
"
"vdup.s8 d15, d0[7]
\n
"
"vld1.8 {d2-d3}, [%[r1]]
\n
"
// r1
"add %[r1], #8
\n
"
"vmlal.s8 q8, d24, d12
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vmlal.s8 q9, d24, d13
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d6, d0[3]
\n
"
"vext.s8 d25, d4, d5, #2
\n
"
// d25=r02
"vdup.s8 d7, d0[4]
\n
"
"vdup.s8 d8, d0[5]
\n
"
"vdup.s8 d8, d1[0]
\n
"
"vdup.s8 d9, d1[3]
\n
"
"vdup.s8 d9, d1[1]
\n
"
"vdup.s8 d10, d1[4]
\n
"
"vdup.s8 d11, d1[5]
\n
"
"vmlal.s8 q10, d24, d14
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmlal.s8 q11, d24, d15
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d10, d1[2]
\n
"
"vaddw.s16 q12, q12, d12
\n
"
"vdup.s8 d11, d1[3]
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vmlal.s8 q8, d25, d8
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"vmlal.s8 q9, d25, d9
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vmull.s8 q7, d4, d10
\n
"
"pld [%[r1], #128]
\n
"
"vmlal.s8 q6, d5, d11
\n
"
"vld1.s8 {d6-d7}, [%[r1]]
\n
"
// d6=r10 d7=r10n
"vaddw.s16 q14, q14, d12
\n
"
"add %[r1], #8
\n
"
"vaddw.s16 q14, q14, d14
\n
"
"vaddw.s16 q15, q15, d13
\n
"
"vdup.s8 d12, d1[4]
\n
"
"vaddw.s16 q15, q15, d15
\n
"
"vdup.s8 d13, d1[5]
\n
"
"vld1.8 {d2-d3}, [%[r2]]
\n
"
// r2
"vmlal.s8 q10, d25, d10
\n
"
"add %[r2], #8
\n
"
"vmlal.s8 q11, d25, d11
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d14, d1[6]
\n
"
"vdup.s8 d6, d0[6]
\n
"
"vdup.s8 d15, d1[7]
\n
"
"vdup.s8 d7, d0[7]
\n
"
"vdup.s8 d8, r5
\n
"
"vmlal.s8 q8, d6, d12
\n
"
"vdup.s8 d9, d1[6]
\n
"
"vmlal.s8 q9, d6, d13
\n
"
"vdup.s8 d10, d1[7]
\n
"
"vdup.s8 d11, r6
\n
"
"vext.s8 d26, d6, d7, #1
\n
"
// d26=r11
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vdup.s8 d8, d2[0]
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vdup.s8 d9, d2[1]
\n
"
"vaddw.s16 q12, q12, d12
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"vmlal.s8 q10, d6, d14
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vmlal.s8 q11, d6, d15
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"vmull.s8 q6, d2, d9
\n
"
"vdup.s8 d10, d2[2]
\n
"
"vmull.s8 q7, d4, d10
\n
"
"vdup.s8 d11, d2[3]
\n
"
"vmlal.s8 q6, d5, d11
\n
"
"vaddw.s16 q14, q14, d12
\n
"
"vmlal.s8 q8, d26, d8
\n
"
"vaddw.s16 q14, q14, d14
\n
"
"vmlal.s8 q9, d26, d9
\n
"
"vaddw.s16 q15, q15, d13
\n
"
"vaddw.s16 q15, q15, d15
\n
"
"vext.s8 d27, d6, d7, #2
\n
"
// d27=r12
"vld1.32 {d12-d15}, [%[output0]]
\n
"
"vdup.s8 d12, d2[4]
\n
"
"vadd.s32 q6, q6, q12
\n
"
"vdup.s8 d13, d2[5]
\n
"
"vadd.s32 q7, q7, q13
\n
"
"vst1.32 {d12-d15}, [%[output0]]!
\n
"
"vmlal.s8 q10, d26, d10
\n
"
"vld1.32 {d12-d15}, [%[output1]]
\n
"
"vmlal.s8 q11, d26, d11
\n
"
"vadd.s32 q6, q6, q14
\n
"
"vadd.s32 q7, q7, q15
\n
"
"vdup.s8 d14, d2[6]
\n
"
"vst1.32 {d12-d15}, [%[output1]]!
\n
"
"vdup.s8 d15, d2[7]
\n
"
"subs %[ow], #1
\n
"
"vmlal.s8 q8, d27, d12
\n
"
"bne 0b
\n
"
"vmlal.s8 q9, d27, d13
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
ow
]
"+r"
(
ow
),
[
output0
]
"+r"
(
output0
),
[
output1
]
"+r"
(
output1
)
"pld [%[r2], #128]
\n
"
:
[
kernel0
]
"r"
(
kernel0
),
[
kernel1
]
"r"
(
kernel1
)
"vld1.s8 {d4-d5}, [%[r2]]
\n
"
// d4=r20 d5=r20n
"add %[r2], #8
\n
"
"vdup.s8 d8, d3[0]
\n
"
"vdup.s8 d9, d3[1]
\n
"
"vmlal.s8 q10, d27, d14
\n
"
"vmlal.s8 q11, d27, d15
\n
"
"vdup.s8 d10, d3[2]
\n
"
"vdup.s8 d11, d3[3]
\n
"
"vmlal.s8 q8, d4, d8
\n
"
"vmlal.s8 q9, d4, d9
\n
"
"vext.s8 d24, d4, d5, #1
\n
"
// d24=r21
"vdup.s8 d12, d3[4]
\n
"
"vdup.s8 d13, d3[5]
\n
"
"vmlal.s8 q10, d4, d10
\n
"
"vmlal.s8 q11, d4, d11
\n
"
"vdup.s8 d14, d3[6]
\n
"
"vdup.s8 d15, d3[7]
\n
"
"vmlal.s8 q8, d24, d12
\n
"
"vmlal.s8 q9, d24, d13
\n
"
// "pld [%[ktmp], #128] \n"
"vld1.s8 {d0}, [%[ktmp]]
\n
"
"add %[ktmp], #4
\n
"
"vext.s8 d25, d4, d5, #2
\n
"
// d25=r22
"vdup.s8 d8, d0[0]
\n
"
"vdup.s8 d9, d0[1]
\n
"
"vmlal.s8 q10, d24, d14
\n
"
"vmlal.s8 q11, d24, d15
\n
"
"vdup.s8 d10, d0[2]
\n
"
"vdup.s8 d11, d0[3]
\n
"
"pld [%[outptr0], #256]
\n
"
"vld1.s32 {d12-d15}, [%[outptr0]]
\n
"
"vmlal.s8 q8, d25, d8
\n
"
"vmlal.s8 q9, d25, d9
\n
"
"pld [%[outptr1], #256]
\n
"
"vld1.s32 {d0-d3}, [%[outptr1]]
\n
"
"vaddw.s16 q6, q6, d16
\n
"
"vaddw.s16 q7, q7, d17
\n
"
"vmlal.s8 q10, d25, d10
\n
"
"vmlal.s8 q11, d25, d11
\n
"
"vaddw.s16 q0, q0, d18
\n
"
"vaddw.s16 q1, q1, d19
\n
"
"pld [%[outptr2], #256]
\n
"
"vld1.s32 {d16-d19}, [%[outptr2]]
\n
"
"vst1.s32 {d12-d15}, [%[outptr0]]!
\n
"
"pld [%[outptr3], #256]
\n
"
"vld1.s32 {d4-d7}, [%[outptr3]]
\n
"
"vst1.s32 {d0-d3}, [%[outptr1]]!
\n
"
"vaddw.s16 q8, q8, d20
\n
"
"vaddw.s16 q9, q9, d21
\n
"
"vaddw.s16 q2, q2, d22
\n
"
"vaddw.s16 q3, q3, d23
\n
"
"sub %[ktmp], #36
\n
"
"vst1.s32 {d16-d19}, [%[outptr2]]!
\n
"
"subs %[nn], #1
\n
"
"vst1.s32 {d4-d7}, [%[outptr3]]!
\n
"
"bne 0b
\n
"
:
[
nn
]
"+r"
(
nn
),
[
outptr0
]
"+r"
(
outptr0
),
[
outptr1
]
"+r"
(
outptr1
),
[
outptr2
]
"+r"
(
outptr2
),
[
outptr3
]
"+r"
(
outptr3
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
ktmp
]
"+r"
(
ktmp
)
:
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
);
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
"r5"
,
"r6"
);
}
}
for
(;
remain
>
0
;
remain
--
)
{
if
(
remain
>
0
)
{
asm
volatile
(
asm
volatile
(
"vld1.s8 {d0[]}, [%[r0]]!
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
"vld1.s8 {d1[]}, [%[r0]]!
\n
"
"ldr r5, [%[kernel0], #8]
\n
"
"vld1.8 {d1}, [%[kernel1]]
\n
"
"vld1.s8 {d4-d7}, [%[ktmp]]!
\n
"
// d4 d5 d6 d7 = 0~7
"ldr r6, [%[kernel1], #8]
\n
"
"vsli.64 d0, d1, #32
\n
"
// d0 = 00 01
"0:
\n
"
"vld1.8 d4, [%[r0]]
\n
"
"vld1.s8 {d2[]}, [%[r0]]
\n
"
"vld1.8 d5, [%[r1]]
\n
"
"sub %[r0], %[r0], #2
\n
"
"vld1.8 d6, [%[r2]]
\n
"
"vld1.s8 {d3[]}, [%[r1]]!
\n
"
"add %[r0], #1
\n
"
"add %[r1], #1
\n
"
"vsli.64 d2, d3, #32
\n
"
// d2 = 02 10
"add %[r2], #1
\n
"
"vdup.s8 d2, r5
\n
"
"vmull.s8 q8, d0, d4
\n
"
"vdup.s8 d3, r6
\n
"
"vext.8 d8, d0, d2, #3
\n
"
"vld1.s8 {d0[]}, [%[r1]]!
\n
"
"vext.8 d9, d0, d2, #6
\n
"
"vld1.s8 {d1[]}, [%[r1]]
\n
"
"vext.8 d10, d1, d3, #3
\n
"
"sub %[r1], %[r1], #2
\n
"
"vext.8 d11, d1, d3, #6
\n
"
"vsli.64 d0, d1, #32
\n
"
// d0 = 11 12
"vmull.s8 q6, d4, d0
\n
"
"vmull.s8 q7, d5, d8
\n
"
"vmlal.s8 q8, d2, d5
\n
"
"vmlal.s8 q6, d6, d9
\n
"
"vaddl.s16 q12, d12, d14
\n
"
"vld1.s8 {d2[]}, [%[r2]]!
\n
"
"vdup.s32 d2, d24[1]
\n
"
"vld1.s8 {d3[]}, [%[r2]]!
\n
"
"vadd.s32 d24, d24, d2
\n
"
"vadd.s32 d24, d24, d25
\n
"
"vsli.64 d2, d3, #32
\n
"
// d2 = 20 21
"vmull.s8 q6, d4, d1
\n
"
"vmull.s8 q7, d5, d10
\n
"
"vmlal.s8 q8, d0, d6
\n
"
"vmlal.s8 q6, d6, d11
\n
"
"vaddl.s16 q13, d12, d14
\n
"
"vld1.s8 {d0[]}, [%[r2]]
\n
"
"vdup.s32 d2, d26[1]
\n
"
"sub %[r2], %[r2], #2
\n
"
"vadd.s32 d26, d26, d2
\n
"
"veor d1, d1, d1
\n
"
"vadd.s32 d26, d26, d27
\n
"
"vld1.s8 {d4}, [%[ktmp]]
\n
"
// d4 = 0~4 xxxx
"ldr r7, [%[output0]]
\n
"
"sub %[ktmp], #32
\n
"
"vdup.s32 d14, r7
\n
"
"vadd.s32 d14, d14, d24
\n
"
"vsli.64 d0, d1, #32
\n
"
// d0 = 22 zero
"vst1.32 d14[0], [%[output0]]!
\n
"
"ldr r7, [%[output1]]
\n
"
"vmlal.s8 q8, d2, d7
\n
"
"vdup.s32 d14, r7
\n
"
"vadd.s32 d14, d14, d26
\n
"
"vld1.s32 {d20[0]}, [%[outptr0]]
\n
"
"vst1.32 d14[0], [%[output1]]!
\n
"
"vmlal.s8 q8, d0, d4
\n
"
"subs %[remain], #1
\n
"
"bne 0b
\n
"
"vld1.s32 {d20[1]}, [%[outptr1]]
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
remain
]
"+r"
(
remain
),
[
output0
]
"+r"
(
output0
),
"vadd.s16 d16, d16, d17
\n
"
[
output1
]
"+r"
(
output1
)
:
[
kernel0
]
"r"
(
kernel0
),
[
kernel1
]
"r"
(
kernel1
)
"vld1.s32 {d21[0]}, [%[outptr2]]
\n
"
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"vld1.s32 {d21[1]}, [%[outptr3]]
\n
"
"q8"
,
"q9"
,
"q10"
,
"r5"
,
"r6"
,
"r7"
);
"vaddw.s16 q10, q10, d16
\n
"
"vst1.s32 {d20[0]}, [%[outptr0]]!
\n
"
"vst1.s32 {d20[1]}, [%[outptr1]]!
\n
"
"vst1.s32 {d21[0]}, [%[outptr2]]!
\n
"
"vst1.s32 {d21[1]}, [%[outptr3]]!
\n
"
:
[
outptr0
]
"+r"
(
outptr0
),
[
outptr1
]
"+r"
(
outptr1
),
[
outptr2
]
"+r"
(
outptr2
),
[
outptr3
]
"+r"
(
outptr3
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
ktmp
]
"+r"
(
ktmp
)
:
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q8"
,
"q10"
);
r0
++
;
r1
++
;
r2
++
;
}
}
r0
+=
2
;
r1
+=
2
;
r2
+=
2
;
}
}
ktmp
+=
4
*
9
;
}
}
}
}
#pragma omp parallel for
for
(;
oc
<
output_c
;
++
oc
)
{
for
(
int
p
=
remain_outch_start
;
p
<
outch
;
p
++
)
{
for
(
int
ic
=
0
;
ic
<
input_c
;
++
ic
)
{
const
int8_t
*
ktmp
=
const
int8_t
*
kernel0
=
w_data
+
(
oc
*
input_c
+
ic
)
*
9
;
weight_tm
.
Slice
(
p
/
4
+
p
%
4
,
p
/
4
+
p
%
4
+
1
).
data
<
int8_t
>
();
int32_t
*
output0
=
out_data
+
oc
*
out_image_size
;
int32_t
*
output0n
=
output0
+
output_w
;
for
(
int
q
=
0
;
q
<
inch
;
q
++
)
{
int32_t
*
outptr0
=
out_data
+
p
*
outh
*
outw
;
int
oh
=
0
;
int32_t
*
outptr0n
=
outptr0
+
outw
;
for
(;
oh
<
output_h
-
1
;
oh
+=
2
)
{
const
int8_t
*
img0
=
in_data
+
q
*
h
*
w
;
const
int8_t
*
r0
=
in_data
+
ic
*
image_size
+
oh
*
input_w
;
const
int8_t
*
r0
=
img0
;
const
int8_t
*
r1
=
r0
+
input_w
;
const
int8_t
*
r1
=
img0
+
w
;
const
int8_t
*
r2
=
r1
+
input_w
;
const
int8_t
*
r2
=
img0
+
w
*
2
;
const
int8_t
*
r3
=
r2
+
input_w
;
const
int8_t
*
r3
=
img0
+
w
*
3
;
int8x8_t
_k00
=
vdup_n_s8
(
ktmp
[
0
]);
int
ow
=
output_w
>>
3
;
int8x8_t
_k01
=
vdup_n_s8
(
ktmp
[
1
]);
int
remain
=
output_w
&
0x7
;
int8x8_t
_k02
=
vdup_n_s8
(
ktmp
[
2
]);
if
(
ow
>
0
)
{
int8x8_t
_k10
=
vdup_n_s8
(
ktmp
[
3
]);
int8x8_t
_k11
=
vdup_n_s8
(
ktmp
[
4
]);
int8x8_t
_k12
=
vdup_n_s8
(
ktmp
[
5
]);
int8x8_t
_k20
=
vdup_n_s8
(
ktmp
[
6
]);
int8x8_t
_k21
=
vdup_n_s8
(
ktmp
[
7
]);
int8x8_t
_k22
=
vdup_n_s8
(
ktmp
[
8
]);
int
i
=
0
;
for
(;
i
+
1
<
outh
;
i
+=
2
)
{
int
nn
=
outw
>>
3
;
int
remain
=
outw
&
7
;
if
(
nn
>
0
)
{
asm
volatile
(
asm
volatile
(
"0:
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
"ldr r5, [%[kernel0], #8]
\n
"
"pld [%[r0], #128]
\n
"
"vld1.s8 {d4-d5}, [%[r0]]
\n
"
// d4=r00 d5=r00n
"0:
\n
"
"add %[r0], #8
\n
"
"vld1.8 {d2-d3}, [%[r0]]
\n
"
// r0
"add %[r0], #8
\n
"
"pld [%[r3], #128]
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vld1.s8 {d6-d7}, [%[r3]]
\n
"
// d6=r30 d7=r30n
"vext.8 d5, d2, d3, #2
\n
"
"add %[r3], #8
\n
"
"vdup.s8 d6, d0[0]
\n
"
"vdup.s8 d7, d0[1]
\n
"
"vext.s8 d8, d4, d5, #1
\n
"
// d8=r01
"vdup.s8 d8, d0[2]
\n
"
"vext.s8 d10, d6, d7, #1
\n
"
// d10=r31
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmull.s8 q8, d4, %[_k00]
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vmull.s8 q9, d6, %[_k20]
\n
"
"vaddl.s16 q12, d12, d14
\n
"
"vaddl.s16 q13, d13, d15
\n
"
"vext.s8 d9, d4, d5, #2
\n
"
// d9=r02
"vext.s8 d11, d6, d7, #2
\n
"
// d11=r32
"vld1.8 {d2-d3}, [%[r1]]
\n
"
// r1
"add %[r1], #8
\n
"
"vmlal.s8 q8, d8, %[_k01]
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vmlal.s8 q9, d10, %[_k21]
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"pld [%[r1], #128]
\n
"
"vmull.s8 q6, d2, d6
\n
"
// next row
"vld1.s8 {d4-d5}, [%[r1]]
\n
"
// d4=r10 d5=r10n
"vmull.s8 q7, d4, d7
\n
"
"add %[r1], #8
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vaddl.s16 q8, d12, d14
\n
"
"vmlal.s8 q8, d9, %[_k02]
\n
"
"vaddl.s16 q9, d13, d15
\n
"
"vmlal.s8 q9, d11, %[_k22]
\n
"
"vdup.s8 d6, d0[3]
\n
"
"vext.s8 d8, d4, d5, #1
\n
"
// d8=r11
"vdup.s8 d7, d0[4]
\n
"
"vdup.s8 d8, d0[5]
\n
"
"vmlal.s8 q8, d4, %[_k10]
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmlal.s8 q9, d4, %[_k00]
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vext.s8 d9, d4, d5, #2
\n
"
// d9=r12
"vaddw.s16 q12, q12, d12
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"vmlal.s8 q8, d8, %[_k11]
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vmlal.s8 q9, d8, %[_k01]
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"pld [%[r2], #128]
\n
"
"vld1.8 {d2-d3}, [%[r2]]
\n
"
// r2
"vld1.s8 {d6-d7}, [%[r2]]
\n
"
// d6=r20 d7=r20n
"add %[r2], #8
\n
"
"add %[r2], #8
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vmlal.s8 q8, d9, %[_k12]
\n
"
"vmlal.s8 q9, d9, %[_k02]
\n
"
"vmull.s8 q6, d2, d6
\n
"
// next row
"vmull.s8 q7, d4, d7
\n
"
"vext.s8 d10, d6, d7, #1
\n
"
// d10=r21
"vmlal.s8 q6, d5, d8
\n
"
"vaddw.s16 q8, q8, d12
\n
"
"vmlal.s8 q8, d6, %[_k20]
\n
"
"vaddw.s16 q8, q8, d14
\n
"
"vmlal.s8 q9, d6, %[_k10]
\n
"
"vaddw.s16 q9, q9, d13
\n
"
"vaddw.s16 q9, q9, d15
\n
"
"vext.s8 d11, d6, d7, #2
\n
"
// d11=r22
"vdup.s8 d6, d0[6]
\n
"
"vmlal.s8 q8, d10, %[_k21]
\n
"
"vdup.s8 d7, d0[7]
\n
"
"vmlal.s8 q9, d10, %[_k11]
\n
"
"vdup.s8 d8, r5
\n
"
"vmull.s8 q6, d2, d6
\n
"
"pld [%[outptr0], #256]
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vld1.s32 {d0-d3}, [%[outptr0]]
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vaddw.s16 q12, q12, d12
\n
"
"vmlal.s8 q8, d11, %[_k22]
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"vmlal.s8 q9, d11, %[_k12]
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"pld [%[outptr0n], #256]
\n
"
"vld1.s32 {d12-d15}, [%[outptr0n]]
\n
"
"vld1.32 {d12-d15}, [%[output0]]
\n
"
"vadd.s32 q6, q6, q12
\n
"
"vaddw.s16 q0, q0, d16
\n
"
"vadd.s32 q7, q7, q13
\n
"
"vaddw.s16 q1, q1, d17
\n
"
"vst1.32 {d12-d15}, [%[output0]]!
\n
"
"vaddw.s16 q6, q6, d18
\n
"
"vaddw.s16 q7, q7, d19
\n
"
"vld1.8 {d2-d3}, [%[r3]]
\n
"
// r3
"add %[r3], #8
\n
"
"vst1.s32 {d0-d3}, [%[outptr0]]!
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"subs %[nn], #1
\n
"
"vmull.s8 q6, d2, d6
\n
"
// next row
"vst1.s32 {d12-d15}, [%[outptr0n]]!
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"bne 0b
\n
"
"vaddw.s16 q8, q8, d12
\n
"
"vaddw.s16 q8, q8, d14
\n
"
:
[
nn
]
"+r"
(
nn
),
[
outptr0
]
"+r"
(
outptr0
),
"vaddw.s16 q9, q9, d13
\n
"
[
outptr0n
]
"+r"
(
outptr0n
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
"vaddw.s16 q9, q9, d15
\n
"
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
)
:
[
_k00
]
"w"
(
_k00
),
[
_k01
]
"w"
(
_k01
),
[
_k02
]
"w"
(
_k02
),
"vld1.32 {d12-d15}, [%[output0n]]
\n
"
[
_k10
]
"w"
(
_k10
),
[
_k11
]
"w"
(
_k11
),
[
_k12
]
"w"
(
_k12
),
"vadd.s32 q6, q6, q8
\n
"
[
_k20
]
"w"
(
_k20
),
[
_k21
]
"w"
(
_k21
),
[
_k22
]
"w"
(
_k22
)
"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"
,
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"q8"
,
"q9"
);
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
"r5"
);
}
}
if
(
remain
>
0
)
{
for
(;
remain
>
0
;
remain
--
)
{
asm
volatile
(
asm
volatile
(
"vld1.s8 {d0[0]}, [%[r0]]!
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
"vld1.s8 {d0[1]}, [%[r0]]!
\n
"
"ldr r5, [%[kernel0], #8]
\n
"
"vld1.s8 {d0[2]}, [%[r0]]
\n
"
"sub %[r0], #2
\n
"
"0:
\n
"
"vld1.8 d4, [%[r0]]
\n
"
"vld1.s8 {d0[3]}, [%[r1]]!
\n
"
"vld1.8 d5, [%[r1]]
\n
"
"vld1.s8 {d0[4]}, [%[r1]]!
\n
"
"vld1.8 d6, [%[r2]]
\n
"
"vld1.s8 {d0[5]}, [%[r1]]
\n
"
"vld1.8 d7, [%[r3]]
\n
"
"sub %[r1], #2
\n
"
"add %[r0], #1
\n
"
"add %[r1], #1
\n
"
"vld1.s8 {d0[6]}, [%[r2]]!
\n
"
"add %[r2], #1
\n
"
"vld1.s8 {d0[7]}, [%[r2]]!
\n
"
// d0=r
"add %[r3], #1
\n
"
"vdup.s8 d2, r5
\n
"
"vld1.s8 {d4[]}, [%[r2]]
\n
"
// d4=r22
"vext.8 d8, d0, d2, #3
\n
"
"sub %[r2], #2
\n
"
"vext.8 d9, d0, d2, #6
\n
"
"vext.s8 d1, d0, d4, #3
\n
"
"vmull.s8 q6, d4, d0
\n
"
"vmull.s8 q7, d5, d8
\n
"
"vld1.s8 {d1[6]}, [%[r3]]!
\n
"
"vmlal.s8 q6, d6, d9
\n
"
"vld1.s8 {d1[7]}, [%[r3]]!
\n
"
// d1=rn
"vaddl.s16 q12, d12, d14
\n
"
"vdup.s32 d2, d24[1]
\n
"
"vld1.s8 {d2}, [%[ktmp]]!
\n
"
// d2=k01234567
"vadd.s32 d24, d24, d2
\n
"
"vadd.s32 d24, d24, d25
\n
"
"vld1.s8 {d5[]}, [%[r3]]
\n
"
// d5=r32
"sub %[r3], #2
\n
"
"ldr r7, [%[output0]]
\n
"
"vdup.s32 d14, r7
\n
"
"veor d3, d3
\n
"
"vadd.s32 d14, d14, d24
\n
"
"vst1.32 d14[0], [%[output0]]!
\n
"
"vmull.s8 q8, d0, d2
\n
"
"vmull.s8 q9, d1, d2
\n
"
"vmull.s8 q6, d5, d0
\n
"
"vmull.s8 q7, d6, d8
\n
"
"vld1.s8 {d3[0]}, [%[ktmp]]
\n
"
// d3=k8 ... zeros
"vmlal.s8 q6, d7, d9
\n
"
"sub %[ktmp], #8
\n
"
"vaddl.s16 q12, d12, d14
\n
"
"vdup.s32 d2, d24[1]
\n
"
"vmlal.s8 q8, d4, d3
\n
"
"vadd.s32 d24, d24, d2
\n
"
"vmlal.s8 q9, d5, d3
\n
"
"vadd.s32 d24, d24, d25
\n
"
"vld1.s32 {d6[0]}, [%[outptr0]]
\n
"
"ldr r7, [%[output0n]]
\n
"
"vdup.s32 d14, r7
\n
"
"vadd.s16 d16, d16, d17
\n
"
"vadd.s32 d14, d14, d24
\n
"
"vadd.s16 d18, d18, d19
\n
"
"vst1.32 d14[0], [%[output0n]]!
\n
"
"vld1.s32 {d6[1]}, [%[outptr0n]]
\n
"
"subs %[remain], #1
\n
"
"bne 0b
\n
"
"vpadd.s16 d16, d16, d18
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
"vpadal.s16 d6, d16
\n
"
[
remain
]
"+r"
(
remain
),
[
output0
]
"+r"
(
output0
),
[
output0n
]
"+r"
(
output0n
)
"vst1.s32 {d6[0]}, [%[outptr0]]!
\n
"
:
[
kernel0
]
"r"
(
kernel0
)
"vst1.s32 {d6[1]}, [%[outptr0n]]!
\n
"
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
"q8"
,
"q9"
,
"q10"
,
"r5"
,
"r7"
);
:
[
outptr0
]
"+r"
(
outptr0
),
[
outptr0n
]
"+r"
(
outptr0n
),
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
r3
]
"+r"
(
r3
),
[
ktmp
]
"+r"
(
ktmp
)
:
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q8"
,
"q9"
);
r0
++
;
r1
++
;
r2
++
;
r3
++
;
}
}
output0
+=
output_w
;
r0
+=
2
+
w
;
output0n
+=
output_w
;
r1
+=
2
+
w
;
r2
+=
2
+
w
;
r3
+=
2
+
w
;
outptr0
+=
outw
;
outptr0n
+=
outw
;
}
}
// remain output height
for
(;
i
<
outh
;
i
++
)
{
for
(;
oh
<
output_h
;
++
oh
)
{
int
nn
=
outw
>>
3
;
const
int8_t
*
r0
=
in_data
+
ic
*
image_size
+
oh
*
input_w
;
int
remain
=
outw
&
7
;
const
int8_t
*
r1
=
r0
+
input_w
;
if
(
nn
>
0
)
{
const
int8_t
*
r2
=
r1
+
input_w
;
int
ow
=
output_w
>>
3
;
int
remain
=
output_w
&
0x7
;
if
(
ow
>
0
)
{
asm
volatile
(
asm
volatile
(
"0:
\n
"
"vld1.8 {d0}, [%[kernel0]]
\n
"
"ldr r5, [%[kernel0], #8]
\n
"
"pld [%[r0], #128]
\n
"
"vld1.s8 {d4-d5}, [%[r0]]
\n
"
// d4=r00 d5=r00n
"0:
\n
"
"add %[r0], #8
\n
"
"vld1.8 {d2-d3}, [%[r0]]
\n
"
// r0
"add %[r0], #8
\n
"
"vext.s8 d8, d4, d5, #1
\n
"
// d8=r01
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vmull.s8 q8, d4, %[_k00]
\n
"
"vdup.s8 d6, d0[0]
\n
"
"vdup.s8 d7, d0[1]
\n
"
"vext.s8 d9, d4, d5, #2
\n
"
// d9=r02
"vdup.s8 d8, d0[2]
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q9, d8, %[_k01]
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"pld [%[r1], #128]
\n
"
"vaddl.s16 q12, d12, d14
\n
"
"vld1.s8 {d6-d7}, [%[r1]]
\n
"
// d6=r10 d7=r10n
"vaddl.s16 q13, d13, d15
\n
"
"add %[r1], #8
\n
"
"vld1.8 {d2-d3}, [%[r1]]
\n
"
// r1
"vmlal.s8 q8, d9, %[_k02]
\n
"
"add %[r1], #8
\n
"
"vext.8 d4, d2, d3, #1
\n
"
"vext.s8 d10, d6, d7, #1
\n
"
// d10=r11
"vext.8 d5, d2, d3, #2
\n
"
"vdup.s8 d6, d0[3]
\n
"
"vmlal.s8 q9, d6, %[_k10]
\n
"
"vdup.s8 d7, d0[4]
\n
"
"vdup.s8 d8, d0[5]
\n
"
"vext.s8 d11, d6, d7, #2
\n
"
// d11=r12
"vmull.s8 q6, d2, d6
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q8, d10, %[_k11]
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vaddw.s16 q12, q12, d12
\n
"
"pld [%[r2], #128]
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"vld1.s8 {d4-d5}, [%[r2]]
\n
"
// d4=r20 d5=r20n
"vaddw.s16 q13, q13, d13
\n
"
"add %[r2], #8
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"vmlal.s8 q9, d11, %[_k12]
\n
"
"vld1.8 {d2-d3}, [%[r2]]
\n
"
// r2
"add %[r2], #8
\n
"
"vext.s8 d8, d4, d5, #1
\n
"
// d8=r21
"vext.8 d4, d2, d3, #1
\n
"
"vext.8 d5, d2, d3, #2
\n
"
"vmlal.s8 q8, d4, %[_k20]
\n
"
"vdup.s8 d6, d0[6]
\n
"
"vdup.s8 d7, d0[7]
\n
"
"vext.s8 d9, d4, d5, #2
\n
"
// d9=r22
"vdup.s8 d8, r5
\n
"
"vmull.s8 q6, d2, d6
\n
"
"vmlal.s8 q9, d8, %[_k21]
\n
"
"vmull.s8 q7, d4, d7
\n
"
"vmlal.s8 q6, d5, d8
\n
"
"vmlal.s8 q8, d9, %[_k22]
\n
"
"vaddw.s16 q12, q12, d12
\n
"
"vaddw.s16 q12, q12, d14
\n
"
"pld [%[outptr0], #256]
\n
"
"vaddw.s16 q13, q13, d13
\n
"
"vld1.s32 {d0-d3}, [%[outptr0]]
\n
"
"vaddw.s16 q13, q13, d15
\n
"
"vadd.s16 q8, q8, q9
\n
"
"vld1.32 {d12-d15}, [%[output0]]
\n
"
"vadd.s32 q6, q6, q12
\n
"
"vaddw.s16 q0, q0, d16
\n
"
"vadd.s32 q7, q7, q13
\n
"
"vaddw.s16 q1, q1, d17
\n
"
"vst1.32 {d12-d15}, [%[output0]]!
\n
"
"subs %[nn], #1
\n
"
"subs %[ow], #1
\n
"
"bne 0b
\n
"
"vst1.s32 {d0-d3}, [%[outptr0]]!
\n
"
:
[
r0
]
"+r"
(
r0
),
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
),
[
ow
]
"+r"
(
ow
),
[
output0
]
"+r"
(
output0
)
"bne 0b
\n
"
:
[
kernel0
]
"r"
(
kernel0
)
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q6"
,
"q7"
,
:
[
nn
]
"+r"
(
nn
),
[
outptr0
]
"+r"
(
outptr0
),
[
r0
]
"+r"
(
r0
),
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
"r5"
);
[
r1
]
"+r"
(
r1
),
[
r2
]
"+r"
(
r2
)
:
[
_k00
]
"w"
(
_k00
),
[
_k01
]
"w"
(
_k01
),
[
_k02
]
"w"
(
_k02
),
[
_k10
]
"w"
(
_k10
),
[
_k11
]
"w"
(
_k11
),
[
_k12
]
"w"
(
_k12
),
[
_k20
]
"w"
(
_k20
),
[
_k21
]
"w"
(
_k21
),
[
_k22
]
"w"
(
_k22
)
:
"cc"
,
"memory"
,
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q4"
,
"q5"
,
"q8"
,
"q9"
);
}
}
for
(;
remain
>
0
;
remain
--
)
{
if
(
remain
>
0
)
{
int
sum0
=
0
;
asm
volatile
(
sum0
+=
r0
[
0
]
*
ktmp
[
0
];
"vld1.8 {d0}, [%[kernel0]]
\n
"
sum0
+=
r0
[
1
]
*
ktmp
[
1
];
"ldr r5, [%[kernel0], #8]
\n
"
sum0
+=
r0
[
2
]
*
ktmp
[
2
];
sum0
+=
r1
[
0
]
*
ktmp
[
3
];
"0:
\n
"
sum0
+=
r1
[
1
]
*
ktmp
[
4
];
"vld1.8 d4, [%[r0]]
\n
"
sum0
+=
r1
[
2
]
*
ktmp
[
5
];
"vld1.8 d5, [%[r1]]
\n
"
sum0
+=
r2
[
0
]
*
ktmp
[
6
];
"vld1.8 d6, [%[r2]]
\n
"
sum0
+=
r2
[
1
]
*
ktmp
[
7
];
"add %[r0], #1
\n
"
sum0
+=
r2
[
2
]
*
ktmp
[
8
];
"add %[r1], #1
\n
"
"add %[r2], #1
\n
"
*
outptr0
+=
sum0
;
"vdup.s8 d2, r5
\n
"
"vext.8 d8, d0, d2, #3
\n
"
r0
++
;
"vext.8 d9, d0, d2, #6
\n
"
r1
++
;
r2
++
;
"vmull.s8 q6, d4, d0
\n
"
outptr0
++
;
"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"
);
}
}
r0
+=
2
;
r1
+=
2
;
r2
+=
2
;
}
}
ktmp
+=
9
;
}
}
}
}
#else
// TODO(hjchen2)
#endif
}
}
}
// namespace operators
}
// namespace operators
...
...
test/CMakeLists.txt
浏览文件 @
2d300f69
...
@@ -220,6 +220,10 @@ if (NOT FOUND_MATCH)
...
@@ -220,6 +220,10 @@ if (NOT FOUND_MATCH)
ADD_EXECUTABLE
(
test-dequantize-op operators/test_dequantize_op.cpp test_helper.h test_include.h
)
ADD_EXECUTABLE
(
test-dequantize-op operators/test_dequantize_op.cpp test_helper.h test_include.h
)
target_link_libraries
(
test-dequantize-op paddle-mobile
)
target_link_libraries
(
test-dequantize-op paddle-mobile
)
# test int8 conv op
ADD_EXECUTABLE
(
test-int8-conv-op operators/test_int8_conv_op.cpp test_helper.h test_include.h
)
target_link_libraries
(
test-int8-conv-op paddle-mobile
)
# gen test log
# gen test log
ADD_EXECUTABLE
(
test-log common/test_log.cpp
)
ADD_EXECUTABLE
(
test-log common/test_log.cpp
)
target_link_libraries
(
test-log paddle-mobile
)
target_link_libraries
(
test-log paddle-mobile
)
...
...
test/operators/test_int8_conv_op.cpp
浏览文件 @
2d300f69
...
@@ -139,11 +139,11 @@ int TestConvOp() {
...
@@ -139,11 +139,11 @@ int TestConvOp() {
int
dilation_h
=
1
;
int
dilation_h
=
1
;
int
dilation_w
=
1
;
int
dilation_w
=
1
;
int
batch_size
=
2
;
int
batch_size
=
1
;
int
input_c
=
3
;
int
input_c
=
3
;
int
input_h
=
100
;
int
input_h
=
25
;
int
input_w
=
100
;
int
input_w
=
25
;
int
output_c
=
8
;
int
output_c
=
3
;
framework
::
DDim
input_shape
=
framework
::
DDim
input_shape
=
framework
::
make_ddim
({
batch_size
,
input_c
,
input_h
,
input_w
});
framework
::
make_ddim
({
batch_size
,
input_c
,
input_h
,
input_w
});
framework
::
DDim
filter_shape
=
framework
::
DDim
filter_shape
=
...
@@ -158,11 +158,11 @@ int TestConvOp() {
...
@@ -158,11 +158,11 @@ int TestConvOp() {
auto
input_var
=
scope
.
get
()
->
Var
(
"input"
);
auto
input_var
=
scope
.
get
()
->
Var
(
"input"
);
auto
input
=
input_var
->
template
GetMutable
<
framework
::
LoDTensor
>();
auto
input
=
input_var
->
template
GetMutable
<
framework
::
LoDTensor
>();
SetupTensor
<
Itype
>
(
input
,
input_shape
,
-
7
,
7
);
SetupTensor
<
Itype
>
(
input
,
input_shape
,
-
127
,
12
7
);
auto
filter_var
=
scope
.
get
()
->
Var
(
"filter"
);
auto
filter_var
=
scope
.
get
()
->
Var
(
"filter"
);
auto
filter
=
filter_var
->
template
GetMutable
<
framework
::
LoDTensor
>();
auto
filter
=
filter_var
->
template
GetMutable
<
framework
::
LoDTensor
>();
SetupTensor
<
Itype
>
(
filter
,
filter_shape
,
-
7
,
7
);
SetupTensor
<
Itype
>
(
filter
,
filter_shape
,
-
127
,
12
7
);
auto
output_var
=
scope
.
get
()
->
Var
(
"output"
);
auto
output_var
=
scope
.
get
()
->
Var
(
"output"
);
framework
::
AttributeMap
attrs
;
framework
::
AttributeMap
attrs
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录