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

Hans-Peter Nilsson hp@bitrange.com
Thu Apr 8 18:25:00 GMT 1999


> From: Richard Henderson <rth@cygnus.com>
> Date: Wed, 7 Apr 1999 02:54:26 -0700

> [ As well-meaning as Mr Nilsson was intending to be, he's off on the
>   specifics of frame pointer elimination on Alpha. ]

Um, well, while it is true that I know relatively little (knew less)
about the alpha-specific details of frame pointer elimination,
I tried not to imply anything other than what is common for other
systems; that the fp reg can *sometimes* be eliminated with
sp+offset and then used as a "normal" call-saved register, but
that it should not be fiddled or assumed being eliminated in a
program.  It seems correct from what I deduce from alpha.{h|c|md} and
the small but informational tutorial in
<URL: http://www.unix.digital.com/faqs/publications/base_doc/DOCUMENTATION/V40E_HTML/APS31DTE/DOCU_012.HTM >
which I found by starting from at the alpha-specific link in
readings.html.  (I was (am) curious about where I was wrong.)
 Please correct me where I'm wrong.  (Yes, CAN_DEBUG_WITHOUT_FP,
but I think that's not of interest here.)

If you mean I'm wrong when I say that attempting to use the
frame pointer as a register variable should result in a
compile-time error, then consider the existing code for giving
errors for -ffixed-$15, -fcall-saved-$15 and -fcall-used-$15.

> On Mon, Mar 29, 1999 at 08:01:32PM +1000, Fergus Henderson wrote:
> > ../../egcs-1.1b/gcc/emit-rtl.c:1491: Internal compiler error in function
> > change_address
> 
> Curious.  This abort indicates we created some sort of invalid address.
> Which would appear to have nothing to do with frame pointer elimination
> btw, so I'd like to know what's really happening.

Well, I mentioned it was a secondary effect, but presented only
a few facts, so I guess skepticism is in order ;-)

I'll try to visualize it through a gdb session, using input from
the original bug-report.  Excuse any "lecturing" in the
comments; it is meant for the benefit of the wider audience and
attempting to *not* assume that anything easily said is obvious even for
the most experienced:

(gdb) r </tmp/fhbug.i
Starting program: /mnt/s0d6p1/hp/egcs_dammit_alphaev6/gcc/cc1 </tmp/fhbug.i
# [... stuff deleted]
	ret $31,($26),1
	.end mercury__query__IntroducedFrom__pred__run__14__1_1_0
 mercury__query__IntroducedFrom__pred__run__14__1_1_0_i1
