Fix for PR97317.
authorAndrew MacLeod <amacleod@redhat.com>
Fri, 9 Oct 2020 08:46:50 +0000 (10:46 +0200)
committerAldy Hernandez <aldyh@redhat.com>
Fri, 9 Oct 2020 08:57:51 +0000 (10:57 +0200)
gcc/ChangeLog:

PR tree-optimization/97317
* range-op.cc (operator_cast::op1_range): Handle casts where the precision
of the RHS is only 1 greater than the precision of the LHS.

gcc/testsuite/ChangeLog:
* gcc.dg/pr97317.c: New test.

gcc/range-op.cc
gcc/testsuite/gcc.dg/pr97317.c [new file with mode: 0644]

index 22bc23c1bbfe3cf2313c02fd1df545ea8f6ef331..d1a11b34894e9410cf43d2744b2d348f219e0576 100644 (file)
@@ -1849,14 +1849,25 @@ operator_cast::op1_range (irange &r, tree type,
                                                          type,
                                                          converted_lhs,
                                                          lim_range);
-         // And union this with the entire outer types negative range.
-         int_range_max neg (type,
-                            wi::min_value (TYPE_PRECISION (type),
-                                           SIGNED),
-                            lim - 1);
-         neg.union_ (lhs_neg);
+         // lhs_neg now has all the negative versions of the LHS.
+         // Now union in all the values from SIGNED MIN (0x80000) to
+         // lim-1 in order to fill in all the ranges with the upper
+         // bits set.
+
+         // PR 97317.  If the lhs has only 1 bit less precision than the rhs,
+         // we don't need to create a range from min to lim-1
+         // calculate neg range traps trying to create [lim, lim - 1].
+         wide_int min_val = wi::min_value (TYPE_PRECISION (type), SIGNED);
+         if (lim != min_val)
+           {
+             int_range_max neg (type,
+                                wi::min_value (TYPE_PRECISION (type),
+                                               SIGNED),
+                                lim - 1);
+             lhs_neg.union_ (neg);
+           }
          // And finally, munge the signed and unsigned portions.
-         r.union_ (neg);
+         r.union_ (lhs_neg);
        }
       // And intersect with any known value passed in the extra operand.
       r.intersect (op2);
diff --git a/gcc/testsuite/gcc.dg/pr97317.c b/gcc/testsuite/gcc.dg/pr97317.c
new file mode 100644 (file)
index 0000000..f07327a
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+struct a {
+  unsigned c : 17;
+};
+struct a b;
+int d(void) {
+  short e = b.c;
+  return e ? 0 : b.c;
+}