这些关于GCC优化的评论是否有效?

spr*_*aff 22 c c++ optimization gcc

Demystifying the Restrict Keyword的底部是一个奇怪的建议:

由于在GCC中完成调度的顺序,简化表达式总是更好.不要将内存访问与计算混合在一起.代码可以重写如下:

然后有一个例子基本上改变了这一点

velocity_x[i] += acceleration_x[i] * time_step;
Run Code Online (Sandbox Code Playgroud)

进入这个

const float ax  = acceleration_x[i];       // Then the same follows for y, z
const float vx  = velocity_x[i];           // etc for y, z
const float nvx = vx + ( ax * time_step ); // etc
velocity_x[i]   = nvx;                     // ...
Run Code Online (Sandbox Code Playgroud)

真?我认为与优化编译器必须做的其他事情相比,这种转换是微不足道的,例如lambda参数std::foreach等等.

这只是陈旧,愚蠢的建议吗?或者,GCC不能或不会这样做有充分的理由吗?(这让我担心将上述内容写成velocity += acceleration * time_step我的Vector3f课程!

Dre*_*ann 15

编辑:( 我正在删除有关的详细信息,restrict因为它偏离了被问到的实际问题并导致混淆.使用OP假设restict.)

对于优化编译器,您的问题中的转换确实微不足道,但这不是Acton的论文所暗示的.

以下是本文所做的转换:

这段代码......

  for (size_t i=0;i<count*stride;i+=stride)
  {
    velocity_x[i] += acceleration_x[i] * time_step;
    velocity_y[i] += acceleration_y[i] * time_step;
    velocity_z[i] += acceleration_z[i] * time_step;
    position_x[i] += velocity_x[i]     * time_step;
    position_y[i] += velocity_y[i]     * time_step;
    position_z[i] += velocity_z[i]     * time_step;
  }
Run Code Online (Sandbox Code Playgroud)

...被转换成这段代码:

  for (size_t i=0;i<count*stride;i+=stride)
  {
    const float ax  = acceleration_x[i];
    const float ay  = acceleration_y[i];
    const float az  = acceleration_z[i];
    const float vx  = velocity_x[i];
    const float vy  = velocity_y[i];
    const float vz  = velocity_z[i];
    const float px  = position_x[i];
    const float py  = position_y[i];
    const float pz  = position_z[i];

    const float nvx = vx + ( ax * time_step );
    const float nvy = vy + ( ay * time_step );
    const float nvz = vz + ( az * time_step );
    const float npx = px + ( vx * time_step );
    const float npy = py + ( vy * time_step );
    const float npz = pz + ( vz * time_step );

    velocity_x[i]   = nvx;
    velocity_y[i]   = nvy;
    velocity_z[i]   = nvz;
    position_x[i]   = npx;
    position_y[i]   = npy;
    position_z[i]   = npz;
  }
Run Code Online (Sandbox Code Playgroud)

什么是优化?

优化不是 - 正如所建议的 - 将1个表达式分离为3个表达式.

优化是在对任何特定数据操作的指令之间插入有用的指令.

如果按照数据移动velocity_x[i]vxnvxvelocity_x[i]时,CPU正在做各的那些步骤之间的其他工作.

为什么这是优化?

现代CPU通常具有流水线架构.

由于指令是分阶段执行的,因此CPU允许同时处理多个指令.但是,当指令需要另一个尚未完全执行的指令的结果时,该管道将停止.在停止的指令可以运行之前,不会执行进一步的指令.

为什么我的优化编译器不会自动执行此操作?

有些人.

GCC在这种优化方面表现得相对较差.

我使用gcc 4.7(x86-64架构,在-O3优化)对上面的两个循环进行了反汇编.生成了类似的程序集,但指令的顺序不同,第一个版本产生了显着的停顿,其中单个浮动将被加载,更改并存储在几个指令的范围内.

你可以在这里阅读一些关于gcc的指令调度,或者只是在网上搜索gcc指令调度,看看很多关于这个问题的沮丧文章.

  • 问题不在于"为什么这种转变有效?","为什么这种转变不会在编译器中发生?" 它看起来很简单,假设`velocity_x`等已经应用了`restrict`,它看起来就像优化器应该做的那样.我没有看到手动分离步骤是如何添加任何类型的提示. (7认同)
  • @LieRyan,完全没有 - 别名是C和C++优化器的一个众所周知的问题,并且已经存在了很长时间.它不是可由更好的优化器修复的东西,它是代码结构所固有的. (3认同)
  • 挂起,不是`restrict`关键字的WHOLE POINT,我不必手动进行这种分离? (2认同)