/home/hp/egcs/cvs_dammit/egcs/gcc/emit-rtl.c:1549: Internal compiler error in function change_address
Please submit a full bug report to `egcs-bugs@egcs.cygnus.com'.
See <URL: http://egcs.cygnus.com/faq.html#bugreport > for details.

Breakpoint 1, 0x40031088 in exit ()
(gdb) up
#1  0x809973c in change_address (memref=0x821bda8, mode=VOIDmode, 
    addr=0x821bd9c) at /home/hp/egcs/cvs_dammit/egcs/gcc/emit-rtl.c:1549
-----
  /* If reload is in progress or has completed, ADDR must be valid.
     Otherwise, we can call memory_address to make it valid.  */
  if (reload_completed || reload_in_progress)
    {
      if (! memory_address_p (mode, addr))
=>	abort ();
    }
  else
    addr = memory_address (mode, addr);
----

What's wrong with addr?

(gdb) p addr
$1 = (struct rtx_def *) 0x821bd9c
(gdb) pr
(plus:DI (reg:DI 30 $30)
    (const_int 134851222 [0x809aa96]))

That's not a valid address on an alpha system, and the const_int looks
curiously like a pointer value to gcc-internal data.  How did it get
there?...

(gdb) up
#2  0x807130d in emit_move_insn (x=0x819b85c, y=0x821bda8)
    at /home/hp/egcs/cvs_dammit/egcs/gcc/expr.c:2547
(gdb) up
#3  0x8149e35 in alpha_expand_epilogue ()
    at /home/hp/egcs/cvs_dammit/egcs/gcc/config/alpha/alpha.c:3902
----
      if (fp_is_frame_pointer)
	{
	  emit_insn (gen_blockage ());
	  mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, fp_offset));
	  MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
=>	  FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
	}
----

Hmm, maybe there's crud in fp_offset?

(gdb) p/x fp_offset
$3 = 0x809aa96

Badness.  Now, if you look around there in alpha_expand_epilogue
and alpha_sa_mask, you'll see that fp_offset has this value
because it is uninitialized.  If fact, fp_offset is only
initialized if it is used and should be saved.  But here, fp is
used, but not saved:

(gdb) p call_used_regs[15]
$4 = 1 '\001'
(gdb) p regs_ever_live[15]
$5 = 1 '\001'
(gdb) p fp_is_frame_pointer
$6 = 1
(gdb) p fixed_regs[15]
$7 = 1 '\001'
(gdb) p frame_pointer_needed
$8 = 1

That last one, frame_pointer_needed == 1, is because we're not
optimizing, but would also be true if there was some construct
where a variable-sized stack-frame is needed.

Apparently, initializing fp_offset would only paper over the
real bug, which is that fp should not be treated like this; it
should not be 1 in fixed_regs because then *all* uses of the
frame pointer register as such in the program would have to be
eliminated.  Maybe fp_offset should be set to *always* be an
invalid offset; this may help you seeing this problem.

Poking around some more, finally reduced to "watch
fixed_regs[15]" and restarting, I saw that it was set to 1 in
globalize_reg:

Hardware watchpoint 4: fixed_regs[15]
Old value = 0 '\000'
New value = 1 '\001'
globalize_reg (i=15) at /home/hp/egcs/cvs_dammit/egcs/gcc/regclass.c:630
#1  0x808ed5c in make_decl_rtl (decl=0x81c876c, asmspec=0x81c8764 "$15", 
    top_level=1) at /home/hp/egcs/cvs_dammit/egcs/gcc/varasm.c:717
#2  0x804b275 in rest_of_decl_compilation (decl=0x81c876c, 
    asmspec=0x81c8764 "$15", top_level=1, at_end=0)
    at /home/hp/egcs/cvs_dammit/egcs/gcc/toplev.c:3444
#1  0x808ed5c in make_decl_rtl (decl=0x81c876c, asmspec=0x81c8764 "$15", 
    top_level=1) at /home/hp/egcs/cvs_dammit/egcs/gcc/varasm.c:717

And now it dawned on me that this use of the frame pointer
register was actually abuse; it was not intended to be used like
this, and nobody had checked before.

I thought there was little doubt that the frame pointer was
*not* supposed to be used like this, since there was (as
mentioned) a similar check in regclass.c:fix_register, which is
called for the -ffixed-N, -fcall-used-N and -fcall-saved-N
switches.

So therefore I propose the patch in
<URL: http://egcs.cygnus.com/ml/egcs-patches/1999-04/msg00124.html >
(this looks like a better place than putting the check in globalize_reg).

On the other hand, Mr. Fergus Henderson has made a point that
this use of the frame pointer register was supposed to work at
some time.
 On the one hand again, I don't think the frame pointer register
can be guaranteed to be eliminated in every object and library
in the program.  That just makes some really hard bugs to find.
So it should not be allowed; normally there are other general
registers to use.

> However, I can't replicate this failure with egcs-1.1.2 or current cvs.
> I am testing from alpha-linux, but that shouldn't matter.  Can you
> replicate this moving up to the current release?

I updated "Fri Apr  9 01:01:43 GMT+1" and got the same error.
 Since the error manifests itself because of an uninitialized
variable, it "depends" if you see it as an ICE.  It certainly
*can* manifest itself on any alpha(-linux) platform; I crossed
from host=i686-pc-linux-gnulibc1 to
target=alphaev6-unknown-linux-gnu.  It probably helps if you
initialize fp_offset in alpha_expand_epilogue to some invalid offset as
proposed above, for example to 0x80000000.

brgds, H-P



More information about the Gcc-bugs mailing list