aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-03-04 15:14:49 -0700
committerMartin Sebor <msebor@redhat.com>2020-03-04 15:14:49 -0700
commit10bbbb591cfe6cac200e926a73f3b8065147ce84 (patch)
treee474548ec09e6e9eaf3898560057ebe44a73673b
parent3c1645a379e405c7ce33060846fa424373b1f5f4 (diff)
PR tree-optimization/93986 - ICE on mixed-precision wide_int arguments
gcc/testsuite/ChangeLog: PR tree-optimization/93986 * gcc.dg/pr93986.c: New test. gcc/ChangeLog: PR tree-optimization/93986 * tree-ssa-strlen.c (maybe_warn_overflow): Convert all wide_int operands to the same precision widest_int to avoid ICEs.
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr93986.c16
-rw-r--r--gcc/tree-ssa-strlen.c110
4 files changed, 97 insertions, 40 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b7c9d86c90c..0df606a8211 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2020-03-04 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/93986
+ * tree-ssa-strlen.c (maybe_warn_overflow): Convert all wide_int
+ operands to the same precision widest_int to avoid ICEs.
+
2020-03-04 Bill Schmidt <wschmidt@linux.ibm.com>
PR target/87560
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9fcec5abc9e..468f7673e29 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-03-04 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/93986
+ * gcc.dg/pr93986.c: New test.
+
2020-03-04 David Malcolm <dmalcolm@redhat.com>
PR analyzer/94028
diff --git a/gcc/testsuite/gcc.dg/pr93986.c b/gcc/testsuite/gcc.dg/pr93986.c
new file mode 100644
index 00000000000..bdbc192a01d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr93986.c
@@ -0,0 +1,16 @@
+/* PR tree-optimization/93986 - ICE in decompose, at wide-int.h:984
+ { dg-do compile }
+ { dg-options "-O1 -foptimize-strlen -ftree-slp-vectorize" } */
+
+int dd (void);
+
+void ya (int cm)
+{
+ char s2[cm];
+
+ s2[cm-12] = s2[cm-11] = s2[cm-10] = s2[cm-9]
+ = s2[cm-8] = s2[cm-7] = s2[cm-6] = s2[cm-5] = ' ';
+
+ if (dd ())
+ __builtin_exit (0);
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index b76b54efbd8..81be11de797 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1924,11 +1924,21 @@ maybe_warn_overflow (gimple *stmt, tree len,
if (TREE_NO_WARNING (dest))
return;
+ /* Use maximum precision to avoid overflow in the addition below.
+ Make sure all operands have the same precision to keep wide_int
+ from ICE'ing. */
+
+ /* Convenience constants. */
+ const widest_int diff_min
+ = wi::to_widest (TYPE_MIN_VALUE (ptrdiff_type_node));
+ const widest_int diff_max
+ = wi::to_widest (TYPE_MAX_VALUE (ptrdiff_type_node));
+ const widest_int size_max
+ = wi::to_widest (TYPE_MAX_VALUE (size_type_node));
+
/* The offset into the destination object computed below and not
reflected in DESTSIZE. */
- wide_int offrng[2];
- const int off_prec = TYPE_PRECISION (ptrdiff_type_node);
- offrng[0] = offrng[1] = wi::zero (off_prec);
+ widest_int offrng[2] = { 0, 0 };
if (!si)
{
@@ -1941,15 +1951,17 @@ maybe_warn_overflow (gimple *stmt, tree len,
ARRAY_REF (MEM_REF (vlaptr, 0), N]. */
tree off = TREE_OPERAND (ref, 1);
ref = TREE_OPERAND (ref, 0);
- if (get_range (off, offrng, rvals))
+ wide_int rng[2];
+ if (get_range (off, rng, rvals))
{
- offrng[0] = offrng[0].from (offrng[0], off_prec, SIGNED);
- offrng[1] = offrng[1].from (offrng[1], off_prec, SIGNED);
+ /* Convert offsets to the maximum precision. */
+ offrng[0] = widest_int::from (rng[0], SIGNED);
+ offrng[1] = widest_int::from (rng[1], SIGNED);
}
else
{
- offrng[0] = wi::to_wide (TYPE_MIN_VALUE (ptrdiff_type_node));
- offrng[1] = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
+ offrng[0] = diff_min;
+ offrng[1] = diff_max;
}
}
@@ -1957,25 +1969,25 @@ maybe_warn_overflow (gimple *stmt, tree len,
{
tree mem_off = TREE_OPERAND (ref, 1);
ref = TREE_OPERAND (ref, 0);
- wide_int memoffrng[2];
- if (get_range (mem_off, memoffrng, rvals))
+ wide_int rng[2];
+ if (get_range (mem_off, rng, rvals))
{
- offrng[0] += memoffrng[0];
- offrng[1] += memoffrng[1];
+ offrng[0] += widest_int::from (rng[0], SIGNED);
+ offrng[1] += widest_int::from (rng[1], SIGNED);
}
else
{
- offrng[0] = wi::to_wide (TYPE_MIN_VALUE (ptrdiff_type_node));
- offrng[1] = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
+ offrng[0] = diff_min;
+ offrng[1] = diff_max;
}
}
- wide_int stroffrng[2];
- if (int idx = get_stridx (ref, stroffrng, rvals))
+ wide_int rng[2];
+ if (int idx = get_stridx (ref, rng, rvals))
{
si = get_strinfo (idx);
- offrng[0] += stroffrng[0];
- offrng[1] += stroffrng[1];
+ offrng[0] += widest_int::from (rng[0], SIGNED);
+ offrng[1] += widest_int::from (rng[1], SIGNED);
}
}
@@ -1995,15 +2007,20 @@ maybe_warn_overflow (gimple *stmt, tree len,
/* Compute the range of sizes of the destination object. The range
is constant for declared objects but may be a range for allocated
objects. */
- const int siz_prec = TYPE_PRECISION (size_type_node);
- wide_int sizrng[2];
+ widest_int sizrng[2] = { 0, 0 };
if (si)
{
- destsize = gimple_call_alloc_size (si->alloc, sizrng, rvals);
+ wide_int rng[2];
+ destsize = gimple_call_alloc_size (si->alloc, rng, rvals);
+ if (destsize)
+ {
+ sizrng[0] = widest_int::from (rng[0], UNSIGNED);
+ sizrng[1] = widest_int::from (rng[1], UNSIGNED);
+ }
alloc_call = si->alloc;
}
else
- offrng[0] = offrng[1] = wi::zero (off_prec);
+ offrng[0] = offrng[1] = 0;
if (!destsize)
{
@@ -2014,7 +2031,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
{
/* Remember OFF but clear OFFRNG that may have been set above. */
destoff = off;
- offrng[0] = offrng[1] = wi::zero (off_prec);
+ offrng[0] = offrng[1] = 0;
if (destdecl && TREE_CODE (destdecl) == SSA_NAME)
{
@@ -2024,27 +2041,30 @@ maybe_warn_overflow (gimple *stmt, tree len,
destdecl = NULL_TREE;
}
- if (!get_range (destsize, sizrng, rvals))
+ wide_int rng[2];
+ if (get_range (destsize, rng, rvals))
+ {
+ sizrng[0] = widest_int::from (rng[0], UNSIGNED);
+ sizrng[1] = widest_int::from (rng[1], UNSIGNED);
+ }
+ else
{
/* On failure, rather than failing, set the maximum range
so that overflow in allocated objects whose size depends
on the strlen of the source can still be diagnosed
below. */
- sizrng[0] = wi::zero (siz_prec);
- sizrng[1] = wi::to_wide (TYPE_MAX_VALUE (sizetype));
+ sizrng[0] = 0;
+ sizrng[1] = size_max;
}
}
}
if (!destsize)
{
- sizrng[0] = wi::zero (siz_prec);
- sizrng[1] = wi::to_wide (TYPE_MAX_VALUE (sizetype));
+ sizrng[0] = 0;
+ sizrng[1] = size_max;
};
- sizrng[0] = sizrng[0].from (sizrng[0], siz_prec, UNSIGNED);
- sizrng[1] = sizrng[1].from (sizrng[1], siz_prec, UNSIGNED);
-
/* Return early if the DESTSIZE size expression is the same as LEN
and the offset into the destination is zero. This might happen
in the case of a pair of malloc and memset calls to allocate
@@ -2052,10 +2072,13 @@ maybe_warn_overflow (gimple *stmt, tree len,
if (destsize == len && !plus_one && offrng[0] == 0 && offrng[0] == offrng[1])
return;
- wide_int lenrng[2];
- if (!get_range (len, lenrng, rvals))
+ wide_int rng[2];
+ if (!get_range (len, rng, rvals))
return;
+ widest_int lenrng[2] =
+ { widest_int::from (rng[0], SIGNED), widest_int::from (rng[1], SIGNED) };
+
if (plus_one)
{
lenrng[0] += 1;
@@ -2064,7 +2087,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
/* The size of the remaining space in the destination computed
as the size of the latter minus the offset into it. */
- wide_int spcrng[2] = { sizrng[0], sizrng[1] };
+ widest_int spcrng[2] = { sizrng[0], sizrng[1] };
if (wi::neg_p (offrng[0]) && wi::neg_p (offrng[1]))
{
/* When the offset is negative and the size of the destination
@@ -2075,7 +2098,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
return;
/* The remaining space is necessarily zero. */
- spcrng[0] = spcrng[1] = wi::zero (spcrng->get_precision ());
+ spcrng[0] = spcrng[1] = 0;
}
else if (wi::neg_p (offrng[0]))
{
@@ -2203,7 +2226,16 @@ maybe_warn_overflow (gimple *stmt, tree len,
/* If DESTOFF is not null, use it to format the offset value/range. */
if (destoff)
- get_range (destoff, offrng);
+ {
+ wide_int rng[2];
+ if (get_range (destoff, rng))
+ {
+ offrng[0] = widest_int::from (rng[0], SIGNED);
+ offrng[1] = widest_int::from (rng[1], SIGNED);
+ }
+ else
+ offrng[0] = offrng[1] = 0;
+ }
/* Format the offset to keep the number of inform calls from growing
out of control. */
@@ -2259,8 +2291,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
else if (sizrng[0] == 0)
{
/* Avoid printing impossible sizes. */
- if (wi::ltu_p (sizrng[1],
- wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2))
+ if (wi::ltu_p (sizrng[1], diff_max - 2))
inform (gimple_location (alloc_call),
"at offset %s to an object with size at most %wu "
"declared here",
@@ -2284,8 +2315,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
else if (sizrng[0] == 0)
{
/* Avoid printing impossible sizes. */
- if (wi::ltu_p (sizrng[1],
- wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2))
+ if (wi::ltu_p (sizrng[1], diff_max - 2))
inform (gimple_location (alloc_call),
"at offset %s to an object with size at most %wu allocated "
"by %qD here",