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]

[3.4 PATCH] Fix bitfield-- != 0 transformation in fold-const.c


Hi Mark,

The following patch is a backport of my recent mainline patch to
fix the "bitfield-- != 0" -> "--bitfield != 1" optimization in fold.
http://gcc.gnu.org/ml/gcc-patches/2004-03/msg00582.html

This is a wrong-code regression from gcc 3.3 that has been latent
for a while, but has been exposed by an unrelated change prior to
branching for 3.4.

The following patch has been tested against the gcc-3_4-branch on
i686-pc-linux-gnu with a full bootstrap and regression tested with
no new failures.  The only change relative to the mainline version
is the use of "build" rather than "build2" (which is only on mainline).

Ok for the gcc-3_4-branch?


2004-03-08  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (fold) <EQ_EXPR>: Rewrite optimization to transform
	"foo++ == const" into "++foo == const+incr".

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


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.322.2.6
diff -c -3 -p -r1.322.2.6 fold-const.c
*** fold-const.c	27 Feb 2004 08:14:59 -0000	1.322.2.6
--- fold-const.c	7 Mar 2004 19:05:59 -0000
*************** fold (tree expr)
*** 7218,7367 ****
  	    }
  	}

!       /* Convert foo++ == CONST into ++foo == CONST + INCR.
! 	 First, see if one arg is constant; find the constant arg
! 	 and the other one.  */
!       {
! 	tree constop = 0, varop = NULL_TREE;
! 	int constopnum = -1;
!
! 	if (TREE_CONSTANT (arg1))
! 	  constopnum = 1, constop = arg1, varop = arg0;
! 	if (TREE_CONSTANT (arg0))
! 	  constopnum = 0, constop = arg0, varop = arg1;
!
! 	if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR)
! 	  {
! 	    /* This optimization is invalid for ordered comparisons
! 	       if CONST+INCR overflows or if foo+incr might overflow.
! 	       This optimization is invalid for floating point due to rounding.
! 	       For pointer types we assume overflow doesn't happen.  */
! 	    if (POINTER_TYPE_P (TREE_TYPE (varop))
! 		|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
! 		    && (code == EQ_EXPR || code == NE_EXPR)))
! 	      {
! 		tree newconst
! 		  = fold (build (PLUS_EXPR, TREE_TYPE (varop),
! 				 constop, TREE_OPERAND (varop, 1)));
!
! 		/* Do not overwrite the current varop to be a preincrement,
! 		   create a new node so that we won't confuse our caller who
! 		   might create trees and throw them away, reusing the
! 		   arguments that they passed to build.  This shows up in
! 		   the THEN or ELSE parts of ?: being postincrements.  */
! 		varop = build (PREINCREMENT_EXPR, TREE_TYPE (varop),
! 			       TREE_OPERAND (varop, 0),
! 			       TREE_OPERAND (varop, 1));
!
! 		/* If VAROP is a reference to a bitfield, we must mask
! 		   the constant by the width of the field.  */
! 		if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
! 		    && DECL_BIT_FIELD(TREE_OPERAND
! 				      (TREE_OPERAND (varop, 0), 1)))
! 		  {
! 		    int size
! 		      = TREE_INT_CST_LOW (DECL_SIZE
! 					  (TREE_OPERAND
! 					   (TREE_OPERAND (varop, 0), 1)));
! 		    tree mask, unsigned_type;
! 		    unsigned int precision;
! 		    tree folded_compare;
!
! 		    /* First check whether the comparison would come out
! 		       always the same.  If we don't do that we would
! 		       change the meaning with the masking.  */
! 		    if (constopnum == 0)
! 		      folded_compare = fold (build (code, type, constop,
! 						    TREE_OPERAND (varop, 0)));
! 		    else
! 		      folded_compare = fold (build (code, type,
! 						    TREE_OPERAND (varop, 0),
! 						    constop));
! 		    if (integer_zerop (folded_compare)
! 			|| integer_onep (folded_compare))
! 		      return omit_one_operand (type, folded_compare, varop);
!
! 		    unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
! 		    precision = TYPE_PRECISION (unsigned_type);
! 		    mask = build_int_2 (~0, ~0);
! 		    TREE_TYPE (mask) = unsigned_type;
! 		    force_fit_type (mask, 0);
! 		    mask = const_binop (RSHIFT_EXPR, mask,
! 					size_int (precision - size), 0);
! 		    newconst = fold (build (BIT_AND_EXPR,
! 					    TREE_TYPE (varop), newconst,
! 					    fold_convert (TREE_TYPE (varop),
! 							  mask)));
! 		  }
!
! 		t = build (code, type,
! 			   (constopnum == 0) ? newconst : varop,
! 			   (constopnum == 1) ? newconst : varop);
! 		return t;
! 	      }
! 	  }
! 	else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
! 	  {
! 	    if (POINTER_TYPE_P (TREE_TYPE (varop))
! 		|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
! 		    && (code == EQ_EXPR || code == NE_EXPR)))
! 	      {
! 		tree newconst
! 		  = fold (build (MINUS_EXPR, TREE_TYPE (varop),
! 				 constop, TREE_OPERAND (varop, 1)));
!
! 		/* Do not overwrite the current varop to be a predecrement,
! 		   create a new node so that we won't confuse our caller who
! 		   might create trees and throw them away, reusing the
! 		   arguments that they passed to build.  This shows up in
! 		   the THEN or ELSE parts of ?: being postdecrements.  */
! 		varop = build (PREDECREMENT_EXPR, TREE_TYPE (varop),
! 			       TREE_OPERAND (varop, 0),
! 			       TREE_OPERAND (varop, 1));
!
! 		if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
! 		    && DECL_BIT_FIELD(TREE_OPERAND
! 				      (TREE_OPERAND (varop, 0), 1)))
! 		  {
! 		    int size
! 		      = TREE_INT_CST_LOW (DECL_SIZE
! 					  (TREE_OPERAND
! 					   (TREE_OPERAND (varop, 0), 1)));
! 		    tree mask, unsigned_type;
! 		    unsigned int precision;
! 		    tree folded_compare;
!
! 		    if (constopnum == 0)
! 		      folded_compare = fold (build (code, type, constop,
! 						    TREE_OPERAND (varop, 0)));
! 		    else
! 		      folded_compare = fold (build (code, type,
! 						    TREE_OPERAND (varop, 0),
! 						    constop));
! 		    if (integer_zerop (folded_compare)
! 			|| integer_onep (folded_compare))
! 		      return omit_one_operand (type, folded_compare, varop);
!
! 		    unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
! 		    precision = TYPE_PRECISION (unsigned_type);
! 		    mask = build_int_2 (~0, ~0);
! 		    TREE_TYPE (mask) = TREE_TYPE (varop);
! 		    force_fit_type (mask, 0);
! 		    mask = const_binop (RSHIFT_EXPR, mask,
! 					size_int (precision - size), 0);
! 		    newconst = fold (build (BIT_AND_EXPR,
! 					    TREE_TYPE (varop), newconst,
! 					    fold_convert (TREE_TYPE (varop),
! 							  mask)));
! 		  }
!
! 		t = build (code, type,
! 			   (constopnum == 0) ? newconst : varop,
! 			   (constopnum == 1) ? newconst : varop);
! 		return t;
! 	      }
! 	  }
!       }

        /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
  	 This transformation affects the cases which are handled in later
