为什么编译器会为此循环的每次迭代将成员变量写入内存?

JCx*_*JCx 7 c++ optimization g++ clang clang++

第一个版本通过将值从内存移动到局部变量来进行优化.第二个版本没有.

我原以为编译器可能会选择在这里进行localValue优化,而不是在循环的每次迭代中从内存中读取和写入值.为什么不呢?

class Example
{
    public:
        void processSamples(float * x, int num) 
        {
            float localValue = v1;

            for (int i = 0; i < num; ++i)
            {
                x[i] = x[i] + localValue;
                localValue = 0.5 * x[i];
            }

            v1 = localValue;
        }

        void processSamples2(float * x, int num)
        {

            for (int i = 0; i < num; ++i)
            {
                x[i] = x[i] + v1;
                v1 = 0.5 * x[i];
            }

        }

    float v1;
};
Run Code Online (Sandbox Code Playgroud)

processSamples组装成代码如下:

.L4:
  addss xmm0, DWORD PTR [rax]
  movss DWORD PTR [rax], xmm0
  mulss xmm0, xmm1
  add rax, 4
  cmp rax, rcx
  jne .L4
Run Code Online (Sandbox Code Playgroud)

processSamples2到此:

.L5:
  movss xmm0, DWORD PTR [rax]
  addss xmm0, DWORD PTR example[rip]
  movss DWORD PTR [rax], xmm0
  mulss xmm0, xmm1
  movss DWORD PTR example[rip], xmm0
  add rax, 4
  cmp rax, rdx
  jne .L5
Run Code Online (Sandbox Code Playgroud)

因为编译器不必担心线程(v1不是原子的).难道不能只是假设没有别的东西会看到这个值并继续在循环旋转时将它保存在寄存器中吗?

有关完整程序集和各种编译器可供选择,请参阅https://godbolt.org/g/RiF3B4!

Aas*_*set 11

由于别名:v1是一个成员变量,它可能x指向它.因此,对元素的写入之一x可能会改变v1.

在C99中,您可以在指针类型的函数参数上使用restrict关键字,以通知编译器它不会对函数范围内的任何其他内容进行别名.一些C++编译器也支持它,尽管它不是标准的. (复制自我的一条评论.)

  • @JCx:在C99中,您可以在指针类型的函数参数上使用`restrict`关键字来通知编译器它不会对函数范围内的任何其他内容进行别名.[某些C++编译器也支持它](/sf/ask/54339841/#1965502),尽管它不是标准的. (2认同)
  • 好的 - 用clang测试.限制整理出来.好:) (2认同)
  • @mark - 参数不能指向局部变量,因为调用函数时本地不存在.编译器非常聪明! (2认同)