This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: How can INITIAL_FRAME_POINTER_OFFSET be made correct?


 
> -----Original Message-----
> From: Richard Henderson 
> Sent: 19 March 2004 19:49

>On Fri, Mar 19, 2004 at 03:30:03PM -0000, Dave Korn wrote:
>> INITIAL_FRAME_POINTER_OFFSET is called before the md emit prologue 
>> function has has a chance to run.  So it has to duplicate the exact 
>> calculations that the prologue function does when it's deciding on 
>> the stack frame layout for the current function.
> 
> Yes.  This is true for everyone.  Preferred technique is to 
> use a common function to be used here and in the 
> prologue/epilogue code.

  Yep, that's exactly how I do it: I defined a nice struct to wrap it all up
in

struct dlx_frame_info {
    int     lr_save_size;
    int     lr_save_pointer;
    int     fp_save_size;
    int     fp_save_pointer;
    int     gpr_save_size;
    int     gpr_save_pointer;
    int     aligned_outarg_size;
    int     aligned_vars_size;
    int     stack_size;
};

and a generic routine to perform the calculations:

void
dlx_init_frame_info (info, vars)
    struct dlx_frame_info *info;
    int vars;
{
    /* Start by initing all sizes to zero. */
    memset (info, 0, sizeof *info);
    /* Calculate space needed for various areas.  These magic 4s are bad
really. */
    info->lr_save_size = !current_function_is_leaf ||
regs_ever_live[LINK_REGNUM] ? 4 : 0;
    /* fp_save_size MUST be setup correctly before we iterate across gprs */
    info->fp_save_size = frame_pointer_needed ? 4 : 0;
    info->gpr_save_size = dlx_gpr_save_area_iterate (info, NULL, NULL) * 4;
    info->aligned_outarg_size =
DLX_ALIGN(current_function_outgoing_args_size,4);
    info->aligned_vars_size = DLX_ALIGN(vars,4);
    info->stack_size = info->aligned_outarg_size + info->lr_save_size +
info->fp_save_size + info->gpr_save_size + info->aligned_vars_size;
    info->lr_save_pointer = info->aligned_outarg_size;
    info->fp_save_pointer = info->lr_save_pointer + info->lr_save_size;
    info->gpr_save_pointer = info->aligned_outarg_size + info->lr_save_size
+ info->fp_save_size;
}

which I then call like this:

static void
dlx_output_function_prologue(file, vars)
    FILE *file;
    int vars;
{
struct dlx_frame_info info;
int regno;

    /* Allocate space in the stack frame and lay it out. */
    dlx_init_frame_info (&info, vars);

        ....more....

and like this:

static void
dlx_output_function_epilogue(file, vars)
    FILE *file;
    int vars;
{
struct dlx_frame_info info;

    /* Allocate space in the stack frame and lay it out. */
    dlx_init_frame_info (&info, vars);

        ....more....

and like this:

#define INITIAL_FRAME_POINTER_OFFSET(DEPTH)            \
    {                                                   \
    struct dlx_frame_info info;                         \
        dlx_init_frame_info (&info, get_frame_size ()); \
        (DEPTH) = info.stack_size;                     \
    }

  When I started to suspect that I might be getting inconsistent results, I
added a machine_function structure as well to cache the resulting frame info
struct in and actually verify with a memcmp that subsequent calls were
generating the same data in that struct; that's what gave me the clue that
something was changing in the input data the function was relying on.

> >   Is it valid that regs_ever_live[] changes between IFPO 
> and emit_prologue?
> 
> No.  Whenever reload adds a new spill register, it's supposed 
> to go back through the allocation loop, which will recompute 
> that offset.

  Gotcha.  I added trace code which shows me that IFPO is the first one of
those points to get called, followed by emit_prologue and then
emit_epilogue.  I noticed also that IFPO gets called several times per
function (and the others just once each): I suppose that's each time the
allocation loop needs to recompute the offset, and it's not important that
all those calls agree with each other, just so long as the very last call
produces the same state as is used in the prologue and epilogue.

> I don't suppose your link register is marked CALL_USED?  

  Bingo!

> That's probably a mistake...
> 
> 
> r~


  Turns out it certainly is, or at any rate it fixes my va-arg-11.c failure
and several others too.  I'm not sure why it's a mistake, though: function
calls are performed by a jump-and-link instruction that clobbers the LR; in
the definition of CALL_USED_REGISTERS in the documentation, it seems to
suggest that means I should include it.  Is it wrong because that counts as
being clobbered by the caller, rather than by the callee, perhaps?

  Aha: I've just noticed that the call* patterns in the .md file explicitly
include the link register as a clobber in the parallel.  So yes, it does
count as being clobbered by the call insn, rather than CALL_USED.  I'm
unsure why declaring it call used in addition doesn't just result in
needless loads and saves but actual inconsistent state, but there you go: it
seems to be playing nicely now.  Thanks for catching that one.




    cheers, 
      DaveK
-- 
Can't think of a witty .sigline today....





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]