--- 7218,7298 ----
  	    }
  	}

!       /* Convert foo++ == CONST into ++foo == CONST + INCR.  */
!       if (TREE_CONSTANT (arg1)
! 	  && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
! 	      || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
! 	  /* This optimization is invalid for ordered comparisons
! 	     if CONST+INCR overflows or if foo+incr might overflow.
! 	     This optimization is invalid for floating point due to rounding.
! 	     For pointer types we assume overflow doesn't happen.  */
! 	  && (POINTER_TYPE_P (TREE_TYPE (arg0))
! 	      || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
! 		  && (code == EQ_EXPR || code == NE_EXPR))))
! 	{
! 	  tree varop, newconst;
!
! 	  if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
! 	    {
! 	      newconst = fold (build (PLUS_EXPR, TREE_TYPE (arg0),
! 				      arg1, TREE_OPERAND (arg0, 1)));
! 	      varop = build (PREINCREMENT_EXPR, TREE_TYPE (arg0),
! 			     TREE_OPERAND (arg0, 0),
! 			     TREE_OPERAND (arg0, 1));
! 	    }
! 	  else
! 	    {
! 	      newconst = fold (build (MINUS_EXPR, TREE_TYPE (arg0),
! 				      arg1, TREE_OPERAND (arg0, 1)));
! 	      varop = build (PREDECREMENT_EXPR, TREE_TYPE (arg0),
! 			     TREE_OPERAND (arg0, 0),
! 			     TREE_OPERAND (arg0, 1));
! 	    }
!
!
! 	  /* If VAROP is a reference to a bitfield, we must mask
! 	     the constant by the width of the field.  */
! 	  if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
! 	      && DECL_BIT_FIELD(TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
! 	    {
! 	      tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
! 	      int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
! 	      tree folded_compare;
! 	      tree mask = 0;
!
! 	      /* First check whether the comparison would come out
! 		 always the same.  If we don't do that we would
! 		 change the meaning with the masking.  */
! 	      folded_compare = fold (build (code, type,
! 					    TREE_OPERAND (varop, 0),
! 					    arg1));
! 	      if (integer_zerop (folded_compare)
! 		  || integer_onep (folded_compare))
! 		return omit_one_operand (type, folded_compare, varop);
!
! 	      if (size < HOST_BITS_PER_WIDE_INT)
! 		{
! 		  unsigned HOST_WIDE_INT lo = ((unsigned HOST_WIDE_INT) 1
! 					       << size) - 1;
! 		  mask = build_int_2 (lo, 0);
! 		}
! 	      else if (size < 2 * HOST_BITS_PER_WIDE_INT)
! 		{
! 		  HOST_WIDE_INT hi = ((HOST_WIDE_INT) 1
! 				      << (size - HOST_BITS_PER_WIDE_INT)) - 1;
! 		  mask = build_int_2 (~0, hi);
! 		}
!
! 	      if (mask)
! 		{
! 		  mask = fold_convert (TREE_TYPE (varop), mask);
! 		  newconst = fold (build (BIT_AND_EXPR, TREE_TYPE (varop),
! 					  newconst, mask));
! 		}
! 	    }
!
! 	  return fold (build (code, type, varop, newconst));
! 	}

        /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
  	 This transformation affects the cases which are handled in later


int main()
{
  int b = 0;

  struct {
    unsigned int bit0:1;
    unsigned int bit1:1;
    unsigned int bit2:1;
    unsigned int bit3:1;
    unsigned int bit4:1;
    unsigned int bit5:1;
    unsigned int bit6:1;
    unsigned int bit7:1;
    unsigned int ubyte:24;
  } sdata = {0x01};

  while ( sdata.bit0-- > 0 ) {
    b++ ;
    if ( b > 100 ) break;
  }

  if (b != 1)
    abort ();
  return 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]