Commit 0d3d674b by Alexandre Oliva Committed by Alexandre Oliva

[PR86153] simplify more overflow tests in VRP

PR 86153 was originally filed when changes to the C++11's
implementation of vector resize(size_type) limited inlining that were
required for testsuite/g++.dg/pr83239.C to verify that we did not
issue an undesired warning.

That was worked by increasing the limit for inlining, but that in turn
caused the C++98 implementation of vector resize, that is
significantly different, to also be fully inlined, and that happened
to issue the very warnings the test was meant to verify we did NOT
issue.

The reason we issued the warnings was that we failed to optimize out
some parts of _M_fill_insert, used by the C++98 version of vector
resize, although the call of _M_fill_insert was guarded by a test that
could never pass: test testcase only calls resize when the vector size
is >= 3, to decrement the size by two.  The limitation we hit in VRP
was that the compared values could pass as an overflow test, if the
vector size was 0 or 1 (we knew it wasn't), but even with dynamic
ranges we failed to decide that the test result could be determined at
compile time, even though after the test we introduced ASSERT_EXPRs
that required a condition known to be false from earlier ones.

I pondered turning ASSERT_EXPRs that show impossible conditions into
traps, to enable subsequent instructions to be optimized, but I ended
up finding an earlier spot in which an overflow test that would have
introduced the impossible ASSERT_EXPR can have its result deduced from
earlier known ranges and resolved to the other path.

Although such overflow tests could be uniformly simplified to compares
against a constant, the original code would only perform such
simplifications when the test could be resolved to an equality test
against zero.  I've thus avoided introducing compares against other
constants, and instead added code that will only simplify overflow
tests that weren't simplified before when the condition can be
evaluated at compile time.


for  gcc/ChangeLog

	PR testsuite/86153
	PR middle-end/83239
	* vr-values.c
	(vr_values::vrp_evaluate_conditional_warnv_with_ops): Extend
	simplification of overflow tests to cover cases in which we
	can determine the result of the comparison.

for  gcc/testsuite/ChangeLog

	PR testsuite/86153
	PR middle-end/83239
	* gcc.dg/vrp-overflow-1.c: New.

From-SVN: r267252
parent de62200f
2018-12-19 Alexandre Oliva <aoliva@redhat.com>
PR testsuite/86153
PR middle-end/83239
* vr-values.c
(vr_values::vrp_evaluate_conditional_warnv_with_ops): Extend
simplification of overflow tests to cover cases in which we
can determine the result of the comparison.
2018-12-19 Bin Cheng <bin.cheng@linux.alibaba.com> 2018-12-19 Bin Cheng <bin.cheng@linux.alibaba.com>
* auto-profile.c (afdo_indirect_call): Skip generating histogram * auto-profile.c (afdo_indirect_call): Skip generating histogram
2018-12-19 Alexandre Oliva <aoliva@redhat.com> 2018-12-19 Alexandre Oliva <aoliva@redhat.com>
PR testsuite/86153
PR middle-end/83239
* gcc.dg/vrp-overflow-1.c: New.
PR c++/87012 PR c++/87012
* g++.dg/cpp0x/pr87012.C: New. * g++.dg/cpp0x/pr87012.C: New.
......
/* { dg-do run } */
/* { dg-options "-O2 -fno-tree-forwprop" } */
extern void __attribute__((noreturn)) unreachable (void);
int fle22 (int a)
{
unsigned i = a / 4;
unsigned j = i - 2;
if (j == 7) /* A dynamic range excludes a value from j for the rest of f1. */
return -1;
if (i <= 2) /* This dynamic range cannot be combined or compared with that of j. */
return 0;
if (i <= j) /* And so we couldn't compute this result. */
unreachable ();
return 1;
}
int fle32 (int a)
{
unsigned i = a / 4;
unsigned j = i - 3;
if (j == 7) /* A dynamic range excludes a value from j for the rest of f1. */
return -1;
if (i <= 2) /* This dynamic range cannot be combined or compared with that of j. */
return 0;
if (i <= j) /* And so we couldn't compute this result. */
unreachable ();
return 1;
}
int flt22 (int a)
{
unsigned i = a / 4;
unsigned j = i - 2;
if (j == 7)
return -1;
if (i <= 2)
return 0;
if (i < j)
unreachable ();
return 1;
}
int flt32 (int a)
{
unsigned i = a / 4;
unsigned j = i - 3;
if (j == 7)
return -1;
if (i <= 2)
return 0;
if (i < j)
unreachable ();
return 1;
}
int fgt22 (int a)
{
unsigned i = a / 4;
unsigned j = i + 2;
if (j == -7)
return -1;
if (i >= -3)
return 0;
if (i > j)
unreachable ();
return 1;
}
int fgt32 (int a)
{
unsigned i = a / 4;
unsigned j = i + 3;
if (j == -7)
return -1;
if (i >= -3)
return 0;
if (i > j)
unreachable ();
return 1;
}
int fge22 (int a)
{
unsigned i = a / 4;
unsigned j = i + 2;
if (j == -7)
return -1;
if (i >= -3)
return 0;
if (i >= j)
unreachable ();
return 1;
}
int fge32 (int a)
{
unsigned i = a / 4;
unsigned j = i + 3;
if (j == -7)
return -1;
if (i >= -3)
return 0;
if (i >= j)
unreachable ();
return 1;
}
int main (int argc, char *argv[]) {
fle22 (argc);
fle32 (argc);
flt22 (argc);
flt32 (argc);
fgt22 (argc);
fgt32 (argc);
fge22 (argc);
fge32 (argc);
}
...@@ -2336,6 +2336,39 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, ...@@ -2336,6 +2336,39 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code,
op1 = wide_int_to_tree (TREE_TYPE (op0), 0); op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
code = (code == GT_EXPR || code == GE_EXPR) ? EQ_EXPR : NE_EXPR; code = (code == GT_EXPR || code == GE_EXPR) ? EQ_EXPR : NE_EXPR;
} }
else
{
value_range vro, vri;
if (code == GT_EXPR || code == GE_EXPR)
{
vro.set (VR_ANTI_RANGE, TYPE_MIN_VALUE (TREE_TYPE (op0)), x);
vri.set (VR_RANGE, TYPE_MIN_VALUE (TREE_TYPE (op0)), x);
}
else if (code == LT_EXPR || code == LE_EXPR)
{
vro.set (VR_RANGE, TYPE_MIN_VALUE (TREE_TYPE (op0)), x);
vri.set (VR_ANTI_RANGE, TYPE_MIN_VALUE (TREE_TYPE (op0)), x);
}
else
gcc_unreachable ();
value_range *vr0 = get_value_range (op0);
/* If vro, the range for OP0 to pass the overflow test, has
no intersection with *vr0, OP0's known range, then the
overflow test can't pass, so return the node for false.
If it is the inverted range, vri, that has no
intersection, then the overflow test must pass, so return
the node for true. In other cases, we could proceed with
a simplified condition comparing OP0 and X, with LE_EXPR
for previously LE_ or LT_EXPR and GT_EXPR otherwise, but
the comments next to the enclosing if suggest it's not
generally profitable to do so. */
vro.intersect (vr0);
if (vro.undefined_p ())
return boolean_false_node;
vri.intersect (vr0);
if (vri.undefined_p ())
return boolean_true_node;
}
} }
if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment