On Fri, Apr 27, 2007 at 08:24:11AM -0700, Richard Henderson wrote: > On Fri, Apr 27, 2007 at 04:00:13PM +0200, Rask Ingemann Lambertsen wrote: > > I don't see how emit_move_complex_push() can ever generate a push > > instruction. Here's a backtrace: > > emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)), > read_complex_part (y, imag_first)); > return emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)), > read_complex_part (y, !imag_first)); > > Note that we're replacing (pre_dec:CSI sp) with two > instances of (pre_dec:SI sp).
Yes. emit_move_insn() will call emit_move_insn_1(), which goes on to call emit_move_multi_word(). Here, first emit_move_resolve_push() is called to update the stack pointer. Then follows a loop to emit a sequence of move insns, each moving one word, using emit_move_insn(). > > Usually, doing so will fool reload's frame pointer elimination if the > > operand is a pseudo which ends up on the stack. Diffing the output between > > the two implementations confirms it: > > This doesn't look like frame pointer elimination at all, > just different stack slots allocated. No, that was the only difference in the asm outputs. > But that said, if > there's a bug in elimination, it should be fixed, not > hacked around in one backend. What happens when splitting during expand is that we get a sequence of push insns: (set (mem:HI (pre_dec:HI (reg:HI %sp))) (subreg:HI (reg:HI obj) 6)) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (subreg:HI (reg:HI obj) 4)) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (subreg:HI (reg:HI obj) 2)) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (subreg:HI (reg:HI obj) 0)) During register allocation, the pseudo obj is put on the stack, let's say (mem:DI (plus:HI (reg:HI %bp) (const_int -16)). So the insns look like this: (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %bp) -10))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %bp) -12))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %bp) -14))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %bp) -16))) Now, reload comes along and eliminates %bp to %sp, let's say with an elimination offset of 20. We get: (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %sp) 10))) Reload sees that we decremented %sp by two and increases the elimination offset accordingly for the next insn: (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %sp) 8+2))) And so on for the next two insns: (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %sp) 6+4))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %sp) 4+6))) The stack pointer is not a valid base register, so reload fixes it up: (set (reg:HI %di) (reg:HI %sp)) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %di) 10))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %di) 10))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %di) 10))) (set (mem:HI (pre_dec:HI (reg:HI %sp))) (mem:HI (plus:HI (reg:HI %di) 10))) I seems likely that reload inheritance contributes to the mess in some way. -- Rask Ingemann Lambertsen