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

Why does the compiler write a member variable to memory for each iteration of this loop?

本文关键字:成员 迭代 变量 内存 编译器 循环 为什么      更新时间:2023-10-16

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

我预计编译器无论如何都会选择在这里进行 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;
};

processSamples组装成这样的代码:

.L4:
  addss xmm0, DWORD PTR [rax]
  movss DWORD PTR [rax], xmm0
  mulss xmm0, xmm1
  add rax, 4
  cmp rax, rcx
  jne .L4

过程样本2到这个:

.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

由于编译器不必担心线程(v1 不是原子的)。 难道它不能假设没有其他东西会查看此值并在循环旋转时继续将其保存在寄存器中吗?

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

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

在 C99 中,可以在指针类型的函数参数上使用 limit 关键字来通知编译器它不会为函数范围内的任何其他内容添加别名。一些C++编译器也支持它,尽管它不是标准的。 (摘自我的一条评论。