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

Reply via email to