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

时间:2017-10-16 12:43:37

标签: 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;
};

processSamples组装成这样的代码:

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

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

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

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

1 个答案:

答案 0 :(得分:11)

由于aliasingimport os def is_server_up(ip_addr): return os.system('ping -c 1 ' + ip_addr + ' > /dev/null') == 0 是一个成员变量,可能是v1指向它。因此,对x元素的一次写入可能会更改x

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