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]

[4.1] Fix PR rtl-optimization/29631


It's a regression present on the 4.1 branch for the Alpha architecture, 
another fallout of the fix for PR middle-end/25125.  For the simple loop

void f(short delta)
{
    short p0 = 2, s;
    for (s = 0; s < 2; s++)
    {
        p0 += delta;
        ff(s);
        if (nunmap[p0] == 17)

the middle-end+tree-opt now generate the convoluted

f (delta)
{
  long unsigned int ivtmp.59;
  short unsigned int pretmp.53;
  short int p0;

<bb 0>:
  pretmp.53 = (short unsigned int) delta;
  p0 = 2;
  ivtmp.59 = 0;

<L0>:;
  p0 = (short int) (pretmp.53 + (short unsigned int) p0);
  ff ((int) (unsigned int) ivtmp.59);
  if (nunmap[(int) p0] == 17) goto <L1>; else goto <L2>;

and the overly clever game on the sign of things fools the old loop optimizer 
into thinking that (the promoted RTL variable associated with) p0 is a BIV 
with (the promoted RTL variable associated with) pretmp.53 as increment.  Now 
pretmp.53 is unsigned so the promotion is done using zero-extension, while 
the correct increment is the sign-extension of pretmp.53.

I presume that reverting the fix for PR middle-end/25125 is still not an 
option, so the old loop optimizer should cope with this new RTL dialect, or 
at least not break on it.  Hence this patch that makes basic_induction_var 
more stringent when it detects a candidate for promoted BIV.

Of course the risk is to pessimize, especially on the Alpha, but I ran the 
unpatched and patched compilers at -O2 on the 200+ .i files of the gcc/ 
directory and found 0 difference on x86-64 and 1 difference on Alpha...
in the big loop of strength_reduce in loop.c :-)  Good enough I'd say.

Bootstrapped/regtested with --enable-checking=release,rtl,rtlflag on 
alpha-dec-osf5.1 and x86_64-linux-gnu, applied to 4.1 branch.


2006-10-31  Eric Botcazou  <ebotcazou@libertysurf.fr>

	PR rtl-optimization/29631
	* loop.c (basic_induction_var): Add new parameter inner_mode.
	<PLUS>: If set, convert the increment to it before sign-extending.
	<CONST_INT>: Likewise.
	<SUBREG>: Set it.
	<ASHIFTRT>: Likewise.  Return 0 if flag_wrapv.


2006-10-31  Eric Botcazou  <ebotcazou@libertysurf.fr>

	* gcc.c-torture/execute/20061031-1.c: New test.


-- 
Eric Botcazou
Index: loop.c
===================================================================
--- loop.c	(revision 117884)
+++ loop.c	(working copy)
@@ -664,7 +664,8 @@ static bool extension_within_bounds_p (c
 				       HOST_WIDE_INT, rtx);
 static void check_ext_dependent_givs (const struct loop *, struct iv_class *);
 static int basic_induction_var (const struct loop *, rtx, enum machine_mode,
-				rtx, rtx, rtx *, rtx *, rtx **);
+				rtx, rtx, rtx *, rtx *, rtx **,
+				enum machine_mode);
 static rtx simplify_giv_expr (const struct loop *, rtx, rtx *, int *);
 static int general_induction_var (const struct loop *loop, rtx, rtx *, rtx *,
 				  rtx *, rtx *, int, int *, enum machine_mode);
@@ -6644,7 +6645,7 @@ check_insn_for_bivs (struct loop *loop, 
 	  if (basic_induction_var (loop, SET_SRC (set),
 				   GET_MODE (SET_SRC (set)),
 				   dest_reg, p, &inc_val, &mult_val,
-				   &location))
+				   &location, VOIDmode))
 	    {
 	      /* It is a possible basic induction variable.
 	         Create and initialize an induction structure for it.  */
@@ -7552,11 +7553,12 @@ update_giv_derive (const struct loop *lo
    If X is an assignment of an invariant into DEST_REG, we set
    *MULT_VAL to CONST0_RTX, and store the invariant into *INC_VAL.
 
-   We also want to detect a BIV when it corresponds to a variable
-   whose mode was promoted.  In that case, an increment
-   of the variable may be a PLUS that adds a SUBREG of that variable to
-   an invariant and then sign- or zero-extends the result of the PLUS
-   into the variable.
+   We also want to detect a BIV when it corresponds to a variable whose
+   mode was promoted.  In that case, an increment of the variable may be
+   a PLUS that adds a SUBREG of that variable to an invariant and then
+   sign- or zero-extends the result of the PLUS into the variable.  Or
+   it may be a PLUS that adds the variable to an invariant, takes SUBREG
+   of the result and then sign- or zero-extends it into the variable.
 
    Most GIVs in such cases will be in the promoted mode, since that is the
    probably the natural computation mode (and almost certainly the mode
@@ -7571,16 +7573,19 @@ update_giv_derive (const struct loop *lo
    those overflows are defined.  So we only check for SIGN_EXTEND and
    not ZERO_EXTEND.
 
+   If we happen to detect such a promoted BIV, we set inner_mode to the
+   mode in which the BIV is incremented.
+
    If we cannot find a biv, we return 0.  */
 
 static int
 basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
 		     rtx dest_reg, rtx p, rtx *inc_val, rtx *mult_val,
-		     rtx **location)
+		     rtx **location, enum machine_mode inner_mode)
 {
   enum rtx_code code;
   rtx *argp, arg;
-  rtx insn, set = 0, last, inc;
+  rtx insn, last, inc;
 
   code = GET_CODE (x);
   *location = NULL;
@@ -7620,7 +7625,13 @@ basic_induction_var (const struct loop *
 	 *inc_val initialization sequence generated here and when *inc_val
 	 is going to be actually used, emit it at some suitable place.  */
       last = get_last_insn ();
-      inc = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+      if (inner_mode != VOIDmode)
+	{
+	  arg = convert_modes (inner_mode, GET_MODE (x), arg, 0);
+	  inc = convert_modes (GET_MODE (dest_reg), inner_mode, arg, 0);
+	}
+      else
+	inc = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
       if (get_last_insn () != last)
 	{
 	  delete_insns_since (last);
@@ -7634,12 +7645,11 @@ basic_induction_var (const struct loop *
 
     case SUBREG:
       /* If what's inside the SUBREG is a BIV, then the SUBREG.  This will
-	 handle addition of promoted variables.
-	 ??? The comment at the start of this function is wrong: promoted
-	 variable increments don't look like it says they do.  */
+	 handle addition of promoted variables.  */
       return basic_induction_var (loop, SUBREG_REG (x),
 				  GET_MODE (SUBREG_REG (x)),
-				  dest_reg, p, inc_val, mult_val, location);
+				  dest_reg, p, inc_val, mult_val,
+				  location, GET_MODE (x));
 
     case REG:
       /* If this register is assigned in a previous insn, look at its
@@ -7653,7 +7663,7 @@ basic_induction_var (const struct loop *
       insn = p;
       while (1)
 	{
-	  rtx dest;
+	  rtx set, dest;
 	  do
 	    {
 	      insn = PREV_INSN (insn);
@@ -7677,7 +7687,8 @@ basic_induction_var (const struct loop *
 					 ? GET_MODE (x)
 					 : GET_MODE (SET_SRC (set))),
 					dest_reg, insn,
-					inc_val, mult_val, location);
+					inc_val, mult_val,
+					location, inner_mode);
 
 	  while (GET_CODE (dest) == SUBREG
 		 || GET_CODE (dest) == ZERO_EXTRACT
@@ -7708,7 +7719,13 @@ basic_induction_var (const struct loop *
 	{
 	  /* Possible bug here?  Perhaps we don't know the mode of X.  */
 	  last = get_last_insn ();
-	  inc = convert_modes (GET_MODE (dest_reg), mode, x, 0);
+	  if (inner_mode != VOIDmode)
+	    {
+	      x = convert_modes (inner_mode, mode, x, 0);
+	      inc = convert_modes (GET_MODE (dest_reg), inner_mode, x, 0);
+	    }
+	  else
+	    inc = convert_modes (GET_MODE (dest_reg), mode, x, 0);
 	  if (get_last_insn () != last)
 	    {
 	      delete_insns_since (last);
@@ -7727,10 +7744,16 @@ basic_induction_var (const struct loop *
       if (flag_wrapv)
 	return 0;
       return basic_induction_var (loop, XEXP (x, 0), GET_MODE (XEXP (x, 0)),
-				  dest_reg, p, inc_val, mult_val, location);
+				  dest_reg, p, inc_val, mult_val,
+				  location, inner_mode);
 
     case ASHIFTRT:
       /* Similar, since this can be a sign extension.  */
+      if (flag_wrapv)
+	return 0;
+      if (rtx_equal_p (dest_reg, XEXP (x, 0)))
+	return 0;
+
       for (insn = PREV_INSN (p);
 	   (insn && NOTE_P (insn)
 	    && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG);
@@ -7738,18 +7761,29 @@ basic_induction_var (const struct loop *
 	;
 
       if (insn)
-	set = single_set (insn);
+	{
+	  rtx op0 = XEXP (x, 0), op1 = XEXP (x, 1);
+	  rtx set = single_set (insn);
+	  enum machine_mode inner_mode;
+
+	  /* We're looking for sign-extension by double shift.  */
+	  if (!(set
+		&& SET_DEST (set) == op0
+		&& GET_CODE (SET_SRC (set)) == ASHIFT
+		&& GET_CODE (op1) == CONST_INT
+		&& INTVAL (op1) >= 0
+		&& XEXP (SET_SRC (set), 1) == op1))
+	    return 0;
 
-      if (! rtx_equal_p (dest_reg, XEXP (x, 0))
-	  && set && SET_DEST (set) == XEXP (x, 0)
-	  && GET_CODE (XEXP (x, 1)) == CONST_INT
-	  && INTVAL (XEXP (x, 1)) >= 0
-	  && GET_CODE (SET_SRC (set)) == ASHIFT
-	  && XEXP (x, 1) == XEXP (SET_SRC (set), 1))
-	return basic_induction_var (loop, XEXP (SET_SRC (set), 0),
-				    GET_MODE (XEXP (x, 0)),
-				    dest_reg, insn, inc_val, mult_val,
-				    location);
+	  mode = GET_MODE (op0);
+	  inner_mode = mode_for_size (GET_MODE_BITSIZE (mode) - INTVAL (op1),
+				      MODE_INT, 1);
+	  if (inner_mode != BLKmode)
+	    return basic_induction_var (loop, XEXP (SET_SRC (set), 0),
+					mode, dest_reg, insn,
+					inc_val, mult_val,
+					location, inner_mode);
+	}
       return 0;
 
     default:
/* PR rtl-optimization/29631 */
/* Origin: Falk Hueffner <falk@debian.org> */

const signed char nunmap[] = { 17, -1, 1 };

__attribute__((noinline))
void ff(int i) {
    asm volatile("");
}

__attribute__((noinline))
void f(short delta)
{
    short p0 = 2, s;
    for (s = 0; s < 2; s++)
    {
        p0 += delta;
        ff(s);
        if (nunmap[p0] == 17)
            asm volatile("# nop");
    }
}

int main(void)
{
    f(-1);
    return 0;
}

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