[PR86153] simplify more overflow tests in VRP
Alexandre Oliva
aoliva@redhat.com
Wed Dec 19 11:04:00 GMT 2018
On Dec 18, 2018, Jeff Law <law@redhat.com> wrote:
>> 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.
> That limitation was precisely what my (unsubmitted) patch was trying
> to address :)
This patch is what I was getting at in my earlier email.
These transformations are already performed elsewhere, e.g. when
forwprop is enabled, but given sufficiently complex code to begin with,
as in the pr83239 testcases, forwprop presumably runs too early to be
able to simplify the tests and then nonearly vrp comes to the rescue.
Presumably with more convoluted tests than the ones I'm introducing,
forwprop would be unable to infer the ranges, and then we'd really
depend on vrp, but I didn't dig deep enough to try and create a testcase
that wouldn't be optimized by forwprop, only by vrp. That's why the
tests disable forwprop.
[PR86153] simplify vrp overflow simplifications
It turns out there was apparently no reason to avoid simplifying every
overflow comparison to a compare with a constant, it was not
profitable because earlier VRP couldn't deal with that as well as it
does now.
So, make the transformation unconditionally, even in cases we'd have
transformed differently before my previous patch, and let the
nowbetter optimizations resolve them to boolean constants or to
equality tests when possible.
The only significant difference is that where we'd turn A>B after
B=A+1 into B!=0, we'll now turn it into A!=1u. That might seem
worse, but considering that test canonicalization will have moved the
(probably) earliest SSA version to the first operand, that form is
more likely to allow the later SSA definition, presumably in terms of
the earlier one, to be completely removed, which would have otherwise
required propagation of the assignment to B into the compare, which is
possible in equality tests, but not in other kinds of overflow tests.
Regstrapped on x86_64 and i686linuxgnu. Ok to install?
for gcc/ChangeLog
PR testsuite/86153
PR middleend/83239
* vrvalues.c
(vr_values::vrp_evaluate_conditional_warnv_with_ops): Simplify
the handling of overflow comparisons.
for gcc/testsuite/ChangeLog
PR testsuite/86153
PR middleend/83239
* gcc.dg/vrpoverflow2.c: New.

gcc/testsuite/gcc.dg/vrpoverflow2.c  35 ++++++++++++++++++
gcc/vrvalues.c  66 +++
2 files changed, 40 insertions(+), 61 deletions()
create mode 100644 gcc/testsuite/gcc.dg/vrpoverflow2.c
diff git a/gcc/testsuite/gcc.dg/vrpoverflow2.c b/gcc/testsuite/gcc.dg/vrpoverflow2.c
new file mode 100644
index 000000000000..a905471bcaa1
 /dev/null
+++ b/gcc/testsuite/gcc.dg/vrpoverflow2.c
@@ 0,0 +1,35 @@
+/* { dgdo run } */
+/* { dgoptions "O2 fnotreeforwprop" } */
+
+void __attribute__((noreturn)) undefined ();
+
+int tij (unsigned i)
+{
+ unsigned j = i + 1;
+
+ if (j == 0)
+ return 0;
+
+ if (i > j)
+ undefined ();
+
+ return 1;
+}
+
+int tji (unsigned i)
+{
+ unsigned j = i  1;
+
+ if (i == 0)
+ return 0;
+
+ if (j > i)
+ undefined ();
+
+ return 1;
+}
+
+int main (int argc, char *argv[]) {
+ tij (argc);
+ tji (argc);
+}
diff git a/gcc/vrvalues.c b/gcc/vrvalues.c
index d71a703ab550..49c5da9cb515 100644
 a/gcc/vrvalues.c
+++ b/gcc/vrvalues.c
@@ 2305,70 +2305,14 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code,
&& !POINTER_TYPE_P (TREE_TYPE (op0)))
return NULL_TREE;
 /* If OP0 CODE OP1 is an overflow comparison, if it can be expressed
 as a simple equality test, then prefer that over its current form
 for evaluation.

 An overflow test which collapses to an equality test can always be
 expressed as a comparison of one argument against zero. Overflow
 occurs when the chosen argument is zero and does not occur if the
 chosen argument is not zero. */
+ /* If OP0 CODE OP1 is an overflow comparison, it can be expressed as
+ a test involving only one of the operands and a constant, so
+ prefer that over its current form for evaluation. */
tree x;
if (overflow_comparison_p (code, op0, op1, use_equiv_p, &x))
{
 wide_int max = wi::max_value (TYPE_PRECISION (TREE_TYPE (op0)), UNSIGNED);
 /* B = A  1; if (A < B) > B = A  1; if (A == 0)
 B = A  1; if (A > B) > B = A  1; if (A != 0)
 B = A + 1; if (B < A) > B = A + 1; if (B == 0)
 B = A + 1; if (B > A) > B = A + 1; if (B != 0) */
 if (integer_zerop (x))
 {
 op1 = x;
 code = (code == LT_EXPR  code == LE_EXPR) ? EQ_EXPR : NE_EXPR;
 }
 /* B = A + 1; if (A > B) > B = A + 1; if (B == 0)
 B = A + 1; if (A < B) > B = A + 1; if (B != 0)
 B = A  1; if (B > A) > B = A  1; if (A == 0)
 B = A  1; if (B < A) > B = A  1; if (A != 0) */
 else if (wi::to_wide (x) == max  1)
 {
 op0 = op1;
 op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
 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;
 }
+ op1 = x;
+ code = (code == LT_EXPR  code == LE_EXPR) ? LE_EXPR : GT_EXPR;
}
if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges

Alexandre Oliva, freedom fighter https://FSFLA.org/blogs/lxo
Be the change, be Free! FSF Latin America board member
GNU Toolchain Engineer Free Software Evangelist
Hay que enGNUrecerse, pero sin perder la terGNUra jamásGNUChe
More information about the Gccpatches
mailing list