Re-use of stack slots can lead to data corruption
@AndreasK points out that the current logic for allocating stack slots in the linear register allocator (see e.g. `GHC.CmmToAsm.Reg.Linear.StackMap.getStackSlotFor`) does not take into account the possibility for registers to grow.
Here is a possible scenario which showcases the issue:
- We write to register `%v1` at format `FF64` (and let's say this is the first time this register is mentioned). We allocate a real register with format `FF64` to hold the data.
- Then, suppose we need to spill `%v1`, e.g. because it is getting clobbered. `getStackSlotFor` finds a new stack slot for it, say stack slot 0. At this point `%v1` takes up a single stack slot, and the next free stack slot is stack slot 1.
- Say we also need to spill something else, say `%v2 :: FF64`, and that we use stack slot 1 for that.
- Later, we write to `%v1` at format `FF64x2`. In the register assignment map, `%v1` now has format `FF64x2`.
- Now, suppose we need to spill `%v1` once more. What we should really do is find a new stack slot, because we need two consecutive stack slots to spill `%v1`. However, we instead simply re-use stack slot 0 (see `getStackSlotFor`).
- Then, the spill instruction we generate to spill `%v1` at this larger format will clobber the data in stack slot 1. This means that if we later try to reload `%v2` from memory, we will get the high bits of `%v1` that we spilled just now instead of the original data that was in `%v2` when we spilled it.
It's quite tricky to produce a test case that triggers this behaviour, but it is certainly a bug in the current implementation.
issue