------- Additional Comments From aoliva at gcc dot gnu dot org 2005-04-15 05:56 ------- Subject: [PR tree-optimization/21029, RFC] harmful chrec type conversions
I started out by handling the specific case that the Ada front-end triggers, reduced to function f() in the attached testcase. Later on, as I understood the failure more, I figured I'd exercise some other cases, and painted myself into a corner in which each combination of widening-or-narrowing signedness-changing-or-not conversion that chrec_convert() might be asked to handle would be harmed by simply converting CHREC_LEFT and CHREC_RIGHT to the requested type, and the strategy we already used for widening conversions gave us correct results. Are there good reasons to try to perform the conversions in place and try to work around the loss of information elsewhere, or is this approach reasonable? This is not a final patch; if the idea is considered sound, I'd simply remove the if and the then-dead remaining code in chrec_convert. Meanwhile, I'm bootstrapping this on amd64-linux-gnu. Comments? Index: gcc/ChangeLog from Alexandre Oliva <[EMAIL PROTECTED]> PR tree-optimization/21029 * tree-chrec.c (chrec_convert): Handle same-precision integral types that differ in signedness like widening conversions. Index: gcc/tree-chrec.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree-chrec.c,v retrieving revision 2.14 diff -u -p -r2.14 tree-chrec.c --- gcc/tree-chrec.c 5 Apr 2005 07:06:23 -0000 2.14 +++ gcc/tree-chrec.c 15 Apr 2005 05:40:27 -0000 @@ -1033,7 +1033,16 @@ chrec_convert (tree type, if (ct == type) return chrec; - if (TYPE_PRECISION (ct) < TYPE_PRECISION (type)) + if (1 /* Even truncations need to carry information about + well-defined overflows in narrowing conversions that might + have invoked undefined behavior should the operations be + performed directly in the narrow type. */ + || TYPE_PRECISION (ct) < TYPE_PRECISION (type) + /* Sign changes may involve well-defined overflows; avoid + silently dropping the signedness change. + ??? Should we limit ourselves to same-precision types here? */ + || (INTEGRAL_TYPE_P (ct) && INTEGRAL_TYPE_P (type) + && TYPE_UNSIGNED (ct) != TYPE_UNSIGNED (type))) return count_ev_in_wider_type (type, chrec); switch (TREE_CODE (chrec)) Index: gcc/testsuite/ChangeLog from Alexandre Oliva <[EMAIL PROTECTED]> PR tree-optimization/21029 * gcc.dg/tree-ssa/pr21029.c: New. Index: gcc/testsuite/gcc.dg/tree-ssa/pr21029.c =================================================================== RCS file: gcc/testsuite/gcc.dg/tree-ssa/pr21029.c diff -N gcc/testsuite/gcc.dg/tree-ssa/pr21029.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gcc/testsuite/gcc.dg/tree-ssa/pr21029.c 15 Apr 2005 05:40:41 -0000 @@ -0,0 +1,176 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +/* PR tree-optimization/21029 + + f() used to get optimized to an infinite loop by tree-vrp, because + j is assumed to be non-negative. Even though the conversion from + unsigned to signed has unspecified results if the expression value + is not representable in the signed type, the compiler itself (e.g., + the Ada front end) depends on wrap-around behavior. */ + +unsigned int g(void) { + return (unsigned int)g; +} + +unsigned int f(void) { + unsigned int k = g (); + + unsigned char i = 123; + signed char j; + + do + if ((j = (signed char) i) < 0) + break; + else + i++; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +/* Now let's torture it a bit further. Narrowing conversions need + similar treatment. */ + +unsigned int f1 (void) { + unsigned int k = g (); + + unsigned short i = 123; + signed char j; + + do + if ((j = (signed char) i) < 0) + break; + else + i++; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +/* And so do widening conversions. */ + +unsigned int f2 (void) { + unsigned int k = g (); + + unsigned char i = 123; + signed short j; + + do + if ((j = (signed short) (signed char) i) < 0) + break; + else + i++; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +/* Check same-sign truncations with an increment that turns into + decrements. */ + +unsigned int f3 (void) { + unsigned int k = g (); + + signed short i = 5; + signed char j; + + do + if ((j = (signed char) i) < 0) + break; + else + i += 255; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +/* Check that the truncation above doesn't confuse the result of the + test after a widening conversion. */ + +unsigned int f4 (void) { + unsigned int k = g (); + + signed short i = -123; + signed int j; + + do + if ((j = (signed int) (signed char) i) > 0) + break; + else + i += 255; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +/* Even if we omit the widening truncation, the narrowing truncation + is implementation-defined. */ + +unsigned int f5 (void) { + unsigned int k = g (); + + signed long i = -123; + signed char j; + + do + if ((j = (signed char) i) > 0) + break; + else + i += 255; + while (1); + + /* This is here just so that the compiler introduces ASSERT_EXPR so + as to run the vrp pass. Yuck. */ + if (i <= k) + k = i - 2; + else + k = k + 3; + + return k; +} + +int main (void) { + f (); + f1 (); + f2 (); + f3 (); + f4 (); + f5 (); + return 0; +} -- Alexandre Oliva http://www.ic.unicamp.br/~oliva/ Red Hat Compiler Engineer [EMAIL PROTECTED], gcc.gnu.org} Free Software Evangelist [EMAIL PROTECTED], gnu.org} -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21029