即使我只编译armv7
,NEON乘法累加内在函数似乎被分解为单独的乘法和加法。
我已经体验过几个版本的Xcode,最新的4.5版,iOS SDK 5到6版,以及不同的优化设置,都是通过Xcode和命令行直接构建的。
例如,构建和反汇编包含<{p}}的test.cpp
#include <arm_neon.h>
float32x4_t test( float32x4_t a, float32x4_t b, float32x4_t c )
{
float32x4_t result = a;
result = vmlaq_f32( result, b, c );
return result;
}
与
clang++ -c -O3 -arch armv7 -o "test.o" test.cpp
otool -arch armv7 -tv test.o
结果
test.o:
(__TEXT,__text) section
__Z4test19__simd128_float32_tS_S_:
00000000 f10d0910 add.w r9, sp, #16 @ 0x10
00000004 46ec mov ip, sp
00000006 ecdc2b04 vldmia ip, {d18-d19}
0000000a ecd90b04 vldmia r9, {d16-d17}
0000000e ff420df0 vmul.f32 q8, q9, q8
00000012 ec432b33 vmov d19, r2, r3
00000016 ec410b32 vmov d18, r0, r1
0000001a ef400de2 vadd.f32 q8, q8, q9
0000001e ec510b30 vmov r0, r1, d16
00000022 ec532b31 vmov r2, r3, d17
00000026 4770 bx lr
而不是预期使用vmla.f32
。
我做错了什么,拜托?
答案 0 :(得分:3)
这是llvm-clang的错误或优化。 armcc或gcc会按照您的预期生成vmla,但如果您阅读 Cortex-A系列程序员指南v3 ,它会说:
20.2.3计划
在某些情况下,可能会有相当长的延迟,尤其是VMLA乘法累加(整数为5个周期;浮点数为7个周期)。应优化使用这些指令的代码,以避免在准备好之前尝试使用结果值,否则会发生停顿。尽管有几个周期结果延迟,但这些指令完全管道化了几个 操作可以立即进行。
因此,llvm-clang将vmla分离为multiply并累积以填充管道是有意义的。
答案 1 :(得分:1)
霓虹灯乘加指令执行操作
c = c + a * b
请注意,目的地和其中一个来源是相同的。如果要执行操作
d = c + a * b
编译器必须将其分解为两个指令
d = c
d = d + a * b
替代方案,它可以将其分解为乘法+添加指令
d = a * b
d = d + c
在Cortex-A8 / A9上,两种变体具有相同的吞吐量,但在Cortex-A8上,第二种变体具有较低的延迟,因为乘法 - 加法指令在许多情况下会导致失速。