Commit 68e72840 by Steven Bosscher

re PR middle-end/53153 (ice in tree_low_cst, at tree.c:6569)

gcc/
	PR middle-end/53153
	* gimplify.c (preprocess_case_label_vec_for_gimple): New function,
	split out from ...
	(gimplify_switch_expr): ... here.
	* gimple.h (preprocess_case_label_vec_for_gimple): Add prototype.
	* tree-ssa-forwprop.c (simplify_gimple_switch_label_vec): New function
	to clean up case labels with values outside the index type range.
	(simplify_gimple_switch): Call it if something changed.
	Remove strange and unnecessary assert.

testsuite/
	PR middle-end/53153
	* gcc.dg/pr53153.c: New test.

From-SVN: r187048
parent 69416e98
2012-05-02 Steven Bosscher <steven@gcc.gnu.org>
PR middle-end/53153
* gimplify.c (preprocess_case_label_vec_for_gimple): New function,
split out from ...
(gimplify_switch_expr): ... here.
* gimple.h (preprocess_case_label_vec_for_gimple): Add prototype.
* tree-ssa-forwprop.c (simplify_gimple_switch_label_vec): New function
to clean up case labels with values outside the index type range.
(simplify_gimple_switch): Call it if something changed.
Remove strange and unnecessary assert.
2012-05-02 Richard Guenther <rguenther@suse.de> 2012-05-02 Richard Guenther <rguenther@suse.de>
* fold-const.c (div_if_zero_remainder): sizetypes no longer * fold-const.c (div_if_zero_remainder): sizetypes no longer
......
...@@ -922,6 +922,7 @@ gimple gimple_build_transaction (gimple_seq, tree); ...@@ -922,6 +922,7 @@ gimple gimple_build_transaction (gimple_seq, tree);
gimple gimple_build_predict (enum br_predictor, enum prediction); gimple gimple_build_predict (enum br_predictor, enum prediction);
enum gimple_statement_structure_enum gss_for_assign (enum tree_code); enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
void sort_case_labels (VEC(tree,heap) *); void sort_case_labels (VEC(tree,heap) *);
void preprocess_case_label_vec_for_gimple (VEC(tree,heap) *, tree, tree *);
void gimple_set_body (tree, gimple_seq); void gimple_set_body (tree, gimple_seq);
gimple_seq gimple_body (tree); gimple_seq gimple_body (tree);
bool gimple_has_body_p (tree); bool gimple_has_body_p (tree);
......
...@@ -1538,7 +1538,7 @@ gimplify_statement_list (tree *expr_p, gimple_seq *pre_p) ...@@ -1538,7 +1538,7 @@ gimplify_statement_list (tree *expr_p, gimple_seq *pre_p)
return GS_ALL_DONE; return GS_ALL_DONE;
} }
/* Compare two case labels. Because the front end should already have /* Compare two case labels. Because the front end should already have
made sure that case ranges do not overlap, it is enough to only compare made sure that case ranges do not overlap, it is enough to only compare
the CASE_LOW values of each case label. */ the CASE_LOW values of each case label. */
...@@ -1565,8 +1565,179 @@ sort_case_labels (VEC(tree,heap)* label_vec) ...@@ -1565,8 +1565,179 @@ sort_case_labels (VEC(tree,heap)* label_vec)
{ {
VEC_qsort (tree, label_vec, compare_case_labels); VEC_qsort (tree, label_vec, compare_case_labels);
} }
/* Prepare a vector of case labels to be used in a GIMPLE_SWITCH statement.
LABELS is a vector that contains all case labels to look at.
INDEX_TYPE is the type of the switch index expression. Case labels
in LABELS are discarded if their values are not in the value range
covered by INDEX_TYPE. The remaining case label values are folded
to INDEX_TYPE.
If a default case exists in LABELS, it is removed from LABELS and
returned in DEFAULT_CASEP. If no default case exists, but the
case labels already cover the whole range of INDEX_TYPE, a default
case is returned pointing to one of the existing case labels.
Otherwise DEFAULT_CASEP is set to NULL_TREE.
DEFAULT_CASEP may be NULL, in which case the above comment doesn't
apply and no action is taken regardless of whether a default case is
found or not. */
void
preprocess_case_label_vec_for_gimple (VEC(tree,heap) *labels,
tree index_type,
tree *default_casep)
{
tree min_value, max_value;
tree default_case = NULL_TREE;
size_t i, len;
i = 0;
min_value = TYPE_MIN_VALUE (index_type);
max_value = TYPE_MAX_VALUE (index_type);
while (i < VEC_length (tree, labels))
{
tree elt = VEC_index (tree, labels, i);
tree low = CASE_LOW (elt);
tree high = CASE_HIGH (elt);
bool remove_element = FALSE;
/* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can if (low)
{
gcc_checking_assert (TREE_CODE (low) == INTEGER_CST);
gcc_checking_assert (!high || TREE_CODE (high) == INTEGER_CST);
/* This is a non-default case label, i.e. it has a value.
See if the case label is reachable within the range of
the index type. Remove out-of-range case values. Turn
case ranges into a canonical form (high > low strictly)
and convert the case label values to the index type.
NB: The type of gimple_switch_index() may be the promoted
type, but the case labels retain the original type. */
if (high)
{
/* This is a case range. Discard empty ranges.
If the bounds or the range are equal, turn this
into a simple (one-value) case. */
int cmp = tree_int_cst_compare (high, low);
if (cmp < 0)
remove_element = TRUE;
else if (cmp == 0)
high = NULL_TREE;
}
if (! high)
{
/* If the simple case value is unreachable, ignore it. */
if ((TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (low, min_value) < 0)
|| (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (low, max_value) > 0))
remove_element = TRUE;
else
low = fold_convert (index_type, low);
}
else
{
/* If the entire case range is unreachable, ignore it. */
if ((TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (high, min_value) < 0)
|| (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (low, max_value) > 0))
remove_element = TRUE;
else
{
/* If the lower bound is less than the index type's
minimum value, truncate the range bounds. */
if (TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (low, min_value) < 0)
low = min_value;
low = fold_convert (index_type, low);
/* If the upper bound is greater than the index type's
maximum value, truncate the range bounds. */
if (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (high, max_value) > 0)
high = max_value;
high = fold_convert (index_type, high);
}
}
CASE_LOW (elt) = low;
CASE_HIGH (elt) = high;
}
else
{
gcc_assert (!default_case);
default_case = elt;
/* The default case must be passed separately to the
gimple_build_switch routines. But if DEFAULT_CASEP
is NULL, we do not remove the default case (it would
be completely lost). */
if (default_casep)
remove_element = TRUE;
}
if (remove_element)
VEC_ordered_remove (tree, labels, i);
else
i++;
}
len = i;
if (!VEC_empty (tree, labels))
sort_case_labels (labels);
if (default_casep && !default_case)
{
/* If the switch has no default label, add one, so that we jump
around the switch body. If the labels already cover the whole
range of the switch index_type, add the default label pointing
to one of the existing labels. */
if (len
&& TYPE_MIN_VALUE (index_type)
&& TYPE_MAX_VALUE (index_type)
&& tree_int_cst_equal (CASE_LOW (VEC_index (tree, labels, 0)),
TYPE_MIN_VALUE (index_type)))
{
tree low, high = CASE_HIGH (VEC_index (tree, labels, len - 1));
if (!high)
high = CASE_LOW (VEC_index (tree, labels, len - 1));
if (tree_int_cst_equal (high, TYPE_MAX_VALUE (index_type)))
{
for (i = 1; i < len; i++)
{
high = CASE_LOW (VEC_index (tree, labels, i));
low = CASE_HIGH (VEC_index (tree, labels, i - 1));
if (!low)
low = CASE_LOW (VEC_index (tree, labels, i - 1));
if ((TREE_INT_CST_LOW (low) + 1
!= TREE_INT_CST_LOW (high))
|| (TREE_INT_CST_HIGH (low)
+ (TREE_INT_CST_LOW (high) == 0)
!= TREE_INT_CST_HIGH (high)))
break;
}
if (i == len)
{
tree label = CASE_LABEL (VEC_index (tree, labels, 0));
default_case = build_case_label (NULL_TREE, NULL_TREE,
label);
}
}
}
}
if (default_casep)
*default_casep = default_case;
}
/* Gimplify a SWITCH_EXPR, and collect the vector of labels it can
branch to. */ branch to. */
static enum gimplify_status static enum gimplify_status
...@@ -1588,9 +1759,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1588,9 +1759,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
{ {
VEC (tree,heap) *labels; VEC (tree,heap) *labels;
VEC (tree,heap) *saved_labels; VEC (tree,heap) *saved_labels;
tree min_value, max_value;
tree default_case = NULL_TREE; tree default_case = NULL_TREE;
size_t i, len;
gimple gimple_switch; gimple gimple_switch;
/* If someone can be bothered to fill in the labels, they can /* If someone can be bothered to fill in the labels, they can
...@@ -1606,155 +1775,22 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1606,155 +1775,22 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
labels = gimplify_ctxp->case_labels; labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels; gimplify_ctxp->case_labels = saved_labels;
i = 0; preprocess_case_label_vec_for_gimple (labels, index_type,
min_value = TYPE_MIN_VALUE (index_type); &default_case);
max_value = TYPE_MAX_VALUE (index_type);
while (i < VEC_length (tree, labels))
{
tree elt = VEC_index (tree, labels, i);
tree low = CASE_LOW (elt);
tree high = CASE_HIGH (elt);
bool remove_element = FALSE;
if (low)
{
gcc_checking_assert (TREE_CODE (low) == INTEGER_CST);
gcc_checking_assert (!high || TREE_CODE (high) == INTEGER_CST);
/* This is a non-default case label, i.e. it has a value.
See if the case label is reachable within the range of
the index type. Remove out-of-range case values. Turn
case ranges into a canonical form (high > low strictly)
and convert the case label values to the index type.
NB: The type of gimple_switch_index() may be the promoted
type, but the case labels retain the original type. */
if (high)
{
/* This is a case range. Discard empty ranges.
If the bounds or the range are equal, turn this
into a simple (one-value) case. */
int cmp = tree_int_cst_compare (high, low);
if (cmp < 0)
remove_element = TRUE;
else if (cmp == 0)
high = NULL_TREE;
}
if (! high)
{
/* If the simple case value is unreachable, ignore it. */
if ((TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (low, min_value) < 0)
|| (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (low, max_value) > 0))
remove_element = TRUE;
else
low = fold_convert (index_type, low);
}
else
{
/* If the entire case range is unreachable, ignore it. */
if ((TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (high, min_value) < 0)
|| (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (low, max_value) > 0))
remove_element = TRUE;
else
{
/* If the lower bound is less than the index type's
minimum value, truncate the range bounds. */
if (TREE_CODE (min_value) == INTEGER_CST
&& tree_int_cst_compare (low, min_value) < 0)
low = min_value;
low = fold_convert (index_type, low);
/* If the upper bound is greater than the index type's
maximum value, truncate the range bounds. */
if (TREE_CODE (max_value) == INTEGER_CST
&& tree_int_cst_compare (high, max_value) > 0)
high = max_value;
high = fold_convert (index_type, high);
}
}
CASE_LOW (elt) = low;
CASE_HIGH (elt) = high;
}
else
{
/* The default case must be the last label in the list. */
gcc_assert (!default_case);
default_case = elt;
remove_element = TRUE;
}
if (remove_element)
VEC_ordered_remove (tree, labels, i);
else
i++;
}
len = i;
if (!VEC_empty (tree, labels))
sort_case_labels (labels);
if (!default_case) if (!default_case)
{ {
/* If the switch has no default label, add one, so that we jump gimple new_default;
around the switch body. If the labels already cover the whole
range of the switch index_type, add the default label pointing
to one of the existing labels. */
if (len
&& TYPE_MIN_VALUE (index_type)
&& TYPE_MAX_VALUE (index_type)
&& tree_int_cst_equal (CASE_LOW (VEC_index (tree, labels, 0)),
TYPE_MIN_VALUE (index_type)))
{
tree low, high = CASE_HIGH (VEC_index (tree, labels, len - 1));
if (!high)
high = CASE_LOW (VEC_index (tree, labels, len - 1));
if (tree_int_cst_equal (high, TYPE_MAX_VALUE (index_type)))
{
for (i = 1; i < len; i++)
{
high = CASE_LOW (VEC_index (tree, labels, i));
low = CASE_HIGH (VEC_index (tree, labels, i - 1));
if (!low)
low = CASE_LOW (VEC_index (tree, labels, i - 1));
if ((TREE_INT_CST_LOW (low) + 1
!= TREE_INT_CST_LOW (high))
|| (TREE_INT_CST_HIGH (low)
+ (TREE_INT_CST_LOW (high) == 0)
!= TREE_INT_CST_HIGH (high)))
break;
}
if (i == len)
{
tree label = CASE_LABEL (VEC_index (tree, labels, 0));
default_case = build_case_label (NULL_TREE, NULL_TREE,
label);
}
}
}
if (!default_case) default_case
{ = build_case_label (NULL_TREE, NULL_TREE,
gimple new_default; create_artificial_label (UNKNOWN_LOCATION));
new_default = gimple_build_label (CASE_LABEL (default_case));
default_case gimplify_seq_add_stmt (&switch_body_seq, new_default);
= build_case_label (NULL_TREE, NULL_TREE,
create_artificial_label (UNKNOWN_LOCATION));
new_default = gimple_build_label (CASE_LABEL (default_case));
gimplify_seq_add_stmt (&switch_body_seq, new_default);
}
} }
gimple_switch = gimple_build_switch_vec (SWITCH_COND (switch_expr), gimple_switch = gimple_build_switch_vec (SWITCH_COND (switch_expr),
default_case, labels); default_case, labels);
gimplify_seq_add_stmt (pre_p, gimple_switch); gimplify_seq_add_stmt (pre_p, gimple_switch);
gimplify_seq_add_seq (pre_p, switch_body_seq); gimplify_seq_add_seq (pre_p, switch_body_seq);
VEC_free(tree, heap, labels); VEC_free(tree, heap, labels);
......
2012-05-02 Steven Bosscher <steven@gcc.gnu.org>
PR middle-end/53153
* gcc.dg/pr53153.c: New test.
2012-05-02 Richard Guenther <rguenther@suse.de> 2012-05-02 Richard Guenther <rguenther@suse.de>
* g++.dg/tree-ssa/pr19807.C: Adjust. * g++.dg/tree-ssa/pr19807.C: Adjust.
......
/* { dg-do compile } */
/* { dg-options "-O2" } */
extern void bar (void);
/* Case 181 is not in the range for 'char'. */
void
foo1 (char *buf)
{
int x = *buf;
switch (x)
{
case -76:
case 65:
case 181:
bar();
}
}
/* All cases are below the range of char. */
void
foo2 (char *buf)
{
int x = *buf;
switch (x)
{
case -150:
case -140:
case -130:
bar();
}
}
/* All cases are above the range of char. */
void
foo3 (char *buf)
{
int x = *buf;
switch (x)
{
case 130:
case 140:
case 150: /* This case is not in the range for 'char'. */
bar();
}
}
/* The bounding cases are partially out of range for char. */
void
foo4 (char *buf)
{
int x = *buf;
switch (x)
{
case -130 ... -120:
case 100:
case 120 ... 130:
bar();
}
}
...@@ -163,7 +163,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -163,7 +163,7 @@ along with GCC; see the file COPYING3. If not see
static bool forward_propagate_addr_expr (tree name, tree rhs); static bool forward_propagate_addr_expr (tree name, tree rhs);
/* Set to true if we delete EH edges during the optimization. */ /* Set to true if we delete dead edges during the optimization. */
static bool cfg_changed; static bool cfg_changed;
static tree rhs_to_tree (tree type, gimple stmt); static tree rhs_to_tree (tree type, gimple stmt);
...@@ -1319,6 +1319,78 @@ simplify_not_neg_expr (gimple_stmt_iterator *gsi_p) ...@@ -1319,6 +1319,78 @@ simplify_not_neg_expr (gimple_stmt_iterator *gsi_p)
return false; return false;
} }
/* Helper function for simplify_gimple_switch. Remove case labels that
have values outside the range of the new type. */
static void
simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
{
unsigned int branch_num = gimple_switch_num_labels (stmt);
VEC(tree, heap) *labels = VEC_alloc (tree, heap, branch_num);
unsigned int i, len;
/* Collect the existing case labels in a VEC, and preprocess it as if
we are gimplifying a GENERIC SWITCH_EXPR. */
for (i = 1; i < branch_num; i++)
VEC_quick_push (tree, labels, gimple_switch_label (stmt, i));
preprocess_case_label_vec_for_gimple (labels, index_type, NULL);
/* If any labels were removed, replace the existing case labels
in the GIMPLE_SWITCH statement with the correct ones.
Note that the type updates were done in-place on the case labels,
so we only have to replace the case labels in the GIMPLE_SWITCH
if the number of labels changed. */
len = VEC_length (tree, labels);
if (len < branch_num - 1)
{
bitmap target_blocks;
edge_iterator ei;
edge e;
/* Corner case: *all* case labels have been removed as being
out-of-range for INDEX_TYPE. Push one label and let the
CFG cleanups deal with this further. */
if (len == 0)
{
tree label, elt;
label = CASE_LABEL (gimple_switch_default_label (stmt));
elt = build_case_label (build_int_cst (index_type, 0), NULL, label);
VEC_quick_push (tree, labels, elt);
len = 1;
}
for (i = 0; i < VEC_length (tree, labels); i++)
gimple_switch_set_label (stmt, i + 1, VEC_index (tree, labels, i));
for (i++ ; i < branch_num; i++)
gimple_switch_set_label (stmt, i, NULL_TREE);
gimple_switch_set_num_labels (stmt, len + 1);
/* Cleanup any edges that are now dead. */
target_blocks = BITMAP_ALLOC (NULL);
for (i = 0; i < gimple_switch_num_labels (stmt); i++)
{
tree elt = gimple_switch_label (stmt, i);
basic_block target = label_to_block (CASE_LABEL (elt));
bitmap_set_bit (target_blocks, target->index);
}
for (ei = ei_start (gimple_bb (stmt)->succs); (e = ei_safe_edge (ei)); )
{
if (! bitmap_bit_p (target_blocks, e->dest->index))
{
remove_edge (e);
cfg_changed = true;
free_dominance_info (CDI_DOMINATORS);
}
else
ei_next (&ei);
}
BITMAP_FREE (target_blocks);
}
VEC_free (tree, heap, labels);
}
/* STMT is a SWITCH_EXPR for which we attempt to find equivalent forms of /* STMT is a SWITCH_EXPR for which we attempt to find equivalent forms of
the condition which we may be able to optimize better. */ the condition which we may be able to optimize better. */
...@@ -1344,9 +1416,6 @@ simplify_gimple_switch (gimple stmt) ...@@ -1344,9 +1416,6 @@ simplify_gimple_switch (gimple stmt)
def = gimple_assign_rhs1 (def_stmt); def = gimple_assign_rhs1 (def_stmt);
/* ??? Why was Jeff testing this? We are gimple... */
gcc_checking_assert (is_gimple_val (def));
to = TREE_TYPE (cond); to = TREE_TYPE (cond);
ti = TREE_TYPE (def); ti = TREE_TYPE (def);
...@@ -1367,6 +1436,7 @@ simplify_gimple_switch (gimple stmt) ...@@ -1367,6 +1436,7 @@ simplify_gimple_switch (gimple stmt)
if (!fail) if (!fail)
{ {
gimple_switch_set_index (stmt, def); gimple_switch_set_index (stmt, def);
simplify_gimple_switch_label_vec (stmt, ti);
update_stmt (stmt); update_stmt (stmt);
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment