egcs-1.1b alpha-dec-osf3.2 internal error in change_address()

Fergus Henderson fjh@cs.mu.OZ.AU
Fri Apr 9 02:16:00 GMT 1999


On 08-Apr-1999, Richard Henderson <rth@cygnus.com> wrote:
> In general, yes.  However, I would consider it a serious regression
> if for Alpha any function that didn't use alloca ever did not have
> its frame pointer eliminated.  Even at -O0.
...
> So your whole debugging session starts way too late.  You
> would have needed to find out why fp_is_frame_pointer is
> true at all.

At the end of this email is a description of what happens for
egcs-1.1.2, running on the test case `void foo() {}', with no options.
In short, it seems that the frame pointer is not eliminated if
-fomit-frame-pointer is not specified.  The gcc documentation says that
-fomit-frame-pointer is only set at -O, and it seems to me that it
would be surprising if the frame pointer were omitted even if
-fomit-frame-pointer was not enabled, so the observed behaviour seems
to me to be consistent with the documentation.  (Is there any reason
why the frame pointer should be omitted even if -fomit-frame-pointer is
not specified?  If so, I don't see it.)

So, I agree that you should be allowed to use $15 as a global register
variable; but I think that in order to make that work, you should compile
with `-fomit-frame-pointer' (or equivalently with `-O' or `-O2' or higher).

The test case in my original bug report was broken code,
because it used $15 but did not specify `-fomit-frame-pointer'.
The gcc bug is just that gcc should not abort with an internal
compiler error; ideally it should instead report a better error
message.  (In fact even generating incorrect code would in some
respects be better than reporting a spurious ICE; it may take
some time for the user to find the problem, but at least when
they find it they will know that it is their fault and not gcc's.)

In addition, there is also a problem with fix_register()
in regclass.c being overly conservative; it should not disallow
the use of the frame pointer if -fomit-frame-pointer is enabled.

Does everyone agree with this diagnosis?

I have included a completely untested (I haven't even compiled it)
patch to regclass.c to address the second problem.

Index: regclass.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/regclass.c,v
retrieving revision 1.54
diff -u -r1.54 regclass.c
--- regclass.c	1999/02/25 23:45:28	1.54
+++ regclass.c	1999/04/09 09:11:08
@@ -579,9 +579,9 @@
     {
       if ((i == STACK_POINTER_REGNUM
 #ifdef HARD_FRAME_POINTER_REGNUM
-	   || i == HARD_FRAME_POINTER_REGNUM
+	   || (i == HARD_FRAME_POINTER_REGNUM && !flag_omit_frame_pointer)
 #else
-	   || i == FRAME_POINTER_REGNUM
+	   || (i == FRAME_POINTER_REGNUM && !flag_omit_frame_pointer)
 #endif
 	   )
 	  && (fixed == 0 || call_used == 0))
@@ -590,8 +590,10 @@
 	    { "call-saved", "call-used" },
 	    { "no-such-option", "fixed" }};
 	  
-	  error ("can't use '%s' as a %s register", name, 
-		 what_option[fixed][call_used]);
+	  error ("can't use '%s' as a %s register%s", name, 
+		 what_option[fixed][call_used],
+		 (i == STACK_POINTER_REGNUM ? ""
+		  : " without '-fomit-frame-pointer'"));
 	}
       else
 	{

----------
Below is a description of what happens for egcs-1.1.2, running on the
test case `void foo() {}', with no options.

frame_pointer_needed is set to 1 at reload1.c:715 in reload():

 |   /* Does this function require a frame pointer?  */
 | 
 |   frame_pointer_needed = (! flag_omit_frame_pointer
 | #ifdef EXIT_IGNORE_STACK
 |                           /* ?? If EXIT_IGNORE_STACK is set, we will not save
 |                              and restore sp for alloca.  So we can't eliminate
 |                              the frame pointer in that case.  At some point,
 |                              we should improve this by emitting the
 |                              sp-adjusting insns for this case.  */
 |                           || (current_function_calls_alloca
 |                               && EXIT_IGNORE_STACK)
 | #endif
 |                           || FRAME_POINTER_REQUIRED);

Here `flag_omit_frame_pointer' is 0, so the remaining tests are irrelevant.

Then, just below, at reload1.c:734, the `can_eliminate' flag
for the elimination from the frame pointer to the stack pointer
is set to 0, because frame_pointer_needed is 1.

 |       ep->can_eliminate = ep->can_eliminate_previous
 |         = (CAN_ELIMINATE (ep->from, ep->to)
 |            && ! (ep->to == STACK_POINTER_REGNUM && frame_pointer_needed));

It stays 0.

Then, at reload1.c:1626, still in reload(), the code recomputes
frame_pointer_needed based on the can_eliminate flags.

 |       /* See if any registers that we thought we could eliminate the previous
 |          time are no longer eliminable.  If so, something has changed and we
 |          must spill the register.  Also, recompute the number of eliminable
 |          registers and see if the frame pointer is needed; it is if there is
 |          no elimination of the frame pointer that we can perform.  */
 | 
 |       frame_pointer_needed = 1;
 |       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
 |         {
 |           if (ep->can_eliminate && ep->from == FRAME_POINTER_REGNUM
 |               && ep->to != HARD_FRAME_POINTER_REGNUM)
 |             frame_pointer_needed = 0;

But the can_eliminate flags that we need were set to 0 as explained above.
So frame_pointer_needed gets set to 1 again and stays that way.
Indeed it stays that way for the duration, so when we get to
alpha_expand_epilogue() it is 1, and so we generate an epilogue
that uses the frame pointer.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: < http://www.cs.mu.oz.au/~fjh >  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


More information about the Gcc-bugs mailing list