From 8bacfa5896b8d430951e0400f574aa42b30f2174 Mon Sep 17 00:00:00 2001 From: sayle Date: Mon, 11 Oct 2004 16:11:35 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88881 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 +++++ gcc/stmt.c | 104 ++++++++++++++++++++++++++-------------- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.dg/switch-4.c | 24 ++++++++++ 4 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/switch-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4df3fea..947f656 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-10-11 Roger Sayle + + 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 * config/s390/s390-protos.h (s390_offset_p): Add prototype. diff --git a/gcc/stmt.c b/gcc/stmt.c index 3d7ad36..5560dbc 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -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_is_bounded (case_node_ptr, 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, @@ -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 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 - 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 * -add_case_node (struct case_node *head, tree low, tree high, tree label) +static struct case_node * +add_case_node (struct case_node *head, tree type, tree low, tree high, + tree label) { + tree min_value, max_value; 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 just a simple case label. But that's just a degenerate case range. If the bounds are equal, turn this into the one-value case. */ 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. */ r = ggc_alloc (sizeof (struct case_node)); @@ -2307,7 +2344,7 @@ expand_case (tree exp) rtx table_label; int ncases; rtx *labelvec; - int i; + int i, fail; rtx before_case, end, lab; tree vec = SWITCH_LABELS (exp); @@ -2332,34 +2369,36 @@ expand_case (tree exp) gcc_assert (!SWITCH_BODY (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 (); - /* 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. */ 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, after the body of the switch. */ @@ -2380,13 +2419,6 @@ expand_case (tree exp) count = 0; 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 of them (treating them as signed even if they are not). */ if (count++ == 0) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5009857..44270aa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-10-11 Roger Sayle + + PR middle-end/17657 + * gcc.dg/switch-4.c: New test case. + 2004-10-11 Richard Sandiford * gcc.c-torture/execute/20041011-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/switch-4.c b/gcc/testsuite/gcc.dg/switch-4.c new file mode 100644 index 0000000..f2d8530 --- /dev/null +++ b/gcc/testsuite/gcc.dg/switch-4.c @@ -0,0 +1,24 @@ +/* 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; + } +} + -- 2.7.4