C++ compiler optimizations and short-circuit evaluation

1.3k views Asked by At

Here is my code :

b = f() || b;

The function f() has side effect and it must be always executed. Normally, only the right operand can be short-circuited and this code should work. But I am afraid some compilators reverse the two operands, since it's more efficient to short-circuit a function evaluation rather than a simple variable evaluation. I know that g++ -O3 can break some specifications, but I don't know if this code can be affected.

So, is my code risk-free?

I knew Is short-circuiting logical operators mandated? And evaluation order? but my question was about compilers optimizations, I didn't know that they can't break the standards (even if this would be strange).

2

There are 2 answers

2
Cory Kramer On BEST ANSWER

But I am afraid some compilators reverse the two operands

These expressions must be evaluated left-to-right. This is covered in the standard about the operators &&, ||, ?, and ,. They specifically mention the order, as well as enforced sequence points.

§5.14.1 (Logical AND)

The && operator groups left-to-right. The operands are both contextually converted to bool (Clause 4). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.

§5.15.1 (Logical OR)

The || operator groups left-to-right. The operands are both contextually converted to bool (Clause 4). It returns true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.

§5.16.1 (Conditional operator)

Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 4). It is evaluated and if it is true, the result of the conditional expression is the value of the second expression, otherwise that of the third expression. Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.

§5.19.1 (Comma operator)

The comma operator groups left-to-right. A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded value expression (Clause 5). Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field. If the value of the right operand is a temporary (12.2), the result is that temporary.

Regarding your concern about optimizations violating this order, no compilers are not allowed to change the order. Compilers must first and foremost (try to) follow the standard. Then they can try to make your code faster. They may not violate the standard just for the sake of performance. That undermines the entire premise of having a standard.

0
KABoissonneault On

It's explicitly stated by the standard that optimized code should behave "as-if" it was exactly the code that was written, as long as you only rely on standard behavior.

Since the standard requires the boolean statements to be evaluated from left to right, no (compliant) optimization can change the order of evaluation.