diff options
Diffstat (limited to 'gcc/vr-values.cc')
-rw-r--r-- | gcc/vr-values.cc | 291 |
1 files changed, 77 insertions, 214 deletions
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index 4c78759..ff11656 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -513,85 +513,6 @@ simplify_using_ranges::legacy_fold_cond (gcond *stmt, edge *taken_edge_p) } } -/* Searches the case label vector VEC for the ranges of CASE_LABELs that are - used in range VR. The indices are placed in MIN_IDX1, MAX_IDX, MIN_IDX2 and - MAX_IDX2. If the ranges of CASE_LABELs are empty then MAX_IDX1 < MIN_IDX1. - Returns true if the default label is not needed. */ - -static bool -find_case_label_ranges (gswitch *stmt, const irange *vr, - size_t *min_idx1, size_t *max_idx1, - size_t *min_idx2, size_t *max_idx2) -{ - size_t i, j, k, l; - unsigned int n = gimple_switch_num_labels (stmt); - bool take_default; - tree case_low, case_high; - tree min, max; - value_range_kind kind = get_legacy_range (*vr, min, max); - - gcc_checking_assert (!vr->varying_p () && !vr->undefined_p ()); - - take_default = !find_case_label_range (stmt, min, max, &i, &j); - - /* Set second range to empty. */ - *min_idx2 = 1; - *max_idx2 = 0; - - if (kind == VR_RANGE) - { - *min_idx1 = i; - *max_idx1 = j; - return !take_default; - } - - /* Set first range to all case labels. */ - *min_idx1 = 1; - *max_idx1 = n - 1; - - if (i > j) - return false; - - /* Make sure all the values of case labels [i , j] are contained in - range [MIN, MAX]. */ - case_low = CASE_LOW (gimple_switch_label (stmt, i)); - case_high = CASE_HIGH (gimple_switch_label (stmt, j)); - if (tree_int_cst_compare (case_low, min) < 0) - i += 1; - if (case_high != NULL_TREE - && tree_int_cst_compare (max, case_high) < 0) - j -= 1; - - if (i > j) - return false; - - /* If the range spans case labels [i, j], the corresponding anti-range spans - the labels [1, i - 1] and [j + 1, n - 1]. */ - k = j + 1; - l = n - 1; - if (k > l) - { - k = 1; - l = 0; - } - - j = i - 1; - i = 1; - if (i > j) - { - i = k; - j = l; - k = 1; - l = 0; - } - - *min_idx1 = i; - *max_idx1 = j; - *min_idx2 = k; - *max_idx2 = l; - return false; -} - /* Simplify boolean operations if the source is known to be already a boolean. */ bool @@ -1023,6 +944,10 @@ range_fits_type_p (const irange *vr, widest_int tem; signop src_sgn; + /* Now we can only handle ranges with constant bounds. */ + if (vr->undefined_p () || vr->varying_p ()) + return false; + /* We can only handle integral and pointer types. */ src_type = vr->type (); if (!INTEGRAL_TYPE_P (src_type) @@ -1031,17 +956,13 @@ range_fits_type_p (const irange *vr, /* An extension is fine unless VR is SIGNED and dest_sgn is UNSIGNED, and so is an identity transform. */ - src_precision = TYPE_PRECISION (vr->type ()); + src_precision = TYPE_PRECISION (src_type); src_sgn = TYPE_SIGN (src_type); if ((src_precision < dest_precision && !(dest_sgn == UNSIGNED && src_sgn == SIGNED)) || (src_precision == dest_precision && src_sgn == dest_sgn)) return true; - /* Now we can only handle ranges with constant bounds. */ - if (vr->undefined_p () || vr->varying_p ()) - return false; - wide_int vrmin = vr->lower_bound (); wide_int vrmax = vr->upper_bound (); @@ -1374,157 +1295,99 @@ bool simplify_using_ranges::simplify_switch_using_ranges (gswitch *stmt) { tree op = gimple_switch_index (stmt); - int_range_max vr; - bool take_default; + tree type = TREE_TYPE (op); + int_range_max op_range (type); + int_range_max default_range (type); + auto_vec<unsigned> cases; + cases.truncate (0); edge e; - edge_iterator ei; - size_t i = 0, j = 0, n, n2; - tree vec2; switch_update su; - size_t k = 1, l = 0; - - if (TREE_CODE (op) == SSA_NAME) - { - if (!query->range_of_expr (vr, op, stmt) - || vr.varying_p () || vr.undefined_p ()) - return false; - /* Find case label for min/max of the value range. */ - take_default = !find_case_label_ranges (stmt, &vr, &i, &j, &k, &l); - } - else if (TREE_CODE (op) == INTEGER_CST) - { - take_default = !find_case_label_index (stmt, 1, op, &i); - if (take_default) - { - i = 1; - j = 0; - } - else - { - j = i; - } - } - else + // Abort if we don't have a useful range for the switch index. + if (!query->range_of_expr (op_range, op, stmt) + || op_range.varying_p () || op_range.undefined_p ()) return false; - n = gimple_switch_num_labels (stmt); + // Default range starts with full known range of op. + default_range = op_range; + edge default_edge = gimple_switch_default_edge (cfun, stmt); - /* We can truncate the case label ranges that partially overlap with OP's - value range. */ - size_t min_idx = 1, max_idx = 0; - tree min, max; - value_range_kind kind = get_legacy_range (vr, min, max); - if (!vr.undefined_p ()) - find_case_label_range (stmt, min, max, &min_idx, &max_idx); - if (min_idx <= max_idx) + unsigned x, lim = gimple_switch_num_labels (stmt); + for (x = 1; x < lim; x++) { - tree min_label = gimple_switch_label (stmt, min_idx); - tree max_label = gimple_switch_label (stmt, max_idx); + e = gimple_switch_edge (cfun, stmt, x); + tree label = gimple_switch_label (stmt, x); + + // If this edge is the same as the default edge, do nothing else. + if (e == default_edge) + continue; + // Ada sometimes has mismatched labels and index. Just bail. + if (TREE_TYPE (CASE_LOW (label)) != type) + return false; - /* Avoid changing the type of the case labels when truncating. */ - tree case_label_type = TREE_TYPE (CASE_LOW (min_label)); - tree vr_min = fold_convert (case_label_type, min); - tree vr_max = fold_convert (case_label_type, max); + wide_int low = wi::to_wide (CASE_LOW (label)); + wide_int high; + // Singleton cases have no CASE_HIGH. + tree tree_high = CASE_HIGH (label); + if (tree_high) + high = wi::to_wide (tree_high); + else + high = low; - if (kind == VR_RANGE) + // If the case range is fully contained in op_range, leave the + // case as it is, otherwise adjust the labels. + int_range_max case_range (type, low, high); + if (case_range.intersect (op_range)) { - /* If OP's value range is [2,8] and the low label range is - 0 ... 3, truncate the label's range to 2 .. 3. */ - if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0 - && CASE_HIGH (min_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (min_label), vr_min) >= 0) - CASE_LOW (min_label) = vr_min; - - /* If OP's value range is [2,8] and the high label range is - 7 ... 10, truncate the label's range to 7 .. 8. */ - if (tree_int_cst_compare (CASE_LOW (max_label), vr_max) <= 0 - && CASE_HIGH (max_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0) - CASE_HIGH (max_label) = vr_max; - } - else if (kind == VR_ANTI_RANGE) - { - tree one_cst = build_one_cst (case_label_type); - - if (min_label == max_label) - { - /* If OP's value range is ~[7,8] and the label's range is - 7 ... 10, truncate the label's range to 9 ... 10. */ - if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) == 0 - && CASE_HIGH (min_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (min_label), vr_max) > 0) - CASE_LOW (min_label) - = int_const_binop (PLUS_EXPR, vr_max, one_cst); - - /* If OP's value range is ~[7,8] and the label's range is - 5 ... 8, truncate the label's range to 5 ... 6. */ - if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0 - && CASE_HIGH (min_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (min_label), vr_max) == 0) - CASE_HIGH (min_label) - = int_const_binop (MINUS_EXPR, vr_min, one_cst); - } + // If none of the label is in op_range, skip this label. + if (case_range.undefined_p ()) + continue; + + // Part of the label is in op_range, but not all of it. CASE_RANGE + // contains the part that is. Adjust the case range to + // the new min/max. + if (case_range.lower_bound () != low) + CASE_LOW (label) = wide_int_to_tree (type, + case_range.lower_bound ()); + if (case_range.singleton_p ()) + CASE_HIGH (label) = NULL_TREE; else - { - /* If OP's value range is ~[2,8] and the low label range is - 0 ... 3, truncate the label's range to 0 ... 1. */ - if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0 - && CASE_HIGH (min_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (min_label), vr_min) >= 0) - CASE_HIGH (min_label) - = int_const_binop (MINUS_EXPR, vr_min, one_cst); - - /* If OP's value range is ~[2,8] and the high label range is - 7 ... 10, truncate the label's range to 9 ... 10. */ - if (tree_int_cst_compare (CASE_LOW (max_label), vr_max) <= 0 - && CASE_HIGH (max_label) != NULL_TREE - && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0) - CASE_LOW (max_label) - = int_const_binop (PLUS_EXPR, vr_max, one_cst); - } + if (case_range.upper_bound () != high) + CASE_HIGH (label) = wide_int_to_tree (type, + case_range.upper_bound ()); } - - /* Canonicalize singleton case ranges. */ - if (tree_int_cst_equal (CASE_LOW (min_label), CASE_HIGH (min_label))) - CASE_HIGH (min_label) = NULL_TREE; - if (tree_int_cst_equal (CASE_LOW (max_label), CASE_HIGH (max_label))) - CASE_HIGH (max_label) = NULL_TREE; + // Add case label to the keep list. + cases.safe_push (x); + // Remove case_range from needing to be handled by the default. + case_range.invert (); + default_range.intersect (case_range); } - /* We can also eliminate case labels that lie completely outside OP's value - range. */ - - /* Bail out if this is just all edges taken. */ - if (i == 1 - && j == n - 1 - && take_default) + // An undefined DEFAULT range means the current default case is not needed. + unsigned idx = default_range.undefined_p () ? 0 : 1; + unsigned vec_size = cases.length () + idx; + if (vec_size == lim) return false; - /* Build a new vector of taken case labels. */ - vec2 = make_tree_vec (j - i + 1 + l - k + 1 + (int)take_default); - n2 = 0; - - /* Add the default edge, if necessary. */ - if (take_default) - TREE_VEC_ELT (vec2, n2++) = gimple_switch_default_label (stmt); - - for (; i <= j; ++i, ++n2) - TREE_VEC_ELT (vec2, n2) = gimple_switch_label (stmt, i); - - for (; k <= l; ++k, ++n2) - TREE_VEC_ELT (vec2, n2) = gimple_switch_label (stmt, k); + tree vec2 = make_tree_vec (vec_size); + // Add default label if there is one. + if (idx) + { + TREE_VEC_ELT (vec2, 0) = gimple_switch_default_label (stmt); + e = gimple_switch_edge (cfun, stmt, 0); + e->aux = (void *)-1; + } - /* Mark needed edges. */ - for (i = 0; i < n2; ++i) + for (x = 0; x < cases.length (); x++) { - e = find_edge (gimple_bb (stmt), - label_to_block (cfun, - CASE_LABEL (TREE_VEC_ELT (vec2, i)))); - e->aux = (void *)-1; + unsigned swi = cases[x]; + TREE_VEC_ELT (vec2, idx++) = gimple_switch_label (stmt, swi); + e = gimple_switch_edge (cfun, stmt, swi); + e->aux = (void *)-1; } /* Queue not needed edges for later removal. */ + edge_iterator ei; FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs) { if (e->aux == (void *)-1) |