Commit eb172681 by Roger Sayle Committed by Roger Sayle

re PR middle-end/17657 (ICE in expand_case)


	PR middle-end/17657
	* stmt.c (add_case_node): Add additional type argument.  Declare
	as static to match prototype.  Convert the upper and lower bounds
	to the specified index type.  Optimize away case ranges/values
	that are outside the index type's bounds.  Truncate case ranges
	that span the index type's bounds.
	(expand_case): Avoid unnessary computation and memory allocation
	when index type is error_mark_node.  Pass index_type as required
	by change to add_case_node API.  No need to convert case range
	bounds to index_type, this is now done by add_case_node.

	* gcc.dg/switch-4.c: New test case.

From-SVN: r88881
parent 539ed333
2004-10-11 Roger Sayle <roger@eyesopen.com>
PR middle-end/17657
* stmt.c (add_case_node): Add additional type argument. Declare
as static to match prototype. Convert the upper and lower bounds
to the specified index type. Optimize away case ranges/values
that are outside the index type's bounds. Truncate case ranges
that span the index type's bounds.
(expand_case): Avoid unnessary computation and memory allocation
when index type is error_mark_node. Pass index_type as required
by change to add_case_node API. No need to convert case range
bounds to index_type, this is now done by add_case_node.
2004-10-11 Ulrich Weigand <uweigand@de.ibm.com> 2004-10-11 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390-protos.h (s390_offset_p): Add prototype. * config/s390/s390-protos.h (s390_offset_p): Add prototype.
......
...@@ -122,7 +122,8 @@ static int node_has_low_bound (case_node_ptr, tree); ...@@ -122,7 +122,8 @@ static int node_has_low_bound (case_node_ptr, tree);
static int node_has_high_bound (case_node_ptr, tree); static int node_has_high_bound (case_node_ptr, tree);
static int node_is_bounded (case_node_ptr, tree); static int node_is_bounded (case_node_ptr, tree);
static void emit_case_nodes (rtx, case_node_ptr, rtx, tree); static void emit_case_nodes (rtx, case_node_ptr, rtx, tree);
static struct case_node *add_case_node (struct case_node *, tree, tree, tree); static struct case_node *add_case_node (struct case_node *, tree,
tree, tree, tree);
/* Return the rtx-label that corresponds to a LABEL_DECL, /* Return the rtx-label that corresponds to a LABEL_DECL,
...@@ -2115,19 +2116,55 @@ expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED, ...@@ -2115,19 +2116,55 @@ expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
/* Do the insertion of a case label into case_list. The labels are /* Do the insertion of a case label into case_list. The labels are
fed to us in descending order from the sorted vector of case labels used fed to us in descending order from the sorted vector of case labels used
in the tree part of the middle end. So the list we construct is in the tree part of the middle end. So the list we construct is
sorted in ascending order. */ sorted in ascending order. The bounds on the case range, LOW and HIGH,
are converted to case's index type TYPE. */
struct case_node * static struct case_node *
add_case_node (struct case_node *head, tree low, tree high, tree label) add_case_node (struct case_node *head, tree type, tree low, tree high,
tree label)
{ {
tree min_value, max_value;
struct case_node *r; struct case_node *r;
gcc_assert (TREE_CODE (low) == INTEGER_CST);
gcc_assert (!high || TREE_CODE (high) == INTEGER_CST);
min_value = TYPE_MIN_VALUE (type);
max_value = TYPE_MAX_VALUE (type);
/* If there's no HIGH value, then this is not a case range; it's /* If there's no HIGH value, then this is not a case range; it's
just a simple case label. But that's just a degenerate case just a simple case label. But that's just a degenerate case
range. range.
If the bounds are equal, turn this into the one-value case. */ If the bounds are equal, turn this into the one-value case. */
if (!high || tree_int_cst_equal (low, high)) if (!high || tree_int_cst_equal (low, high))
high = low; {
/* If the simple case value is unreachable, ignore it. */
if (tree_int_cst_compare (low, min_value) < 0
|| tree_int_cst_compare (low, max_value) > 0)
return head;
low = fold_convert (type, low);
high = low;
}
else
{
/* If the entire case range is unreachable, ignore it. */
if (tree_int_cst_compare (high, min_value) < 0
|| tree_int_cst_compare (low, max_value) > 0)
return head;
/* If the lower bound is less than the index type's minimum
value, truncate the range bounds. */
if (tree_int_cst_compare (low, min_value) < 0)
low = min_value;
low = fold_convert (type, low);
/* If the upper bound is greater than the index type's maximum
value, truncate the range bounds. */
if (tree_int_cst_compare (high, max_value) > 0)
high = max_value;
high = fold_convert (type, high);
}
/* Add this label to the chain. */ /* Add this label to the chain. */
r = ggc_alloc (sizeof (struct case_node)); r = ggc_alloc (sizeof (struct case_node));
...@@ -2307,7 +2344,7 @@ expand_case (tree exp) ...@@ -2307,7 +2344,7 @@ expand_case (tree exp)
rtx table_label; rtx table_label;
int ncases; int ncases;
rtx *labelvec; rtx *labelvec;
int i; int i, fail;
rtx before_case, end, lab; rtx before_case, end, lab;
tree vec = SWITCH_LABELS (exp); tree vec = SWITCH_LABELS (exp);
...@@ -2332,34 +2369,36 @@ expand_case (tree exp) ...@@ -2332,34 +2369,36 @@ expand_case (tree exp)
gcc_assert (!SWITCH_BODY (exp)); gcc_assert (!SWITCH_BODY (exp));
gcc_assert (SWITCH_LABELS (exp)); gcc_assert (SWITCH_LABELS (exp));
for (i = TREE_VEC_LENGTH (vec); --i >= 0; )
{
tree elt = TREE_VEC_ELT (vec, i);
/* Handle default labels specially. */
if (!CASE_HIGH (elt) && !CASE_LOW (elt))
{
gcc_assert (!default_label_decl);
default_label_decl = CASE_LABEL (elt);
}
else
case_list = add_case_node (case_list, CASE_LOW (elt), CASE_HIGH (elt),
CASE_LABEL (elt));
}
do_pending_stack_adjust (); do_pending_stack_adjust ();
/* Make sure start points to something that won't need any transformation
before the end of this function. */
if (!NOTE_P (get_last_insn ()))
emit_note (NOTE_INSN_DELETED);
start = get_last_insn ();
/* An ERROR_MARK occurs for various reasons including invalid data type. */ /* An ERROR_MARK occurs for various reasons including invalid data type. */
if (index_type != error_mark_node) if (index_type != error_mark_node)
{ {
int fail; for (i = TREE_VEC_LENGTH (vec); --i >= 0; )
{
tree elt = TREE_VEC_ELT (vec, i);
/* Handle default labels specially. */
if (!CASE_HIGH (elt) && !CASE_LOW (elt))
{
gcc_assert (!default_label_decl);
default_label_decl = CASE_LABEL (elt);
}
else
case_list = add_case_node (case_list, index_type,
CASE_LOW (elt), CASE_HIGH (elt),
CASE_LABEL (elt));
}
/* Make sure start points to something that won't need any
transformation before the end of this function. */
start = get_last_insn ();
if (! NOTE_P (start))
{
emit_note (NOTE_INSN_DELETED);
start = get_last_insn ();
}
/* If we don't have a default-label, create one here, /* If we don't have a default-label, create one here,
after the body of the switch. */ after the body of the switch. */
...@@ -2380,13 +2419,6 @@ expand_case (tree exp) ...@@ -2380,13 +2419,6 @@ expand_case (tree exp)
count = 0; count = 0;
for (n = case_list; n; n = n->right) for (n = case_list; n; n = n->right)
{ {
/* Check low and high label values are integers. */
gcc_assert (TREE_CODE (n->low) == INTEGER_CST);
gcc_assert (TREE_CODE (n->high) == INTEGER_CST);
n->low = convert (index_type, n->low);
n->high = convert (index_type, n->high);
/* Count the elements and track the largest and smallest /* Count the elements and track the largest and smallest
of them (treating them as signed even if they are not). */ of them (treating them as signed even if they are not). */
if (count++ == 0) if (count++ == 0)
......
2004-10-11 Roger Sayle <roger@eyesopen.com>
PR middle-end/17657
* gcc.dg/switch-4.c: New test case.
2004-10-11 Richard Sandiford <rsandifo@redhat.com> 2004-10-11 Richard Sandiford <rsandifo@redhat.com>
* gcc.c-torture/execute/20041011-1.c: New test. * gcc.c-torture/execute/20041011-1.c: New test.
......
/* PR middle-end/17657 */
/* { dg-do compile } */
/* { dg-options "-O2" } */
extern signed char foo(int);
void bar (void)
{
signed char tmp = foo (0);
int t1 = tmp;
switch (t1)
{
case 1: foo (1); break;
case 2: foo (2); break;
case 3: foo (3); break;
case 4: foo (4); break;
case 5: foo (5); break;
case 6: foo (6); break;
case 7: foo (7); break;
case 255: foo (8); break;
default: break;
}
}
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