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"?
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With