3 ms·
No, it really isn't on anything modern, like ARM SoCs or x86 CPUs. The number of times I've hit my head to wall trying to understand what the heck the CPU is do
by vardump 7y ago
No, it really isn't on anything modern, like ARM SoCs or x86 CPUs. The number of times I've hit my head to wall trying to understand what the heck the CPU is doing for a given sequence of instructions, like why the number of cycles or memory bandwidth required is way different from my expectation.
A modern CPU willy nilly reorders instructions, stores, and creates new "virtual" registers out of thin air to dissolve stall inducing dependency chains. It can also split instructions, fuse them together and even entirely remove some instructions -- as long as it doesn't affect the end result.
Generally (within limits of CPU memory model) the only thing you're guaranteed is that eventually the result is what you'd expect from sequential execution. That of course applies on the core you're running on, otherwise you naturally need to synchronize with other cores.
Luckily there are tools to find out, which work to some extent, IF you can run it on same CPU model (and really, whole system, incl. memory subsystem!) as what you're interested in.
- dooglius 7y agoCan you give an example? The most complicated assembly->microcode examples I can think of are floating-point instructions like FSIN that run CORDIC loops under the hood, and those are still pretty easy to reason about.
- vardump 7y agoPseudo-code: a = 10; b = 20; c = b + 30; bar = a + b; x = 1; y = 2; z = y + 3; foo = x + y; ... in order to remove dependency stalls might be executed as: b = 20; y = 2; a = 10; x = 1; c = b + 30; z = y + 3; bar = a + b; foo = x + y; This would still be true, even if 'x' and 'a', 'y' and 'b' etc. variables (well, registers) had same name. In that case CPU would just make up new "variables" as required and do the same transformation!
- dooglius 7y agoOkay, you're talking about OoO execution here, and you're right that this can be hard to reason about (in terms of stalls/latencies), however that's orthogonal to microcode translation.
- vardump 7y agoOoO and the fact that CPUs really are free to do whatever transformations they deem fit, as long as the end result within limits of memory model is same.
- jcranmer 7y agoThe CPU must conform to the strictures of the ISA, which is a much more stringent specification than the abstract machines of most language specifications. In particular, the state of registers and flags at any given time need to be preserved, even in the presence of external interrupts. Note that several decades ago, there were processors that weren't capable of actually keeping the state correct after a processor exception, so if you got a division-by-0 error, your program counter had advanced by 30 or so. (This is, I believe, part of the reason why traps are undefined behavior in C: if your processor can't guarantee any state after a machine trap, it's impossible to implement a programming language that has even the loosest guarantees).
- vardump 7y ago> The CPU must conform to the strictures of the ISA, which is a much more stringent specification than the abstract machines of most language specifications. In particular, the state of registers and flags at any given time need to be preserved, even in the presence of external interrupts. https://en.wikipedia.org/wiki/Tomasulo_algorithm https://en.wikipedia.org/wiki/Tomasulo_algorithm. So no, the consistent serialized ISA-conforming state might be reconstructed by replaying after the exception (interrupt) arrives. Alternatively, interrupt might be served only after execution reaches the next checkpoint.
- overgard 7y agoI don't understand how you can acknowledge the cpu is literally rewriting your code on the fly by changing the order of operations and making things massively parallel and rewriting things in a proprietary language, while holding the belief that "microcode is really not that different from assembly". At least you can inspect what a C compiler emits to assembly.
- Jasper_ 7y agoThis has nothing to do with microcode. It doesn't even have anything to do with microops. Reordering instructions (likely register renaming or load-store forwarding here, though the pseudo C code doesn't let me determine) is just part of how the processor retires instructions.
- vardump 7y agoThe example I gave, yes. No assembler code can have anything to do with micro-ops; they're implementation specific. On x86, a lot of instructions are close matches, yet some are removed entirely (say "xor eax, eax") or fused into one micro-op, (like "cmp #123, eax / je <address>"). Future CPUs might even do some data flow analysis to optimize code even further. Say speculative "constant" folding based on runtime profile to remove chunks of code from hot inner loops. Or to replace longer instruction patterns with HW optimized implementation, if that's what it takes to get some extra performance for the next year's model. https://en.wikichip.org/wiki/macro-operation_fusion https://en.wikichip.org/wiki/macro-operation_fusion
- Jasper_ 7y agoRegisters are allocated (and renamed) after instruction decode (e.g. what creates micro-ops), in a separate unit. Micro ops themselves do not have renamed registers. See the diagram here https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf#page=52 https://software.intel.com/sites/default/files/managed/9e/bc...
- vardump 7y agoTrue. I simplified implementation details for clarity.
- 8K832d7tNmiQ 7y agoYou are mixing up how branch prediction works with how processing unit works. One of those only worth of time to learn as hardware engineers, but understanding both of them will give you an introduction to Spectre vulnerability.
- vardump 7y agoNo, branch prediction is not involved with what I was talking about.