【问题标题】:How to auto-vectorize strided writes with GCC?如何使用 GCC 自动矢量化跨步写入?
【发布时间】:2016-01-16 12:29:37
【问题描述】:

当使用 GCC 5.2 使用 -std=c99-O3-mavx2 编译时, 以下代码示例自动矢量化 (assembly here):

#include <stdint.h>

void test(uint32_t *restrict a,
          uint32_t *restrict b) {
  uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
  uint32_t *b_aligned = __builtin_assume_aligned(b, 32);

  for (int i = 0; i < (1L << 10); i += 2) {
    a_aligned[i] = 42 * b_aligned[i];
    a_aligned[i+1] = 3 * a_aligned[i+1];
  }
}

但以下代码示例不会自动矢量化 (assembly here):

#include <stdint.h>

void test(uint32_t *restrict a,
          uint32_t *restrict b) {
  uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
  uint32_t *b_aligned = __builtin_assume_aligned(b, 32);

  for (int i = 0; i < (1L << 10); i += 2) {
    a_aligned[i] = 42 * b_aligned[i];
    a_aligned[i+1] = a_aligned[i+1];
  }
}

样本之间的唯一区别是a_aligned[i+1] 的比例因子。

GCC 4.8、4.9 和 5.1 也是如此。将volatile 添加到a_aligned 的声明会完全禁止自动矢量化。第一个样本对我们来说始终比第二个运行得快,对于较小的类型(例如 uint8_t 而不是 uint32_t)具有更明显的加速。

有没有办法让第二个代码示例使用 GCC 自动矢量化?

【问题讨论】:

  • 所以唯一的区别是缩放因子(3 vs 没有)?尝试明确添加 1 作为比例因子。如果这样可以解决,那就是编译器错误。
  • 或者尝试注释掉声明a_aligned[i+1] = a_aligned[i+1],或者将其重写为a_aligned[i+1] *= 1。编译器可能不知道如何处理您的无操作自赋值,而不是完全按照您说的去做。
  • @Jeff 实际上,唯一的区别是缩放因子。添加显式 1 不会使第二个代码示例自动矢量化 (assembly here)。
  • @DavidHammen 将行注释掉 (assembly here) 并将其重写为复合赋值 (assembly here) 也不起作用。
  • 你可以只删除第 2 行,因为它等同于身份。

标签: c performance gcc vectorization c99


【解决方案1】:

以下版本是矢量化的,但如果你问我,那就太丑了......

#include <stdint.h>

void test(uint32_t *a, uint32_t *aa,
          uint32_t *restrict b) {
  #pragma omp simd aligned(a,aa,b:32)
  for (int i = 0; i < (1L << 10); i += 2) {
    a[i] = 2 * b[i];
    a[i+1] = aa[i+1];
  }
}

-fopenmp编译并用test(a, a, b)调用。

【讨论】:

  • 这种方法有两个注意事项。首先是您在aaa 上丢失了restrict 关键字,这可能会导致您回读aa 的次数超出了您的需要。提供的示例代码很好(在这种情况下,如果 aaa 别名以一种麻烦的方式,GCC 会分支到非矢量化代码),但通常它可能会导致比必要的更多读取。例如,考虑是否将b 替换为a;在这种情况下,会生成许多不需要的额外 vmovdq 指令。
  • 第二个是-O3,GCC会自动内联test()。这意味着在test() 内联的地方,它将识别aaa 并且无法自动矢量化。这可以通过 GCC 的 __attribute__ ((noinline)) 修复,但这仍然会产生不必要的函数调用开销。
猜你喜欢
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 2017-05-15
  • 2010-09-29
  • 2013-03-06
  • 2021-08-10
  • 2019-04-05
相关资源
最近更新 更多