[gnu.g++.bug] inline function result store causes 'bus error'

andrew@frip.WV.TEK.COM (Andrew Klossner) (09/09/89)

At the end of this note is a program which was whittled down from
libg++/src/BitStream.cc.  It illustrates a problem which causes G++ to
generate a fullword store to an address that is not fullword aligned.
GCC does not share this problem.  This is from GCC 1.35 and G++ 1.35.1-,
with m88k back-end work from Michael Meissner (meissner@dg-rtp.DG.COM).

qq() is an inline function which returns an unsigned short.
e is a local variable, declared unsigned short.
The statement

	unsigned short e = qq(p, b, 0, 0);

compiles to code which, on the 88k, ends with

	st	 r24,r30,0x2a  {write r24 to offset 0x2a from the FP}

which is improper because 0x2a is not a multiple of 4.
I have observed similar bad code from a 68k G++ compiler.

While expanding the inline function, integrate.c does this:

      /* If function's value was promoted before return,
	 avoid machine mode mismatch when we substitute INLINE_TARGET.
	 But TARGET is what we will return to the caller.  */
      if (arriving_mode != departing_mode)
	inline_target = gen_rtx (SUBREG, arriving_mode, target, 0);

and so builds this insn:

	(insn/i 37 36 38 (set (subreg:SI (reg/v:HI 37) 0)
	       (reg:SI 56)) -1 (nil)
	   (nil))

then, while spilling registers, reload changes it to

(insn 217 221 41 (set (subreg:SI (mem:HI (plus:SI (reg:SI 30)
                   (const_int 44))) 0)
       (reg:SI 24)) -1 (nil)
   (nil))

Then final calls alter_subreg to replace the (subreg ...) with

	(mem:SI (plus:SI (reg:SI 30)
	        (const_int 42)))

My gut feel is that the (set (subreg ...)) shouldn't have been built in
the first place, but I'm not fluent in GCC/G++ internals.  I would be
grateful for any suggestions.

============================== the program ==============================
static inline unsigned short pp(int a)
{
	return a;
}

static inline unsigned short qq(unsigned short a[], int b, int c, int d)
{
	if (b < c)
		return (a[b] >> 1) |
		       (a[b+1] << (16 - d));
	else
		return (a[b] >> d);
}

int search(unsigned short* p)
{
	int a;
	int b;
	int c;
	int d;
	int x;
	unsigned short e = qq(p, b, 0, 0);
	unsigned short g;
	unsigned short h;

	for (;;)
	{
		if (a == e)
		{
			int f = b;
			for (;;)
			{
				if (++f > d || ++d > c)
					return 0;
				g = qq(0, 0, c, c);
				h = qq(p, 0, a, a);
				x += h;
				g &= pp(2 - a);
				if (g != h)
					break;
			}
		}
	}
}
========================================================================

  -=- Andrew Klossner   (uunet!tektronix!frip.WV.TEK!andrew)    [UUCP]
                        (andrew%frip.wv.tek.com@relay.cs.net)   [ARPA]