From: Aldy Hernandez Date: Mon, 2 Jul 2018 12:18:00 +0000 (+0000) Subject: Abstract a lot of the {PLUS,MINUS}_EXPR code in X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=94ee1558a839de8bf20f4e89aebe8d1453fb6015;p=gcc.git Abstract a lot of the {PLUS,MINUS}_EXPR code in extract_range_from_binary_expr_1 into separate functions. From-SVN: r262306 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b4874ca72db..15f2749d492 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2018-07-02 Aldy Hernandez + + * tree-vrp.c (extract_range_from_binary_expr_1): Abstract a lot of the + {PLUS,MINUS}_EXPR code to... + (adjust_symbolic_bound): ...here, + (combine_bound): ...here, + (set_value_range_with_overflow): ...and here. + 2018-07-02 Aldy Hernandez * tree-vrp.c (extract_range_from_unary_expr): Abstract ABS_EXPR diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 42436b38eba..c966334acbc 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -1275,6 +1275,196 @@ extract_range_from_multiplicative_op_1 (value_range *vr, wide_int_to_tree (type, max), NULL); } +/* If BOUND will include a symbolic bound, adjust it accordingly, + otherwise leave it as is. + + CODE is the original operation that combined the bounds (PLUS_EXPR + or MINUS_EXPR). + + TYPE is the type of the original operation. + + SYM_OPn is the symbolic for OPn if it has a symbolic. + + NEG_OPn is TRUE if the OPn was negated. */ + +static void +adjust_symbolic_bound (tree &bound, enum tree_code code, tree type, + tree sym_op0, tree sym_op1, + bool neg_op0, bool neg_op1) +{ + bool minus_p = (code == MINUS_EXPR); + /* If the result bound is constant, we're done; otherwise, build the + symbolic lower bound. */ + if (sym_op0 == sym_op1) + ; + else if (sym_op0) + bound = build_symbolic_expr (type, sym_op0, + neg_op0, bound); + else if (sym_op1) + { + /* We may not negate if that might introduce + undefined overflow. */ + if (!minus_p + || neg_op1 + || TYPE_OVERFLOW_WRAPS (type)) + bound = build_symbolic_expr (type, sym_op1, + neg_op1 ^ minus_p, bound); + else + bound = NULL_TREE; + } +} + +/* Combine OP1 and OP1, which are two parts of a bound, into one wide + int bound according to CODE. CODE is the operation combining the + bound (either a PLUS_EXPR or a MINUS_EXPR). + + TYPE is the type of the combine operation. + + WI is the wide int to store the result. + + OVF is -1 if an underflow occurred, +1 if an overflow occurred or 0 + if over/underflow occurred. */ + +static void +combine_bound (enum tree_code code, wide_int &wi, int &ovf, + tree type, tree op0, tree op1) +{ + bool minus_p = (code == MINUS_EXPR); + const signop sgn = TYPE_SIGN (type); + const unsigned int prec = TYPE_PRECISION (type); + + /* Combine the bounds, if any. */ + if (op0 && op1) + { + if (minus_p) + { + wi = wi::to_wide (op0) - wi::to_wide (op1); + + /* Check for overflow. */ + if (wi::cmp (0, wi::to_wide (op1), sgn) + != wi::cmp (wi, wi::to_wide (op0), sgn)) + ovf = wi::cmp (wi::to_wide (op0), + wi::to_wide (op1), sgn); + } + else + { + wi = wi::to_wide (op0) + wi::to_wide (op1); + + /* Check for overflow. */ + if (wi::cmp (wi::to_wide (op1), 0, sgn) + != wi::cmp (wi, wi::to_wide (op0), sgn)) + ovf = wi::cmp (wi::to_wide (op0), wi, sgn); + } + } + else if (op0) + wi = wi::to_wide (op0); + else if (op1) + { + if (minus_p) + { + wi = -wi::to_wide (op1); + + /* Check for overflow. */ + if (sgn == SIGNED + && wi::neg_p (wi::to_wide (op1)) + && wi::neg_p (wi)) + ovf = 1; + else if (sgn == UNSIGNED && wi::to_wide (op1) != 0) + ovf = -1; + } + else + wi = wi::to_wide (op1); + } + else + wi = wi::shwi (0, prec); +} + +/* Given a range in [WMIN, WMAX], adjust it for possible overflow and + put the result in VR. + + TYPE is the type of the range. + + MIN_OVF and MAX_OVF indicate what type of overflow, if any, + occurred while originally calculating WMIN or WMAX. -1 indicates + underflow. +1 indicates overflow. 0 indicates neither. */ + +static void +set_value_range_with_overflow (value_range &vr, + tree type, + const wide_int &wmin, const wide_int &wmax, + int min_ovf, int max_ovf) +{ + const signop sgn = TYPE_SIGN (type); + const unsigned int prec = TYPE_PRECISION (type); + vr.type = VR_RANGE; + vr.equiv = NULL; + if (TYPE_OVERFLOW_WRAPS (type)) + { + /* If overflow wraps, truncate the values and adjust the + range kind and bounds appropriately. */ + wide_int tmin = wide_int::from (wmin, prec, sgn); + wide_int tmax = wide_int::from (wmax, prec, sgn); + if (min_ovf == max_ovf) + { + /* No overflow or both overflow or underflow. The + range kind stays VR_RANGE. */ + vr.min = wide_int_to_tree (type, tmin); + vr.max = wide_int_to_tree (type, tmax); + } + else if ((min_ovf == -1 && max_ovf == 0) + || (max_ovf == 1 && min_ovf == 0)) + { + /* Min underflow or max overflow. The range kind + changes to VR_ANTI_RANGE. */ + bool covers = false; + wide_int tem = tmin; + vr.type = VR_ANTI_RANGE; + tmin = tmax + 1; + if (wi::cmp (tmin, tmax, sgn) < 0) + covers = true; + tmax = tem - 1; + if (wi::cmp (tmax, tem, sgn) > 0) + covers = true; + /* If the anti-range would cover nothing, drop to varying. + Likewise if the anti-range bounds are outside of the + types values. */ + if (covers || wi::cmp (tmin, tmax, sgn) > 0) + { + set_value_range_to_varying (&vr); + return; + } + vr.min = wide_int_to_tree (type, tmin); + vr.max = wide_int_to_tree (type, tmax); + } + else + { + /* Other underflow and/or overflow, drop to VR_VARYING. */ + set_value_range_to_varying (&vr); + return; + } + } + else + { + /* If overflow does not wrap, saturate to the types min/max + value. */ + wide_int type_min = wi::min_value (prec, sgn); + wide_int type_max = wi::max_value (prec, sgn); + if (min_ovf == -1) + vr.min = wide_int_to_tree (type, type_min); + else if (min_ovf == 1) + vr.min = wide_int_to_tree (type, type_max); + else + vr.min = wide_int_to_tree (type, wmin); + + if (max_ovf == -1) + vr.max = wide_int_to_tree (type, type_min); + else if (max_ovf == 1) + vr.max = wide_int_to_tree (type, type_max); + else + vr.max = wide_int_to_tree (type, wmax); + } +} + /* Extract range information from a binary operation CODE based on the ranges of each of its operands *VR0 and *VR1 with resulting type EXPR_TYPE. The resulting range is stored in *VR. */ @@ -1495,128 +1685,13 @@ extract_range_from_binary_expr_1 (value_range *vr, || (sym_max_op0 == sym_max_op1 && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1)))) { - const signop sgn = TYPE_SIGN (expr_type); - const unsigned int prec = TYPE_PRECISION (expr_type); - wide_int type_min, type_max, wmin, wmax; + wide_int wmin, wmax; int min_ovf = 0; int max_ovf = 0; - /* Get the lower and upper bounds of the type. */ - if (TYPE_OVERFLOW_WRAPS (expr_type)) - { - type_min = wi::min_value (prec, sgn); - type_max = wi::max_value (prec, sgn); - } - else - { - type_min = wi::to_wide (vrp_val_min (expr_type)); - type_max = wi::to_wide (vrp_val_max (expr_type)); - } - - /* Combine the lower bounds, if any. */ - if (min_op0 && min_op1) - { - if (minus_p) - { - wmin = wi::to_wide (min_op0) - wi::to_wide (min_op1); - - /* Check for overflow. */ - if (wi::cmp (0, wi::to_wide (min_op1), sgn) - != wi::cmp (wmin, wi::to_wide (min_op0), sgn)) - min_ovf = wi::cmp (wi::to_wide (min_op0), - wi::to_wide (min_op1), sgn); - } - else - { - wmin = wi::to_wide (min_op0) + wi::to_wide (min_op1); - - /* Check for overflow. */ - if (wi::cmp (wi::to_wide (min_op1), 0, sgn) - != wi::cmp (wmin, wi::to_wide (min_op0), sgn)) - min_ovf = wi::cmp (wi::to_wide (min_op0), wmin, sgn); - } - } - else if (min_op0) - wmin = wi::to_wide (min_op0); - else if (min_op1) - { - if (minus_p) - { - wmin = -wi::to_wide (min_op1); - - /* Check for overflow. */ - if (sgn == SIGNED - && wi::neg_p (wi::to_wide (min_op1)) - && wi::neg_p (wmin)) - min_ovf = 1; - else if (sgn == UNSIGNED && wi::to_wide (min_op1) != 0) - min_ovf = -1; - } - else - wmin = wi::to_wide (min_op1); - } - else - wmin = wi::shwi (0, prec); - - /* Combine the upper bounds, if any. */ - if (max_op0 && max_op1) - { - if (minus_p) - { - wmax = wi::to_wide (max_op0) - wi::to_wide (max_op1); - - /* Check for overflow. */ - if (wi::cmp (0, wi::to_wide (max_op1), sgn) - != wi::cmp (wmax, wi::to_wide (max_op0), sgn)) - max_ovf = wi::cmp (wi::to_wide (max_op0), - wi::to_wide (max_op1), sgn); - } - else - { - wmax = wi::to_wide (max_op0) + wi::to_wide (max_op1); - - if (wi::cmp (wi::to_wide (max_op1), 0, sgn) - != wi::cmp (wmax, wi::to_wide (max_op0), sgn)) - max_ovf = wi::cmp (wi::to_wide (max_op0), wmax, sgn); - } - } - else if (max_op0) - wmax = wi::to_wide (max_op0); - else if (max_op1) - { - if (minus_p) - { - wmax = -wi::to_wide (max_op1); - - /* Check for overflow. */ - if (sgn == SIGNED - && wi::neg_p (wi::to_wide (max_op1)) - && wi::neg_p (wmax)) - max_ovf = 1; - else if (sgn == UNSIGNED && wi::to_wide (max_op1) != 0) - max_ovf = -1; - } - else - wmax = wi::to_wide (max_op1); - } - else - wmax = wi::shwi (0, prec); - - /* Check for type overflow. */ - if (min_ovf == 0) - { - if (wi::cmp (wmin, type_min, sgn) == -1) - min_ovf = -1; - else if (wi::cmp (wmin, type_max, sgn) == 1) - min_ovf = 1; - } - if (max_ovf == 0) - { - if (wi::cmp (wmax, type_min, sgn) == -1) - max_ovf = -1; - else if (wi::cmp (wmax, type_max, sgn) == 1) - max_ovf = 1; - } + /* Build the bounds. */ + combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1); + combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1); /* If we have overflow for the constant part and the resulting range will be symbolic, drop to VR_VARYING. */ @@ -1627,108 +1702,24 @@ extract_range_from_binary_expr_1 (value_range *vr, return; } - if (TYPE_OVERFLOW_WRAPS (expr_type)) - { - /* If overflow wraps, truncate the values and adjust the - range kind and bounds appropriately. */ - wide_int tmin = wide_int::from (wmin, prec, sgn); - wide_int tmax = wide_int::from (wmax, prec, sgn); - if (min_ovf == max_ovf) - { - /* No overflow or both overflow or underflow. The - range kind stays VR_RANGE. */ - min = wide_int_to_tree (expr_type, tmin); - max = wide_int_to_tree (expr_type, tmax); - } - else if ((min_ovf == -1 && max_ovf == 0) - || (max_ovf == 1 && min_ovf == 0)) - { - /* Min underflow or max overflow. The range kind - changes to VR_ANTI_RANGE. */ - bool covers = false; - wide_int tem = tmin; - type = VR_ANTI_RANGE; - tmin = tmax + 1; - if (wi::cmp (tmin, tmax, sgn) < 0) - covers = true; - tmax = tem - 1; - if (wi::cmp (tmax, tem, sgn) > 0) - covers = true; - /* If the anti-range would cover nothing, drop to varying. - Likewise if the anti-range bounds are outside of the - types values. */ - if (covers || wi::cmp (tmin, tmax, sgn) > 0) - { - set_value_range_to_varying (vr); - return; - } - min = wide_int_to_tree (expr_type, tmin); - max = wide_int_to_tree (expr_type, tmax); - } - else - { - /* Other underflow and/or overflow, drop to VR_VARYING. */ - set_value_range_to_varying (vr); - return; - } - } - else - { - /* If overflow does not wrap, saturate to the types min/max - value. */ - if (min_ovf == -1) - min = wide_int_to_tree (expr_type, type_min); - else if (min_ovf == 1) - min = wide_int_to_tree (expr_type, type_max); - else - min = wide_int_to_tree (expr_type, wmin); - - if (max_ovf == -1) - max = wide_int_to_tree (expr_type, type_min); - else if (max_ovf == 1) - max = wide_int_to_tree (expr_type, type_max); - else - max = wide_int_to_tree (expr_type, wmax); - } - - /* If the result lower bound is constant, we're done; - otherwise, build the symbolic lower bound. */ - if (sym_min_op0 == sym_min_op1) - ; - else if (sym_min_op0) - min = build_symbolic_expr (expr_type, sym_min_op0, - neg_min_op0, min); - else if (sym_min_op1) - { - /* We may not negate if that might introduce - undefined overflow. */ - if (! minus_p - || neg_min_op1 - || TYPE_OVERFLOW_WRAPS (expr_type)) - min = build_symbolic_expr (expr_type, sym_min_op1, - neg_min_op1 ^ minus_p, min); - else - min = NULL_TREE; - } - - /* Likewise for the upper bound. */ - if (sym_max_op0 == sym_max_op1) - ; - else if (sym_max_op0) - max = build_symbolic_expr (expr_type, sym_max_op0, - neg_max_op0, max); - else if (sym_max_op1) - { - /* We may not negate if that might introduce - undefined overflow. */ - if (! minus_p - || neg_max_op1 - || TYPE_OVERFLOW_WRAPS (expr_type)) - max = build_symbolic_expr (expr_type, sym_max_op1, - neg_max_op1 ^ minus_p, max); - else - max = NULL_TREE; - } + /* Adjust the range for possible overflow. */ + set_value_range_with_overflow (*vr, expr_type, + wmin, wmax, min_ovf, max_ovf); + if (vr->type == VR_VARYING) + return; + + /* Build the symbolic bounds if needed. */ + adjust_symbolic_bound (vr->min, code, expr_type, + sym_min_op0, sym_min_op1, + neg_min_op0, neg_min_op1); + adjust_symbolic_bound (vr->max, code, expr_type, + sym_max_op0, sym_max_op1, + neg_max_op0, neg_max_op1); + /* ?? It would probably be cleaner to eliminate min/max/type + entirely and hold these values in VR directly. */ + min = vr->min; + max = vr->max; + type = vr->type; } else {