match.pd part of the patch. gcc/ChangeLog:
2017-05-18 Robin Dapp <rd...@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 }