为什么我的C ++编译器没有优化这些内存写入?

时间:2015-09-29 21:40:47

标签: c++ optimization

我创建了这个程序。它没有任何兴趣,但使用处理能力。

使用objdump -d查看输出,即使使用O3进行编译,我也可以在结尾处看到三个rand调用和相应的mov指令。

为什么编译器没有意识到内存不会被使用,只是用while(1){}替换下半部分?我使用的是gcc,但我最感兴趣的是标准要求。

/*
 * Create a program that does nothing except slow down the computer.
 */
#include <cstdlib>
#include <unistd.h>

int getRand(int max) {
  return rand() % max;
}

int main() {
  for (int thread = 0; thread < 5; thread++) {
    fork();
  }
  int len = 1000;
  int *garbage = (int*)malloc(sizeof(int)*len);
  for (int x = 0; x < len; x++) {
    garbage[x] = x;
  }
  while (true) {
    garbage[getRand(len)] = garbage[getRand(len)] - garbage[getRand(len)];
  }
}

4 个答案:

答案 0 :(得分:10)

因为GCC不够智能,无法在动态分配的内存上执行此优化。但是,如果您将garbage更改为本地数组,GCC会将循环编译为:

.L4:
    call    rand
    call    rand
    call    rand
    jmp .L4

这只是反复调用rand(这是必需的,因为调用有副作用),但优化了读写。

如果GCC更智能,它还可以优化rand次来电,因为它的副作用只会影响以后的rand次来电,而且在这种情况下也没有。{但是,这种优化可能会浪费编译器编写者的注意力。时间。

答案 1 :(得分:5)

通常,它不能告诉rand()这里没有可观察到的副作用,并且不需要删除这些调用。

它可以删除写入,但可能是使用数组足以抑制它。

标准既不要求也不禁止它正在做什么。只要程序具有正确的可观察行为,任何优化都只是实现的质量问题。

答案 2 :(得分:3)

此代码导致未定义行为,因为它具有无限循环且没有可观察行为。因此,任何结果都是允许的。

在C ++ 14中,文本是1.10 / 27:

  

实现可能假设任何线程最终将执行以下操作之一:

     
      
  • 终止,
  •   
  • 调用库I / O函数,
  •   
  • 访问或修改易失性对象,或
  •   
  • 执行同步操作或原子操作。
  •   
     

[注意:这是为了允许编译器转换,例如删除空循环,即使无法证明终止也是如此。 - 后注]

我不会说rand()算作I / O函数。

Related question

答案 3 :(得分:0)

让它有机会因阵列溢出而崩溃!编译器不会推测getRand的输出范围。