On 3/3/20 11:50 AM, Richard Biener wrote:
On March 3, 2020 4:39:34 PM GMT+01:00, Martin Sebor <mse...@gmail.com> wrote:
On 3/3/20 2:42 AM, Richard Biener wrote:
On Tue, Mar 3, 2020 at 12:04 AM Martin Sebor <mse...@gmail.com>
wrote:
The wide_int APIs expect operands to have the same precision and
abort when they don't. This is especially insidious in code where
the operands normally do have the same precision but where mixed
precision arguments can come up as a result of unusual combinations
optimization options. That is also what precipitated pr93986.
If you want sth like (signed) arbitrary precision arithmetic then you
can
use widest_int instead. Or, since you're working with offsets,
offset_int
is another good choice.
Yes, I would much prefer not to have to do all this myself (and
risk getting it wrong). Unfortunately, the APIs that obtain
the ranges all use wide_int, so I'd have to convert them one way
or the other. I could change some of the APIs but not all of
them (e.g., get_range_info).
You can convert wide_int to both offset and widest int.
Yes, I realize that. But it seems like six of one vs half a dozen
of the other. Either way some variables need converting. I don't
really have a preference for either approach. I just copied
the solution I already used in gimple_call_alloc_size, and I chose
that one there because the get_range calls take wide_int, and
because gimple_call_alloc_size's caller (the function I'm changing
now) also uses wide_int.
Everything could be changed to widest_int instead but I'm not sure
it would make sense (e.g., get_range_info). And unless everything
is changed, the APIs that interoperate need to convert between one
another.
I went ahead and rewrote the patch to use widest_int. It let me get
rid of some conversions but it introduced others. Most of them look
pretty much the same between the two approaches but there are more
of them with widest_int because of the extra variables. The updated
patch is also about one and half times longer.
Is one approach significantly better than the other or were you just
pointing out another way of doing it?
Either way, please choose one and approve.
Thanks
Martin
Richard.
Martin
The attached patch adjusts the code to extend all wide_int operands
to the same precision to avoid the ICE.
Besides the usual bootstrap/testing I also compiled all string tests
in gcc.dg with the same options as in the test case in pr93986 in
an effort to weed out any lingering bugs like it (found none).
Martin
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.
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..356aada5fe0 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 expected 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",