From: Richard Guenther Date: Wed, 2 Apr 2008 12:51:37 +0000 (+0000) Subject: re PR tree-optimization/14495 ([tree-ssa] Propagate range info into a switch statement) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8aea0bf08194b3bb9699c0a71ad02284b7a4ebc0;p=gcc.git re PR tree-optimization/14495 ([tree-ssa] Propagate range info into a switch statement) 2008-04-02 Richard Guenther PR tree-optimization/14495 * tree-vrp.c (vrp_visit_cond_stmt): Do not handle SWITCH_EXPR here ... (vrp_visit_switch_stmt): ... but here (new function). (find_case_label_index): New helper function. (vrp_visit_stmt): Dispatch to vrp_visit_switch_stmt. * gcc.dg/tree-ssa/vrp40.c: New testcase. From-SVN: r133834 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 714c38027cf..c9d8a4812a4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2008-04-02 Richard Guenther + + PR tree-optimization/14495 + * tree-vrp.c (vrp_visit_cond_stmt): Do not handle + SWITCH_EXPR here ... + (vrp_visit_switch_stmt): ... but here (new function). + (find_case_label_index): New helper function. + (vrp_visit_stmt): Dispatch to vrp_visit_switch_stmt. + 2008-04-02 Paolo Bonzini * fwprop.c: Fix ISO-C99ism. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 873e2b76705..03ac5b43e38 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-04-02 Richard Guenther + + PR tree-optimization/14495 + * gcc.dg/tree-ssa/vrp40.c: New testcase. + 2008-04-02 Eric Botcazou * gnat.dg/specs/discr_record_constant.ads: New test. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp40.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp40.c new file mode 100644 index 00000000000..23f080acfe4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp40.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-vrp1" } */ + +int f(int a) { + switch (a & 1) { + case 0: + case 1: return 3; + case 2: return 5; + case 3: return 7; + case 4: return 11; + case 5: return 13; + case 6: return 17; + case 7: return 19; + } +} + +/* { dg-final { scan-tree-dump "return 3;" "vrp1" } } */ +/* { dg-final { cleanup-tree-dump "vrp1" } } */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index d77653fd4ed..1d8ade783a9 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -5439,11 +5439,6 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p) bool sop; *taken_edge_p = NULL; - - /* FIXME. Handle SWITCH_EXPRs. */ - if (TREE_CODE (stmt) == SWITCH_EXPR) - return SSA_PROP_VARYING; - cond = COND_EXPR_COND (stmt); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -5537,6 +5532,147 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p) } +/* 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. */ + +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; + + /* Find case label for minimum of the value range or the next one. */ + for (low = start_idx - 1, high = n - 1; high - low > 1; ) + { + tree t; + int cmp; + 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) + 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) + { + *idx = i; + return true; + } + } + } + + *idx = i; + return false; +} + +/* 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 + SSA_PROP_VARYING. */ + +static enum ssa_prop_result +vrp_visit_switch_stmt (tree stmt, edge *taken_edge_p) +{ + tree op, val; + value_range_t *vr; + size_t i = 0, j = 0, n; + tree vec; + bool min_take_default, max_take_default; + + *taken_edge_p = NULL; + op = TREE_OPERAND (stmt, 0); + if (TREE_CODE (op) != SSA_NAME) + return SSA_PROP_VARYING; + + vr = get_value_range (op); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nVisiting switch expression with operand "); + print_generic_expr (dump_file, op, 0); + fprintf (dump_file, " with known range "); + dump_value_range (dump_file, vr); + fprintf (dump_file, "\n"); + } + + if (vr->type != VR_RANGE + || symbolic_range_p (vr)) + return SSA_PROP_VARYING; + + /* Find the single edge that is taken from the switch expression. */ + 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); + + /* Check if we reach the default label only. */ + 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); + 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. */ + val = TREE_VEC_ELT (vec, i); + if (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 " + "range\n"); + return SSA_PROP_VARYING; + } + for (++i; i <= j; ++i) + { + if (CASE_LABEL (TREE_VEC_ELT (vec, i)) != CASE_LABEL (val)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " not a single destination for this " + "range\n"); + return SSA_PROP_VARYING; + } + } + } + + *taken_edge_p = find_edge (bb_for_stmt (stmt), + label_to_block (CASE_LABEL (val))); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " will take edge to "); + print_generic_stmt (dump_file, CASE_LABEL (val), 0); + } + + return SSA_PROP_INTERESTING; +} + + /* Evaluate statement STMT. If the statement produces a useful range, return SSA_PROP_INTERESTING and record the SSA name with the interesting range into *OUTPUT_P. @@ -5575,8 +5711,10 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p) || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)) return vrp_visit_assignment (stmt, output_p); } - else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR) + else if (TREE_CODE (stmt) == COND_EXPR) return vrp_visit_cond_stmt (stmt, taken_edge_p); + else if (TREE_CODE (stmt) == SWITCH_EXPR) + return vrp_visit_switch_stmt (stmt, taken_edge_p); /* All other statements produce nothing of interest for VRP, so mark their outputs varying and prevent further simulation. */