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: Why doesn't -fomit-frame-pointer work(very well)?



>On Wed, Apr 03, 2002 at 06:01:40PM -0500, Peter Barada wrote:
>> So it looks like it tried to eliminate the frame pointer and then
>> failed.
>
>Hum.  I suspect that reload doesn't like %sp being modifed
>and used within the same insn.  In fact, IIRC this is illegal
>on ARM, so there may well be code in there to prevent this.

I didn't find any explicit code to disallow modifying %sp in an
instruction that refers to it.  After adding in ARG_POINTER_REGNUM to
mimic what others have done (i386, h8300, etc), I have in 3.0.4(for
the non-FPA case): 

1) bumped FIRST_PSEUDO_REGISTER from 24 to 26 to make room for %frame
   and %arg
2) defined DWARF_FRAME_REGISTER to 24 (original value of FIRST_PSEUDO_REGISTER)
3) Set FIXED_REGISTERS[24] and FIXED_REGISTERS[26] both to 1.
4) Set HARD_FRAME_POINTER_REGNUM to 14
5) Set FRAME_POINTER_REGNUM to 24
6) Set ARG_POINTER_REGNUM to 25
7) Set REG_CLASS_CONTENTS[GENERAL_REGS] and
   REG_CLASS_CONTANTS[ALL_REGS] to 0x1ffffff
8) Added ELIMINABLE_REGS:
 #define ELIMINABLE_REGS					\
 {{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},		\
  { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},	\
  { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},		\
  { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}	\

9) Added CAN_ELIMINATE:
 #define CAN_ELIMINATE(FROM, TO) \
   ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1)

10) Added INITIAL_ELIMINATION_OFFSET:
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
   (OFFSET) = m68k_initial_elimination_offset(FROM, TO)

where m68k_initial_eliminatio_offset came from Roman Zippel.

11) Set REGISTER_NAMES[24]="%frame" and REGISTER_NAMES[25]="%arg"

And when I run my simple test case:

typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;
extern void putzi(char c, char **p);
extern int _vformat (void (*putsub)(char c, char **p),
                     char **putbuf, const char *fmt, va_list argp);
int printf(const char *template, ...)
{
  int retval;
  va_list args;

  __builtin_stdarg_start((args),template);
  retval = _vformat(putzi, (char **)0, template, args);
  __builtin_va_end(args);

  return (retval);
}

It produces the following:

printf:
	pea 12(%a6)
	move.l 8(%a6),-(%sp)
	clr.l -(%sp)
	pea putzi
	jbsr _vformat
	lea (16,%sp),%sp
	rts

Which is a parial elimination of the ARG_POINTER_REGNUM to
STACK_POINTER_REGNUM.  It decided it can't eliminate it because:

$34 = {from = 25, to = 15, initial_offset = 0, can_eliminate = 1, 
  can_eliminate_previous = 1, offset = 0, previous_offset = 0, 
  ref_outside_mem = 0, from_rtx = 0x4001c030, to_rtx = 0x4001c000}
(gdb) p &reg_eliminate[0].can_eliminate
$35 = (int *) 0x82e7d34
(gdb) watch *$35
Hardware watchpoint 20: *$35
(gdb) c
Continuing.
Hardware watchpoint 20: *$35

Old value = 1
New value = 0
eliminate_regs_in_insn (insn=0x400237e0, replace=0)
    at /home/pbarada/work/cvs-wavemark/cross-linux-tools/gcc-304/gcc/reload1.c:3237
(gdb) p reg_eliminate[0]
$36 = {from = 25, to = 15, initial_offset = 4, can_eliminate = 0, 
  can_eliminate_previous = 1, offset = 8, previous_offset = 4, 
  ref_outside_mem = 1, from_rtx = 0x4001c030, to_rtx = 0x4001c000}
(gdb) call debug_rtx(insn)

(insn 17 14 19 (set (mem/f:SI (pre_dec:SI (reg/f:SI 15 %sp)) 0)
        (plus:SI (reg/f:SI 15 %sp)
            (const_int 16 [0x10]))) 60 {pushasi} (nil)
    (nil))
(gdb) 

>From the comment at reload.c:3223:

     We also detect a cases where register elimination cannot be done,
     namely, if a register would be both changed and referenced outside a MEM
     in the resulting insn since such an insn is often undefined and, even if
     not, we cannot know what meaning will be given to it.  Note that it is
     valid to have a register used in an address in an insn that changes it
     (presumably with a pre- or post-increment or decrement).

In this case we're trying to eliminate %arg in favor of %sp, and this
instruction uses %arg to form an address, but does not change %arg.
It does change %sp, so I can see how this fits the comment.  But since
%sp is only used as an address(and not a value), then the note about
'register used in an address' should be valid.

Looking why ref_outside_mem is set to TRUE, I found the initial call
to elimination_effects(reload.c:3093) on the above insn is made with
mem_mode=0(VOIDmode), so at line 2712, ep->ref_outside_mem is set to
1(after finding that %arg is mentioned in the instruction).

I'm wondering if the code at line 2831 should be:
      elimination_effects (SET_DEST (x), GET_MODE(insn));
      elimination_effects (SET_SRC (x), GET_MODE(insn));

Since we know in the SET what the mode of the move is so
pre_dec/post_inc can discern the size of the adjustment.

If mem_mode is never changed in elimination_effects(), and since
it is only passed to itself and is statically defined, it could be
removed completely, and ep->ref_outside_mem *always* set to 1 at line 2439.

Any ideas?

-- 
Peter Barada                                   Peter.Barada@motorola.com
Wizard                                         781-852-2768 (direct)
WaveMark Solutions(wholly owned by Motorola)   781-270-0193 (fax)


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