Clang’s -O0 output: branch displacement and size increase
maskray.me
maskray.me
I've long held the opinion that O0 on all the major compilers should be considered more like an O-1 because of the glaring stupidities it leaves in its output, which almost looks like it was pessimising instead of not optimising.
This article is also only the 2nd time I've seen "relaxation" used in this context. The first was https://news.ycombinator.com/item?id=10219007 over 8 years ago.
In particular, GCC generates fairly debuggable code at all optimization levels, so there is less motivation for -O0 in the first place.
``` Mode | Execution Time | Debuggability | Compile Time O0 | 1.0000 | 1.0000 | 1.0000 Og | 0.3439 | 0.5357 | 1.8630 O1 | 0.3082 | 0.4241 | 1.7880 O2g | 0.2823 | 0.4845 | 3.0420 O2 | 0.2514 | 0.3908 | 2.9380 ```
Both GNU assembler and LLVM integrate assembler parse and match instructions only once. hey then store an internal representation in memory and perform fixed-point iteration. The section/fragment representation gives a lot of flexibility.
In contrast, nasm parses and matches instructions multiple times depending on the optimization level. It also assigns addresses during parsing and uses an ad-hoc method for JMP/JCC instructions. The end conditions of the fixed-point iteration algorithm (global_offset_changed and stall_count) seem unconventional. -O0 does not "relax all" short jumps to near jumps.
Not true, gas will do the relaxation by default.
> This article is also only the 2nd time I've seen "relaxation" used in this context.
It's been the standard term among toolchain developers for quite a while. I remember seeing it all over the linker in 2007 when working on ARM stuff.
Right. A ~5% additional increase in debug artifact size is really not a high tax.