Thanks to the help of segher and iant on IRC (thanks again!), I narrowed my problem down to something I can fully understand and explain (well I hope).
There is a bad interaction between the IRA handling of subregs and reload's use of REG_EQUIV annotations. Each one seems to be in its right to do what it does, but the end result is wrong generated code. Here's what happens, using some simplified RTL: Before IRA: (insn 1 [(set (subreg:SI (reg:DI 6835) 0) (set (subreg:SI (reg:DI 6835) 4)]) (insn 2 (set (reg:SI 229) (mem:SI (subreg:SI (reg:DI 6835) 0))) (REG_EQUIV (mem:SI (subreg:SI (reg:DI 6835) 0)))) (insn 3 (set (reg:SI 3346) (...))) (insn 4 (use (reg:SI 3346)) (REG_DEAD (reg:SI 3346))) (insn 5 (use (reg:SI 229))) (insn 6 (use (subreg:SI (reg:DI 6835) 4)) (REG_DEAD (reg:DI 6835))) IRA does the following allocation: pseudo reg 6835 gets hard reg 8 pseudo reg 3346 gets hard reg 8 pseudo reg 229 gets spilled IRA is in its right to allocate hard reg 8 for both reg 3346 and 6835, because it tracks conflicts at the word level, and SI reg 3346 only conflicts with the high part of DI reg 6835. Had reg 229 been allocated to a hard register, the code would be correct. In my example though, the register pressure is high and reg 229 gets no hard register. Reload then chooses to use the equivalent memory location for this register. We end up with a reload for (insn 5) that does: (insn 6061 (set (reg:SI 44) (mem:SI (reg:SI 8))) (insn 5 (use (reg:SI 44))) The expression used in (insn 6061) for the reload value is the allocated version of the REG_EQUIV expression, but at the point it gets inserted, r8 has been clobbered by (insn 4). To try to sum it up, the use of the memory equivalence by reload extends the liveness of one half the reg 6835, thus generating code that isn't wrong because the interference graph computed by IRA isn't right anymore. I'm not sure what the right fix is: 1/ Denying REG_EQUIVs which contain subregs 2/ Tightening the interference graph computed by IRA 3/ Some hack in reload to prevent this equivalence to be used in this case 1/ seems simple but I'm not sure about its consequences. 2/ would incur a degradation in register allocation quality. I don't know about 3/. What do people think?