The greedy register allocator uses the CostPerUse hints to prefer the lower registers, but it has to balance many optimization goals at once, so it is not always obvious what is going on. For example, it will:
- Defer using a callee-saved register for the first time until it is worth the cost of spilling it in the prologue. It won't create a prolog spill just to use a better register. - Try to reuse function argument and return value registers to minimize register copies around function calls.
IIRC, the CostPerUse attribute gave a code size savings of around 1% on x86-64 and Thumb2. On both architectures, the effect is reduced by the fact that all register operands must be from the low register set before you can use the smaller encoding.
I was curious about this claim so I wrote a quick and dirty perl script to test it out:
vmlinuz-linux = 2.71957329365681
bash = 3.95324321387071
firefox = 3.56640365053712
geany = 3.44776119402985
gzip = 4.17925462998247
perl = 4.10894941634241
python = 3.82481751824818
tar = 3.93348845041101
thunar = 3.82471016115786
radeon_drv.so = 4.02697782644402
Seems spot on, except for the kernel. I'm not sure why that has shorter instructions on average.EDIT: I ran it on git too; average was 3.96747336803081. It seems Linus' x86 wizardry does not extend to userspace in this case.
Those instructions tend to be larger, so it may partly explain the difference in average instruction size. The same explanation would apply to why the Radeon driver has a higher average.
It calls "objdump -d" on the binary, which is binutil's disassembler.
objdump prints each instruction out in the following format:
5dc: 67 80 7d 00 00 cmpb $0x0,0x0(%ebp)
The first part is the instruction offset; the second is the bytes that comprise the instruction; the third part is the instruction in AT&T assembly syntax.The script uses regexs to cut off the front and back, then counts the number of bytes (in hex format) in the second part.
Then it calculates the average for all instructions.
Lea too if your arithmetic fits in it... but then that has issue restrictions... Three operand and the various conditional stuff in arm64 is worth more overall.
Edit: Ah well, beaten by your edit. :)
Maybe I'm missing something obvious, but why is code size a big concern for Facebook's server code?
http://arstechnica.com/business/2012/04/exclusive-a-behind-t...
Partially as a consequence of this, the REX prefixes take up a lot of space in most x86-64 instruction streams. In fact, the average size of each instruction is almost exactly 4 bytes, exactly the same as in classic 32-bit RISC architectures. (This is why I dislike it when people link to that old Linus post about how x86 is better than RISC architectures because of code size; it may have been true then, but not now.)