Bit*_*ank 6 c gcc arm intrinsics neon
我需要为项目编写优化的NEON代码,我非常乐意编写汇编语言,但为了便携性/可维护性,我使用的是NEON instrinsics.这段代码需要尽可能快,所以我利用我在ARM优化方面的经验来正确地交错指令并避免管道停顿.无论我做什么,GCC都会对我起作用,并且会创建更慢的代码.
有谁知道如何让GCC摆脱困境并将我的内在函数转换为代码?
这是一个例子:我有一个简单的循环来否定和复制浮点值.它一次使用4组4个,以便为内存加载和执行指令留出一些时间.剩下很多寄存器,所以它没有理由把事情搞糟.
float32x4_t f32_0, f32_1, f32_2, f32_3;
int x;
for (x=0; x<n-15; x+=16)
{
f32_0 = vld1q_f32(&s[x]);
f32_1 = vld1q_f32(&s[x+4]);
f32_2 = vld1q_f32(&s[x+8]);
f32_3 = vld1q_f32(&s[x+12]);
__builtin_prefetch(&s[x+64]);
f32_0 = vnegq_f32(f32_0);
f32_1 = vnegq_f32(f32_1);
f32_2 = vnegq_f32(f32_2);
f32_3 = vnegq_f32(f32_3);
vst1q_f32(&d[x], f32_0);
vst1q_f32(&d[x+4], f32_1);
vst1q_f32(&d[x+8], f32_2);
vst1q_f32(&d[x+12], f32_3);
}
Run Code Online (Sandbox Code Playgroud)
这是它生成的代码:
vld1.32 {d18-d19}, [r5]
vneg.f32 q9,q9 <-- GCC intentionally causes stalls
add r7,r7,#16
vld1.32 {d22-d23}, [r8]
add r5,r1,r4
vneg.f32 q11,q11 <-- all of my interleaving is undone (why?!!?)
add r8,r3,#256
vld1.32 {d20-d21}, [r10]
add r4,r1,r3
vneg.f32 q10,q10
add lr,r1,lr
vld1.32 {d16-d17}, [r9]
add ip,r1,ip
vneg.f32 q8,q8
Run Code Online (Sandbox Code Playgroud)
更多信息:
-c -fPIE -march=armv7-a -Wall -O3 -mfloat-abi=hard -mfpu=neon
当我在ASM代码中编写完全与我的内在函数相关的循环时(甚至没有使用额外的src/dest寄存器来获得一些免费的ARM循环),它仍然比GCC的代码更快.
更新:我很欣赏詹姆斯的答案,但在方案中,它并没有真正帮助解决问题.使用cortex-a7选项,我最简单的函数表现得更好,但大多数人看不到任何变化.令人遗憾的是,GCC对内在函数的优化并不是很好.几年前,当我使用Microsoft ARM编译器时,它始终为NEON内在函数创建精心设计的输出,而GCC始终绊倒.有了GCC 4.9.x,一切都没有改变.我当然很欣赏海湾合作委员会的FOSS性质和更大的GNU努力,但不可否认的是,它并没有像英特尔,微软甚至ARM的编译器那样出色.
从广义上讲,您在此处看到的优化类别称为"指令调度".GCC使用指令调度来尝试为程序的每个基本块中的指令构建更好的计划.这里,"时间表"指的是块中指令的任何正确排序,"更好"的时间表可以是避免失速和其他管道危险的时间表,或者是减少变量的有效范围的时间表(导致更好的寄存器分配) ),或指令上的其他一些订购目标.
为了避免由于危险而导致的停顿,GCC使用您所针对的处理器的管道模型(有关这些管理器的规范语言的详细信息,请参见此处,此处为示例管道模型).该模型给出了处理器功能单元的GCC调度算法的一些指示,以及这些功能单元上的指令的执行特性.然后,GCC可以安排指令,以最小化由于需要相同处理器资源的多个指令而导致的结构性危
没有-mcpu
或-mtune
选项(对编译器),或a --with-cpu
或--with-tune
选项(对于编译器的配置),GCC for ARM或AArch64将尝试使用代表性模型来进行您所针对的体系结构修订.在这种情况下,-march=armv7-a
使编译器尝试安排指令,就像-mtune=cortex-a8
在命令行上传递一样.
因此,您在输出中看到的是GCC尝试将您的输入转换为在Cortex-A8上运行时期望执行良好的计划,以及在实现ARMv7-A体系结构的处理器上运行得相当好.
要改进这一点,您可以尝试:
-mcpu=cortex-a7
)请注意,完全禁用指令调度可能会在其他地方引起问题,因为GCC将不再尝试减少代码中的管道危险.
编辑关于您的编辑,GCC中的性能错误可以在GCC Bugzilla中报告(请参阅https://gcc.gnu.org/bugs/),就像正确的错误一样.自然地,所有的优化都涉及到一定程度的启发式,编译器可能无法击败经验丰富的汇编程序员,但如果编译器正在做一些特别令人震惊的事情,那么值得强调一下.