循环内 if(循环不变)if 语句的编译器优化

Den*_*er9 1 c optimization loops micro-optimization compiler-optimization

我在 C 中有一个这样的函数(在伪代码中,删除不重要的部分):

int func(int s, int x, int *a, int *r) {
    int i;

    // do some stuff

    for (i = 0; i < a_really_big_int; ++i) {
        if (s)
            r[i] = x ^ i;
        else
            r[i] = x ^ a[i];
        // and maybe a couple other ways of computing r
        // that are equally fast individually
    }

    // do some other stuff

}
Run Code Online (Sandbox Code Playgroud)

这段代码被调用得太多,以至于这个循环实际上是代码中的速度瓶颈。我想知道几件事:

  1. 由于 switchs是函数中的常量,好的编译器会优化循环,以便分支不会一直减慢速度吗?

  2. 如果没有,优化这段代码的好方法是什么?

====

编辑:这是一个包含更完整示例的更新:

int func(int s,
         int start, int stop, int stride,
         double *x, double *b,
         int *a, int *flips, int *signs, int i_max,
         double *c)
{
  int i,k,st;
  for (k=start; k<stop; k += stride) {
    b[k] = 0;
    for (i=0;i<i_max;++i) {

      /* this is the code in question */
      if (s) st = k^flips[i];
      else st = a[k]^flips[i];
      /* done with code in question */

      b[k] += x[st] * (__builtin_popcount(st & signs[i])%2 ? -c[i] : c[i]);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑2

如果有人好奇,我最终重构了代码并将整个内部 for 循环(带有i_max)提升到外面,使really_big_int循环变得更加简单,并且希望易于矢量化!(并且还避免无数次执行一堆额外的逻辑)

wal*_*lyk 5

优化代码的一种明显方法是将条件拉到循环之外:

if (s)
    for (i=0;i<a_really_big_int;++i) {
        r[i] = x ^ i;
    }
else
    for (i=0;i<a_really_big_int;++i) {
        r[i] = x ^ a[i];
    }
Run Code Online (Sandbox Code Playgroud)

精明的编译器也许能够将其更改为一次多个元素的 r[] 赋值。

  • ...现在它可以使用 `_mm*_xor_si*()`、`_mm*_set_epi32()` 和未对齐的加载/存储进行矢量化(除非您可以确保输入对齐),但希望编译器可以自己完成 (2认同)