Rendered at 16:15:45 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
nyrikki 15 hours ago [-]
IMHO this may be because with hyper-restrictive calling convention or register budgets, the compiler typically resorts to writing explicit MOV or stack PUSH/POP instructions to free up space.
Because modern CPUs have hundreds of hidden physical registers, the CPU's Register Renaming unit looks at those forced stack move instructions, realizes they are just recycling the same local variables, and maps them to hidden hardware registers anyway. The CPU essentially executes the "stack spills" at the hardware register level, rendering the compiler's bad register constraints almost completely harmless.
Particularly the siphash result makes me think this is what is happening.
Unfortunately I don’t think there is a way to observe this as a consumer.
mfro 13 hours ago [-]
I would kill to see the equipment intel uses to study these things
throwaway81523 10 hours ago [-]
I thought VTune would let you see into it to some extent.
Scene_Cast2 22 hours ago [-]
I wonder how much effect the CPU's register remapping has on these results. Also, they ran it on an ancient CPU, but I'm not sure how much that matters.
CalChris 20 hours ago [-]
How much effect the CPU's register remapping has? Probably a lot and the article doesn't discuss it at all.
However, the Intel Xeon E-2236 was released in 2019; so it's hardly ancient and the current E-2400 isn't so different.
As for hardware register renaming, Tomasulo dates to 1967 and out-of-order ROBs were common in the 90s. I don't know that there's been any major new ideas microarchitectural ideas in register renaming since the 90s.
I still think it's a meaningful experiment but could be improved with consideration of microarchitectural features.
hinkley 21 hours ago [-]
Probably not that much because one of the legacies of x86 is that library calling conventions are based on this same registry scarcity. To make an API call there is a convention that a limited number of registers are treated as callee-preserves and the rest are caller-preserves. So your compiler spills them defensively before calling out.
You can make a programming language that uses whatever convention you want, but every time you make a system call or a call to a C or Rust library, you're using essentially an FFI and your FFI logic will have to handle the register spill and recovery to match the convention. And if you convert your code to a library, then it'll have to be dumbed down as well.
nyrikki 15 hours ago [-]
Calling conventions are a compiler feature, and in some languages like zig, will let the LLVM backend fully optimize. In zig you can specify a different calling convention at any function call, and you have to be explicit if you want a ABI contract at all.
Intel introduced the RAT (Register address table) with the P6 in 1995. Although IIRC it depended on ROT(Register Order Table) and wouldn’t affect the outcome the same way.
I think Netburst is where it really was extended to support out-of-order pipeline stages.
As long as the CPU does’t violate the interface contract it can micro-optimize at will.
derdi 21 hours ago [-]
This is pretty meaningless without showing any assembly code. What does the inner loop for siphash look like? How many GPRs does it use? Where are the spills placed? What does perf say about any of this?
Because modern CPUs have hundreds of hidden physical registers, the CPU's Register Renaming unit looks at those forced stack move instructions, realizes they are just recycling the same local variables, and maps them to hidden hardware registers anyway. The CPU essentially executes the "stack spills" at the hardware register level, rendering the compiler's bad register constraints almost completely harmless.
Particularly the siphash result makes me think this is what is happening.
Unfortunately I don’t think there is a way to observe this as a consumer.
However, the Intel Xeon E-2236 was released in 2019; so it's hardly ancient and the current E-2400 isn't so different.
As for hardware register renaming, Tomasulo dates to 1967 and out-of-order ROBs were common in the 90s. I don't know that there's been any major new ideas microarchitectural ideas in register renaming since the 90s.
I still think it's a meaningful experiment but could be improved with consideration of microarchitectural features.
You can make a programming language that uses whatever convention you want, but every time you make a system call or a call to a C or Rust library, you're using essentially an FFI and your FFI logic will have to handle the register spill and recovery to match the convention. And if you convert your code to a library, then it'll have to be dumbed down as well.
Intel introduced the RAT (Register address table) with the P6 in 1995. Although IIRC it depended on ROT(Register Order Table) and wouldn’t affect the outcome the same way.
I think Netburst is where it really was extended to support out-of-order pipeline stages.
As long as the CPU does’t violate the interface contract it can micro-optimize at will.