Joshua Snider
Joshua Snider

Reputation: 797

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

I created this program. It does nothing of interest but use processing power.

Looking at the output with objdump -d, I can see the three rand calls and corresponding mov instructions near the end even when compiling with O3 .

Why doesn't the compiler realize that memory isn't going to be used and just replace the bottom half with while(1){}? I'm using gcc, but I'm mostly interested in what is required by the standard.

/*
 * 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)];
  }
}

Upvotes: 4

Views: 310

Answers (4)

user1196549
user1196549

Reputation:

Leave it a chance to crash by array overflow ! The compiler won't speculate on the range of outputs of getRand.

Upvotes: 0

Alan Stokes
Alan Stokes

Reputation: 18974

It can't, in general, tell that rand() doesn't have observable side-effects here, and it isn't required to remove those calls.

It could remove the writes, but it may be the use of arrays is enough to suppress that.

The standard neither requires nor prohibits what it is doing. As long as the program has the correct observable behaviour any optimisation is purely a quality of implementation matter.

Upvotes: 5

interjay
interjay

Reputation: 110155

Because GCC isn't smart enough to perform this optimization on dynamically allocated memory. However, if you change garbageto be a local array instead, GCC compiles the loop to this:

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

This just calls rand repeatedly (which is needed because the call has side effects), but optimizes out the reads and writes.

If GCC was even smarter, it could also optimize out the randcalls, because its side effects only affect any later randcalls, and in this case there aren't any. However, this sort of optimization would probably be a waste of compiler writers' time.

Upvotes: 10

M.M
M.M

Reputation: 141628

This code causes undefined behaviour because it has an infinite loop with no observable behaviour. Therefore any result is permissible.

In C++14 the text is 1.10/27:

The implementation may assume that any thread will eventually do one of the following:

  • terminate,
  • make a call to a library I/O function,
  • access or modify a volatile object, or
  • perform a synchronization operation or an atomic operation.

[Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. —end note ]

I wouldn't say that rand() counts as an I/O function.

Related question

Upvotes: 3

Related Questions