It is difficult to answer this question adequately for an arbitrary compiler. What can be done with this code depends not only on the compiler, but also on the target architecture. I will try to explain what a production compiler can do with good features for this code.
From the point of view of processing time, it would be advisable only to calculate the product of variables1 and variable2 once, since they do not change in the cycle.
You're right. And, as Mr. Kat noted, this is called eliminating a common subexpression . Thus, the compiler can generate code that evaluates an expression only once (or even evaluates it at compile time if the values for the two operands are known to be constant at a time).
A decent compiler can also perform subexpression exceptions for functions if it can determine that functions have no side effects. For example, GCC can analyze a function if its body is available, but there are also pure and const attributes that can be used to specifically label functions that should undergo this optimization (see Function Attributes ).
Given that there is no side effect, and the compiler can determine it (there is nothing worthwhile in your example), two of these fragments are equivalent in this respect (I checked with clang :-)).
This requires additional memory, but I'm not sure how much the optimizer affects this overhead.
In fact, this does not require additional memory. Multiplication is performed in the processor registers , and the result is also stored in the register. It is about eliminating a large amount of code and using a single register to store a result that is always large (and, of course, makes life easier when it comes to register allocation , especially in a loop). Therefore, if this optimization can be performed, it will be done at no additional cost.
The first expression is easiest to read.
Both GCC and Clang will perform this optimization. However, I'm not sure about other compilers, so you have to check it yourself. But it is hard to imagine any good compiler that does not perform subexpression exception.
Will any of these changes change if I declare my variables as constants?
It can be. This is called a constant expression — an expression that contains only constants. A constant expression can be evaluated at compile time, rather than at run time. So, for example, if you have multiple A, B, and C, where both A and B are constants, the compiler will precompute the expression A*B only a few C against this precomputed value. Compilers can also do this even with inconsistent values, if they can determine its value at compile time and make sure that it is not changed. For example:
$ cat test.c inline int foo(int a, int b) { return a * b; } int main() { int a; int b; a = 1; b = 2; return foo(a, b); } $ clang -Wall -pedantic -O4 -o test ./test.c $ otool -tv ./test ./test: (__TEXT,__text) section _main: 0000000100000f70 movl $0x00000002,%eax 0000000100000f75 ret
There is another optimization that may occur in the case of the above fragments. Below are some of them that come to mind:
The first most obvious one is looping through. Since the number of iterations is known at runtime, the compiler may decide to deploy the loop . Regardless of whether this optimization is applied or not, it depends on the architecture (that is, some processors can “lock your loop” and execute code faster than its deployed version, which also makes the code more convenient for the cache, using less space, avoiding additional synthesis cycles μOP, etc.).
The second optimization, which can literally speed up work up to 50 times, is the SIMD instruction (SSE, AVX, etc.). For example, GCC is very good at this (Intel should be too, if not better). I checked that the following function:
uint8_t dumb_checksum(const uint8_t *p, size_t size) { uint8_t s = 0; size_t i; for (i = 0; i < size; ++i) s = (uint8_t)(s + p[i]); return s; }
... is converted to a loop, where each step sums 16 values at once (i.e., as in _mm_add_epi8 ) with an additional code, alignment processing and an odd (<16) number of iterations. However, Klang completely failed the last time I checked. Thus, GCC can also shorten your loop in the same way, even if the number of iterations is unknown.
And if I can offer you not to optimize your code, if you do not find it a bottleneck. Otherwise, you can spend a lot of time on false and premature optimization.
Hope this answers your questions. Good luck