C++ 你能调试自动矢量化循环吗?

C++ 你能调试自动矢量化循环吗?,c++,vectorization,sse,simd,avx2,C++,Vectorization,Sse,Simd,Avx2,我正在开发一个有很多SIMD内在代码的代码库。既然我们有了AVX2,我们仍然需要在不支持AVX2的处理器上运行SIMD代码,这将大大增加工作量。此外,AVX2随机播放的128位车道交叉限制也使事情变得复杂。出于这些原因,现在是更多地依赖自动矢量化的好时机。让我害怕的主要事情是一个简单的更改可能会破坏并行性,以及在出现问题时调试自动矢量化代码的可能性 我已经用g++-O1-g-ftree vectorize编译了以下内容,并尝试用GDB逐步实现,有人知道为什么-ftree vectorize不能与

我正在开发一个有很多SIMD内在代码的代码库。既然我们有了AVX2,我们仍然需要在不支持AVX2的处理器上运行SIMD代码,这将大大增加工作量。此外,AVX2随机播放的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的值表示,而有时它会跳20


似乎主要的问题是很难将SIMD状态映射到原始C状态进行调试。但实际上,可以这样做吗?

在自动矢量化代码上使用调试器是很棘手的,尤其是当您想要检查需要不同行为的变量时,例如循环计数器

您可以使用调试构建-O0或-Og,也可以了解编译器如何将代码矢量化,并检查寄存器asm和寄存器。根据需要追踪的bug类型,自动矢量化构建可能会有问题,也可能没有问题

从评论中听起来,您更感兴趣的是检查自动矢量化的效率,而不是实际调试以修复代码中的逻辑错误。查看asm和基准可能是您最好的选择。即使是一个简单的rdtsc在调用之前/之后,或者在测试性能和正确性的单元测试中

有时编译器会生成一个循环的多个版本,例如,对于输入数组重叠的情况,以及对于它们不重叠的情况。在gdb中使用指令单步执行、stepi和布局asm可以有所帮助,直到找到实际完成大部分工作的循环。然后你可以关注它是如何矢量化的。如果要消除检查和备用版本,限制指针可能会有所帮助。还有p=\uu内置的\u假设\u对齐的p,16

您还可以使用尝试静态分析迭代需要多少周期。将IACA标记放在循环体顶部和循环结束后,希望GCC将它们放在自动矢量化循环中的适当位置,并且内联asm不会中断自动矢量化


没有一个优化答案会包含指向的链接,所以请点击这里。

为什么要调试它?如果您想验证它是否得到了矢量化,那么检查汇编代码或以完全优化设置运行基准测试不是更好吗?如果你想找到一个bug,调试非矢量化的或者非优化的版本。是的,编译器bug在发生的时候非常严重。我不知道源代码级调试器是否是实现它的正确工具,但无论如何,我理解。到目前为止,错误调试大多是假设性的。我记得在Visual C++ 2010矢量化程序中提交了一个错误,它将一个未对齐的负载与算术指令不正确地融合到一个x86指令中,导致它在一个不对齐的数组上运行时崩溃。从汇编代码来看这是非常困难的。当生成多个版本的代码时,情况更糟一些用于处理SIMD余数或未对齐的部分,一些用于处理别名数组等。如果我可以一次遍历GDB 4、8或16中的循环,并并排查看相应的汇编代码,这可能有助于一些人理解。实际上,我真正想要的是一个源代码到源代码的编译器,它用向量类型和运算符重写代码。有这样的事情吗?使用gcc,-fdump tree optimized生成一个具有类似C的语法的文件,该语法显示执行了哪些优化。