【问题标题】:Inform c or c++ compiler loop length is mutliple of 8通知 c 或 c++ 编译器循环长度是 8 的倍数
【发布时间】:2021-10-21 16:22:03
【问题描述】:

我想用c++编写如下函数(使用gcc 11.1和-O3 -mavx -std=c++17编译)

void f( float * __restrict__ a, float * __restrict__ b, float * __restrict__ c, int64_t n) {
    for (int64_t i = 0; i != n; ++i) {
        a[i] = b[i] + c[i];
    }
}

这会生成大约 60 行汇编代码,其中许多处理 n 不是 8 的倍数的情况。https://godbolt.org/z/61MYPG7an

我知道n 始终是 8 的倍数。我可以更改此代码的一种方法是将for (int64_t i = 0; i != n; ++i) 替换为for (int64_t i = 0; i != (n / 8 * 8); ++i)。这只生成大约 20 条汇编指令。 https://godbolt.org/z/vhvdKMfE9

然而,在第二个神螺栓链接的第 5 行,有一条指令将n 的最低三位归零。如果有办法通知编译器n 将始终是 8 的倍数,那么可以省略该指令而不改变行为。有谁知道在任何 c 或 c++ 编译器(尤其是 gcc 或 clang)上执行此操作的方法?就我而言,这实际上并不重要,但我很感兴趣,但不知道该去哪里看。

【问题讨论】:

  • 你已经有了#include <immintrin.h>,为什么不直接使用那些内在函数呢?
  • 嗨弗拉德,这是其他实验遗留下来的。我这里不需要。对不起!
  • 下面的答案更简洁,但我是说你可以一次循环 8 个元素,并使用内在的 AVX 函数处理它们。

标签: c++ c gcc clang


【解决方案1】:

用__builtin_unreachable声明假设

void f(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int64_t n) {
    if(n % 8 != 0) __builtin_unreachable(); // control flow cannot reach this branch so the condition is not necessary and is optimized out
    for (int64_t i = 0; i != n; ++i) { // if control flow reaches this point n is a multiple of 8
        a[i] = b[i] + c[i];
    }
}

这会产生much shorter code。

【讨论】:

  • 我怀疑您可以使用__assume(...) 在 MSVC 中实现类似的功能。 if (n % 8 != 0 ) __assume(0); 或 __assume(n % 8 == 0)
猜你喜欢
  • 1970-01-01
  • 2012-12-11
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多