我正在开发一个拥有大量SIMD内部代码的代码库。现在我们有AVX2,我们仍然需要在非AVX2处理器上运行的SIMD代码,这将是更多的工作。此外,AVX2 shuffle的128位车道交叉限制也使事情复杂化。由于这些原因,现在是更多地依赖自动矢量化的好时机。令我害怕的主要事情是,在发生问题时,可能会出现单一的无辜变更,从而导致并行性和调试自动矢量化代码的前景。
我用g ++ -O1 -g -ftree-vectorize编译了以下内容并尝试使用GDB(有没有人知道为什么-ftree-vectorize不能与-O0一起使用?)
float a[1000], b[1000], c[1000];
int main(int argc, char **argv)
{
for (int i = 0; i < argc; ++i)
c[i] = a[i] + b[i];
return 0;
}
但没有得到任何有意义的结果。例如,有时i的值表示&lt; optimized out&gt;而其他时候它会跳过20。
似乎主要的问题是很难将SIMD状态映射到原始C状态以进行调试。但实际上,可以这样做吗?
答案 0 :(得分:0)
在自动矢量化代码上使用调试器很棘手,尤其是当你想检查需要表现不同的变量时(例如循环计数器)。
您可以使用调试版本(-O0
或-Og
),也可以了解编译器如何对代码进行矢量化,并检查寄存器asm和寄存器。根据您需要跟踪的错误类型,您可能会或可能不会遇到自动矢量化构建的问题。
从评论中可以看出,您更感兴趣的是检查自动矢量化的效率,而不是实际调试以修复代码中的逻辑错误。看看asm和基准,可能是你最好的选择。 (甚至在调用之前/之后的简单rdtsc
,或者在测试性能和正确性的单元测试中。)
有时编译器会生成一个循环的多个版本,例如对于输入数组重叠的情况,以及它们不重叠的情况。单步执行(通过指令,使用stepi
,在gdb中使用layout asm
)可以提供帮助,直到找到实际执行大部分工作的循环。然后你可以专注于它的矢量化方式。如果您想要消除检查和备用版本,restrict
指针可能会有所帮助。还有p = __builtin_assume_aligned(p, 16)
。
您还可以使用Intel's free code analyzer尝试静态分析迭代所需的周期数。将IACA标记放在循环体的顶部,并在循环结束后,希望GCC将它们放在自动向量化循环中的适当位置,并且内联asm不会破坏自动向量化。
通过指向http://agner.org/optimize/的链接,无法完成优化答案,所以请转到此处。