11

I've had this question for a long time but never knew where to look. If a certain operation is written many times will the compiler simplify it or will it run the exact same operation and get the exact same answer?

For example, in the following c-like pseudo-code (i%3)*10 is repeated many times.

for(int i=0; i<100; i++) {
    array[(i%3)*10] = someFunction((i%3)*10);
    int otherVar = (i%3)*10 + array[(i%3)*10];
    int lastVar = (i%3)*10 - otherVar;
    anotherFunction(lastVar);
}

I understand a variable would be better for visual purposes, but is it also faster? Is (i%3)*10 calculated 5 times per loop?

There are certain cases where I don't know if its faster to use a variable or just leave the original operation.

Edit: using gcc (MinGW.org GCC-8.2.0-3) 8.2.0 on win 10

EarthenSky
  • 182
  • 12
  • 3
    If you really want to do micro-optimization, you could always just try both versions of the code and time it to see which one is faster. Generally it often depends on if and how your compiler will optimize the code, in all likelihood the result is the same anyway. – Blaze Aug 27 '19 at 07:00
  • 3
    Question about whether compiler will do an optimization is meaningless, unless you specify what compiler you are using. – user694733 Aug 27 '19 at 07:01
  • Not to mention simplifiying lines 3 and 4 to `int lastVar = -array[(i%3)*10];` , or even lines 2 to 5 with `anotherFunction(-someFunction((i%3)*10));` if the array isn't otherwise used. – Weather Vane Aug 27 '19 at 07:03
  • 3
    related (if not the same) : [Performance of duplicate computations](https://stackoverflow.com/questions/54733084/performance-of-duplicate-computations) – Sander De Dycker Aug 27 '19 at 07:06
  • 3
    Nevermind what the compiler will do, from a readability and maintenance, use temporary variables to remove the replication and therefore remove all the copies. – SPlatten Aug 27 '19 at 07:07
  • 4
    also, the optimization you're referring to is called [common subexpression elimination](https://en.wikipedia.org/wiki/Common_subexpression_elimination) if you're interested in finding out more about it and/or what search terms to use – Sander De Dycker Aug 27 '19 at 07:09
  • 1
    What would be the meanging, the consequence for you if you get an answer basically "Yes." ? I am asking because I believe we are looking at an XY problem. https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Yunnosch Aug 27 '19 at 07:18
  • 1
    in case of floating-point types then in most cases it can't optimize: [Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?](https://stackoverflow.com/q/6430448/995714), [Why does Clang optimize away x * 1.0 but NOT x + 0.0?](https://stackoverflow.com/q/33272994/995714), [Can floating point multiplication by zero be optimised at runtime?](https://stackoverflow.com/q/15214673/995714), [Are compilers allowed to optimize floating point constant multiplication](https://stackoverflow.com/q/28214572/995714) – phuclv Aug 28 '19 at 02:35

3 Answers3

10

Which optimizations are done depends on the compiler, the compiler optimization flag(s) you specify, and the architecture.

Here are a few possible optimizations for your example:

  • Loop Unrolling This makes the binary larger and thus is a trade-off; for example you may not want this on a tiny microprocessor with very little memory.
  • Common Subexpression Elimination (CSE) you can be pretty sure that your (i % 3) * 10 will only be executed once per loop iteration.

About your concern about visual clarity vs. optimization: When dealing with a 'local situation' like yours, you should focus on code clarity.

Optimization gains are often to be made at a higher level; for example in the algorithm you use.

There's a lot to be said about optimization; the above are just a few opening remarks. It's great that you're interested in how things work, because this is important for a good (C/C++) programmer.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
2

As a matter of course, you should remove the obfuscation present in your code:

for (int i = 0; i < 100; ++i) {
    int i30 = i % 3 * 10;
    int r = someFunction(i30);
    array[i30] = r;
    anotherFunction(-r);
}

Suddenly, it looks quite a lot simpler.

Leave it to the compiler (with appropriate options) to optimize your code unless you find you actually have to take a hand after measuring.
In this case, unrolling three times looks like a good idea for the compiler to pursue. Though inlining might always reveal even better options.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
0

Yes, operations done several times in sequence will be optimized by a compiler.

To go into more detail, all major compilers (GCC, Clang, and MSVC) store the value of (i%3)*10 into a temporary (scratch, junk) register, and then use that whenever an equivalent expression is used again.
This optimization is called GCSE (GNU Common Subexpression Elimination) for GCC, and just CSE otherwise.
This takes a decent chunk out of the time that it takes to compute the loop.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76