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 only] PR c/20187: folding comparisons of truncated values


PR c/20187 is a 3.4-only regression from 2.95.3.  We were folding:

   (unsigned char) (unsigned long long) (a & (a * b)) != (unsigned char) 0

into:

   (a & (a * b)) != 0

thus discarding the truncation.  The code that does this is:

      /* If we are widening one operand of an integer comparison,
         see if the other operand is similarly being widened.  Perhaps we
         can do the comparison in the narrower type.  */
      else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
               && TREE_CODE (arg0) == NOP_EXPR
               && (tem = get_unwidened (arg0, NULL_TREE)) != arg0
               && (code == EQ_EXPR || code == NE_EXPR
                   || TREE_UNSIGNED (TREE_TYPE (arg0))
                      == TREE_UNSIGNED (TREE_TYPE (tem)))
               && (t1 = get_unwidened (arg1, TREE_TYPE (tem))) != 0
               && (TREE_TYPE (t1) == TREE_TYPE (tem)
                   || (TREE_CODE (t1) == INTEGER_CST
                       && int_fits_type_p (t1, TREE_TYPE (tem)))))
        return fold (build (code, type, tem,
                            fold_convert (TREE_TYPE (tem), t1)));

and the problem is that (somewhat counter-intuitively),
get_unwidened can actually return something that's wider
than its argument.

This was fixed in mainline and 4.0 by the patch for PR19283:

2005-01-07  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/19283
	* fold-const.c (fold_widened_comparison): Return NULL if shorter_type
	is not shorter than the original type.

http://gcc.gnu.org/ml/gcc-patches/2005-01/msg00344.html

fold_widened_comparison doesn't exist in 3.4, but this patch
simply applies the same check to the equivalent 3.4 code.

Bootstrapped & regression tested on i686-pc-linux-gnu.  OK for 3.4?
If it is, I'll apply the testcase to 4.1 and 4.0 as well (it already
passes on both).

Richard


	PR c/20187
	* fold-const.c (fold): When shortening comparisons of widened operands,
	check whether the tree returned by get_unwidened really is wider.

testsuite/
	PR c/20187
	* gcc.c-torture/execute/pr20187-1.c: New test.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.322.2.17
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.322.2.17 fold-const.c
*** fold-const.c	26 May 2005 05:43:50 -0000	1.322.2.17
--- fold-const.c	28 Jul 2005 12:27:59 -0000
*************** fold (tree expr)
*** 7500,7505 ****
--- 7500,7507 ----
        else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
  	       && TREE_CODE (arg0) == NOP_EXPR
  	       && (tem = get_unwidened (arg0, NULL_TREE)) != arg0
+ 	       && (TYPE_PRECISION (TREE_TYPE (tem))
+ 		   > TYPE_PRECISION (TREE_TYPE (arg0)))
  	       && (code == EQ_EXPR || code == NE_EXPR
  		   || TREE_UNSIGNED (TREE_TYPE (arg0))
  		      == TREE_UNSIGNED (TREE_TYPE (tem)))
diff -c /dev/null testsuite/gcc.c-torture/execute/pr20187-1.c
*** /dev/null	2005-06-16 22:49:09.000000000 +0100
--- testsuite/gcc.c-torture/execute/pr20187-1.c	2005-07-28 13:27:41.000000000 +0100
***************
*** 0 ****
--- 1,15 ----
+ int a = 0x101;
+ int b = 0x100;
+ 
+ int
+ test (void)
+ {
+   return (((unsigned char) (unsigned long long) ((a ? a : 1) & (a * b)))
+ 	  ? 0 : 1);
+ }
+ 
+ int
+ main (void)
+ {
+   return 1 - test ();
+ }


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