This is the mail archive of the
mailing list for the GCC project.
Re: PUSH and POP next to first/last register use
- From: Sami Khawam <S dot Khawam at ee dot ed dot ac dot uk>
- Cc: Paolo Bonzini <paolo dot bonzini at lu dot unisi dot ch>, wilson at specifixinc dot com, gcc at gcc dot gnu dot org
- Date: Wed, 09 Feb 2005 17:48:17 +0000
- Subject: Re: PUSH and POP next to first/last register use
- References: <41F7813C.email@example.com> <41F7A3A5.firstname.lastname@example.org>
Thank you Jim and Paolo for your answers.
Acctually I do not need to worry about the order in
which the pushes and pops are done, as these would
be taken care of in the special assembler I am
using. All I need in the output assembly is to have
the PUSH appearing before the first time the reg is
used and the POP just after the last time it is
used. The reason is that the (simple) assembler I am
using operates on each basic-block seperately and it
would be confused to see a PUSH of a register
without seeing that register being used.
Here is what I did to implement this
'shrink-wrapping'; however I am getting errors:
I increased the number of registers from 32 to 64,
with the last 32 being a unallocatable by gcc
(FIXED_REGISTERS is set high). In the proglogue and
epilogue I emit the following moves:
emit_move_insn (gen_rtx_REG (SImode, regno+32),
gen_rtx_REG (SImode, regno));
emit_move_insn (gen_rtx_REG (SImode, regno),
gen_rtx_REG (SImode, regno+32));
My intetion was then to create a special case in the
machine description where all the MOVES to a ref
above 32 are printed as "PUSH" and anything MOVES
from a reg above 32 become "POP". However, having
the previous definitions in the pro and epilogue
crash the compiler with:
internal compiler error: in final, at final.c:1569
Many thanks for your help!
The University of Edinburgh
Paolo Bonzini wrote:
> I suppose this would require using REGNO_FIRST_UID(N) and
> REGNO_LAST_UID(N) at some point, however I would be very grateful if
> you can help me with it, as it seems that REGNO_FIRST_UID(N) is still
> reset to 0 when TARGET_ASM_FUNCTION_PROLOGUE is called.
REGNO_FIRST_UID and REGNO_LAST_UID are set by reg_scan (see passes.c),
but they do not take into account the CFG -- i.e. REGNO_FIRST_UID is not
guaranteed to dominate all uses, and REGNO_LAST_UID is not guaranteed to
Using them is almost never the right thing to do -- witness the fact
that there are only three users in the whole of gcc's middle-end:
1) in CSE, and it is just a way to pick an order for registers
2) in initialize_uninitialized_subregs, and only as an optimization to
skip insns that surely don't refer to a reg.
3) loop.c, which is 9000 lines of complex code with a lot of heuristics
that were designed two major releases ago -- a lot of things changed
since then, and loop.c is going to be removed sooner or later.
What you want to do would mean multiple pushes or pops, right? You may
want to do a dominator/postdominator walk, it is quite cheap in HEAD.
This is called "shrink-wrapping". I would think this works best if you emit the saves/restores into the prologue/epilogue, and then run a shrink-wrapping optimization pass that tries to move them inward as far as you can.
This should be feasible for store/load instructions, but for push/pop this will be complicated. This will change stack offsets, so it will interfere with frame pointer elimination. You need to worry about other things that change the stack, like alloca and Variable Length Array allocations and deallocations. You will need to worry about the -fdefer-pop optimization, as that may leave the stack unbalanced for some sections of code. And of course if you have overlapping register lifetimes, then the push/pops for those registers will conflict. You either have to use the union of the register lifetimes for both registers, or else only shrink-wrap one of them. This all sounds like more trouble than it is worth for a target that uses push/pop for register saves and restores.
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com