Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the optimizing compiler allowed to omit a function call indirectly used in a short-circuit?

Tags:

c++

c

The C and C++ languages evaluate || and && in left-to-right order, and must "short-circuit" the right-hand side if the left-hand side establishes the truth value of the entire expression.

Does either language allow for the generated code to not call foo(), if the result of foo() is stored in a local variable only used on the right-hand-side of a short-circuit operator?

In the example below, the generated code for bar() must emit a call to foo(). When compiling baz(), could a conformant optimizing compiler remove the invocation of foo() since x is known at compile-time?

int foo(int f);

int bar(int x) {
  int const foo_value = foo(x);
  if (x || foo_value) {
    return 123;
  }
  return 456;
}

int baz(/* assume "void" here for C */) {
  return bar(1); // Can this collapse down to "return 123"?
}
like image 996
Charles Nicholson Avatar asked Dec 10 '22 23:12

Charles Nicholson


2 Answers

Compiler optimizations are not permitted to change the observable behavior of the program.

int foo(int f);

int bar(int x) {
  int const foo_value = foo(x);
  if (x || foo_value) {
    return 123;
  }
  return 456;
}

int baz(/* assume "void" here for C */) {
  return bar(1); // Can this collapse down to "return 123"?
}

Consider foo is (C++):

int foo(int f) {
    std::cout << "hello, foo is called. I am an observable side effect";
    return 42;
}

Then the compiler cannot optimize the call to foo away. The compiler must prove that foo has no side effects. If it cannot do that, bar and in turn foo must be called. Or rather: You cannot tell the difference whether it is called or some optimization is applied, because observable behavior must not change.

Note that certain optimizations are specifically permitted to change observable behavior, for example copy elision. Though this isnt really in contrast to what I said before, because the C++ standard specifies what is allowed and what not, and optimizations may not deviate from that.

like image 187
463035818_is_not_a_number Avatar answered Dec 12 '22 12:12

463035818_is_not_a_number


Omitting the function call would not be allowed because it would constitute a change in behavior.

Because bar was not declared static, it could be called from a different translation unit. If such code were to call bar(0), then foo has to be called to determine the return value of the function.

In addition, because foo is not defined in this translation unit, the compiler can't make any assumptions about about the function's side effects and therefore can't optimize it away.

like image 45
dbush Avatar answered Dec 12 '22 14:12

dbush