This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[3.4 only] PR c/20187: folding comparisons of truncated values
- From: Richard Sandiford <richard at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: gdr at integrable-solutions dot net
- Date: Thu, 28 Jul 2005 13:31:15 +0100
- Subject: [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 ();
+ }