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

Why doesn't my C++ compiler optimize these memory writes away?

本文关键字:内存 优化 我的 C++ 编译器 为什么      更新时间:2023-10-16

我创建了这个程序。除了使用处理能力之外,它没有做任何有趣的事情。

查看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)];
  }
}

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

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

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

如果GCC更聪明,它也可以优化rand调用,因为它的副作用只影响后来的rand调用,而在这种情况下没有任何副作用。然而,这种优化可能会浪费编译器编写者的时间。

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

它可以删除写操作,但可能使用数组就足以抑制写操作。

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

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

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

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

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

[注:这是为了允许编译器转换,比如删除空循环,即使不能证明终止。-end note]

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

相关的问题

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