avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] the framepointer


From: Andy H
Subject: Re: [avr-gcc-list] the framepointer
Date: Sat, 19 Apr 2008 08:27:55 -0400
User-agent: Thunderbird 2.0.0.12 (Windows/20080213)

Hi Ruud

the source you refer to has assembler prolog/epilog. ie its old. The latest is written in RTL and does much better job of minimizing the code. (I have attached below)

The frame pointer should only be used if it is needed. It will be omitted otherwise with fomit_frame_pointer.

If stack space is needed for variables, then it will not be omitted.

R28/29 is used as frame_pointer. It can also be used for other purposes. This register must be preserved by function. If function does not need frame but calls another function, R28/29 will be saved.

In most causes you want to use -fomit_frame_pointer.

There are still situation we need to fix. One is that gcc will not readily use R28/R29 - if it is not needed by frame. Also, it does not factor the "free usage" of R28/R29 when it tries to figure out if frame pointer is needed or not (obviously R28/29 can be used to hold 16 bit value)

best regards
Andy



/*  Output function prologue.  */

void
expand_prologue (void)
{
 int live_seq;
 HARD_REG_SET set;
 int minimize;
 HOST_WIDE_INT size = get_frame_size();
 /* Define templates for push instructions.  */
 rtx pushbyte = gen_rtx_MEM (QImode,
                 gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
 rtx pushword = gen_rtx_MEM (HImode,
                 gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
 rtx insn;

 last_insn_address = 0;

 /* Init cfun->machine.  */
 cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
 cfun->machine->is_signal = signal_function_p (current_function_decl);
cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl);

 /* Prologue: naked.  */
 if (cfun->machine->is_naked)
   {
     return;
   }

 avr_regs_to_save (&set);
 live_seq = sequent_regs_live ();
 minimize = (TARGET_CALL_PROLOGUES
         && !cfun->machine->is_interrupt
         && !cfun->machine->is_signal
         && !cfun->machine->is_OS_task
         && live_seq);

 if (cfun->machine->is_interrupt || cfun->machine->is_signal)
   {
     if (cfun->machine->is_interrupt)
       {
         /* Enable interrupts.  */
         insn = emit_insn (gen_enable_interrupt ());
         RTX_FRAME_RELATED_P (insn) = 1;
       }
/* Push zero reg. */
     insn = emit_move_insn (pushbyte, zero_reg_rtx);
     RTX_FRAME_RELATED_P (insn) = 1;

     /* Push tmp reg.  */
     insn = emit_move_insn (pushbyte, tmp_reg_rtx);
     RTX_FRAME_RELATED_P (insn) = 1;

     /* Push SREG.  */
     insn = emit_move_insn (tmp_reg_rtx,
                            gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
     RTX_FRAME_RELATED_P (insn) = 1;
     insn = emit_move_insn (pushbyte, tmp_reg_rtx);
     RTX_FRAME_RELATED_P (insn) = 1;

     /* Push RAMPZ.  */
     if(AVR_HAVE_RAMPZ
&& (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
       {
         insn = emit_move_insn (tmp_reg_rtx,
gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
         RTX_FRAME_RELATED_P (insn) = 1;
         insn = emit_move_insn (pushbyte, tmp_reg_rtx);
         RTX_FRAME_RELATED_P (insn) = 1;
       }
/* Clear zero reg. */
     insn = emit_move_insn (zero_reg_rtx, const0_rtx);
     RTX_FRAME_RELATED_P (insn) = 1;

     /* Prevent any attempt to delete the setting of ZERO_REG!  */
     emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
   }
 if (minimize && (frame_pointer_needed || live_seq > 6))
   {
     insn = emit_move_insn (gen_rtx_REG (HImode, REG_X),
                            gen_int_mode (size, HImode));
     RTX_FRAME_RELATED_P (insn) = 1;

     insn =
       emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode),
                       gen_int_mode (size + live_seq, HImode)));
     RTX_FRAME_RELATED_P (insn) = 1;
   }
 else
   {
     int reg;
     for (reg = 0; reg < 32; ++reg)
       {
         if (TEST_HARD_REG_BIT (set, reg))
           {
             /* Emit push of register to save.  */
             insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
             RTX_FRAME_RELATED_P (insn) = 1;
           }
       }
     if (frame_pointer_needed)
       {
     if(!cfun->machine->is_OS_task)
       {
             /* Push frame pointer.  */
         insn = emit_move_insn (pushword, frame_pointer_rtx);
             RTX_FRAME_RELATED_P (insn) = 1;
       }

         if (!size)
           {
             insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
             RTX_FRAME_RELATED_P (insn) = 1;
           }
         else
           {
             /*  Creating a frame can be done by direct manipulation of the
                 stack or via the frame pointer. These two methods are:
                   fp=sp
                   fp-=size
                   sp=fp
               OR
                   sp-=size
                   fp=sp
the optimum method depends on function type, stack and frame size.
             To avoid a complex logic, both methods are tested and shortest
             is selected.  */
             rtx myfp;
             /*  First method.  */
             if (TARGET_TINY_STACK)
               {
                 if (size < -63 || size > 63)
warning (0, "large frame pointer change (%d) with -mtiny-stack", size); /* The high byte (r29) doesn't change - prefer 'subi' (1 cycle)
                    over 'sbiw' (2 cycles, same size).  */
                 myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
               }
             else
               {
                 /*  Normal sized addition.  */
                 myfp = frame_pointer_rtx;
               }
             /* Calculate length.  */
             int method1_length;
             method1_length =
get_attr_length (gen_move_insn (frame_pointer_rtx, stack_pointer_rtx));
             method1_length +=
           get_attr_length (gen_move_insn (myfp,
gen_rtx_PLUS (GET_MODE(myfp), myfp, gen_int_mode (-size,
                                               GET_MODE(myfp)))));
             method1_length +=
get_attr_length (gen_move_insn (stack_pointer_rtx, frame_pointer_rtx)); /* Method 2-Adjust Stack pointer. */
             int sp_plus_length = 0;
             if (size <= 6)
               {
                 sp_plus_length =
           get_attr_length (gen_move_insn (stack_pointer_rtx,
gen_rtx_PLUS (HImode, stack_pointer_rtx, gen_int_mode (-size,
                                               HImode))));
         sp_plus_length +=
get_attr_length (gen_move_insn (frame_pointer_rtx, stack_pointer_rtx));
               }
             /* Use shortest method.  */
             if (size <= 6 && (sp_plus_length < method1_length))
               {
                 insn = emit_move_insn (stack_pointer_rtx,
gen_rtx_PLUS (HImode, stack_pointer_rtx, gen_int_mode (-size, HImode)));
                 RTX_FRAME_RELATED_P (insn) = 1;
         insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
                 RTX_FRAME_RELATED_P (insn) = 1;
               }
             else
{ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
                 RTX_FRAME_RELATED_P (insn) = 1;
                 insn = emit_move_insn (myfp,
gen_rtx_PLUS (GET_MODE(myfp), myfp, gen_int_mode (-size, GET_MODE(myfp))));
                 RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn ( stack_pointer_rtx, frame_pointer_rtx);
                 RTX_FRAME_RELATED_P (insn) = 1;
               }
           }
       }
   }
}







reply via email to

[Prev in Thread] Current Thread [Next in Thread]