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]

[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  <aoliva@redhat.com>

	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  <aoliva@redhat.com>

	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   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}

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