如何阻止GCC破坏我的霓虹灯本质?

如何阻止GCC破坏我的霓虹灯本质?,c,gcc,arm,neon,intrinsics,C,Gcc,Arm,Neon,Intrinsics,我需要为一个项目编写优化的NEON代码,我非常乐意编写汇编语言,但为了可移植性/可维护性,我使用NEON Instrinsic。这段代码需要尽可能快,所以我利用我在ARM优化方面的经验来正确地交错指令,避免管道停顿。无论我做什么,GCC都会对我不利,并且会创建速度较慢、充满停顿的代码 有人知道如何让GCC让路,把我的内在语言翻译成代码吗 这里有一个例子:我有一个简单的循环,它对浮点值进行求反和复制。它一次使用4组4,以便为内存加载和指令执行留出时间。剩下的寄存器很多,所以没有理由把事情弄得这么糟

我需要为一个项目编写优化的NEON代码,我非常乐意编写汇编语言,但为了可移植性/可维护性,我使用NEON Instrinsic。这段代码需要尽可能快,所以我利用我在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);
} 
float32x4_t f32_0、f32_1、f32_2、f32_3;
int x;

对于(x=0;x广义而言,您在这里看到的优化类称为“指令调度”。GCC使用指令调度来尝试为程序的每个基本块中的指令构建更好的调度。这里,“调度”指的是块中指令的任何正确顺序,以及“更好”计划可以是一个避免暂停和其他管道危险的计划,或者是一个减少变量活动范围(导致更好的寄存器分配)的计划,或者是指令上的一些其他排序目标

为了避免由于危险而导致的暂停,GCC使用了您所针对的处理器的管道模型(有关用于这些处理器的规范语言的详细信息以及管道模型示例,请参阅)。此模型对处理器功能单元的GCC调度算法以及这些功能单元上指令的执行特征给出了一些指示。然后,GCC可以调度指令,以最大限度地减少由于多条指令需要相同的处理器资源而造成的结构危险

不带
-mcpu
-mtune
选项(对于编译器),或
--带cpu
,或
--带tune
选项(对于编译器的配置),GCC for ARM或AArch64将尝试为您目标的体系结构版本使用代表性模型。在这种情况下,
-march=armv7-a
,会导致编译器尝试调度指令,就好像在命令行上传递了
-mtune=cortex-a8

因此,您在输出中看到的是GCC试图将您的输入转换为一个计划,它希望在Cortex-A8上运行时能够很好地执行,并在实现ARMv7-a架构的处理器上运行得相当好

要对此进行改进,您可以尝试:

  • 明确设置目标处理器(
    -mcpu=cortex-a7
  • 完全禁用指令调度(`-fno-schedule-insns-fno-schedule-insns2)
请注意,完全禁用指令调度可能会在其他地方给您带来问题,因为GCC将不再试图减少代码中的管道危险


编辑关于您的编辑,GCC中的性能错误可以在GCC Bugzilla中报告(请参阅)正如正确性错误一样。当然,所有的优化都会涉及到一定程度的启发式,编译器可能无法击败经验丰富的汇编程序员,但如果编译器正在做一些特别令人震惊的事情,它可能值得强调。

有用的信息是您与编译器一起使用的GCC版本正在调整的CPU(-mcpu=???或-mtune=??)。一般来说,答案是,因为GCC认为它使用的交错比您要求的交错更能提高处理器利用率。另一个问题是,您如何检测到暂停?@coredump-禁用优化会使它产生更慢的代码,仍然会弄乱内部。如果您希望o写汇编,写汇编。反正它更可读。尝试显式的
-mcpu=cortex-a7
来更改编译器正在使用的指令调度模型。如果您想使用更极端的标志来尝试,您可以要求GCC不要使用
-fno schedule insns-fno-schedule-insns2
@JamesGreenhalgh尝试任何指令调度感谢您的建议。设置-mcpu=cortex-a7可以生成更好的代码,从而更好地交错指令并加快速度。设置-fno调度选项都会降低输出速度。
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