Live data from Hacker News

You can't fool the optimizer

xania.org

171–180 of 193 posts

Re: You can't fool the optimizer

#171

Sometimes you can fool the (C) optimizer by using the 'volatile' keyword in front of a variable in code that would otherwise be optimized out. https://www.embeddedrelated.com/thread/4749/when-and-how-to-...

That's not really "fooling" the optimizer, that's kind of the point of volatile. The optimizer not making optimizations is the intended behaviour.

You're right, but the article failed to mention that there was a way around the optimizations.

Re: You can't fool the optimizer

#172
post #120

Recursive Popcount: unsigned int popcount(unsigned int n) { return (n &= n - 1u) ? (1u + popcount(n)) : 0u; } Clang 21.1 x64: popcount: mov eax, -1 .LBB0_1: lea ecx, [rdi - 1] inc eax and ecx, edi mov edi, ecx jne .LBB0_1 ret GCC 15.2: popcount: blsr edi, edi popcnt eax, edi ret Both compiled with -O3 -march=znver5

Because the function is not quite correct. It should be return n ? (1u + popcount(n & n - 1u)) : 0u; which both Clang and GCC promptly optimize to a single popcnt.

There should be testsuites, which are based on testing which compilation passes the compiler chose.

Re: You can't fool the optimizer

#173
post #142
post #60

Earlier quoted context omitted.

I don’t disagree, but profiling also won’t help you with death by a thousand indirections.

Sure, but that's mostly a myth.

So how do you see in a profiler, that everything is 1.2x slower than it could be?

Re: You can't fool the optimizer

#174
post #77

Earlier quoted context omitted.

Those aren't isomorphic. The C spec says `is_divisible_by_6` short-circuits. You don't want the compiler optimising away null checks. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 6.5.13, semantics

So you claim that the compiler "knows about this but doesn't optimize because of some safety measures"? As far as I remember, compilers don't optimize math expressions / brackets, probably because the order of operations might affect the precision of ints/floats, also because of complexity. But my example is trivial (x % 2 == 0 && x % 3 == 0 is exactly the same as x % 6 == 0 for all C/C++ int), yet the compiler produ…

> the order of operations might affect the precision of ints/floats

That's only the problem of floats, with ints this issue doesn't exist.

Why do you write (x % 2 == 0 && x % 3 == 0) instead of (x % 2 == 0 & x % 3 == 0), when the latter is what you think you mean?

Are you sure, that dividing by 6 is actually faster, than dividing by 2 and 3? A division operation is quite costly compared to other arithmetic and 2 and 3 are likely to have some special optimization (2 is a bitshift), which isn't necessary the case for 6.

Re: You can't fool the optimizer

#175

Sometimes you can fool the (C) optimizer by using the 'volatile' keyword in front of a variable in code that would otherwise be optimized out. https://www.embeddedrelated.com/thread/4749/when-and-how-to-...

Fooling for you is making someone not do X by telling them not to do X?

Re: You can't fool the optimizer

#176
post #16

Earlier quoted context omitted.

> It probably shouldn't do that if you create a dynamic library that needs a symbol table but for an ELF binary it could, no? It can't do that because the program might load a dynamic library that depends on the function (it's perfectly OK for a `.so` to depend on a function from the main executable, for example). That's one of the reasons why a very cheap optimization is to always use `static` for functions when you…

Sadly most C++ projects are organized in a way that hampers static functions. To achieve incremental builds, stuff is split into separate source files that are compiled and optimized separately, and only at the final step linked, which requires symbols of course. I get it though, because carefully structuring your #includes to get a single translation unit is messy, and compile times get too long.

That's one major reason why I don't like C++. I think the concept of header and implementation files is fine, but idiomatic C++ code basically makes it broken. Surely a class should go into the implementation file? (Internal) Types belong into the implementation, what belongs into headers are interfaces and function signatures. A class is a type, so it does not belong into a header file.

Re: You can't fool the optimizer

#177

Earlier quoted context omitted.

In C, I'm pretty confident the loop is defined by the standard to terminate. Also I did take the excuse to plug it (the optimized llvm ir) into Alive: https://alive2.llvm.org/ce/#g:!((g:!((g:!((h:codeEditor,i:(f...

> In C, I'm pretty confident the loop is defined by the standard to terminate. Huh? What's that supposed to mean?

That it is Undefined Behavior for a loop with a non-constant conditional and that doesn't cause side effects in its body to not terminate.

For example, you can use this make the compiler "prove" the Collatz Conjecture:

https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(file...

Re: You can't fool the optimizer

#179
post #126

Earlier quoted context omitted.

> If you use `&` instead of `&&` (so that all array elements are accessed unconditionally), the optimization will happen But then you're accessing four elements of a string that could have a strlen of less than 3. If the strlen is 1 then the short circuit case saves you because s[1] will be '\0' instead of 'e' and then you don't access elements past the end of the string. The "optimized" version is UB for short strin…

UB doesn't exist in the processor (it does, but not here). If the compiler knows the pointer is aligned it can do the transformation.

For the compiler to know the pointer is aligned it would have to actually be aligned and there is no guarantee that it is.

Re: You can't fool the optimizer

#180
post #178

Earlier quoted context omitted.

So how do you see in a profiler, that everything is 1.2x slower than it could be?

No-one's getting out of bed for 1.2x.

Depends. If you have a real-time system, that might very well will be what you chase after. Also why not make your program a bit faster when it is no work, by starting it the right way upfront. I mean I wouldn't rewrite a program for this, but when I program some new part and I can avoid an indirection, why not do it? Less complexity, less (failure) state, better performance.
Post reply on HN