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]

fix rtl/23560


Yet another rtl strength reduction bug.

This time, ivopts transforms the loop and creates an unsigned counter
that runs from -7u to +7u.  Odd, but certainly legal.  In the middle,
there's a conditional that's transformed from (i == 8 || i == 9) to
(ivtmp <= 1).  Also fine.

Well, rtl-loop comes along and tries to eliminate the ivtmp biv with
a giv that's a pointer value.  Except after the transformation to the
giv, the LEU comparison is incorrect.

Solved by not allowing this transformation unless the biv can be shown
to not wrap.

I've not investigated how often this suppresses the transformation, or
how often the transformation still applies.  I'm not terribly
interrested either.  All this code is hopelessly broken, and not fixable
at the rtl level.  Fortunately, we're near being about to delete it all.
In the meantime, this patch only suppresses transformations, so it 
should therefore be safe.

I've also deleted a whole bunch of code that was already if 0'ed out.

Tested on i686-linux.



r~


	* loop.c (biased_biv_may_wrap_p): New.
	(maybe_eliminate_biv_1): Use it to suppress non-equality
	comparison transformations.  Delete disabled code.

Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.522.8.2
diff -u -p -d -c -r1.522.8.2 loop.c
*** loop.c	14 Apr 2005 06:14:28 -0000	1.522.8.2
--- loop.c	26 Aug 2005 05:26:36 -0000
*************** biv_fits_mode_p (const struct loop *loop
*** 8766,8771 ****
--- 8766,8828 ----
  }
  
  
