tree-vrp.c (find_case_label_ranges): New function.

2012-08-01  Tom de Vries  <tom@codesourcery.com>

	* tree-vrp.c (find_case_label_ranges): New function.
	(vrp_visit_switch_stmt, simplify_switch_using_ranges): Use
	find_case_label_ranges instead of find_case_label_range.  Handle second
	range.

From-SVN: r190043
This commit is contained in:
Tom de Vries 2012-08-01 16:53:05 +00:00 committed by Tom de Vries
parent 5f564b8f56
commit 8bb37e9ad3
2 changed files with 107 additions and 6 deletions

View File

@ -1,3 +1,10 @@
2012-08-01 Tom de Vries <tom@codesourcery.com>
* tree-vrp.c (find_case_label_ranges): New function.
(vrp_visit_switch_stmt, simplify_switch_using_ranges): Use
find_case_label_ranges instead of find_case_label_range. Handle second
range.
2012-08-01 Michael Matz <matz@suse.de> 2012-08-01 Michael Matz <matz@suse.de>
* tree-complex.c (init_parameter_lattice_values): Don't call var_ann. * tree-complex.c (init_parameter_lattice_values): Don't call var_ann.

View File

@ -6754,6 +6754,84 @@ find_case_label_range (gimple stmt, tree min, tree max, size_t *min_idx,
} }
} }
/* 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 (gimple stmt, value_range_t *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 = vr->min, max = vr->max;
gcc_checking_assert (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE);
take_default = !find_case_label_range (stmt, min, max, &i, &j);
/* Set second range to emtpy. */
*min_idx2 = 1;
*max_idx2 = 0;
if (vr->type == 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;
}
/* Visit switch statement STMT. If we can determine which edge /* Visit switch statement STMT. If we can determine which edge
will be taken out of STMT's basic block, record it in will be taken out of STMT's basic block, record it in
*TAKEN_EDGE_P and return SSA_PROP_INTERESTING. Otherwise, return *TAKEN_EDGE_P and return SSA_PROP_INTERESTING. Otherwise, return
@ -6764,7 +6842,7 @@ vrp_visit_switch_stmt (gimple stmt, edge *taken_edge_p)
{ {
tree op, val; tree op, val;
value_range_t *vr; value_range_t *vr;
size_t i = 0, j = 0; size_t i = 0, j = 0, k, l;
bool take_default; bool take_default;
*taken_edge_p = NULL; *taken_edge_p = NULL;
@ -6782,12 +6860,13 @@ vrp_visit_switch_stmt (gimple stmt, edge *taken_edge_p)
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
if (vr->type != VR_RANGE if ((vr->type != VR_RANGE
&& vr->type != VR_ANTI_RANGE)
|| symbolic_range_p (vr)) || symbolic_range_p (vr))
return SSA_PROP_VARYING; return SSA_PROP_VARYING;
/* Find the single edge that is taken from the switch expression. */ /* Find the single edge that is taken from the switch expression. */
take_default = !find_case_label_range (stmt, vr->min, vr->max, &i, &j); take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
/* Check if the range spans no CASE_LABEL. If so, we only reach the default /* Check if the range spans no CASE_LABEL. If so, we only reach the default
label */ label */
@ -6821,6 +6900,16 @@ vrp_visit_switch_stmt (gimple stmt, edge *taken_edge_p)
return SSA_PROP_VARYING; return SSA_PROP_VARYING;
} }
} }
for (; k <= l; ++k)
{
if (CASE_LABEL (gimple_switch_label (stmt, k)) != CASE_LABEL (val))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " not a single destination for this "
"range\n");
return SSA_PROP_VARYING;
}
}
} }
*taken_edge_p = find_edge (gimple_bb (stmt), *taken_edge_p = find_edge (gimple_bb (stmt),
@ -8215,18 +8304,20 @@ simplify_switch_using_ranges (gimple stmt)
size_t i = 0, j = 0, n, n2; size_t i = 0, j = 0, n, n2;
tree vec2; tree vec2;
switch_update su; switch_update su;
size_t k = 1, l = 0;
if (TREE_CODE (op) == SSA_NAME) if (TREE_CODE (op) == SSA_NAME)
{ {
vr = get_value_range (op); vr = get_value_range (op);
/* We can only handle integer ranges. */ /* We can only handle integer ranges. */
if (vr->type != VR_RANGE if ((vr->type != VR_RANGE
&& vr->type != VR_ANTI_RANGE)
|| symbolic_range_p (vr)) || symbolic_range_p (vr))
return false; return false;
/* Find case label for min/max of the value range. */ /* Find case label for min/max of the value range. */
take_default = !find_case_label_range (stmt, vr->min, vr->max, &i, &j); take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
} }
else if (TREE_CODE (op) == INTEGER_CST) else if (TREE_CODE (op) == INTEGER_CST)
{ {
@ -8253,7 +8344,7 @@ simplify_switch_using_ranges (gimple stmt)
return false; return false;
/* Build a new vector of taken case labels. */ /* Build a new vector of taken case labels. */
vec2 = make_tree_vec (j - i + 1 + (int)take_default); vec2 = make_tree_vec (j - i + 1 + l - k + 1 + (int)take_default);
n2 = 0; n2 = 0;
/* Add the default edge, if necessary. */ /* Add the default edge, if necessary. */
@ -8263,6 +8354,9 @@ simplify_switch_using_ranges (gimple stmt)
for (; i <= j; ++i, ++n2) for (; i <= j; ++i, ++n2)
TREE_VEC_ELT (vec2, n2) = gimple_switch_label (stmt, i); 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);
/* Mark needed edges. */ /* Mark needed edges. */
for (i = 0; i < n2; ++i) for (i = 0; i < n2; ++i)
{ {