From: espindola Date: Fri, 18 Apr 2008 21:23:10 +0000 (+0000) Subject: 2008-04-18 Rafael Espindola X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=d31e54f19a2df9446469fb87557a812eb5854f49 2008-04-18 Rafael Espindola * tree-vrp.c (find_case_label_index): Fix the binary search. (find_case_label_range): New. (vrp_visit_switch_stmt): Use find_case_label_range. (simplify_switch_using_ranges): Use find_case_label_range. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@134452 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c3296981345..a86b7494707 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2008-04-18 Rafael Espindola + * tree-vrp.c (find_case_label_index): Fix the binary search. + (find_case_label_range): New. + (vrp_visit_switch_stmt): Use find_case_label_range. + (simplify_switch_using_ranges): Use find_case_label_range. + 2008-04-18 Eric Botcazou * gimplify.c (gimplify_modify_expr_rhs) : Gimplify the LHS diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 76477c850ac..e9106c47f19 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -5528,48 +5528,52 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p) return (*taken_edge_p) ? SSA_PROP_INTERESTING : SSA_PROP_VARYING; } +/* Searches the case label vector VEC for the index *IDX of the CASE_LABEL + that includes the value VAL. The search is restricted to the range + [START_IDX, n - 2] where n is the size of VEC (n - 1 is the default label). -/* Searches the case label vector VEC for the index *IDX the CASE_LABEL - includes the value VAL. The search starts at index START_IDX and - true is returned if *IDX corresponds to such an index. False is - returned in case VAL hits the default case label and *IDX in this - case is the next higher or the next lower case label index. */ + If there is a CASE_LABEL for VAL, its index is placed in IDX and true is + returned. + + If there is no CASE_LABEL for VAL and the is one that is larger than VAL, + it is placed in IDX and false is returned. + + If VAL is larger than any CASE_LABEL, n - 1 is placed on IDX and false is + returned. */ static bool find_case_label_index (tree vec, size_t start_idx, tree val, size_t *idx) { size_t n = TREE_VEC_LENGTH (vec); - size_t low, high, i = start_idx; + size_t low, high; + + /* Find case label for minimum of the value range or the next one. + At each iteration we are searching in [low, high - 1]. */ - /* Find case label for minimum of the value range or the next one. */ - for (low = start_idx - 1, high = n - 1; high - low > 1; ) + for (low = start_idx, high = n - 1; high != low; ) { tree t; int cmp; - i = (high + low) / 2; + /* Note that i != high, so we never ask for n - 1. */ + size_t i = (high + low) / 2; t = TREE_VEC_ELT (vec, i); /* Cache the result of comparing CASE_LOW and val. */ cmp = tree_int_cst_compare (CASE_LOW (t), val); - if (cmp > 0) + if (cmp == 0) + { + /* Ranges cannot be empty. */ + *idx = i; + return true; + } + else if (cmp > 0) high = i; else - low = i; - - if (CASE_HIGH (t) == NULL) - { - /* A singe-valued case label. */ - if (cmp == 0) - { - *idx = i; - return true; - } - } - else - { - /* A case range. We can only handle integer ranges. */ - if (cmp <= 0 && tree_int_cst_compare (CASE_HIGH (t), val) >= 0) + { + low = i + 1; + if (CASE_HIGH (t) != NULL + && tree_int_cst_compare (CASE_HIGH (t), val) >= 0) { *idx = i; return true; @@ -5577,10 +5581,66 @@ find_case_label_index (tree vec, size_t start_idx, tree val, size_t *idx) } } - *idx = i; + *idx = high; return false; } +/* Searches the case label vector VEC for the range of CASE_LABELs that is used + for values between MIN and MAX. The first index is placed in MIN_IDX. The + last index is placed in MAX_IDX. If the range of CASE_LABELs is empty + then MAX_IDX < MIN_IDX. + Returns true if the default label is not needed. */ + +static bool +find_case_label_range (tree vec, tree min, tree max, size_t *min_idx, size_t *max_idx) +{ + size_t i, j; + bool min_take_default = !find_case_label_index (vec, 0, min, &i); + bool max_take_default = !find_case_label_index (vec, i, max, &j); + + if (i == j + && min_take_default + && max_take_default) + { + /* Only the default case label reached. + Return an empty range. */ + *min_idx = 1; + *max_idx = 0; + return false; + } + else + { + bool take_default = min_take_default || max_take_default; + tree low, high; + size_t k; + + if (max_take_default) + j--; + + /* If the case label range is continuous, we do not need + the default case label. Verify that. */ + high = CASE_LOW (TREE_VEC_ELT (vec, i)); + if (CASE_HIGH (TREE_VEC_ELT (vec, i))) + high = CASE_HIGH (TREE_VEC_ELT (vec, i)); + for (k = i + 1; k <= j; ++k) + { + low = CASE_LOW (TREE_VEC_ELT (vec, k)); + if (!integer_onep (int_const_binop (MINUS_EXPR, low, high, 0))) + { + take_default = true; + break; + } + high = low; + if (CASE_HIGH (TREE_VEC_ELT (vec, k))) + high = CASE_HIGH (TREE_VEC_ELT (vec, k)); + } + + *min_idx = i; + *max_idx = j; + return !take_default; + } +} + /* Visit switch statement STMT. If we can determine which edge will be taken out of STMT's basic block, record it in *TAKEN_EDGE_P and return SSA_PROP_INTERESTING. Otherwise, return @@ -5593,7 +5653,7 @@ vrp_visit_switch_stmt (tree stmt, edge *taken_edge_p) value_range_t *vr; size_t i = 0, j = 0, n; tree vec; - bool min_take_default, max_take_default; + bool take_default; *taken_edge_p = NULL; op = TREE_OPERAND (stmt, 0); @@ -5618,27 +5678,23 @@ vrp_visit_switch_stmt (tree stmt, edge *taken_edge_p) vec = SWITCH_LABELS (stmt); n = TREE_VEC_LENGTH (vec); - /* Find case label for minimum of the value range or the next one. */ - min_take_default = !find_case_label_index (vec, 0, vr->min, &i); - - /* Find case label for maximum of the value range or the previous one. */ - max_take_default = !find_case_label_index (vec, i, vr->max, &j); + take_default = !find_case_label_range (vec, vr->min, vr->max, &i, &j); - /* Check if we reach the default label only. */ + /* Check if the range spans no CASE_LABEL. If so, we only reach the default + label */ if (j < i) - val = TREE_VEC_ELT (vec, n - 1); - /* Check if we reach exactly one label and not the default label. */ - else if (i == j - && !min_take_default - && !max_take_default) - val = TREE_VEC_ELT (vec, i); + { + gcc_assert (take_default); + val = TREE_VEC_ELT (vec, n - 1); + } else { - /* Check if labels with index i to j are all reaching the same label. - If we don't hit a single case label only, the default case also has - to branch to the same label. */ + /* Check if labels with index i to j and maybe the default label + are all reaching the same label. */ + val = TREE_VEC_ELT (vec, i); - if (CASE_LABEL (TREE_VEC_ELT (vec, n - 1)) != CASE_LABEL (val)) + if (take_default + && CASE_LABEL (TREE_VEC_ELT (vec, n - 1)) != CASE_LABEL (val)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " not a single destination for this " @@ -6323,32 +6379,7 @@ simplify_switch_using_ranges (tree stmt) /* Find case label for min/max of the value range. */ vec = SWITCH_LABELS (stmt); n = TREE_VEC_LENGTH (vec); - take_default = !find_case_label_index (vec, 0, vr->min, &i); - take_default |= !find_case_label_index (vec, i, vr->max, &j); - - /* If the case label range is continuous, we do not need to - preserve the default case label. Verify that. */ - if (!take_default && j > i) - { - tree low, high; - size_t k; - - high = CASE_LOW (TREE_VEC_ELT (vec, i)); - if (CASE_HIGH (TREE_VEC_ELT (vec, i))) - high = CASE_HIGH (TREE_VEC_ELT (vec, i)); - for (k = i + 1; k <= j; ++k) - { - low = CASE_LOW (TREE_VEC_ELT (vec, k)); - if (!integer_onep (int_const_binop (MINUS_EXPR, low, high, 0))) - { - take_default = true; - break; - } - high = low; - if (CASE_HIGH (TREE_VEC_ELT (vec, k))) - high = CASE_HIGH (TREE_VEC_ELT (vec, k)); - } - } + take_default = !find_case_label_range (vec, vr->min, vr->max, &i, &j); /* Bail out if this is just all edges taken. */ if (i == 0