This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/3] Simplify wrapped binops
- From: Robin Dapp <rdapp at linux dot vnet dot ibm dot com>
- To: "Bin.Cheng" <amker dot cheng at gmail dot com>, Richard Biener <richard dot guenther at gmail dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 18 May 2017 16:47:51 +0200
- Subject: [PATCH 2/3] Simplify wrapped binops
- Authentication-results: sourceware.org; auth=none
- References: <5790A709.4060804@linux.vnet.ibm.com> <fea2a49d-5f2a-ae24-8601-44e52a2d76b4@linux.vnet.ibm.com> <CAFiYyc2UKpz4krcaxow_=yF6_eFZU_=M5k+6VTHZscDz+g=2uw@mail.gmail.com> <6bc1abab-9b54-fb67-fe98-9aaf993859dd@linux.vnet.ibm.com> <CAFiYyc28DaMGuzcMPZQ+AmHXuuNDAyAorMbW0Vo02EEoyZ+xSg@mail.gmail.com> <aba5346a-027f-ee35-0406-3998ab484621@linux.vnet.ibm.com> <CAFiYyc0aExY-MmRczHKJuQ8UFOpMy_+dzV-n05UJJOhuZVywTg@mail.gmail.com> <CAFiYyc0gnMe7j+DgTeudnpH-zD22nK7Cuv4a2zj4Va-anApTBA@mail.gmail.com> <27be603c-4499-ca96-f252-40934d3e420d@linux.vnet.ibm.com> <CAFiYyc1s699beSC9bpDGxY_2ppenDLoP3nbjYSnThF1cp2YHDA@mail.gmail.com> <d6e24bfd-fc3e-4160-fe27-db3eda5b857c@linux.vnet.ibm.com> <CAFiYyc1AcFG8JzoO3LYW9iyGsPj+7Kv17weZp+U3vTaeiqdhKA@mail.gmail.com> <260c4925-29e2-d50a-871e-397e2f9f4efb@linux.vnet.ibm.com> <CAFiYyc2_WX+3vzX27iRO9byK4zoc8N43F-d=Cg2xXoHwLRTgGQ@mail.gmail.com> <CAHFci299r3v3jbaZn0pzKPmk+yvF=Hwnbq+hxYGJCz-y8Qx0jg@mail.gmail.com>
match.pd part of the patch.
gcc/ChangeLog:
2017-05-18 Robin Dapp <rdapp@linux.vnet.ibm.com>
* match.pd: Simplify wrapped binary operations.
* tree-vrp.c (extract_range_from_binary_expr_1): Add overflow
parameter.
(extract_range_from_binary_expr): Likewise.
* tree-vrp.h: Export.
diff --git a/gcc/match.pd b/gcc/match.pd
index 80a17ba..3fa18b9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1290,6 +1290,85 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (cst && !TREE_OVERFLOW (cst))
(plus { cst; } @0))))
+/* ((T)(A +- CST)) +- CST -> (T)(A) +- CST) */
+#if GIMPLE
+ (for outer_op (plus minus)
+ (for inner_op (plus minus)
+ (simplify
+ (outer_op (convert (inner_op@3 @0 INTEGER_CST@1)) INTEGER_CST@2)
+ (if (TREE_CODE (type) == INTEGER_TYPE
+ && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@3)))
+ (with
+ {
+ bool ovf = true;
+
+ tree cst = NULL_TREE;
+ tree inner_type = TREE_TYPE (@3);
+ value_range vr = VR_INITIALIZER;
+
+ /* Convert combined constant to tree of outer type if
+ there was no overflow in the original operation. */
+ wide_int minv, maxv;
+ if (TYPE_OVERFLOW_UNDEFINED (inner_type)
+ || (extract_range_from_binary_expr (&vr, inner_op,
+ inner_type, @0, @1, &ovf), vr.type == VR_RANGE))
+ {
+ wide_int w1 = @1;
+ wide_int w2 = @2;
+
+ wide_int combined_cst;
+
+ /* Extend @1 to TYPE. */
+ w1 = w1.from (w1, TYPE_PRECISION (type),
+ ovf ? SIGNED : TYPE_SIGN (TREE_TYPE (@1)));
+
+ if (inner_op == MINUS_EXPR)
+ w1 = wi::neg (w1);
+
+ if (outer_op == MINUS_EXPR)
+ w2 = wi::neg (w2);
+
+ /* Combine in outer, larger type. */
+ combined_cst = wi::add (w1, w2);
+
+ cst = wide_int_to_tree (type, combined_cst);
+ }
+ }
+ (if (cst)
+ (outer_op (convert @0) { cst; }))
+ )))))
+#endif
+
+/* ((T)(A)) +- CST -> (T)(A +- CST) */
+#if GIMPLE
+ (for outer_op (plus minus)
+ (simplify
+ (outer_op (convert @0) INTEGER_CST@2)
+ (if (TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+ && TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
+ && TREE_CODE (type) == INTEGER_TYPE)
+ /* Perform binary operation inside the cast if the constant fits
+ and there is no overflow. */
+ (with
+ {
+ bool ovf = true;
+ tree cst_inner = NULL_TREE;
+ value_range vr = VR_INITIALIZER;
+
+ bool fits = int_fits_type_p (@2, TREE_TYPE (@0));
+ if (fits)
+ {
+ tree cst_inner = fold_convert (TREE_TYPE (@0), @2);
+
+ extract_range_from_binary_expr (&vr, outer_op, TREE_TYPE (@0),
+ @0, cst_inner, &ovf);
+ }
+ }
+ (if (vr.type == VR_RANGE && cst_inner)
+ (convert (outer_op @0 { cst_inner; })))
+ ))))
+#endif
+
/* ~A + A -> -1 */
(simplify
(plus:c (bit_not @0) @0)
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 0db8a3c..00f99a8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -63,8 +63,6 @@ along with GCC; see the file COPYING3. If not see
#include "domwalk.h"
#include "tree-cfgcleanup.h"
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
/* Allocation pools for tree-vrp allocations. */
static object_allocator<value_range> vrp_value_range_pool ("Tree VRP value ranges");
static bitmap_obstack vrp_equiv_obstack;
@@ -1940,7 +1938,8 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
static void
extract_range_from_binary_expr_1 (value_range *vr,
enum tree_code code, tree expr_type,
- value_range *vr0_, value_range *vr1_)
+ value_range *vr0_, value_range *vr1_,
+ bool *ovf)
{
value_range vr0 = *vr0_, vr1 = *vr1_;
value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
@@ -2012,12 +2011,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
if (vr0.type == VR_ANTI_RANGE
&& ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
{
- extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
+ extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_,
+ ovf);
if (vrtem1.type != VR_UNDEFINED)
{
value_range vrres = VR_INITIALIZER;
extract_range_from_binary_expr_1 (&vrres, code, expr_type,
- &vrtem1, vr1_);
+ &vrtem1, vr1_, ovf);
vrp_meet (vr, &vrres);
}
return;
@@ -2026,12 +2026,13 @@ extract_range_from_binary_expr_1 (value_range *vr,
if (vr1.type == VR_ANTI_RANGE
&& ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
{
- extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
+ extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0,
+ ovf);
if (vrtem1.type != VR_UNDEFINED)
{
value_range vrres = VR_INITIALIZER;
extract_range_from_binary_expr_1 (&vrres, code, expr_type,
- vr0_, &vrtem1);
+ vr0_, &vrtem1, ovf);
vrp_meet (vr, &vrres);
}
return;
@@ -2270,6 +2271,10 @@ extract_range_from_binary_expr_1 (value_range *vr,
max_ovf = 1;
}
+ if (ovf != NULL)
+ *ovf = (min_ovf == 1 && max_ovf == 1)
+ || (min_ovf == -1 && max_ovf == -1);
+
/* If we have overflow for the constant part and the resulting
range will be symbolic, drop to VR_VARYING. */
if ((min_ovf && sym_min_op0 != sym_min_op1)
@@ -2589,7 +2594,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
saved_flag_wrapv = flag_wrapv;
flag_wrapv = 1;
extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
- &vr0, &vr1p);
+ &vr0, &vr1p, ovf);
flag_wrapv = saved_flag_wrapv;
return;
}
@@ -3012,14 +3017,24 @@ extract_range_from_binary_expr_1 (value_range *vr,
set_value_range (vr, type, min, max, NULL);
}
+static void
+extract_range_from_binary_expr_1 (value_range *vr,
+ enum tree_code code, tree expr_type,
+ value_range *vr0_, value_range *vr1_)
+{
+ extract_range_from_binary_expr_1 (vr, code, expr_type,
+ vr0_, vr1_, NULL);
+}
+
/* Extract range information from a binary expression OP0 CODE OP1 based on
the ranges of each of its operands with resulting type EXPR_TYPE.
The resulting range is stored in *VR. */
-static void
+void
extract_range_from_binary_expr (value_range *vr,
enum tree_code code,
- tree expr_type, tree op0, tree op1)
+ tree expr_type, tree op0, tree op1,
+ bool *ovf)
{
value_range vr0 = VR_INITIALIZER;
value_range vr1 = VR_INITIALIZER;
@@ -3027,20 +3042,38 @@ extract_range_from_binary_expr (value_range *vr,
/* Get value ranges for each operand. For constant operands, create
a new value range with the operand to simplify processing. */
if (TREE_CODE (op0) == SSA_NAME)
- vr0 = *(get_value_range (op0));
+ {
+ value_range *vtmp = get_value_range (op0);
+ if (ovf != NULL && vtmp == NULL)
+ {
+ vr->type = VR_VARYING;
+ return;
+ }
+ else
+ vr0 = *vtmp;
+ }
else if (is_gimple_min_invariant (op0))
set_value_range_to_value (&vr0, op0, NULL);
else
set_value_range_to_varying (&vr0);
if (TREE_CODE (op1) == SSA_NAME)
- vr1 = *(get_value_range (op1));
+ {
+ value_range *vtmp = get_value_range (op1);
+ if (ovf != NULL && vtmp == NULL)
+ {
+ vr->type = VR_VARYING;
+ return;
+ }
+ else
+ vr1 = *vtmp;
+ }
else if (is_gimple_min_invariant (op1))
set_value_range_to_value (&vr1, op1, NULL);
else
set_value_range_to_varying (&vr1);
- extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
+ extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1, ovf);
/* Try harder for PLUS and MINUS if the range of one operand is symbolic
and based on the other operand, for example if it was deduced from a
@@ -3068,7 +3101,7 @@ extract_range_from_binary_expr (value_range *vr,
else
set_value_range (&n_vr1, VR_RANGE, op1, op1, NULL);
- extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
+ extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1, ovf);
}
if (vr->type == VR_VARYING
@@ -3092,7 +3125,7 @@ extract_range_from_binary_expr (value_range *vr,
else
set_value_range (&n_vr0, VR_RANGE, op0, op0, NULL);
- extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1);
+ extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1, ovf);
}
/* If we didn't derive a range for MINUS_EXPR, and
@@ -3111,6 +3144,14 @@ extract_range_from_binary_expr (value_range *vr,
set_value_range_to_nonnull (vr, TREE_TYPE (op0));
}
+void
+extract_range_from_binary_expr (value_range *vr,
+ enum tree_code code,
+ tree expr_type, tree op0, tree op1)
+{
+ extract_range_from_binary_expr (vr, code, expr_type, op0, op1, NULL);
+}
+
/* Extract range information from a unary operation CODE based on
the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
The resulting range is stored in *VR. */
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index ef2c68a..ad55ad2 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -56,4 +56,9 @@ extern void extract_range_from_unary_expr (value_range *vr,
tree type,
value_range *vr0_,
tree op0_type);
+extern void extract_range_from_binary_expr (value_range *vr,
+ enum tree_code code,
+ tree expr_type, tree op0, tree op1,
+ bool *ovf);
+#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }