← Back to context

Comment by maxime_cb

1 hour ago

Author here. The disassembly for the old enum handling had many spills, simply because the old value enum can't fit in a single register. If you have an instruction that two operands with two of those big value enums, it needs 4 registers instead of 2. That, coupled with better cache-friendliness, explains a lot.

Absolutely, I agree. I suspect that explicit branch for the hot path is doing a lot too.

Separating the hot path into a prefix before calling into a separate cold function should still generate better code. Your prefix only needs to allocate registers and stack space for just that single path. You would only pay the spilling costs in the old code off the hot path rather than every instruction. And I would expect the branch prediction accuracy of that prefix check to be higher than having the hot and cold paths all dispatching through the same tree of branches.

However it's speculation until you measure so I could be wrong.

Good article in any case, I enjoyed reading along.

100% agreed (see my sibling comment), this all accumulates for in-language function calls,etc since code at runtime often spends a surprising amount of time just moving around values instead of doing useful work, having them just as singular register values really helps a ton.