+ /* Return false iff it is provable that biv BL plus BIAS will not wrap
+    at any point in its update sequence.  Note that at the rtl level we
+    may not have information about the signedness of BL; in that case,
+    check for both signed and unsigned overflow.  */
+ 
+ static bool
+ biased_biv_may_wrap_p (const struct loop *loop, struct iv_class *bl,
+ 		       unsigned HOST_WIDE_INT bias)
+ {
+   HOST_WIDE_INT incr;
+   bool check_signed, check_unsigned;
+   enum machine_mode mode;
+ 
+   /* If the increment is not monotonic, we'd have to check separately
+      at each increment step.  Not Worth It.  */
+   incr = get_monotonic_increment (bl);
+   if (incr == 0)
+     return true;
+ 
+   /* If this biv is the loop iteration variable, then we may be able to
+      deduce a sign based on the loop condition.  */
+   /* ??? This is not 100% reliable; consider an unsigned biv that is cast
+      to signed for the comparison.  However, this same bug appears all
+      through loop.c.  */
+   check_signed = check_unsigned = true;
+   if (bl->biv->src_reg == LOOP_INFO (loop)->iteration_var)
+     {
+       switch (LOOP_INFO (loop)->comparison_code)
+ 	{
+ 	case GTU: case GEU: case LTU: case LEU:
+ 	  check_signed = false;
+ 	  break;
+ 	case GT: case GE: case LT: case LE:
+ 	  check_unsigned = false;
+ 	  break;
+ 	default:
+ 	  break;
+ 	}
+     }
+ 
+   mode = GET_MODE (bl->biv->src_reg);
+ 
+   if (check_unsigned
+       && !biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
+     return true;
+ 
+   if (check_signed)
+     {
+       bias += (GET_MODE_MASK (mode) >> 1) + 1;
+       if (!biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
+ 	return true;
+     }
+ 
+   return false;
+ }
+ 
+ 
  /* Given that X is an extension or truncation of BL, return true
     if it is unaffected by overflow.  LOOP is the loop to which
     BL belongs and INCR is its per-iteration increment.  */
*************** maybe_eliminate_biv_1 (const struct loop
*** 10176,10370 ****
        else
  	break;
  
!       if (CONSTANT_P (arg))
! 	{
! 	  /* First try to replace with any giv that has constant positive
! 	     mult_val and constant add_val.  We might be able to support
! 	     negative mult_val, but it seems complex to do it in general.  */
! 
! 	  for (v = bl->giv; v; v = v->next_iv)
! 	    if (GET_CODE (v->mult_val) == CONST_INT
! 		&& INTVAL (v->mult_val) > 0
! 		&& (GET_CODE (v->add_val) == SYMBOL_REF
! 		    || GET_CODE (v->add_val) == LABEL_REF
! 		    || GET_CODE (v->add_val) == CONST
! 		    || (REG_P (v->add_val)
! 			&& REG_POINTER (v->add_val)))
! 		&& ! v->ignore && ! v->maybe_dead && v->always_computable
! 		&& v->mode == mode)
! 	      {
! 		if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
! 		  continue;
! 
! 		/* Don't eliminate if the linear combination that makes up
! 		   the giv overflows when it is applied to ARG.  */
! 		if (GET_CODE (arg) == CONST_INT)
! 		  {
! 		    rtx add_val;
! 
! 		    if (GET_CODE (v->add_val) == CONST_INT)
! 		      add_val = v->add_val;
! 		    else
! 		      add_val = const0_rtx;
! 
! 		    if (const_mult_add_overflow_p (arg, v->mult_val,
! 						   add_val, mode, 1))
! 		      continue;
! 		  }
! 
! 		if (! eliminate_p)
! 		  return 1;
! 
! 		/* Replace biv with the giv's reduced reg.  */
! 		validate_change (insn, &XEXP (x, 1 - arg_operand), v->new_reg, 1);
! 
! 		/* If all constants are actually constant integers and
! 		   the derived constant can be directly placed in the COMPARE,
! 		   do so.  */
! 		if (GET_CODE (arg) == CONST_INT
! 		    && GET_CODE (v->add_val) == CONST_INT)
! 		  {
! 		    tem = expand_mult_add (arg, NULL_RTX, v->mult_val,
! 					   v->add_val, mode, 1);
! 		  }
! 		else
! 		  {
! 		    /* Otherwise, load it into a register.  */
! 		    tem = gen_reg_rtx (mode);
! 		    loop_iv_add_mult_emit_before (loop, arg,
! 						  v->mult_val, v->add_val,
! 						  tem, where_bb, where_insn);
! 		  }
! 
! 		validate_change (insn, &XEXP (x, arg_operand), tem, 1);
! 
! 		if (apply_change_group ())
! 		  return 1;
! 	      }
! 
! 	  /* Look for giv with positive constant mult_val and nonconst add_val.
! 	     Insert insns to calculate new compare value.
! 	     ??? Turn this off due to possible overflow.  */
! 
! 	  for (v = bl->giv; v; v = v->next_iv)
! 	    if (GET_CODE (v->mult_val) == CONST_INT
! 		&& INTVAL (v->mult_val) > 0
! 		&& ! v->ignore && ! v->maybe_dead && v->always_computable
! 		&& v->mode == mode
! 		&& 0)
! 	      {
! 		rtx tem;
! 
! 		if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
! 		  continue;
! 
! 		if (! eliminate_p)
! 		  return 1;
! 
! 		tem = gen_reg_rtx (mode);
! 
! 		/* Replace biv with giv's reduced register.  */
! 		validate_change (insn, &XEXP (x, 1 - arg_operand),
! 				 v->new_reg, 1);
! 
! 		/* Compute value to compare against.  */
! 		loop_iv_add_mult_emit_before (loop, arg,
! 					      v->mult_val, v->add_val,
! 					      tem, where_bb, where_insn);
! 		/* Use it in this insn.  */
! 		validate_change (insn, &XEXP (x, arg_operand), tem, 1);
! 		if (apply_change_group ())
! 		  return 1;
! 	      }
! 	}
!       else if (REG_P (arg) || MEM_P (arg))
! 	{
! 	  if (loop_invariant_p (loop, arg) == 1)
! 	    {
! 	      /* Look for giv with constant positive mult_val and nonconst
! 		 add_val. Insert insns to compute new compare value.
! 		 ??? Turn this off due to possible overflow.  */
! 
! 	      for (v = bl->giv; v; v = v->next_iv)
! 		if (GET_CODE (v->mult_val) == CONST_INT && INTVAL (v->mult_val) > 0
! 		    && ! v->ignore && ! v->maybe_dead && v->always_computable
! 		    && v->mode == mode
! 		    && 0)
! 		  {
! 		    rtx tem;
! 
! 		    if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
! 		      continue;
! 
! 		    if (! eliminate_p)
! 		      return 1;
! 
! 		    tem = gen_reg_rtx (mode);
! 
! 		    /* Replace biv with giv's reduced register.  */
! 		    validate_change (insn, &XEXP (x, 1 - arg_operand),
! 				     v->new_reg, 1);
! 
! 		    /* Compute value to compare against.  */
! 		    loop_iv_add_mult_emit_before (loop, arg,
! 						  v->mult_val, v->add_val,
! 						  tem, where_bb, where_insn);
! 		    validate_change (insn, &XEXP (x, arg_operand), tem, 1);
! 		    if (apply_change_group ())
! 		      return 1;
! 		  }
! 	    }
! 
! 	  /* This code has problems.  Basically, you can't know when
! 	     seeing if we will eliminate BL, whether a particular giv
! 	     of ARG will be reduced.  If it isn't going to be reduced,
! 	     we can't eliminate BL.  We can try forcing it to be reduced,
! 	     but that can generate poor code.
  
! 	     The problem is that the benefit of reducing TV, below should
! 	     be increased if BL can actually be eliminated, but this means
! 	     we might have to do a topological sort of the order in which
! 	     we try to process biv.  It doesn't seem worthwhile to do
! 	     this sort of thing now.  */
  
! #if 0
! 	  /* Otherwise the reg compared with had better be a biv.  */
! 	  if (!REG_P (arg)
! 	      || REG_IV_TYPE (ivs, REGNO (arg)) != BASIC_INDUCT)
! 	    return 0;
  
! 	  /* Look for a pair of givs, one for each biv,
! 	     with identical coefficients.  */
! 	  for (v = bl->giv; v; v = v->next_iv)
! 	    {
! 	      struct induction *tv;
  
! 	      if (v->ignore || v->maybe_dead || v->mode != mode)
! 		continue;
  
! 	      for (tv = REG_IV_CLASS (ivs, REGNO (arg))->giv; tv;
! 		   tv = tv->next_iv)
! 		if (! tv->ignore && ! tv->maybe_dead
! 		    && rtx_equal_p (tv->mult_val, v->mult_val)
! 		    && rtx_equal_p (tv->add_val, v->add_val)
! 		    && tv->mode == mode)
! 		  {
! 		    if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
! 		      continue;
  
! 		    if (! eliminate_p)
! 		      return 1;
  
! 		    /* Replace biv with its giv's reduced reg.  */
! 		    XEXP (x, 1 - arg_operand) = v->new_reg;
! 		    /* Replace other operand with the other giv's
! 		       reduced reg.  */
! 		    XEXP (x, arg_operand) = tv->new_reg;
! 		    return 1;
! 		  }
! 	    }
! #endif
! 	}
  
        /* If we get here, the biv can't be eliminated.  */
        return 0;
--- 10233,10288 ----
        else
  	break;
  
!       if (GET_CODE (arg) != CONST_INT)
! 	return 0;
  
!       /* Unless we're dealing with an equality comparison, if we can't
! 	 determine that the original biv doesn't wrap, then we must not
! 	 apply the transformation.  */
!       /* ??? Actually, what we must do is verify that the transformed
! 	 giv doesn't wrap.  But the general case of this transformation
! 	 was disabled long ago due to wrapping problems, and there's no
! 	 point reviving it this close to end-of-life for loop.c.  The
! 	 only case still enabled is known (via the check on add_val) to
! 	 be pointer arithmetic, which in theory never overflows for
! 	 valid programs.  */
!       /* Without lifetime analysis, we don't know how COMPARE will be
! 	 used, so we must assume the worst.  */
!       if (code != EQ && code != NE
! 	  && biased_biv_may_wrap_p (loop, bl, INTVAL (arg)))
! 	return 0;
  
!       /* Try to replace with any giv that has constant positive mult_val
!          and a pointer add_val.  */
!       for (v = bl->giv; v; v = v->next_iv)
! 	if (GET_CODE (v->mult_val) == CONST_INT
! 	    && INTVAL (v->mult_val) > 0
! 	    && (GET_CODE (v->add_val) == SYMBOL_REF
! 		|| GET_CODE (v->add_val) == LABEL_REF
! 		|| GET_CODE (v->add_val) == CONST
! 		|| (REG_P (v->add_val) && REG_POINTER (v->add_val)))
! 	    && ! v->ignore && ! v->maybe_dead && v->always_computable
! 	    && v->mode == mode)
! 	  {
! 	    if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn))
! 	      continue;
  
! 	    if (! eliminate_p)
! 	      return 1;
  
! 	    /* Replace biv with the giv's reduced reg.  */
! 	    validate_change (insn, &XEXP (x, 1 - arg_operand), v->new_reg, 1);
  
! 	    /* Load the value into a register.  */
! 	    tem = gen_reg_rtx (mode);
! 	    loop_iv_add_mult_emit_before (loop, arg, v->mult_val, v->add_val,
! 					  tem, where_bb, where_insn);
  
! 	    validate_change (insn, &XEXP (x, arg_operand), tem, 1);
  
! 	    if (apply_change_group ())
! 	      return 1;
! 	  }
  
        /* If we get here, the biv can't be eliminated.  */
        return 0;


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