gcc 2.95.2: bug in expand_builtin_dwarf_reg_size?

Chris Torek torek@elf.bsdi.com
Wed Jan 12 14:12:00 GMT 2000

(as configured for BSD/OS on sparc - a private config file)

That this turned up at all is due to a configuration error on my
part, as I let the DBX_REGISTER_NUMBER macro default to the value
from <sparc/sysv4.h>:


The problem turns up when compiling libgcc2's stack-unwinding code,
which includes this line:

  memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));

(inside copy_reg, around line 3649 of libgcc2.c).

This in turn invokes expand_builtin_dwarf_reg_size in dwarf2out.c,
which diligently (and repeatedly -- maybe the ranges array should
be static?) makes lists of the various register sizes.

Since I am using 32-bit mode under the bi-architectural (sparc v8
and v9 both) compiler, the initial loop:

  for (; i < FIRST_PSEUDO_REGISTER; ++i)

finds every register to be four bytes, so that we have n_ranges==1,
and ranges[0] is:

	(gdb) p/d ranges[0]
	$30 = {
	  beg = 0, 
	  end = 100, 
	  size = 4

This fails the "usual case" test (n_ranges != 3) and falls into
the "else" code, which reads, in part:

	int beg = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
	int end = DWARF_FRAME_REGNUM (ranges[n_ranges].end);

magic 8 above; this means that beg==0 but end==108:

	(gdb) p beg
	$32 = 0x0
	(gdb) p/d end
	$33 = 108

This gets us to line 656:

	if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg)
	  abort ();

which naturally aborts.

It seems to me as though the "ranges" array should probably be
populated with DWARF_FRAME_REGNUMs.  After all, those are the values
we are trying to look up at runtime, as it were.  But if there is
some sort of arbitrary mapping, the simple scheme in this function
is not going to work anyway -- the mapped table will not be in any
sort of sensible order.  (For instance, if "hard register 17" maps
to "dwarf register 31" and "hard register 18" maps to "dwarf register
12" and "hard 19" maps to "dwarf 331", things get messy quickly.)

The problem will go away if I just switch the register numbering
to that used in SunOS/Linux, eliminating the mystery "8" offset.
(Why *are* these different?)  In any case, though, I am not sure
why "3 ranges" is considered "*the* usual case", when "1 range"
seems likely to be another "usual case".  If n_ranges==1, the
routine could simply build a constant, e.g.:

Index: dwarf2out.c
RCS file: /master/usr.bin/egcs/D/gcc/dwarf2out.c,v
retrieving revision
diff -c -2 -r1.1.1.2 dwarf2out.c
*** dwarf2out.c	1999/12/09 18:05:51
--- dwarf2out.c	2000/01/12 21:09:38
*** 622,627 ****
    /* The usual case: fp regs surrounded by general regs.  */
!   if (n_ranges == 3 && ranges[0].size == ranges[2].size)
        if ((DWARF_FRAME_REGNUM (ranges[1].end)
--- 622,630 ----
+   /* An easy case: everything has just one size.  */
+   if (n_ranges == 1)
+     t = build_int_2 (ranges[0].size, 0);
    /* The usual case: fp regs surrounded by general regs.  */
!   else if (n_ranges == 3 && ranges[0].size == ranges[2].size)
        if ((DWARF_FRAME_REGNUM (ranges[1].end)

This does not actually help any, as the do/while loop builds an
expression that amounts to:

	reg <= 100 ? 4 : 4

which promptly collapses into a plain "4".  So there is no point
in testing for n_ranges==1 (other than, perhaps, slightly faster
compilation, not that people should be using this function much),
but the comment ("the" usual case) seems misleading.

(Perhaps the special "3 ranges" code here should go away as well,
and the optimizer should find expressions like:

	(e1 <= 80 ? (e1 <= 40 ? e2 : e3) : e2)

[with side-effect-free integral "e1"] and turn them into:

	(e1 >= 41 && e <= 80 ? e3 : e2)

since that does improve the output code, especially under
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA, USA	Domain:	torek@bsdi.com	+1 510 234 3167
http://claw.bsdi.com/torek/  (not always up)	I report spam to abuse@.

More information about the Gcc-bugs mailing list