This is the mail archive of the gcc-patches@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]

[PATCH] PR optimization/11700: ICE during reload


This patch should fix PR optimization/11700 which is an ICE on legal
during reload on m68k targets.  As identified by Janis, this latent
bug was exposed by my changes to improve handling of complex parts
during RTL generation.

The series of events goes like this.  Reload calls find_equiv_reg
is looking for a suitable source for the instruction:

(insn 20 19 21 0 (set (mem:SI (pre_dec:SI (reg/f:SI 15 %sp)) [0 S4 A8])
        (const_int 0 [0x0])) 23 {pushexthisi_const} (nil)
    (nil))

In looking for a (const_int 0), it comes across the earlier pattern:

(set (reg/v:DF 16 %fp0 [orig:29 __retval ] [29])
    (const_double:DF 0 [0x0] 0.0 [0x0.0p+0]))

And the logic in find_equiv_reg realizes that both the lowpart and the
highpart subregs of this const_double contain the zero value its looking
for.  The relevant code is at line 6439 of reload.c.  Given that the
"operand_subword" of the SET_SRC contains the relevant constant, reload
then tries calling "operand_subword" on the SET_DEST to retrieve the
register it would need for its substitution.

Unfortunately, "(reg/v:DG 16 %fp0)" is a hard reg and requesting mode
changing subregs of them is not always valid, unless requesting the
lowpart.  operand_subword -> simplify_gen_subreg -> simplify_subreg.

I believe the bug is that simplify_subreg, which is supposed to be
a speculative "fail-soft" routine that should return zero if no
simplification is possible, ends up calling subreg_hard_regno to
simplify "(SUBREG:SI (reg/v:DF 16 %fp0) 0)" which is a "fail-hard"
routine that calls abort if the subreg isn't representable as a hard
register.  The issue is that m68k is a big-endian target so the lowpart
of "reg:DF %fp0" has offset 4.  The subreg above is requesting the
highpart of a hard register for which subreg_offset_representable_p
returns false.

The fix below is to check that the subreg offset is representable in
simplify_subreg before trying to simplify the expression directly to
a hard register.  This indeed fixes this failure in a m68k-linux-gnu
cross-compiler's cc1 hosted from i686-pc-linux-gnu.

[It might be that subreg_offset_representable_p is also incorrect
in this particular case (storing negative values in an unsigned int
looks very suspicious), but even so simplify_subreg has no business
calling a routine that can call abort without validating the arguments
its passing first.]

The following patch has also been tested on i686-pc-linux-gnu with a
complete "make bootstrap", all languages except treelang, and regression
tested with a top-level "make -k check" with no new failures.


Ok for mainline?


2003-08-30  Roger Sayle  <roger@eyesopen.com>

	PR optimization/11700.
	* simplify-rtx.c (simplify_subreg): Check that the subreg offset
	of a hard register is representable before trying to simplify it
	using subreg_hard_regno.

	* gcc.c-torture/compile/20030830-1.c: New test case.

Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.156
diff -c -3 -p -r1.156 simplify-rtx.c
*** simplify-rtx.c	26 Aug 2003 13:22:14 -0000	1.156
--- simplify-rtx.c	30 Aug 2003 15:03:23 -0000
*************** simplify_subreg (enum machine_mode outer
*** 3017,3026 ****
  #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
        && REGNO (op) != ARG_POINTER_REGNUM
  #endif
!       && REGNO (op) != STACK_POINTER_REGNUM)
      {
!       int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte),
! 					   0);

        /* ??? We do allow it if the current REG is not valid for
  	 its mode.  This is a kludge to work around how float/complex
--- 3017,3028 ----
  #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
        && REGNO (op) != ARG_POINTER_REGNUM
  #endif
!       && REGNO (op) != STACK_POINTER_REGNUM
!       && subreg_offset_representable_p (REGNO (op), innermode,
! 					byte, outermode))
      {
!       rtx tem = gen_rtx_SUBREG (outermode, op, byte);
!       int final_regno = subreg_hard_regno (tem, 0);

        /* ??? We do allow it if the current REG is not valid for
  	 its mode.  This is a kludge to work around how float/complex


/* Derived from PR optimization/11700.  */
/* The compiler used to ICE during reload for m68k targets.  */

void check_complex (__complex__ double, __complex__ double,
                    __complex__ double, __complex__ int);
void check_float (double, double, double, int);
extern double _Complex conj (double _Complex);
extern double carg (double _Complex __z);

static double minus_zero;

void
conj_test (void)
{
  check_complex (conj (({ __complex__ double __retval;
			  __real__ __retval = (0.0);
			  __imag__ __retval = (0.0);
			  __retval; })),
		 ({ __complex__ double __retval;
		    __real__ __retval = (0.0);
		    __imag__ __retval = (minus_zero);
		    __retval; }), 0, 0);
}

void
carg_test (void)
{
  check_float (carg (({ __complex__ double __retval;
			__real__ __retval = (2.0);
			__imag__ __retval = (0);
			__retval; })), 0, 0, 0);
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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