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] Fix PR34971, wrong-code with ROTATE_EXPRs


fold manages to create ROTATE_EXPRs of quantities with bitsizes that
do not match their mode bitsize.  This is a problem, because expansion
doesn't handle this at all.  While I have a patch to fix expansion here,
we should simply admit that rotates of bitfields are not going to help
us anywhere and so simply avoid generating them.

This is what this patch does, bootstrapped and tested on 
x86_64-unknown-linux-gnu, applied to trunk.  I'll apply this for 4.3.1,
but without the assert in expr.c, as it is 4.3 that introduced generating
more of those rotates.

Richard.

2008-02-26  Richard Guenther  <rguenther@suse.de>

	PR middle-end/34971
	* expr.c (expand_expr_real_1): Assert on rotates that operate
	on partial modes.
	* fold-const.c (fold_binary): Use the types precision, not the
	bitsize of the mode if folding rotate expressions.  Build rotates
	only for full modes.

	* gcc.c-torture/execute/pr34971.c: New testcase.

Index: testsuite/gcc.c-torture/execute/pr34971.c
===================================================================
*** testsuite/gcc.c-torture/execute/pr34971.c	(revision 0)
--- testsuite/gcc.c-torture/execute/pr34971.c	(revision 0)
***************
*** 0 ****
--- 1,22 ----
+ struct foo
+ {
+   unsigned long long b:40;
+ } x;
+ 
+ extern void abort (void);
+ 
+ void test1(unsigned long long res)
+ {
+   /* Build a rotate expression on a 40 bit argument.  */
+   if ((x.b<<8) + (x.b>>32) != res)
+     abort ();
+ }
+ 
+ int main()
+ {
+   x.b = 0x0100000001;
+   test1(0x0000000101);
+   x.b = 0x0100000000;
+   test1(0x0000000001);
+   return 0;
+ }

Index: fold-const.c
===================================================================
*** fold-const.c	(revision 132668)
--- fold-const.c	(working copy)
*************** fold_binary (enum tree_code code, tree t
*** 9886,9898 ****
  	 is a rotate of A by B bits.  */
        {
  	enum tree_code code0, code1;
  	code0 = TREE_CODE (arg0);
  	code1 = TREE_CODE (arg1);
  	if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
  	     || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
  	    && operand_equal_p (TREE_OPERAND (arg0, 0),
  			        TREE_OPERAND (arg1, 0), 0)
! 	    && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
  	  {
  	    tree tree01, tree11;
  	    enum tree_code code01, code11;
--- 9886,9903 ----
  	 is a rotate of A by B bits.  */
        {
  	enum tree_code code0, code1;
+ 	tree rtype;
  	code0 = TREE_CODE (arg0);
  	code1 = TREE_CODE (arg1);
  	if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
  	     || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
  	    && operand_equal_p (TREE_OPERAND (arg0, 0),
  			        TREE_OPERAND (arg1, 0), 0)
! 	    && (rtype = TREE_TYPE (TREE_OPERAND (arg0, 0)),
! 	        TYPE_UNSIGNED (rtype))
! 	    /* Only create rotates in complete modes.  Other cases are not
! 	       expanded properly.  */
! 	    && TYPE_PRECISION (rtype) == GET_MODE_PRECISION (TYPE_MODE (rtype)))
  	  {
  	    tree tree01, tree11;
  	    enum tree_code code01, code11;
*************** fold_binary (enum tree_code code, tree t
*** 11636,11642 ****
        if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
  	{
  	  tree tem = build_int_cst (TREE_TYPE (arg1),
! 				    GET_MODE_BITSIZE (TYPE_MODE (type)));
  	  tem = const_binop (MINUS_EXPR, tem, arg1, 0);
  	  return fold_build2 (RROTATE_EXPR, type, op0, tem);
  	}
--- 11641,11647 ----
        if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
  	{
  	  tree tem = build_int_cst (TREE_TYPE (arg1),
! 				    TYPE_PRECISION (type));
  	  tem = const_binop (MINUS_EXPR, tem, arg1, 0);
  	  return fold_build2 (RROTATE_EXPR, type, op0, tem);
  	}
*************** fold_binary (enum tree_code code, tree t
*** 11655,11662 ****
  			    fold_build2 (code, type,
  					 TREE_OPERAND (arg0, 1), arg1));
  
!       /* Two consecutive rotates adding up to the width of the mode can
! 	 be ignored.  */
        if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
  	  && TREE_CODE (arg0) == RROTATE_EXPR
  	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
--- 11660,11667 ----
  			    fold_build2 (code, type,
  					 TREE_OPERAND (arg0, 1), arg1));
  
!       /* Two consecutive rotates adding up to the precision of the
! 	 type can be ignored.  */
        if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
  	  && TREE_CODE (arg0) == RROTATE_EXPR
  	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
*************** fold_binary (enum tree_code code, tree t
*** 11664,11670 ****
  	  && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
  	  && ((TREE_INT_CST_LOW (arg1)
  	       + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
! 	      == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
  	return TREE_OPERAND (arg0, 0);
  
        /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
--- 11669,11675 ----
  	  && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
  	  && ((TREE_INT_CST_LOW (arg1)
  	       + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
! 	      == (unsigned int) TYPE_PRECISION (type)))
  	return TREE_OPERAND (arg0, 0);
  
        /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
Index: expr.c
===================================================================
*** expr.c	(revision 132668)
--- expr.c	(working copy)
*************** expand_expr_real_1 (tree exp, rtx target
*** 8898,8907 ****
      case BIT_XOR_EXPR:
        goto binop;
  
-     case LSHIFT_EXPR:
-     case RSHIFT_EXPR:
      case LROTATE_EXPR:
      case RROTATE_EXPR:
        /* If this is a fixed-point operation, then we cannot use the code
  	 below because "expand_shift" doesn't support sat/no-sat fixed-point
           shifts.   */
--- 8898,8913 ----
      case BIT_XOR_EXPR:
        goto binop;
  
      case LROTATE_EXPR:
      case RROTATE_EXPR:
+       /* The expansion code only handles expansion of mode precision
+ 	 rotates.  */
+       gcc_assert (GET_MODE_PRECISION (TYPE_MODE (type))
+ 		  == TYPE_PRECISION (type));
+ 
+       /* Falltrough.  */
+     case LSHIFT_EXPR:
+     case RSHIFT_EXPR:
        /* If this is a fixed-point operation, then we cannot use the code
  	 below because "expand_shift" doesn't support sat/no-sat fixed-point
           shifts.   */


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