diff options
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 2265 |
1 files changed, 2265 insertions, 0 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c new file mode 100644 index 00000000000..e4adcfaf8d1 --- /dev/null +++ b/gcc/tree-vrp.c @@ -0,0 +1,2265 @@ +/* Support routines for Value Range Propagation (VRP). + Copyright (C) 2005 Free Software Foundation, Inc. + Contributed by Diego Novillo <dnovillo@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "ggc.h" +#include "flags.h" +#include "tree.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "tree-dump.h" +#include "timevar.h" +#include "diagnostic.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" +#include "tree-ssa-propagate.h" +#include "tree-chrec.h" + +/* Set of SSA names found during the dominator traversal of a + sub-graph in maybe_add_assert_expr_on_edges. */ +static sbitmap found; + +/* Loop structure of the program. Used to analyze scalar evolutions + inside adjust_range_with_scev. */ +static struct loops *cfg_loops; + +/* Local functions. */ +static int compare_values (tree val1, tree val2); + +/* Given a conditional predicate COND that has WHICH as one of its + operands, return the other operand. No error checking is done. + This helper assumes that COND is a comparison and WHICH is one of + its operands. */ + +static inline tree +get_opposite_operand (tree cond, tree which) +{ + if (TREE_OPERAND (cond, 0) == which) + return TREE_OPERAND (cond, 1); + else + return TREE_OPERAND (cond, 0); +} + + +/* Given a comparison code, return its opposite. Note that this is *not* + the same as inverting its truth value (invert_tree_comparison). Here we + just want to literally flip the comparison around. + + So, '<' gets '>', '<=' gets '>='. Both '==' and '!=' are returned + unchanged. */ + +static enum tree_code +opposite_comparison (enum tree_code code) +{ + switch (code) + { + case EQ_EXPR: + case NE_EXPR: + case ORDERED_EXPR: + case UNORDERED_EXPR: + case LTGT_EXPR: + case UNEQ_EXPR: + return code; + case GT_EXPR: + return LT_EXPR; + case GE_EXPR: + return LE_EXPR; + case LT_EXPR: + return GT_EXPR; + case LE_EXPR: + return GE_EXPR; + case UNGT_EXPR: + return UNLT_EXPR; + case UNGE_EXPR: + return UNLE_EXPR; + case UNLT_EXPR: + return UNGT_EXPR; + case UNLE_EXPR: + return UNGE_EXPR; + default: + gcc_unreachable (); + } +} + + +/* Set value range VR to {T, MIN, MAX}. */ + +static inline void +set_value_range (value_range *vr, enum value_range_type t, tree min, tree max) +{ +#if defined ENABLE_CHECKING + if (t == VR_RANGE || t == VR_ANTI_RANGE) + { + int cmp; + + gcc_assert (min && max); + + if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE) + gcc_assert (min != TYPE_MIN_VALUE (TREE_TYPE (min)) + || max != TYPE_MAX_VALUE (TREE_TYPE (max))); + + cmp = compare_values (min, max); + gcc_assert (cmp == 0 || cmp == -1 || cmp == -2); + } +#endif + + if (t == VR_RANGE + && INTEGRAL_TYPE_P (TREE_TYPE (min)) + && min == TYPE_MIN_VALUE (TREE_TYPE (min)) + && max == TYPE_MAX_VALUE (TREE_TYPE (max))) + { + /* Ranges that cover all the possible values for the type decay + to VARYING. */ + vr->type = VR_VARYING; + vr->min = NULL_TREE; + vr->max = NULL_TREE; + return; + } + + vr->type = t; + vr->min = min; + vr->max = max; +} + + +/* Similar to set_value_range but return true if any field of VR + changed from its previous value. */ + +static inline bool +update_value_range (value_range *vr, enum value_range_type t, tree min, + tree max) +{ + bool is_new = vr->type != t || vr->min != min || vr->max != max; + if (is_new) + set_value_range (vr, t, min, max); + + return is_new; +} + + +/* Return value range information for VAR. Create an empty range if + none existed. */ + +value_range * +get_value_range (tree var) +{ + value_range *vr; + tree sym; + + vr = SSA_NAME_VALUE_RANGE (var); + if (vr) + return vr; + + /* Create a default value range. */ + vr = ggc_alloc (sizeof (*vr)); + memset ((void *) vr, 0, sizeof (*vr)); + SSA_NAME_VALUE_RANGE (var) = vr; + + /* If VAR is a default definition for a PARM_DECL, then we have to + assume a VARYING range for it. */ + sym = SSA_NAME_VAR (var); + if (TREE_CODE (sym) == PARM_DECL && var == var_ann (sym)->default_def) + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + + return vr; +} + + +/* Return true if value range VR involves at least one symbol. */ + +static inline bool +symbolic_range_p (value_range *vr) +{ + return (!is_gimple_min_invariant (vr->min) + || !is_gimple_min_invariant (vr->max)); +} + + +/* Return true if EXPR computes a non-zero value. */ + +bool +expr_computes_nonzero (tree expr) +{ + /* Type casts won't change anything, so just strip it. */ + STRIP_NOPS (expr); + + /* Calling alloca, guarantees that the value is non-NULL. */ + if (alloca_call_p (expr)) + return true; + + /* The address of a non-weak symbol is never NULL, unless the user + has requested not to remove NULL pointer checks. */ + if (flag_delete_null_pointer_checks + && TREE_CODE (expr) == ADDR_EXPR + && DECL_P (TREE_OPERAND (expr, 0)) + && !DECL_WEAK (TREE_OPERAND (expr, 0))) + return true; + + /* IOR of any value with a nonzero value will result in a nonzero + value. */ + if (TREE_CODE (expr) == BIT_IOR_EXPR + && integer_nonzerop (TREE_OPERAND (expr, 1))) + return true; + + return false; +} + + +/* Return true if VR is ~[0, 0]. */ + +static inline bool +range_is_nonnull (value_range *vr) +{ + return vr->type == VR_ANTI_RANGE + && integer_zerop (vr->min) + && integer_zerop (vr->max); +} + + +/* Return true if VR is [0, 0]. */ + +static inline bool +range_is_null (value_range *vr) +{ + return vr->type == VR_RANGE + && integer_zerop (vr->min) + && integer_zerop (vr->max); +} + + +/* Set value range VR to a non-NULL range of type TYPE. */ + +static void +set_value_range_to_nonnull (value_range *vr, tree type) +{ + tree zero = build_int_cst (type, 0); + set_value_range (vr, VR_ANTI_RANGE, zero, zero); +} + + +/* Set value range VR to a NULL range of type TYPE. */ + +static void +set_value_range_to_null (value_range *vr, tree type) +{ + tree zero = build_int_cst (type, 0); + set_value_range (vr, VR_RANGE, zero, zero); +} + + +/* Compare two values VAL1 and VAL2. Return + + -2 if VAL1 and VAL2 cannot be compared at compile-time, + -1 if VAL1 < VAL2, + 0 if VAL1 == VAL2, + +1 if VAL1 > VAL2, and + +2 if VAL1 != VAL2 + + This is similar to tree_int_cst_compare but supports pointer values + and values that cannot be compared at compile time. */ + +static int +compare_values (tree val1, tree val2) +{ + if (val1 == val2) + return 0; + + /* Do some limited symbolic comparisons. */ + if (!POINTER_TYPE_P (TREE_TYPE (val1))) + { + /* We can determine some comparisons against +INF and -INF even + if the other value is an expression. */ + if (val1 == TYPE_MAX_VALUE (TREE_TYPE (val1)) + && TREE_CODE (val2) == MINUS_EXPR) + { + /* +INF > NAME - CST. */ + return 1; + } + else if (val1 == TYPE_MIN_VALUE (TREE_TYPE (val1)) + && TREE_CODE (val2) == PLUS_EXPR) + { + /* -INF < NAME + CST. */ + return -1; + } + else if (TREE_CODE (val1) == MINUS_EXPR + && val2 == TYPE_MAX_VALUE (TREE_TYPE (val2))) + { + /* NAME - CST < +INF. */ + return -1; + } + else if (TREE_CODE (val1) == PLUS_EXPR + && val2 == TYPE_MIN_VALUE (TREE_TYPE (val2))) + { + /* NAME + CST > -INF. */ + return 1; + } + } + + if ((TREE_CODE (val1) == SSA_NAME + || TREE_CODE (val1) == PLUS_EXPR + || TREE_CODE (val1) == MINUS_EXPR) + && (TREE_CODE (val2) == SSA_NAME + || TREE_CODE (val2) == PLUS_EXPR + || TREE_CODE (val2) == MINUS_EXPR)) + { + tree n1, c1, n2, c2; + + /* If VAL1 and VAL2 are of the form 'NAME [+-] CST' or 'NAME', + return -1 or +1 accordingly. If VAL1 and VAL2 don't use the + same name, return -2. */ + if (TREE_CODE (val1) == SSA_NAME) + { + n1 = val1; + c1 = NULL_TREE; + } + else + { + n1 = TREE_OPERAND (val1, 0); + c1 = TREE_OPERAND (val1, 1); + } + + if (TREE_CODE (val2) == SSA_NAME) + { + n2 = val2; + c2 = NULL_TREE; + } + else + { + n2 = TREE_OPERAND (val2, 0); + c2 = TREE_OPERAND (val2, 1); + } + + /* Both values must use the same name. */ + if (n1 != n2) + return -2; + + if (TREE_CODE (val1) == SSA_NAME) + { + if (TREE_CODE (val2) == SSA_NAME) + /* NAME == NAME */ + return 0; + else if (TREE_CODE (val2) == PLUS_EXPR) + /* NAME < NAME + CST */ + return -1; + else if (TREE_CODE (val2) == MINUS_EXPR) + /* NAME > NAME - CST */ + return 1; + } + else if (TREE_CODE (val1) == PLUS_EXPR) + { + if (TREE_CODE (val2) == SSA_NAME) + /* NAME + CST > NAME */ + return 1; + else if (TREE_CODE (val2) == PLUS_EXPR) + /* NAME + CST1 > NAME + CST2, if CST1 > CST2 */ + return compare_values (c1, c2); + else if (TREE_CODE (val2) == MINUS_EXPR) + /* NAME + CST1 > NAME - CST2 */ + return 1; + } + else if (TREE_CODE (val1) == MINUS_EXPR) + { + if (TREE_CODE (val2) == SSA_NAME) + /* NAME - CST < NAME */ + return -1; + else if (TREE_CODE (val2) == PLUS_EXPR) + /* NAME - CST1 < NAME + CST2 */ + return -1; + else if (TREE_CODE (val2) == MINUS_EXPR) + /* NAME - CST1 > NAME - CST2, if CST1 < CST2. Notice that + C1 and C2 are swapped in the call to compare_values. */ + return compare_values (c2, c1); + } + + gcc_unreachable (); + } + + /* We cannot compare non-constants. */ + if (!is_gimple_min_invariant (val1) || !is_gimple_min_invariant (val2)) + return -2; + + if (!POINTER_TYPE_P (TREE_TYPE (val1))) + return tree_int_cst_compare (val1, val2); + else + { + tree t; + + /* First see if VAL1 and VAL2 are not the same. */ + if (val1 == val2 || operand_equal_p (val1, val2, 0)) + return 0; + + /* If VAL1 is a lower address than VAL2, return -1. */ + t = fold (build2 (LT_EXPR, TREE_TYPE (val1), val1, val2)); + if (t == boolean_true_node) + return -1; + + /* If VAL1 is a higher address than VAL2, return +1. */ + t = fold (build2 (GT_EXPR, TREE_TYPE (val1), val1, val2)); + if (t == boolean_true_node) + return 1; + + /* If VAL1 is different than VAL2, return +2. */ + t = fold (build2 (NE_EXPR, TREE_TYPE (val1), val1, val2)); + if (t == boolean_true_node) + return 2; + + return -2; + } +} + + +/* Return 1 if VAL is inside value range VR (VR->MIN <= VAL <= VR->MAX), + 0 if VAL is not inside VR, + -2 if we cannot tell either way. */ + +static inline int +value_inside_range (tree val, value_range *vr) +{ + int cmp1, cmp2; + + cmp1 = compare_values (val, vr->min); + if (cmp1 == -2 || cmp1 == 2) + return -2; + + cmp2 = compare_values (val, vr->max); + if (cmp2 == -2 || cmp2 == 2) + return -2; + + return (cmp1 == 0 || cmp1 == 1) && (cmp2 == -1 || cmp2 == 0); +} + + +/* Return true if value ranges VR0 and VR1 have a non-empty + intersection. */ + +static inline bool +value_ranges_intersect_p (value_range *vr0, value_range *vr1) +{ + return (value_inside_range (vr1->min, vr0) == 1 + || value_inside_range (vr1->max, vr0) == 1 + || value_inside_range (vr0->min, vr1) == 1 + || value_inside_range (vr0->max, vr1) == 1); +} + + +/* Extract value range information from an ASSERT_EXPR EXPR and store + it in *VR_P. */ + +static void +extract_range_from_assert (value_range *vr_p, tree expr) +{ + tree var, cond, limit, type; + value_range *var_vr; + + var = ASSERT_EXPR_VAR (expr); + cond = ASSERT_EXPR_COND (expr); + + gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison); + + /* Find VAR in the ASSERT_EXPR conditional. */ + limit = get_opposite_operand (cond, var); + type = TREE_TYPE (limit); + + gcc_assert (limit != var); + + /* For pointer arithmetic, we only keep track of anti-ranges + (NE_EXPR). Notice that we don't need to handle EQ_EXPR in these + cases because assertions with equalities are never generated. + The assert pass generates straight assignments in those cases. */ + if (POINTER_TYPE_P (type) && TREE_CODE (cond) != NE_EXPR) + { + set_value_range (vr_p, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + if (TREE_CODE (cond) == NE_EXPR) + set_value_range (vr_p, VR_ANTI_RANGE, limit, limit); + else if (TREE_CODE (cond) == LE_EXPR) + set_value_range (vr_p, VR_RANGE, TYPE_MIN_VALUE (type), limit); + else if (TREE_CODE (cond) == LT_EXPR) + { + tree one = build_int_cst (type, 1); + set_value_range (vr_p, VR_RANGE, TYPE_MIN_VALUE (type), + fold (build (MINUS_EXPR, type, limit, one))); + } + else if (TREE_CODE (cond) == GE_EXPR) + set_value_range (vr_p, VR_RANGE, limit, TYPE_MAX_VALUE (type)); + else if (TREE_CODE (cond) == GT_EXPR) + { + tree one = build_int_cst (type, 1); + set_value_range (vr_p, VR_RANGE, + fold (build (PLUS_EXPR, type, limit, one)), + TYPE_MAX_VALUE (type)); + } + else + gcc_unreachable (); + + /* If VAR already has a known range and the two ranges have a + non-empty intersection, we can refine the resulting range. + Since the assert expression creates an equivalency and at the + same time it asserts a predicate, we can take the intersection of + the two ranges to get better precision. */ + var_vr = get_value_range (var); + if (var_vr->type == VR_RANGE + && vr_p->type == VR_RANGE + && value_ranges_intersect_p (var_vr, vr_p)) + { + tree min, max; + + /* Use the larger of the two minimums. */ + if (compare_values (vr_p->min, var_vr->min) == -1) + min = var_vr->min; + else + min = vr_p->min; + + /* Use the smaller of the two maximums. */ + if (compare_values (vr_p->max, var_vr->max) == 1) + max = var_vr->max; + else + max = vr_p->max; + + set_value_range (vr_p, vr_p->type, min, max); + } +} + + +/* Extract range information from SSA name VAR and store it in VR. If + VAR has an interesting range, use it. Otherwise, create the + range [VAR, VAR] and return it. This is useful in situations where + we may have conditionals testing values of VARYING names. For + instance, + + x_3 = y_5; + if (x_3 > y_5) + ... + + Even if y_5 is deemed VARYING, we can determine that x_3 > y_5 is + always false. */ + +static void +extract_range_from_ssa_name (value_range *vr, tree var) +{ + value_range *var_vr = get_value_range (var); + + if (var_vr->type != VR_UNDEFINED && var_vr->type != VR_VARYING) + *vr = *var_vr; + else + set_value_range (vr, VR_RANGE, var, var); +} + + +/* Extract range information from a binary expression EXPR based on + the ranges of each of its operands and the expression code. */ + +static void +extract_range_from_binary_expr (value_range *vr, tree expr) +{ + enum tree_code code = TREE_CODE (expr); + tree op0, op1, min, max; + value_range vr0, vr1; + int cmp; + + /* Not all binary expressions can be applied to ranges in a + meaningful way. Handle only arithmetic operations. */ + if (code != PLUS_EXPR + && code != MINUS_EXPR + && code != MULT_EXPR + && code != TRUNC_DIV_EXPR + && code != FLOOR_DIV_EXPR + && code != CEIL_DIV_EXPR + && code != EXACT_DIV_EXPR + && code != ROUND_DIV_EXPR + && code != MIN_EXPR + && code != MAX_EXPR) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* Get value ranges for each operand. For constant operands, create + a new value range with the operand to simplify processing. */ + op0 = TREE_OPERAND (expr, 0); + if (TREE_CODE (op0) == SSA_NAME) + vr0 = *(get_value_range (op0)); + else + { + if (is_gimple_min_invariant (op0)) + set_value_range (&vr0, VR_RANGE, op0, op0); + else + set_value_range (&vr0, VR_VARYING, NULL_TREE, NULL_TREE); + } + + op1 = TREE_OPERAND (expr, 1); + if (TREE_CODE (op1) == SSA_NAME) + vr1 = *(get_value_range (op1)); + else + { + if (is_gimple_min_invariant (op1)) + set_value_range (&vr1, VR_RANGE, op1, op1); + else + set_value_range (&vr1, VR_VARYING, 0, 0); + } + + /* If either range is UNDEFINED, so is the result. */ + if (vr0.type == VR_UNDEFINED || vr1.type == VR_UNDEFINED) + { + set_value_range (vr, VR_UNDEFINED, NULL_TREE, NULL_TREE); + return; + } + + /* If either range is VARYING, so is the result. */ + if (vr0.type == VR_VARYING || vr1.type == VR_VARYING) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* If the ranges are of different types, the result is VARYING. */ + if (vr0.type != vr1.type) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* TODO. Refuse to do any symbolic range operations for now. */ + if (symbolic_range_p (&vr0) || symbolic_range_p (&vr1)) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* Now evaluate the expression to determine the new range. */ + if (POINTER_TYPE_P (TREE_TYPE (expr)) + || POINTER_TYPE_P (TREE_TYPE (op0)) + || POINTER_TYPE_P (TREE_TYPE (op1))) + { + /* For pointer types, we are really only interested in asserting + whether the expression evaluates to non-NULL. FIXME. We + used to gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR), + but ivopts is generating expressions with pointer + multiplication in them. */ + if (code == PLUS_EXPR) + { + /* Assume that pointers can never wrap around. FIXME, Is + this always safe? */ + tree zero = build_int_cst (TREE_TYPE (expr), 0); + set_value_range (vr, VR_ANTI_RANGE, zero, zero); + } + else + { + /* Subtracting from a pointer, may yield 0, so just drop the + resulting range to varying. */ + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + } + + return; + } + + /* For integer ranges, apply the operation to each end of the + range and see what we end up with. */ + if (code == PLUS_EXPR + || code == MULT_EXPR + || code == MIN_EXPR + || code == MAX_EXPR) + { + /* For operations that make the resulting range directly + proportional to the original ranges, apply the operation to + the same end of each range. */ + min = int_const_binop (code, vr0.min, vr1.min, 0); + max = int_const_binop (code, vr0.max, vr1.max, 0); + } + else + { + /* For operations that make the resulting range inversely + proportional to the original ranges (-, /), apply the + operation to the opposite ends of each range. */ + min = int_const_binop (code, vr0.min, vr1.max, 0); + max = int_const_binop (code, vr0.max, vr1.min, 0); + } + + cmp = compare_values (min, max); + if (cmp == -2 || cmp == 1) + { + /* If the new range has its limits swapped around (MIN > MAX), + then the operation caused one of them to wrap around, mark + the new range VARYING. */ + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + } + else + set_value_range (vr, vr0.type, min, max); +} + + +/* Extract range information from a unary expression EXPR based on + the range of its operand and the expression code. */ + +static void +extract_range_from_unary_expr (value_range *vr, tree expr) +{ + enum tree_code code = TREE_CODE (expr); + tree min, max, op0; + value_range vr0; + int cmp; + + /* Get value ranges for the operand. For constant operands, create + a new value range with the operand to simplify processing. */ + op0 = TREE_OPERAND (expr, 0); + if (TREE_CODE (op0) == SSA_NAME) + vr0 = *(get_value_range (op0)); + else + { + if (is_gimple_min_invariant (op0)) + set_value_range (&vr0, VR_RANGE, op0, op0); + else + set_value_range (&vr0, VR_VARYING, NULL_TREE, NULL_TREE); + } + + /* If VR0 is UNDEFINED, so is the result. */ + if (vr0.type == VR_UNDEFINED) + { + set_value_range (vr, VR_UNDEFINED, NULL_TREE, NULL_TREE); + return; + } + + /* If VR0 is VARYING, so is the result. */ + if (vr0.type == VR_VARYING) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* TODO. Refuse to do any symbolic range operations for now. */ + if (symbolic_range_p (&vr0)) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* If the operand is neither a pointer nor an integral type, set the + range to VARYING. TODO, we may set the range to non-zero. */ + if (!INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && !POINTER_TYPE_P (TREE_TYPE (op0))) + { + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* If the expression involves pointers, we are only interested in + determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). */ + if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0))) + { + if (range_is_nonnull (&vr0) || expr_computes_nonzero (expr)) + set_value_range_to_nonnull (vr, TREE_TYPE (expr)); + else if (range_is_null (&vr0)) + set_value_range_to_null (vr, TREE_TYPE (expr)); + else + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + + return; + } + + /* Handle unary expressions on integer ranges. */ + if ((code == NOP_EXPR || code == CONVERT_EXPR) + && (TYPE_SIZE (TREE_TYPE (vr0.min)) != TYPE_SIZE (TREE_TYPE (expr)))) + { + /* When converting types of different sizes, set the result to + VARYING. Things like sign extensions and precision loss may + change the range. For instance, if x_3 is of type 'long long + int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it + is impossible to know at compile time whether y_5 will be + ~[0, 0]. */ + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + /* Apply the operation to each end of the range and see what we end + up with. */ + min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min); + max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); + + cmp = compare_values (min, max); + if (cmp == -2 || cmp == 1) + { + /* If the new range has its limits swapped around (MIN > MAX), + then the operation caused one of them to wrap around, mark + the new range VARYING. */ + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); + } + else + set_value_range (vr, vr0.type, min, max); +} + + +/* Try to compute a useful range out of expression EXPR and store it + in *VR_P. */ + +static void +extract_range_from_expr (value_range *vr, tree expr) +{ + enum tree_code code = TREE_CODE (expr); + + if (code == ASSERT_EXPR) + extract_range_from_assert (vr, expr); + else if (code == SSA_NAME) + extract_range_from_ssa_name (vr, expr); + else if (TREE_CODE_CLASS (code) == tcc_binary) + extract_range_from_binary_expr (vr, expr); + else if (TREE_CODE_CLASS (code) == tcc_unary) + extract_range_from_unary_expr (vr, expr); + else if (expr_computes_nonzero (expr)) + set_value_range_to_nonnull (vr, TREE_TYPE (expr)); + else + set_value_range (vr, VR_VARYING, NULL_TREE, NULL_TREE); +} + + +/* Given a range VR, a loop L and a variable VAR, determine whether it + would be profitable to adjust VR using scalar evolution information + for VAR. If so, update VR with the new limits. */ + +static void +adjust_range_with_scev (value_range *vr, struct loop *l, tree var) +{ + tree init, step, chrec; + bool init_is_max; + + /* TODO. Don't adjust anti-ranges. An anti-range may provide + better opportunities than a regular range, but I'm not sure. */ + if (vr->type == VR_ANTI_RANGE) + return; + + chrec = analyze_scalar_evolution (l, var); + if (TREE_CODE (chrec) != POLYNOMIAL_CHREC) + return; + + init = CHREC_LEFT (chrec); + step = CHREC_RIGHT (chrec); + + /* If STEP is symbolic, we can't know whether INIT will be the + minimum or maximum value in the range. */ + if (!is_gimple_min_invariant (step)) + return; + + /* FIXME. When dealing with unsigned types, + analyze_scalar_evolution sets STEP to very large unsigned values + when the evolution goes backwards. This confuses this analysis + because we think that INIT is the smallest value that the range + can take, instead of the largest. Ignore these chrecs for now. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (step)) && TYPE_UNSIGNED (TREE_TYPE (step))) + return; + + /* If STEP is negative, then INIT is the maximum value the range + will take. Otherwise, INIT is the minimum value. */ + init_is_max = (tree_int_cst_sgn (step) < 0); + + if (!POINTER_TYPE_P (TREE_TYPE (init)) + && (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)) + { + /* For VARYING or UNDEFINED ranges, just about anything we get + from scalar evolutions should be better. */ + if (init_is_max) + set_value_range (vr, VR_RANGE, TYPE_MIN_VALUE (TREE_TYPE (init)), init); + else + set_value_range (vr, VR_RANGE, init, TYPE_MAX_VALUE (TREE_TYPE (init))); + } + else if (vr->type == VR_RANGE) + { + if (init_is_max) + { + /* INIT is the maximum value. If INIT is lower than + VR->MAX, set VR->MAX to INIT. */ + if (compare_values (init, vr->max) == -1) + set_value_range (vr, VR_RANGE, vr->min, init); + } + else + { + /* If INIT is bigger than VR->MIN, set VR->MIN to INIT. */ + if (compare_values (init, vr->min) == 1) + set_value_range (vr, VR_RANGE, init, vr->max); + } + } +} + + +/* Given two numeric value ranges VR0, VR1 and a comparison code COMP: + + - Return BOOLEAN_TRUE_NODE if VR0 COMP VR1 always returns true for all the + values in the ranges. + + - Return BOOLEAN_FALSE_NODE if the comparison always returns false. + + - Return NULL_TREE if it is not always possible to determine the value of + the comparison. */ + +static tree +compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1) +{ + /* VARYING or UNDEFINED ranges cannot be compared. */ + if (vr0->type == VR_VARYING + || vr0->type == VR_UNDEFINED + || vr1->type == VR_VARYING + || vr1->type == VR_UNDEFINED) + return NULL_TREE; + + /* Anti-ranges need to be handled separately. */ + if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE) + { + /* If both are anti-ranges, then we cannot compute any + comparison. */ + if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE) + return NULL_TREE; + + /* These comparisons are never statically computable. */ + if (comp == GT_EXPR + || comp == GE_EXPR + || comp == LT_EXPR + || comp == LE_EXPR) + return NULL_TREE; + + /* Equality can be computed only between a range and an + anti-range. ~[VAL1, VAL2] == [VAL1, VAL2] is always false. */ + if (vr0->type == VR_RANGE) + { + /* To simplify processing, make VR0 the anti-range. */ + value_range *tmp = vr0; + vr0 = vr1; + vr1 = tmp; + } + + gcc_assert (comp == NE_EXPR || comp == EQ_EXPR); + + if (compare_values (vr0->min, vr1->min) == 0 + && compare_values (vr0->max, vr1->max) == 0) + return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node; + + return NULL_TREE; + } + + /* Simplify processing. If COMP is GT_EXPR or GE_EXPR, switch the + operands around and change the comparison code. */ + if (comp == GT_EXPR || comp == GE_EXPR) + { + value_range *tmp; + comp = (comp == GT_EXPR) ? LT_EXPR : LE_EXPR; + tmp = vr0; + vr0 = vr1; + vr1 = tmp; + } + + if (comp == EQ_EXPR) + { + /* Equality may only be computed if both ranges represent + exactly one value. */ + if (compare_values (vr0->min, vr0->max) == 0 + && compare_values (vr1->min, vr1->max) == 0) + { + int cmp_min = compare_values (vr0->min, vr1->min); + int cmp_max = compare_values (vr0->max, vr1->max); + if (cmp_min == 0 && cmp_max == 0) + return boolean_true_node; + else if (cmp_min != -2 && cmp_max != -2) + return boolean_false_node; + } + + return NULL_TREE; + } + else if (comp == NE_EXPR) + { + int cmp1, cmp2; + + /* If VR0 is completely to the left or completely to the right + of VR1, they are always different. Notice that we need to + make sure that both comparisons yield similar results to + avoid comparing values that cannot be compared at + compile-time. */ + cmp1 = compare_values (vr0->max, vr1->min); + cmp2 = compare_values (vr0->min, vr1->max); + if ((cmp1 == -1 && cmp2 == -1) || (cmp1 == 1 && cmp2 == 1)) + return boolean_true_node; + + /* If VR0 and VR1 represent a single value and are identical, + return false. */ + else if (compare_values (vr0->min, vr0->max) == 0 + && compare_values (vr1->min, vr1->max) == 0 + && compare_values (vr0->min, vr1->min) == 0 + && compare_values (vr0->max, vr1->max) == 0) + return boolean_false_node; + + /* Otherwise, they may or may not be different. */ + else + return NULL_TREE; + } + else if (comp == LT_EXPR || comp == LE_EXPR) + { + int tst; + + /* If VR0 is to the left of VR1, return true. */ + tst = compare_values (vr0->max, vr1->min); + if ((comp == LT_EXPR && tst == -1) + || (comp == LE_EXPR && (tst == -1 || tst == 0))) + return boolean_true_node; + + /* If VR0 is to the right of VR1, return false. */ + tst = compare_values (vr0->min, vr1->max); + if ((comp == LT_EXPR && (tst == 0 || tst == 1)) + || (comp == LE_EXPR && tst == 1)) + return boolean_false_node; + + /* Otherwise, we don't know. */ + return NULL_TREE; + } + + gcc_unreachable (); +} + + +/* Given a value range VR, a value VAL and a comparison code COMP, return + BOOLEAN_TRUE_NODE if VR COMP VR1 always returns true for all the + values in VR. Return BOOLEAN_FALSE_NODE if the comparison + always returns false. Return NULL_TREE if it is not always + possible to determine the value of the comparison. */ + +static tree +compare_range_with_value (enum tree_code comp, value_range *vr, tree val) +{ + if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED) + return NULL_TREE; + + /* Anti-ranges need to be handled separately. */ + if (vr->type == VR_ANTI_RANGE) + { + /* For anti-ranges, the only predicates that we can compute at + compile time are equality and inequality. */ + if (comp == GT_EXPR + || comp == GE_EXPR + || comp == LT_EXPR + || comp == LE_EXPR) + return NULL_TREE; + + /* ~[VAL, VAL] == VAL is always false. */ + if (compare_values (vr->min, val) == 0 + && compare_values (vr->max, val) == 0) + return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node; + + return NULL_TREE; + } + + if (comp == EQ_EXPR) + { + /* EQ_EXPR may only be computed if VR represents exactly + one value. */ + if (compare_values (vr->min, vr->max) == 0) + { + int cmp = compare_values (vr->min, val); + if (cmp == 0) + return boolean_true_node; + else if (cmp == -1 || cmp == 1 || cmp == 2) + return boolean_false_node; + } + + return NULL_TREE; + } + else if (comp == NE_EXPR) + { + /* If VAL is not inside VR, then they are always different. */ + if (compare_values (vr->max, val) == -1 + || compare_values (vr->min, val) == 1) + return boolean_true_node; + + /* If VR represents exactly one value equal to VAL, then return + false. */ + if (compare_values (vr->min, vr->max) == 0 + && compare_values (vr->min, val) == 0) + return boolean_false_node; + + /* Otherwise, they may or may not be different. */ + return NULL_TREE; + } + else if (comp == LT_EXPR || comp == LE_EXPR) + { + int tst; + + /* If VR is to the left of VAL, return true. */ + tst = compare_values (vr->max, val); + if ((comp == LT_EXPR && tst == -1) + || (comp == LE_EXPR && (tst == -1 || tst == 0))) + return boolean_true_node; + + /* If VR is to the right of VAL, return false. */ + tst = compare_values (vr->min, val); + if ((comp == LT_EXPR && (tst == 0 || tst == 1)) + || (comp == LE_EXPR && tst == 1)) + return boolean_false_node; + + /* Otherwise, we don't know. */ + return NULL_TREE; + } + else if (comp == GT_EXPR || comp == GE_EXPR) + { + int tst; + + /* If VR is to the right of VAL, return true. */ + tst = compare_values (vr->min, val); + if ((comp == GT_EXPR && tst == 1) + || (comp == GE_EXPR && (tst == 0 || tst == 1))) + return boolean_true_node; + + /* If VR is to the left of VAL, return false. */ + tst = compare_values (vr->max, val); + if ((comp == GT_EXPR && (tst == -1 || tst == 0)) + || (comp == GE_EXPR && tst == -1)) + return boolean_false_node; + + /* Otherwise, we don't know. */ + return NULL_TREE; + } + + gcc_unreachable (); +} + + +/* Debugging dumps. */ + +void +dump_value_range (FILE *file, value_range *vr) +{ + if (vr == NULL) + fprintf (file, "[]"); + else if (vr->type == VR_UNDEFINED) + fprintf (file, "UNDEFINED"); + else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE) + { + fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : ""); + print_generic_expr (file, vr->min, 0); + fprintf (file, ", "); + print_generic_expr (file, vr->max, 0); + fprintf (file, "]"); + } + else if (vr->type == VR_VARYING) + fprintf (file, "VARYING"); + else + fprintf (file, "INVALID RANGE"); +} + + +/* Dump value range VR to stderr. */ + +void +debug_value_range (value_range *vr) +{ + dump_value_range (stderr, vr); +} + + +/* Dump value ranges of all SSA_NAMEs to FILE. */ + +void +dump_all_value_ranges (FILE *file) +{ + size_t i; + + for (i = 0; i < num_ssa_names; i++) + { + tree var = ssa_name (i); + if (var && SSA_NAME_VALUE_RANGE (var)) + { + print_generic_expr (file, var, 0); + fprintf (file, ": "); + dump_value_range (file, SSA_NAME_VALUE_RANGE (var)); + fprintf (file, "\n"); + } + } + + fprintf (file, "\n"); +} + + +/* Dump all value ranges to stderr. */ + +void +debug_all_value_ranges (void) +{ + dump_all_value_ranges (stderr); +} + + +/*--------------------------------------------------------------------------- + Value Range Propagation +---------------------------------------------------------------------------*/ + +/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, + create a new SSA name N and return the assertion assignment + 'V = ASSERT_EXPR <V, V OP W>'. */ + +static tree +build_assert_expr_for (tree cond, tree v) +{ + tree n, assertion; + + gcc_assert (TREE_CODE (v) == SSA_NAME); + n = duplicate_ssa_name (v, NULL_TREE); + + if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison) + { + /* Build N = ASSERT_EXPR <V, COND>. As a special case, if the + conditional is an EQ_EXPR (V == Z), just build the assignment + N = Z. */ + if (TREE_CODE (cond) == EQ_EXPR) + { + tree other = get_opposite_operand (cond, v); + assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, other); + } + else + assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, + build (ASSERT_EXPR, TREE_TYPE (v), v, cond)); + } + else if (TREE_CODE (cond) == TRUTH_NOT_EXPR) + { + /* Given !V, build the assignment N = false. */ + tree op0 = TREE_OPERAND (cond, 0); + gcc_assert (op0 == v); + assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_false_node); + } + else if (TREE_CODE (cond) == SSA_NAME) + { + /* Given V, build the assignment N = true. */ + gcc_assert (v == cond); + assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_true_node); + } + else + gcc_unreachable (); + + SSA_NAME_DEF_STMT (n) = assertion; + + /* The new ASSERT_EXPR, creates a new SSA name that replaces the + operand of the ASSERT_EXPR. Register the new name and the old one + in the replacement table so that we can fix the SSA web after + adding all the ASSERT_EXPRs. */ + register_new_name_mapping (n, v); + + return assertion; +} + + +/* Return false if EXPR is a predicate expression involving floating + point values. */ + +static inline bool +fp_predicate (tree expr) +{ + return TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison + && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))); +} + + +/* Return an expression predicate that represents the range of values + that can be taken by operand OP after STMT executes. */ + +static tree +infer_value_range (tree stmt, tree op) +{ + if (POINTER_TYPE_P (TREE_TYPE (op))) + { + bool is_store; + unsigned num_uses, num_derefs; + + count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store); + if (num_derefs > 0 && flag_delete_null_pointer_checks) + { + /* We can only assume that a pointer dereference will yield + non-NULL if -fdelete-null-pointer-checks is enabled. */ + tree null = build_int_cst (TREE_TYPE (op), 0); + tree t = build (NE_EXPR, boolean_type_node, op, null); + return t; + } + } + + return NULL_TREE; +} + + +/* Return true if OP is the result of an ASSERT_EXPR that tests the + same condition as COND. */ + +static bool +has_assert_expr (tree op, tree cond) +{ + tree def_stmt = SSA_NAME_DEF_STMT (op); + tree assert_expr, other_cond, other_op; + + /* If OP was not generated by an ASSERT_EXPR, return false. */ + if (TREE_CODE (def_stmt) != MODIFY_EXPR + || TREE_CODE (TREE_OPERAND (def_stmt, 1)) != ASSERT_EXPR) + return false; + + assert_expr = TREE_OPERAND (def_stmt, 1); + other_cond = ASSERT_EXPR_COND (assert_expr); + other_op = ASSERT_EXPR_VAR (assert_expr); + + if (TREE_CODE (cond) == TREE_CODE (other_cond)) + { + tree t1, t2; + + /* If COND is not a comparison predicate, something is wrong. */ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison); + + /* Note that we only need to compare against one of the operands + of OTHER_COND. + + Suppose that we are about to insert the assertion ASSERT_EXPR + <x_4, x_4 != 0> and the defining statement for x_4 is x_4 = + ASSERT_EXPR <x_3, x_3 != 0>. + + In this case, we don't really want to insert a new + ASSERT_EXPR for x_4 because that would be redundant. We + already know that x_4 is not 0. So, when comparing the + conditionals 'x_3 != 0' and 'x_4 != 0', we don't want to + compare x_3 and x_4, we just want to compare the predicate's + code (!=) and the other operand (0). */ + if (TREE_OPERAND (cond, 0) == op) + t1 = TREE_OPERAND (cond, 1); + else + t1 = TREE_OPERAND (cond, 0); + + if (TREE_OPERAND (other_cond, 0) == other_op) + t2 = TREE_OPERAND (other_cond, 1); + else + t2 = TREE_OPERAND (other_cond, 0); + + return (t1 == t2 || operand_equal_p (t1, t2, 0)); + } + + return false; +} + + +/* Traverse all the statements in block BB looking for used variables. + Variables used in BB are added to bitmap FOUND. The algorithm + works in three main parts: + + 1- For every statement S in BB, all the variables used by S are + added to bitmap FOUND. + + 2- If statement S uses an operand N in a way that exposes a known + value range for N, then if N was not already generated by an + ASSERT_EXPR, create a new ASSERT_EXPR for N. For instance, if N + is a pointer and the statement dereferences it, we can assume + that N is not NULL. + + 3- COND_EXPRs are a special case of #2. We can derive range + information from the predicate but need to insert different + ASSERT_EXPRs for each of the sub-graphs rooted at the + conditional block. If the last statement of BB is a conditional + expression of the form 'X op Y', then + + a) Remove X and Y from the set FOUND. + + b) If the conditional dominates its THEN_CLAUSE sub-graph, + recurse into it. On return, if X and/or Y are marked in + FOUND, then an ASSERT_EXPR is added for the corresponding + variable. + + c) Repeat step (b) on the ELSE_CLAUSE. + + d) Mark X and Y in FOUND. + + 3- If BB does not end in a conditional expression, then we recurse + into BB's dominator children. + + At the end of the recursive traversal, ASSERT_EXPRs will have been + added to the edges of COND_EXPR blocks that have sub-graphs using + one or both predicate operands. For instance, + + if (a == 9) + b = a; + else + b = c + 1; + + In this case, an assertion on the THEN clause is useful to + determine that 'a' is always 9 on that edge. However, an assertion + on the ELSE clause would be unnecessary. + + On exit from this function, all the names created by the newly + inserted ASSERT_EXPRs need to be added to the SSA web by rewriting + the SSA names that they replace. + + TODO. Handle SWITCH_EXPR. */ + +static bool +maybe_add_assert_expr (basic_block bb) +{ + block_stmt_iterator si; + tree last; + bool added; + use_optype uses; + + /* Step 1. Mark all the SSA names used in BB in bitmap FOUND. */ + added = false; + last = NULL_TREE; + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt, op; + ssa_op_iter i; + + stmt = bsi_stmt (si); + get_stmt_operands (stmt); + + /* Mark all the SSA names used by STMT in bitmap FOUND. If STMT + is inside the sub-graph of a conditional block, when we + return from this recursive walk, our parent will use the + FOUND bitset to determine if one of the operands it was + looking for was present in the sub-graph. */ + FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) + { + tree cond; + + SET_BIT (found, SSA_NAME_VERSION (op)); + + cond = infer_value_range (stmt, op); + if (!cond) + continue; + + /* Step 3. If OP is used in such a way that we can infer a + value range for it, create a new ASSERT_EXPR for OP + (unless OP already has an ASSERT_EXPR). */ + gcc_assert (!is_ctrl_stmt (stmt)); + + if (has_assert_expr (op, cond)) + continue; + + if (!stmt_ends_bb_p (stmt)) + { + /* If STMT does not end the block, we can insert the new + assertion right after it. */ + tree t = build_assert_expr_for (cond, op); + bsi_insert_after (&si, t, BSI_NEW_STMT); + added = true; + } + else + { + /* STMT must be the last statement in BB. We can only + insert new assertions on the non-abnormal edge out of + BB. Note that since STMT is not control flow, there + may only be one non-abnormal edge out of BB. */ + edge_iterator ei; + edge e; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (!(e->flags & EDGE_ABNORMAL)) + { + tree t = build_assert_expr_for (cond, op); + bsi_insert_on_edge (e, t); + added = true; + break; + } + } + } + + /* Remember the last statement of the block. */ + last = stmt; + } + + /* Step 3. If BB's last statement is a conditional expression + involving integer operands, recurse into each of the sub-graphs + rooted at BB to determine if we need to add ASSERT_EXPRs. + Notice that we only care about the first operand of the + conditional. Adding assertions for both operands may actually + hinder VRP. FIXME, add example. */ + if (last + && TREE_CODE (last) == COND_EXPR + && !fp_predicate (COND_EXPR_COND (last)) + && NUM_USES (uses = STMT_USE_OPS (last)) > 0) + { + edge e; + edge_iterator ei; + tree op, cond; + + cond = COND_EXPR_COND (last); + + /* Remove the COND_EXPR operand from the FOUND bitmap. + Otherwise, when we finish traversing each of the sub-graphs, + we won't know whether the variables were found in the + sub-graphs or if they had been found in a block upstream from + BB. */ + op = USE_OP (uses, 0); + RESET_BIT (found, SSA_NAME_VERSION (op)); + + /* Look for uses of the operands in each of the sub-graphs + rooted at BB. We need to check each of the outgoing edges + separately, so that we know what kind of ASSERT_EXPR to + insert. */ + FOR_EACH_EDGE (e, ei, bb->succs) + { + /* If BB strictly dominates the sub-graph at E->DEST, + recurse into it. */ + if (e->dest != bb + && dominated_by_p (CDI_DOMINATORS, e->dest, bb)) + added |= maybe_add_assert_expr (e->dest); + + /* Once we traversed the sub-graph, check if any block inside + used either of the predicate's operands. If so, add the + appropriate ASSERT_EXPR. */ + if (TEST_BIT (found, SSA_NAME_VERSION (op))) + { + /* We found a use of OP in the sub-graph rooted at + E->DEST. Add an ASSERT_EXPR according to whether + E goes to THEN_CLAUSE or ELSE_CLAUSE. */ + tree c, t; + + if (e->flags & EDGE_TRUE_VALUE) + c = unshare_expr (cond); + else if (e->flags & EDGE_FALSE_VALUE) + c = invert_truthvalue (cond); + else + gcc_unreachable (); + + t = build_assert_expr_for (c, op); + bsi_insert_on_edge (e, t); + added = true; + } + } + + /* Finally, mark all the COND_EXPR operands as found. */ + SET_BIT (found, SSA_NAME_VERSION (op)); + } + else + { + /* Step 3. Recurse into the dominator children of BB. */ + basic_block son; + + for (son = first_dom_son (CDI_DOMINATORS, bb); + son; + son = next_dom_son (CDI_DOMINATORS, son)) + added |= maybe_add_assert_expr (son); + } + + return added; +} + + +/* Traverse the flowgraph looking for conditional jumps to insert range + expressions. These range expressions are meant to provide information + to optimizations that need to reason in terms of value ranges. They + will not be expanded into RTL. For instance, given: + + x = ... + y = ... + if (x < y) + y = x - 2; + else + x = y + 3; + + this pass will transform the code into: + + x = ... + y = ... + if (x < y) + { + x = ASSERT_EXPR <x, x < y> + y = x - 2 + } + else + { + y = ASSERT_EXPR <y, x <= y> + x = y + 3 + } + + The idea is that once copy and constant propagation have run, other + optimizations will be able to determine what ranges of values can 'x' + take in different paths of the code, simply by checking the reaching + definition of 'x'. */ + +static void +insert_range_assertions (void) +{ + edge e; + edge_iterator ei; + bool update_ssa_p; + + found = sbitmap_alloc (num_ssa_names); + sbitmap_zero (found); + + calculate_dominance_info (CDI_DOMINATORS); + + update_ssa_p = false; + FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) + if (maybe_add_assert_expr (e->dest)) + update_ssa_p = true; + + if (update_ssa_p) + { + bsi_commit_edge_inserts (); + update_ssa (TODO_update_ssa_no_phi); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nSSA form after inserting ASSERT_EXPRs\n"); + dump_function_to_file (current_function_decl, dump_file, dump_flags); + } + + sbitmap_free (found); +} + + +/* Convert range assertion expressions into copies. FIXME, explain why. */ + +static void +remove_range_assertions (void) +{ + basic_block bb; + block_stmt_iterator si; + + FOR_EACH_BB (bb) + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR) + { + tree rhs = TREE_OPERAND (stmt, 1); + tree cond = fold (ASSERT_EXPR_COND (rhs)); + gcc_assert (cond != boolean_false_node); + TREE_OPERAND (stmt, 1) = ASSERT_EXPR_VAR (rhs); + update_stmt (stmt); + } + } +} + + +/* Return true if STMT is interesting for VRP. */ + +static bool +stmt_interesting_for_vrp (tree stmt) +{ + if (TREE_CODE (stmt) == PHI_NODE + && is_gimple_reg (PHI_RESULT (stmt)) + && (INTEGRAL_TYPE_P (TREE_TYPE (PHI_RESULT (stmt))) + || POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (stmt))))) + return true; + else if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree lhs = TREE_OPERAND (stmt, 0); + stmt_ann_t ann = stmt_ann (stmt); + + if (TREE_CODE (lhs) == SSA_NAME + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs))) + && NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) == 0 + && NUM_VUSES (VUSE_OPS (ann)) == 0 + && NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) == 0) + return true; + } + else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR) + return true; + + return false; +} + + +/* Initialize local data structures for VRP. Return true if VRP + is worth running (i.e. if we found any statements that could + benefit from range information). */ + +static bool +vrp_initialize (void) +{ + basic_block bb; + bool do_vrp; + + /* If we don't find any ASSERT_EXPRs in the code, there's no point + running VRP. */ + do_vrp = false; + + FOR_EACH_BB (bb) + { + block_stmt_iterator si; + tree phi; + + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + { + if (!stmt_interesting_for_vrp (phi)) + { + tree lhs = PHI_RESULT (phi); + set_value_range (get_value_range (lhs), VR_VARYING, 0, 0); + DONT_SIMULATE_AGAIN (phi) = true; + } + else + DONT_SIMULATE_AGAIN (phi) = false; + } + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + + if (!stmt_interesting_for_vrp (stmt)) + { + ssa_op_iter i; + tree def; + FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF) + set_value_range (get_value_range (def), VR_VARYING, 0, 0); + DONT_SIMULATE_AGAIN (stmt) = true; + } + else + { + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR) + do_vrp = true; + + DONT_SIMULATE_AGAIN (stmt) = false; + } + } + } + + return do_vrp; +} + + +/* Visit assignment STMT. If it produces an interesting range, record + the SSA name in *OUTPUT_P. */ + +static enum ssa_prop_result +vrp_visit_assignment (tree stmt, tree *output_p) +{ + tree lhs, rhs, def; + ssa_op_iter iter; + + lhs = TREE_OPERAND (stmt, 0); + rhs = TREE_OPERAND (stmt, 1); + + /* We only keep track of ranges in integral and pointer types. */ + if (TREE_CODE (lhs) == SSA_NAME + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs)))) + { + value_range *vr, new_vr; + struct loop *l; + + vr = get_value_range (lhs); + extract_range_from_expr (&new_vr, rhs); + + /* If STMT is inside a loop, we may be able to know something + else about the range of LHS by examining scalar evolution + information. */ + if (cfg_loops && (l = loop_containing_stmt (stmt))) + adjust_range_with_scev (&new_vr, l, lhs); + + if (update_value_range (vr, new_vr.type, new_vr.min, new_vr.max)) + { + *output_p = lhs; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Found new range "); + dump_value_range (dump_file, &new_vr); + fprintf (dump_file, " for "); + print_generic_expr (dump_file, lhs, 0); + fprintf (dump_file, "\n\n"); + } + + if (new_vr.type == VR_VARYING) + return SSA_PROP_VARYING; + + return SSA_PROP_INTERESTING; + } + + return SSA_PROP_NOT_INTERESTING; + } + + /* Every other statements produces no useful ranges. */ + FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) + set_value_range (get_value_range (def), VR_VARYING, 0, 0); + + return SSA_PROP_VARYING; +} + + +/* Given a conditional predicate COND, try to determine if COND yields + true or false based on the value ranges of its operands. */ + +static tree +vrp_evaluate_conditional (tree cond) +{ + gcc_assert (TREE_CODE (cond) == SSA_NAME + || TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison); + + if (TREE_CODE (cond) == SSA_NAME) + { + /* For SSA names, only return a truth value if the range is + known and contains exactly one value. */ + value_range *vr = SSA_NAME_VALUE_RANGE (cond); + if (vr && vr->type == VR_RANGE && vr->min == vr->max) + return vr->min; + } + else + { + /* For comparisons, evaluate each operand and compare their + ranges. */ + tree op0, op1; + value_range *vr0, *vr1; + + op0 = TREE_OPERAND (cond, 0); + vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL; + + op1 = TREE_OPERAND (cond, 1); + vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL; + + if (vr0 && vr1) + return compare_ranges (TREE_CODE (cond), vr0, vr1); + else if (vr0 && vr1 == NULL) + return compare_range_with_value (TREE_CODE (cond), vr0, op1); + else if (vr0 == NULL && vr1) + return compare_range_with_value (opposite_comparison (TREE_CODE (cond)), + vr1, op0); + } + + /* Anything else cannot be computed statically. */ + return NULL_TREE; +} + + +/* Visit conditional statement STMT. If we can determine which edge + will be taken out of STMT's basic block, record it in + *TAKEN_EDGE_P and return SSA_PROP_INTERESTING. Otherwise, return + SSA_PROP_VARYING. */ + +static enum ssa_prop_result +vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p) +{ + tree cond, val; + + *taken_edge_p = NULL; + + /* FIXME. Handle SWITCH_EXPRs. But first, the assert pass needs to + add ASSERT_EXPRs for them. */ + if (TREE_CODE (stmt) == SWITCH_EXPR) + return SSA_PROP_VARYING; + + cond = COND_EXPR_COND (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + tree use; + ssa_op_iter i; + + fprintf (dump_file, "\nVisiting conditional with predicate: "); + print_generic_expr (dump_file, cond, 0); + fprintf (dump_file, "\nWith known ranges\n"); + + FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE) + { + fprintf (dump_file, "\t"); + print_generic_expr (dump_file, use, 0); + fprintf (dump_file, ": "); + dump_value_range (dump_file, SSA_NAME_VALUE_RANGE (use)); + } + + fprintf (dump_file, "\n"); + } + + /* Compute the value of the predicate COND by checking the known + ranges of each of its operands. */ + val = vrp_evaluate_conditional (cond); + if (val) + *taken_edge_p = find_taken_edge (bb_for_stmt (stmt), val); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nPredicate evaluates to: "); + if (val == NULL_TREE) + fprintf (dump_file, "DON'T KNOW\n"); + else + print_generic_stmt (dump_file, val, 0); + } + + return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING; +} + + +/* Evaluate statement STMT. If the statement produces a useful range, + return SSA_PROP_INTERESTING and record the SSA name with the + interesting range into *OUTPUT_P. + + If STMT is a conditional branch and we can determine its truth + value, the taken edge is recorded in *TAKEN_EDGE_P. + + If STMT produces a varying value, return SSA_PROP_VARYING. */ + +static enum ssa_prop_result +vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p) +{ + tree def; + ssa_op_iter iter; + stmt_ann_t ann; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nVisiting statement:\n"); + print_generic_stmt (dump_file, stmt, dump_flags); + fprintf (dump_file, "\n"); + } + + ann = stmt_ann (stmt); + if (TREE_CODE (stmt) == MODIFY_EXPR + && NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) == 0 + && NUM_VUSES (VUSE_OPS (ann)) == 0 + && NUM_V_MUST_DEFS (V_MUST_DEF_OPS (ann)) == 0) + return vrp_visit_assignment (stmt, output_p); + else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR) + return vrp_visit_cond_stmt (stmt, taken_edge_p); + + /* All other statements produce nothing of interest for VRP, so mark + their outputs varying and prevent further simulation. */ + FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) + set_value_range (get_value_range (def), VR_VARYING, 0, 0); + + return SSA_PROP_VARYING; +} + + +/* Meet operation for value ranges. Given two value ranges VR0 and + VR1, store in VR0 the result of meeting VR0 and VR1. + + The meeting rules are as follows: + + 1- If VR0 and VR1 have an empty intersection, set VR0 to VR_VARYING. + + 2- If VR0 and VR1 have a non-empty intersection, set VR0 to the + union of VR0 and VR1. */ + +static void +vrp_meet (value_range *vr0, value_range *vr1) +{ + if (vr0->type == VR_UNDEFINED) + { + *vr0 = *vr1; + return; + } + + if (vr1->type == VR_UNDEFINED) + { + /* Nothing to do. VR0 already has the resulting range. */ + return; + } + + if (vr0->type == VR_VARYING) + { + /* Nothing to do. VR0 already has the resulting range. */ + return; + } + + if (vr1->type == VR_VARYING) + { + *vr0 = *vr1; + return; + } + + /* If either is a symbolic range, drop to VARYING. */ + if (symbolic_range_p (vr0) || symbolic_range_p (vr1)) + { + set_value_range (vr0, VR_VARYING, NULL_TREE, NULL_TREE); + return; + } + + if (vr0->type == VR_RANGE && vr1->type == VR_RANGE) + { + /* If VR0 and VR1 have a non-empty intersection, compute the + union of both ranges. */ + if (value_ranges_intersect_p (vr0, vr1)) + { + tree min, max; + + min = vr0->min; + max = vr0->max; + + /* The lower limit of the new range is the minimum of the + two ranges. */ + if (compare_values (vr0->min, vr1->min) == 1) + min = vr1->min; + + /* The upper limit of the new range is the maximium of the + two ranges. */ + if (compare_values (vr0->max, vr1->max) == -1) + max = vr1->max; + + set_value_range (vr0, vr0->type, min, max); + } + else + { + /* The two ranges don't intersect, set the result to VR_VARYING. */ + set_value_range (vr0, VR_VARYING, NULL_TREE, NULL_TREE); + } + } + else if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE) + { + /* Two anti-ranges meet only if they are both identical. */ + if (compare_values (vr0->min, vr1->min) == 0 + && compare_values (vr0->max, vr1->max) == 0 + && compare_values (vr0->min, vr0->max) == 0) + /* Nothing to do. */ ; + else + set_value_range (vr0, VR_VARYING, NULL_TREE, NULL_TREE); + } + else if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE) + { + /* A range [VAL1, VAL2] and an anti-range ~[VAL3, VAL4] meet + only if the ranges have an empty intersection. The result of + the meet operation is the anti-range. */ + if (!value_ranges_intersect_p (vr0, vr1)) + { + if (vr1->type == VR_ANTI_RANGE) + *vr0 = *vr1; + } + else + set_value_range (vr0, VR_VARYING, NULL_TREE, NULL_TREE); + } + else + gcc_unreachable (); +} + + +/* Visit all arguments for PHI node PHI that flow through executable + edges. If a valid value range can be derived from all the incoming + value ranges, set a new range for the LHS of PHI. */ + +static enum ssa_prop_result +vrp_visit_phi_node (tree phi) +{ + int i; + tree lhs = PHI_RESULT (phi); + value_range *lhs_vr = get_value_range (lhs); + value_range vr_result = *lhs_vr; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nVisiting PHI node: "); + print_generic_expr (dump_file, phi, dump_flags); + } + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + edge e = PHI_ARG_EDGE (phi, i); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "\n Argument #%d (%d -> %d %sexecutable)\n", + i, e->src->index, e->dest->index, + (e->flags & EDGE_EXECUTABLE) ? "" : "not "); + } + + if (e->flags & EDGE_EXECUTABLE) + { + tree arg = PHI_ARG_DEF (phi, i); + value_range vr_arg; + + if (TREE_CODE (arg) == SSA_NAME) + vr_arg = *(get_value_range (arg)); + else + { + vr_arg.type = VR_RANGE; + vr_arg.min = arg; + vr_arg.max = arg; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\t"); + print_generic_expr (dump_file, arg, dump_flags); + fprintf (dump_file, "\n\tValue: "); + dump_value_range (dump_file, &vr_arg); + fprintf (dump_file, "\n"); + } + + vrp_meet (&vr_result, &vr_arg); + + if (vr_result.type == VR_VARYING) + break; + } + } + + if (vr_result.type == VR_VARYING) + { + set_value_range (lhs_vr, VR_VARYING, 0, 0); + return SSA_PROP_VARYING; + } + + /* To prevent infinite iterations in the algorithm, derive ranges + when the new value is slightly bigger or smaller than the + previous one. */ + if (lhs_vr->type == VR_RANGE) + { + if (!POINTER_TYPE_P (TREE_TYPE (lhs))) + { + int cmp_min = compare_values (lhs_vr->min, vr_result.min); + int cmp_max = compare_values (lhs_vr->max, vr_result.max); + + /* If the new minimum is smaller or larger than the previous + one, go all the way to -INF. In the first case, to avoid + iterating millions of times to reach -INF, and in the + other case to avoid infinite bouncing between different + minimums. */ + if (cmp_min > 0 || cmp_min < 0) + vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)); + + /* Similarly, if the new maximum is smaller or larger than + the previous one, go all the way to +INF. */ + if (cmp_max < 0 || cmp_max > 0) + vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)); + + /* If we ended up with a (-INF, +INF) range, set it to + VARYING. */ + if (vr_result.min == TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)) + && vr_result.max == TYPE_MAX_VALUE (TREE_TYPE (vr_result.max))) + { + set_value_range (lhs_vr, VR_VARYING, 0, 0); + return SSA_PROP_VARYING; + } + } + } + + /* If the new range is different than the previous value, keep + iterating. */ + if (update_value_range (lhs_vr, vr_result.type, vr_result.min, vr_result.max)) + return SSA_PROP_INTERESTING; + + /* Nothing changed, don't add outgoing edges. */ + return SSA_PROP_NOT_INTERESTING; +} + + +/* Traverse all the blocks folding conditionals with known ranges. */ + +static void +vrp_finalize (void) +{ + basic_block bb; + int num_pred_folded = 0; + + if (dump_file) + { + fprintf (dump_file, "\nValue ranges after VRP:\n\n"); + dump_all_value_ranges (dump_file); + fprintf (dump_file, "\n"); + } + + FOR_EACH_BB (bb) + { + tree last = last_stmt (bb); + if (last && TREE_CODE (last) == COND_EXPR) + { + tree val = vrp_evaluate_conditional (COND_EXPR_COND (last)); + if (val) + { + if (dump_file) + { + fprintf (dump_file, "Folding predicate "); + print_generic_expr (dump_file, COND_EXPR_COND (last), 0); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, val, 0); + fprintf (dump_file, "\n"); + } + + num_pred_folded++; + COND_EXPR_COND (last) = val; + update_stmt (last); + } + } + } + + if (dump_file && (dump_flags & TDF_STATS)) + fprintf (dump_file, "\nNumber of predicates folded: %d\n\n", + num_pred_folded); +} + + +/* Main entry point to VRP (Value Range Propagation). This pass is + loosely based on J. R. C. Patterson, ``Accurate Static Branch + Prediction by Value Range Propagation,'' in SIGPLAN Conference on + Programming Language Design and Implementation, pp. 67-78, 1995. + Also available at http://citeseer.ist.psu.edu/patterson95accurate.html + + This is essentially an SSA-CCP pass modified to deal with ranges + instead of constants. + + TODO, the main difference between this pass and Patterson's is that + we do not propagate edge probabilities. We only compute whether + edges can be taken or not. That is, instead of having a spectrum + of jump probabilities between 0 and 1, we only deal with 0, 1 and + DON'T KNOW. In the future, it may be worthwhile to propagate + probabilities to aid branch prediction. */ + +static void +execute_vrp (void) +{ + insert_range_assertions (); + + cfg_loops = loop_optimizer_init (NULL); + if (cfg_loops) + scev_initialize (cfg_loops); + + if (vrp_initialize ()) + { + ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node); + vrp_finalize (); + } + + if (cfg_loops) + { + scev_finalize (); + loop_optimizer_finalize (cfg_loops, NULL); + current_loops = NULL; + } + + remove_range_assertions (); +} + +static bool +gate_vrp (void) +{ + return flag_tree_vrp != 0; +} + +struct tree_opt_pass pass_vrp = +{ + "vrp", /* name */ + gate_vrp, /* gate */ + execute_vrp, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_VRP, /* tv_id */ + PROP_ssa | PROP_alias, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_cleanup_cfg + | TODO_ggc_collect + | TODO_verify_ssa + | TODO_dump_func + | TODO_update_ssa, /* todo_flags_finish */ + 0 /* letter */ +}; |