Live data from Hacker News

Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

ridiculousfish.com

11–20 of 34 posts

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#11
post #3

I did some similar experiments myself a long time ago. Something mildly surprising for me at that time was that this got optimized to a single roll instruction: uint32_t roll(uint32_t const x) { return (x > 17); } I haven't managed to make GCC generate a non-constant roll (i.e. (x > (32-c)) ), probably because it couldn't infer that c is in the [0,31] range.

What version of GCC are you using? The non-constant case compiles to "roll" as far back as GCC 4.4.

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#12

This reminds me of something my assembly instructor said in class once (paraphrased): "Once, I was interested in finding out how a C compiler would handle the div instruction. So, I opened up my editor, and wrote this C program: void main () { printf("%f", 14.0 / 3.0); } I compiled it, and took a look at the generated assembly. How many div instructions do you think it used? [Various guesses, mostly "one."] The corre…

I don't spend a lot of time looking at complier outputs, but the optimization is quite obvious in the first case. I don't have a clue how it would optimize it out in the second case though...

In the second case the divide function isn't being exported from the compilation unit and the compiler can tell[1], so the compiler is free to do whatever it wants with the calling convention and in this case it will choose to inline. And once it's inlined finding the correct answer at compile time is still obvious.

[1] Normally you have to declare a function as 'static' to tell the compiler that the function isn't being exported form the compilation unit, since the compiler isn't supposed to be able to tell the difference between function declarations in the .c file itself and function declarations that were included from .h files. But in this case the function is just defined and never declared, so I presume that's the same as a static declaration.

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#13
Question 4 points at a huge surprise. With a scientific computing project, I got (if I recall correctly), correct and expected output at no optimization and -O1, and patently incorrect output at -O2 and -O3.

Cost: one sleepless night in college."What do you mean, optimization doesn't just make it faster?!?"

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#14

This reminds me of something my assembly instructor said in class once (paraphrased): "Once, I was interested in finding out how a C compiler would handle the div instruction. So, I opened up my editor, and wrote this C program: void main () { printf("%f", 14.0 / 3.0); } I compiled it, and took a look at the generated assembly. How many div instructions do you think it used? [Various guesses, mostly "one."] The corre…

It didn't throw an "undefined variable" error?

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#15
post #8
post #7

I am surprised at number 3, I would have thought that it would be optimised to x Edit: No. 5 explains why.

Not really; there's no rounding problem with x random aside: gcc usually uses the LEA instruction for this sort of thing, which lets you compute any combination of {1,2,4,8} * x + y + n in one cycle where x and y are registers and n is a constant number. So even with the LEA instruction you can use either lea eax, [eax*2] or lea eax, [eax+eax] to compute this. And so on. I think add eax, eax is most likely what it do…

x86 has encodings for shifts by 1 that are two bytes, so there's no code size advantage.

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#16

Earlier quoted context omitted.

I don't spend a lot of time looking at complier outputs, but the optimization is quite obvious in the first case. I don't have a clue how it would optimize it out in the second case though...

In the second case the divide function isn't being exported from the compilation unit and the compiler can tell[1], so the compiler is free to do whatever it wants with the calling convention and in this case it will choose to inline. And once it's inlined finding the correct answer at compile time is still obvious. [1] Normally you have to declare a function as 'static' to tell the compiler that the function isn't b…

No, it's still an extern declaration. However the compiler is still allowed to "peek within" an extern function as long as it has the definition available.

You can see this by inspecting the disassembly yourself, you'll see that printf never actually calls divide, and yet the divide function is still defined within the executable output.

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#17
post #15
post #8

Earlier quoted context omitted.

Not really; there's no rounding problem with x random aside: gcc usually uses the LEA instruction for this sort of thing, which lets you compute any combination of {1,2,4,8} * x + y + n in one cycle where x and y are registers and n is a constant number. So even with the LEA instruction you can use either lea eax, [eax*2] or lea eax, [eax+eax] to compute this. And so on. I think add eax, eax is most likely what it do…

x86 has encodings for shifts by 1 that are two bytes, so there's no code size advantage.

Sometimes there are "canonical forms" for these operations depending on what chip is being targeted, where the hardware can automatically break data dependencies and improve hardware-level parallelism, as long as the instruction is encoded in the right form.

I don't know that this is necessarily the reason here, but it's one possible explanation.

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#18
post #3

I did some similar experiments myself a long time ago. Something mildly surprising for me at that time was that this got optimized to a single roll instruction: uint32_t roll(uint32_t const x) { return (x > 17); } I haven't managed to make GCC generate a non-constant roll (i.e. (x > (32-c)) ), probably because it couldn't infer that c is in the [0,31] range.

What version of GCC are you using? The non-constant case compiles to "roll" as far back as GCC 4.4.

It was a really long time ago - around the time of the NIST contest for the AES, so around 2001. And thanks for the "roll" update :)

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#19
post #10
post #3

I did some similar experiments myself a long time ago. Something mildly surprising for me at that time was that this got optimized to a single roll instruction: uint32_t roll(uint32_t const x) { return (x > 17); } I haven't managed to make GCC generate a non-constant roll (i.e. (x > (32-c)) ), probably because it couldn't infer that c is in the [0,31] range.

If c were outside that range, the result would be undefined, and the compiler would not need to consider that possibility.

[deleted]

Re: Will It Optimize? See how well you can anticipate gcc's optimizer (2010)

#20

This reminds me of something my assembly instructor said in class once (paraphrased): "Once, I was interested in finding out how a C compiler would handle the div instruction. So, I opened up my editor, and wrote this C program: void main () { printf("%f", 14.0 / 3.0); } I compiled it, and took a look at the generated assembly. How many div instructions do you think it used? [Various guesses, mostly "one."] The corre…

I've done this many times. This is special case that happens if you test with values inside the code. The compiler that I use, Visual C++, is smart enough to know that the result can be known at compile time, so it does just that in (Release). What you need to do is to read the arguments from a file or standard input.
Post reply on HN