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);
......
...@@ -1566,45 +1566,33 @@ sort_case_labels (VEC(tree,heap)* label_vec) ...@@ -1566,45 +1566,33 @@ sort_case_labels (VEC(tree,heap)* label_vec)
VEC_qsort (tree, label_vec, compare_case_labels); VEC_qsort (tree, label_vec, compare_case_labels);
} }
/* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can /* Prepare a vector of case labels to be used in a GIMPLE_SWITCH statement.
branch to. */
static enum gimplify_status LABELS is a vector that contains all case labels to look at.
gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
{
tree switch_expr = *expr_p;
gimple_seq switch_body_seq = NULL;
enum gimplify_status ret;
tree index_type = TREE_TYPE (switch_expr);
if (index_type == NULL_TREE)
index_type = TREE_TYPE (SWITCH_COND (switch_expr));
ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, is_gimple_val, INDEX_TYPE is the type of the switch index expression. Case labels
fb_rvalue); in LABELS are discarded if their values are not in the value range
if (ret == GS_ERROR || ret == GS_UNHANDLED) covered by INDEX_TYPE. The remaining case label values are folded
return ret; to INDEX_TYPE.
if (SWITCH_BODY (switch_expr)) If a default case exists in LABELS, it is removed from LABELS and
{ returned in DEFAULT_CASEP. If no default case exists, but the
VEC (tree,heap) *labels; case labels already cover the whole range of INDEX_TYPE, a default
VEC (tree,heap) *saved_labels; 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 min_value, max_value;
tree default_case = NULL_TREE; tree default_case = NULL_TREE;
size_t i, len; size_t i, len;
gimple gimple_switch;
/* If someone can be bothered to fill in the labels, they can
be bothered to null out the body too. */
gcc_assert (!SWITCH_LABELS (switch_expr));
/* Save old labels, get new ones from body, then restore the old
labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq);
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
i = 0; i = 0;
min_value = TYPE_MIN_VALUE (index_type); min_value = TYPE_MIN_VALUE (index_type);
...@@ -1616,7 +1604,6 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1616,7 +1604,6 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
tree high = CASE_HIGH (elt); tree high = CASE_HIGH (elt);
bool remove_element = FALSE; bool remove_element = FALSE;
if (low) if (low)
{ {
gcc_checking_assert (TREE_CODE (low) == INTEGER_CST); gcc_checking_assert (TREE_CODE (low) == INTEGER_CST);
...@@ -1686,9 +1673,13 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1686,9 +1673,13 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
} }
else else
{ {
/* The default case must be the last label in the list. */
gcc_assert (!default_case); gcc_assert (!default_case);
default_case = elt; 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; remove_element = TRUE;
} }
...@@ -1702,7 +1693,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1702,7 +1693,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
if (!VEC_empty (tree, labels)) if (!VEC_empty (tree, labels))
sort_case_labels (labels); sort_case_labels (labels);
if (!default_case) if (default_casep && !default_case)
{ {
/* If the switch has no default label, add one, so that we jump /* If the switch has no default label, add one, so that we jump
around the switch body. If the labels already cover the whole around the switch body. If the labels already cover the whole
...@@ -1740,6 +1731,52 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1740,6 +1731,52 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
} }
} }
} }
}
if (default_casep)
*default_casep = default_case;
}
/* Gimplify a SWITCH_EXPR, and collect the vector of labels it can
branch to. */
static enum gimplify_status
gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
{
tree switch_expr = *expr_p;
gimple_seq switch_body_seq = NULL;
enum gimplify_status ret;
tree index_type = TREE_TYPE (switch_expr);
if (index_type == NULL_TREE)
index_type = TREE_TYPE (SWITCH_COND (switch_expr));
ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, is_gimple_val,
fb_rvalue);
if (ret == GS_ERROR || ret == GS_UNHANDLED)
return ret;
if (SWITCH_BODY (switch_expr))
{
VEC (tree,heap) *labels;
VEC (tree,heap) *saved_labels;
tree default_case = NULL_TREE;
gimple gimple_switch;
/* If someone can be bothered to fill in the labels, they can
be bothered to null out the body too. */
gcc_assert (!SWITCH_LABELS (switch_expr));
/* Save old labels, get new ones from body, then restore the old
labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq);
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
preprocess_case_label_vec_for_gimple (labels, index_type,
&default_case);
if (!default_case) if (!default_case)
{ {
...@@ -1751,7 +1788,6 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -1751,7 +1788,6 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
new_default = gimple_build_label (CASE_LABEL (default_case)); new_default = gimple_build_label (CASE_LABEL (default_case));
gimplify_seq_add_stmt (&switch_body_seq, new_default); 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);
......
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