Compilers and argument order of evaluation in C++ - c++

Okay, I'm aware that the standard dictates that a C++ implementation may choose in which order arguments of a function are evaluated, but are there any implementations that actually 'take advantage' of this in a scenario where it would actually affect the program?
Classic Example:
int i = 0;
foo(i++, i++);
Note: I'm not looking for someone to tell me that the order of evaluation can't be relied on, I'm well aware of that. I'm only interested in whether any compilers actually do evaluate out of a left-to-right order because my guess would be that if they did lots of poorly written code would break (rightly so, but they would still probably complain).

It depends on the argument type, the called function's calling convention, the archtecture and the compiler. On an x86, the Pascal calling convention evaluates arguments left to right whereas in the C calling convention (__cdecl) it is right to left. Most programs which run on multiple platforms do take into account the calling conventions to skip surprises.
There is a nice article on Raymond Chen' blog if you are interested. You may also want to take a look at the Stack and Calling section of the GCC manual.
Edit: So long as we are splitting hairs: My answer treats this not as a language question but as a platform one. The language standard does not gurantee or prefer one over the other and leaves it as unspecified. Note the wording. It does not say this is undefined. Unspecified in this sense means something you cannot count on, non-portable behavior. I don't have the C spec/draft handy but it should be similar to that from my n2798 draft (C++)
Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution sequence for a given program and a given input.

I found answer in c++ standards.
Paragraph 5.2.2.8:
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is
unspecified.
In other words, It depends on compiler only.

Read this
It's not an exact copy of your question, but my answer (and a few others) cover your question as well.
There are very good optimization reasons why the compiler might not just choose right-to-left but also interleave them.
The standard doesn't even guarantee a sequential ordering. It only guarantees that when the function gets called, all arguments have been fully evaluated.
And yes, I have seen a few versions of GCC do exactly this. For your example, foo(0,0) would be called, and i would be 2 afterwards. (I can't give you the exact version number of the compiler. It was a while ago - but I wouldn't be surprised to see this behavior pop up again. It's an efficient way to schedule instructions)

All arguments are evaluated. Order not defined (as per standard). But all implementations of C/C++ (that I know of) evaluate function arguments from right to left. EDIT: CLang is an exception (see comment below).
I believe that the right-to-left evaluation order has been very very old (since the first C compilers). Certainly way before C++ was invented, and most implementations of C++ would be keeping the same evaluation order because early C++ implementations simply translated into C.
There are some technical reasons for evaluating function arguments right-to-left. In stack architectures, arguments are typically pushed onto the stack. In C/C++, you can call a function with more arguments than actually specified -- the extra arguments are simiply ignored. If arguments are evaluated left-to-right, and pushed left-to-right, then the stack slot right under the stack pointer will hold the last argument, and there is no way for the function to get at the offset of any particular argument (because the actual number of arguments pushed depends on the caller).
In a right-to-left push order, the stack slot right under the stack pointer will always hold the first argument, and the next slot holds the second argument etc. Argument offsets will always be deterministic for the function (which may be written and compiled elsewhere into a library, separately from where it is called).
Now, right-to-left push order does not mandate right-to-left evaluation order, but in early compilers, memory is scarce. In right-to-left evaluation order, the same stack can be used in-place (essentially, after evaluating the argument -- which may be an expression or a funciton call! -- the return value is already at the right position on the stack). In left-to-right evaluation, the argument values must be stored separately and the pushed back to the stack in reverse order.

Last time I saw differences was between VS2005 and GCC 3.x on an x86 hardware in 2007.
So it's (was?) a very likely situation. So I never rely on evaluation order anymore. Maybe it's better now.

I expect that most modern compilers would attempt to interleave the instructions computing the arguments, given that they are required by the C++ standard to be independent and thus lack any interdependencies. Doing this should help to keep a deeply-pipelined CPU's execution units full and thereby increase throughput. (At least I would expect that a compiler that claims to be an optimising compiler would do so when optimisation flags are given.)

Related

Unexpected reversal of values when using a function to provide int arguments for constructor [duplicate]

Okay, I'm aware that the standard dictates that a C++ implementation may choose in which order arguments of a function are evaluated, but are there any implementations that actually 'take advantage' of this in a scenario where it would actually affect the program?
Classic Example:
int i = 0;
foo(i++, i++);
Note: I'm not looking for someone to tell me that the order of evaluation can't be relied on, I'm well aware of that. I'm only interested in whether any compilers actually do evaluate out of a left-to-right order because my guess would be that if they did lots of poorly written code would break (rightly so, but they would still probably complain).
It depends on the argument type, the called function's calling convention, the archtecture and the compiler. On an x86, the Pascal calling convention evaluates arguments left to right whereas in the C calling convention (__cdecl) it is right to left. Most programs which run on multiple platforms do take into account the calling conventions to skip surprises.
There is a nice article on Raymond Chen' blog if you are interested. You may also want to take a look at the Stack and Calling section of the GCC manual.
Edit: So long as we are splitting hairs: My answer treats this not as a language question but as a platform one. The language standard does not gurantee or prefer one over the other and leaves it as unspecified. Note the wording. It does not say this is undefined. Unspecified in this sense means something you cannot count on, non-portable behavior. I don't have the C spec/draft handy but it should be similar to that from my n2798 draft (C++)
Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution sequence for a given program and a given input.
I found answer in c++ standards.
Paragraph 5.2.2.8:
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is
unspecified.
In other words, It depends on compiler only.
Read this
It's not an exact copy of your question, but my answer (and a few others) cover your question as well.
There are very good optimization reasons why the compiler might not just choose right-to-left but also interleave them.
The standard doesn't even guarantee a sequential ordering. It only guarantees that when the function gets called, all arguments have been fully evaluated.
And yes, I have seen a few versions of GCC do exactly this. For your example, foo(0,0) would be called, and i would be 2 afterwards. (I can't give you the exact version number of the compiler. It was a while ago - but I wouldn't be surprised to see this behavior pop up again. It's an efficient way to schedule instructions)
All arguments are evaluated. Order not defined (as per standard). But all implementations of C/C++ (that I know of) evaluate function arguments from right to left. EDIT: CLang is an exception (see comment below).
I believe that the right-to-left evaluation order has been very very old (since the first C compilers). Certainly way before C++ was invented, and most implementations of C++ would be keeping the same evaluation order because early C++ implementations simply translated into C.
There are some technical reasons for evaluating function arguments right-to-left. In stack architectures, arguments are typically pushed onto the stack. In C/C++, you can call a function with more arguments than actually specified -- the extra arguments are simiply ignored. If arguments are evaluated left-to-right, and pushed left-to-right, then the stack slot right under the stack pointer will hold the last argument, and there is no way for the function to get at the offset of any particular argument (because the actual number of arguments pushed depends on the caller).
In a right-to-left push order, the stack slot right under the stack pointer will always hold the first argument, and the next slot holds the second argument etc. Argument offsets will always be deterministic for the function (which may be written and compiled elsewhere into a library, separately from where it is called).
Now, right-to-left push order does not mandate right-to-left evaluation order, but in early compilers, memory is scarce. In right-to-left evaluation order, the same stack can be used in-place (essentially, after evaluating the argument -- which may be an expression or a funciton call! -- the return value is already at the right position on the stack). In left-to-right evaluation, the argument values must be stored separately and the pushed back to the stack in reverse order.
Last time I saw differences was between VS2005 and GCC 3.x on an x86 hardware in 2007.
So it's (was?) a very likely situation. So I never rely on evaluation order anymore. Maybe it's better now.
I expect that most modern compilers would attempt to interleave the instructions computing the arguments, given that they are required by the C++ standard to be independent and thus lack any interdependencies. Doing this should help to keep a deeply-pipelined CPU's execution units full and thereby increase throughput. (At least I would expect that a compiler that claims to be an optimising compiler would do so when optimisation flags are given.)

Do these macros evaluate to the same code using gcc at compile-time?

Of course this is going to be a function of the compiler you are using, but I figured this would be a simple question to answer.
#define UBRRVAL(baud) (F_CPU/(16*baud)-1)
As compared with
#define UBRRVAL(baud) (F_CPU/16/baud-1)
I know that the latter is going to evaluate to (assuming F_CPU = 20000000):
#define UBRRVAL(baud) (12500000/baud-1)
Considering the forced precidence by the parenthesis I was curious to know if most compilers (gcc in particular) would evaluate the former expression equivalently to the latter at compile-time.
This is code that is going into an embeddded system, so if these expressions are not evaluated at compile-time equivalently, then the latter is more efficient; a single division at run-time is more efficient than a division and a mulitplication of course.
Simple answer, no.
Because neither macro is fully parenthesized, there are cases where the two are very different.
Consider UBRRVAL(2+1). The first would expand to (F_CPU/(16*2+1)-1), which is equivalent to F_CPU/33 - 1. The second would expand to (F_CPU/16/2+1-1), which is equivalent to F_CPU/32. Not the same at all.
Of course, it probably isn't meant to be called with an expression, just with a single constant value, but there's nothing to prevent it, and as such, someone will do it sometime in the future. One of the many evils of macros. I would recommend using a short (static) inline function (or constexpr as suggested in comments, if this is using a recent enough C++ compiler) instead...
Simple answer, yes. Within the specific constraints given both will be fully evaluated at compile time.
Parentheses force precedence but they do not force order of evaluation, except to the extent defined by the "as if" rule. You cannot be sure what code will be emitted if the expression is slightly more complicated so it is not evaluated at compile time. This may well depend on the specific processor.
As a side point, on most processors a 4 bit shift left or shift right are the same cost, and if the baud rate is a power of two the compiler is likely to generate shift operations.
[And be careful about parenthesising macro arguments. You got away with it this time, but only just.]

Can I guarantee the C++ compiler will not reorder my calculations?

I'm currently reading through the excellent Library for Double-Double and Quad-Double Arithmetic paper, and in the first few lines I notice they perform a sum in the following way:
std::pair<double, double> TwoSum(double a, double b)
{
double s = a + b;
double v = s - a;
double e = (a - (s - v)) + (b - v);
return std::make_pair(s, e);
}
The calculation of the error, e, relies on the fact that the calculation follows that order of operations exactly because of the non-associative properties of IEEE-754 floating point math.
If I compile this within a modern optimizing C++ compiler (e.g. MSVC or gcc), can I be ensured that the compiler won't optimize out the way this calculation is done?
Secondly, is this guaranteed anywhere within the C++ standard?
You might like to look at the g++ manual page: http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html#Optimize-Options
Particularly -fassociative-math, -ffast-math and -ffloat-store
According to the g++ manual it will not reorder your expression unless you specifically request it.
Yes, that is safe (at least in this case). You only use two "operators" there, the primary expression (something) and the binary something +/- something (additive).
Section 1.9 Program execution (of C++0x N3092) states:
Operators can be regrouped according to the usual mathematical rules only where the operators really are associative or commutative.
In terms of the grouping, 5.1 Primary expressions states:
A parenthesized expression is a primary expression whose type and value are identical to those of the enclosed expression. ... The parenthesized expression can be used in exactly the same contexts as those where the enclosed expression can be used, and with the same meaning, except as otherwise indicated.
I believe the use of the word "identical" in that quote requires a conforming implementation to guarantee that it will be executed in the specified order unless another order can give the exact same results.
And for adding and subtracting, section 5.7 Additive operators has:
The additive operators + and - group left-to-right.
So the standard dictates the results. If the compiler can ascertain that the same results can be obtained with different ordering of the operations then it may re-arrange them. But whether this happens or not, you will not be able to discern a difference.
This is a very valid concern, because Intel's C++ compiler, which is very widely used, defaults to performing optimizations that can change the result.
See http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/cpp/lin/compiler_c/copts/common_options/option_fp_model.htm#option_fp_model
I would be quite surprised if any compiler wrongly assumed associativity of arithmetic operators with default optimising options.
But be wary of extended precision of FP registers.
Consult compiler documentation on how to ensure that FP values do not have extended precision.
If you really need to, I think you can make a noinline function no_reorder(float x) { return x; }, and then use it instead of parenthesis. Obviously, it's not a particularly efficient solution though.
In general, you should be able to -- the optimizer should be aware of the properties of the real operations.
That said, I'd test the hell out of the compiler I was using.
Yes. The compiler will not change the order of your calculations within a block like that.
Between compiler optimizations and out-of-order execution on the processor, it is almost a guarantee that things will not happen exactly as you ordered them.
HOWEVER, it is also guaranteed that this will NEVER change the result. C++ follows standard order of operations and all optimizations preserve this behavior.
Bottom line: Don't worry about it. Write your C++ code to be mathematically correct and trust the compiler. If anything goes wrong, the problem was almost certainly not the compiler.
As per the other answers you should be able to rely on the compiler doing the right thing -- most compilers allow you to compile and inspect the assembler (use -S for gcc) -- you may want to do that to make sure you get the order of operation you expect.
Different optimization levels (in gcc, -O _O2 etc) allows code to be re-arranged (however sequential code like this is unlikely to be affected) -- but I would suggest you should then isolate that particular part of code into a separate file, so that you can control the optimization level for just the calculation.
The short answer is: the compiler will probably change the order of your calculations, but it will never change the behavior of your program (unless your code makes use of expression with undefined behavior: http://blog.regehr.org/archives/213)
However, you can still influence this behavior by deactivating all compiler optimizations (option "-O0" with gcc). If you still needs the compiler to optimize the rest of your code, you may put this function in a separate ".c" which you can compile with "-O0".
Additionally, you can use some hacks. For instance, if you interleaves your code with extern function calls the compiler may consider that it is unsafe to re-order your code as the function may have unknown side-effect. Calling "printf" to print the value of your intermediate results will conduct to similar behavior.
Anyway, unless you have any very good reason (e.g. debugging) you typically don't want to care about that, and you should trust the compiler.

Sequence points, conditionals and optimizations

I had an argument today with one of my collegues regarding the fact that a compiler could change the semantics of a program when agressive optimizations are enabled.
My collegue states that when optimizations are enabled, a compiler might change the order of some instructions. So that:
function foo(int a, int b)
{
if (a > 5)
{
if (b < 6)
{
// Do something
}
}
}
Might be changed to:
function foo(int a, int b)
{
if (b < 6)
{
if (a > 5)
{
// Do something
}
}
}
Of course, in this case, it doesn't change the program general behavior and isn't really important.
From my understanding, I believe that the two if (condition) belong to two different sequence points and that the compiler can't change their order, even if changing it would keep the same general behavior.
So, dear SO users, what is the truth regarding this ?
If the compiler can verify that there is no observable difference between those two, then it is free to make such optimizations.
Sequence points are a conceptual thing: the compiler has to generate code such that it behaves as if all the semantic rules like sequence points were followed. The generated code doesn't actually have to follow those rules if not following them produces no observable difference in the behavior of the program.
Even if you had:
if (a > 5 && b < 6)
the compiler could freely rearrange this to be
if (b < 6 && a > 5)
because there is no observable difference between the two (in this specific case where a and b are both int values). [This assumes that it is safe to read both a and b; if reading one of them could cause some error (e.g., one has a trap value), then the compiler would be more restricted in what optimizations it could make.]
As there is no observable difference between the two program snippets - provided the implementation is one that doesn't use trap values or anything else that might cause the inner comparison to do something other than just evaluate to true or false - the compiler could optimize one to the other under the "as if" rule. If there was some observable difference or some way that a conforming program might behave differently then the compiler would be non-conforming if it changed one form to the other.
For C++, see 1.9 [intro.execution] / 5.
A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. However, if any such execution sequence contains an undefined
operation, this International Standard places no requirement on the implementation executing that program with that input (not even with regard to operations preceding the first undefined operation).
[This provision is sometimes called the "as-if" rule, because an implementation is free to disregard any requirement of this International Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. For instance, an actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no side effects affecting the observable behavior of the program are produced.]
Yes, the if statement is a sequence point.
However, a smart and agressive compiler can still reorder the different expressions, statements and alter the sequence points providing no side effects appear.
Sequence points only apply to the abstract machine.
If the target specific optimizer can prove that reversing the order of two instructions has no side effects, it can change them at will.
The end of a full expression (including those that control logical constructs like if, while, et cetera) is a sequence point. However, the sequence point really only provides a guarantee that side-effects of previously-evaluated statements have completed.
If a statement has no observable side-effects the compiler can do what it feels is best.
The truth is that if a>5 is false more often than b<6 is false or vice versa then the sequence will make a very minor difference as it will have to compute both conditionals on more occasions.
In reality though it is so trivial it is not worth bothering about in this particular case.
There are cases where it actually does make a difference, i.e. when you are filtering a large collection of data on several criteria and have to decide which filter to apply first, particularly if only one of them is O(log N) or constant and the subsequent checks are linear through what is left.
Lots of PC programmer replies =)
The compiler may, and likely would, optimize the sequence points for speed if "b" is passed to the function in a quickly-accessed register while "a" is passed on the stack. That's a quite common case for many compilers for 8-bit and 16-bit MCU:s.
Through the optimization it doesn't need to first stack "b", then load "a" into a register, then evaluate "a", then load "b" back into a register, then evaluate "b". Quite a mess I'd rather hope the compiler handled by rearranging the sequence points.
Though of course as already mentioned, to be standard compliant the compiler needs to ensure that it doesn't change the program behavior by the optimization.

Why C/C++ does not defined expression evaluation order?

As you may know C/C++ does not specified expression evaluation order. What are the reasons to left them undefined.
It allows compiler optimizations.
One example would be the reordering of arithmetic instructions for the maximum usage of the ALUs or hiding memory latency with calculations.
One of the C/C++ design goals is the efficient implementation for complilers. So the compilers are given relatively free rein in choosing the evaluation order of various subexpression within a complicated expression; this order is not constrained by operator precedence and associativity as we think. In such situation when we a modifying the same vairiable in multiple sub expression, the behaviour become undefied. An increment or decrement operation is not guaranteed to be performed immediately after giving upthe previous value and before any other part of the expression is evalauted. The only guarantee is that the update will be performed before the expression is considered finished.
Undefined behavious means undefined and anything can happen.
Source:C programmig FAQ by Steve Summit