&& ! tree_int_cst_equal (CASE_LOW (elt), CASE_HIGH (elt)))
m_count++;
}
+
+ /* Get the number of unique non-default targets out of the GIMPLE_SWITCH
+ block. Assume a CFG cleanup would have already removed degenerate
+ switch statements, this allows us to just use EDGE_COUNT. */
+ m_uniq = EDGE_COUNT (gimple_bb (swtch)->succs) - 1;
}
/* Checks whether the range given by individual case statements of the switch
/* A switch on a constant should have been optimized in tree-cfg-cleanup. */
gcc_checking_assert (!TREE_CONSTANT (m_index_expr));
+ /* Prefer bit test if possible. */
+ if (tree_fits_uhwi_p (m_range_size)
+ && bit_test_cluster::can_be_handled (tree_to_uhwi (m_range_size), m_uniq)
+ && bit_test_cluster::is_beneficial (m_count, m_uniq))
+ {
+ m_reason = "expanding as bit test is preferable";
+ return;
+ }
+
+ if (m_uniq <= 2)
+ {
+ /* This will be expanded as a decision tree . */
+ m_reason = "expanding as jumps is preferable";
+ return;
+ }
+
/* If there is no common successor, we cannot do the transformation. */
if (!m_final_bb)
{
XDELETEVEC (m_default_values);
}
-/* The main function of the pass scans statements for switches and invokes
- process_switch on them. */
-
-namespace {
+/* Constructor. */
-const pass_data pass_data_convert_switch =
+group_cluster::group_cluster (vec<cluster *> &clusters,
+ unsigned start, unsigned end)
{
- GIMPLE_PASS, /* type */
- "switchconv", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_SWITCH_CONVERSION, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
-};
+ gcc_checking_assert (end - start + 1 >= 1);
+ m_prob = profile_probability::never ();
+ m_cases.create (end - start + 1);
+ for (unsigned i = start; i <= end; i++)
+ {
+ m_cases.quick_push (static_cast<simple_cluster *> (clusters[i]));
+ m_prob += clusters[i]->m_prob;
+ }
+ m_subtree_prob = m_prob;
+}
-class pass_convert_switch : public gimple_opt_pass
+/* Destructor. */
+
+group_cluster::~group_cluster ()
{
-public:
- pass_convert_switch (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_convert_switch, ctxt)
- {}
+ for (unsigned i = 0; i < m_cases.length (); i++)
+ delete m_cases[i];
- /* opt_pass methods: */
- virtual bool gate (function *) { return flag_tree_switch_conversion != 0; }
- virtual unsigned int execute (function *);
+ m_cases.release ();
+}
-}; // class pass_convert_switch
+/* Dump content of a cluster. */
-unsigned int
-pass_convert_switch::execute (function *fun)
+void
+group_cluster::dump (FILE *f, bool details)
{
- basic_block bb;
- bool cfg_altered = false;
-
- FOR_EACH_BB_FN (bb, fun)
- {
- gimple *stmt = last_stmt (bb);
- if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
- {
- if (dump_file)
- {
- expanded_location loc = expand_location (gimple_location (stmt));
+ unsigned total_values = 0;
+ for (unsigned i = 0; i < m_cases.length (); i++)
+ total_values += m_cases[i]->get_range (m_cases[i]->get_low (),
+ m_cases[i]->get_high ());
- fprintf (dump_file, "beginning to process the following "
- "SWITCH statement (%s:%d) : ------- \n",
- loc.file, loc.line);
- print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
- putc ('\n', dump_file);
- }
+ unsigned comparison_count = 0;
+ for (unsigned i = 0; i < m_cases.length (); i++)
+ {
+ simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]);
+ comparison_count += sc->m_range_p ? 2 : 1;
+ }
- switch_conversion sconv;
- sconv.expand (as_a <gswitch *> (stmt));
- cfg_altered |= sconv.m_cfg_altered;
- if (!sconv.m_reason)
- {
- if (dump_file)
- {
- fputs ("Switch converted\n", dump_file);
- fputs ("--------------------------------\n", dump_file);
- }
+ unsigned HOST_WIDE_INT range = get_range (get_low (), get_high ());
+ fprintf (f, "%s", get_type () == JUMP_TABLE ? "JT" : "BT");
- /* Make no effort to update the post-dominator tree.
- It is actually not that hard for the transformations
- we have performed, but it is not supported
- by iterate_fix_dominators. */
- free_dominance_info (CDI_POST_DOMINATORS);
- }
- else
- {
- if (dump_file)
- {
- fputs ("Bailing out - ", dump_file);
- fputs (sconv.m_reason, dump_file);
- fputs ("\n--------------------------------\n", dump_file);
- }
- }
- }
- }
+ if (details)
+ fprintf (f, "(values:%d comparisons:%d range:" HOST_WIDE_INT_PRINT_DEC
+ " density: %.2f%%)", total_values, comparison_count, range,
+ 100.0f * comparison_count / range);
- return cfg_altered ? TODO_cleanup_cfg : 0;;
+ fprintf (f, ":");
+ PRINT_CASE (f, get_low ());
+ fprintf (f, "-");
+ PRINT_CASE (f, get_high ());
+ fprintf (f, " ");
}
-} // anon namespace
+/* Emit GIMPLE code to handle the cluster. */
-gimple_opt_pass *
-make_pass_convert_switch (gcc::context *ctxt)
+void
+jump_table_cluster::emit (tree index_expr, tree,
+ tree default_label_expr, basic_block default_bb)
{
- return new pass_convert_switch (ctxt);
+ /* For jump table we just emit a new gswitch statement that will
+ be latter lowered to jump table. */
+ auto_vec <tree> labels;
+ labels.create (m_cases.length ());
+
+ make_edge (m_case_bb, default_bb, 0);
+ for (unsigned i = 0; i < m_cases.length (); i++)
+ {
+ labels.quick_push (unshare_expr (m_cases[i]->m_case_label_expr));
+ make_edge (m_case_bb, m_cases[i]->m_case_bb, 0);
+ }
+
+ gswitch *s = gimple_build_switch (index_expr,
+ unshare_expr (default_label_expr), labels);
+ gimple_stmt_iterator gsi = gsi_start_bb (m_case_bb);
+ gsi_insert_after (&gsi, s, GSI_NEW_STMT);
}
-struct case_node
+/* Return true when cluster starting at START and ending at END (inclusive)
+ can build a jump-table. */
+
+bool
+jump_table_cluster::can_be_handled (const vec<cluster *> &clusters,
+ unsigned start, unsigned end)
{
- case_node *left; /* Left son in binary tree. */
- case_node *right; /* Right son in binary tree;
- also node chain. */
- case_node *parent; /* Parent of node in binary tree. */
- tree low; /* Lowest index value for this label. */
- tree high; /* Highest index value for this label. */
- basic_block case_bb; /* Label to jump to when node matches. */
- tree case_label; /* Label to jump to when node matches. */
- profile_probability prob; /* Probability of taking this case. */
- profile_probability subtree_prob; /* Probability of reaching subtree
- rooted at this node. */
-};
+ /* If the switch is relatively small such that the cost of one
+ indirect jump on the target are higher than the cost of a
+ decision tree, go with the decision tree.
-typedef case_node *case_node_ptr;
+ If range of values is much bigger than number of values,
+ or if it is too large to represent in a HOST_WIDE_INT,
+ make a sequence of conditional branches instead of a dispatch.
-static basic_block emit_case_nodes (basic_block, tree, case_node_ptr,
- basic_block, tree, profile_probability,
- tree, hash_map<tree, tree> *);
+ The definition of "much bigger" depends on whether we are
+ optimizing for size or for speed. If the former, the maximum
+ ratio range/count = 3, because this was found to be the optimal
+ ratio for size on i686-pc-linux-gnu, see PR11823. The ratio
+ 10 is much older, and was probably selected after an extensive
+ benchmarking investigation on numerous platforms. Or maybe it
+ just made sense to someone at some point in the history of GCC,
+ who knows... */
+ if (!flag_jump_tables)
+ return false;
-/* Return the smallest number of different values for which it is best to use a
- jump-table instead of a tree of conditional branches. */
+ unsigned HOST_WIDE_INT max_ratio = optimize_insn_for_size_p () ? 3 : 10;
-static unsigned int
-case_values_threshold (void)
-{
- unsigned int threshold = PARAM_VALUE (PARAM_CASE_VALUES_THRESHOLD);
+ unsigned HOST_WIDE_INT range = get_range (clusters[start]->get_low (),
+ clusters[end]->get_high ());
+ /* Check overflow. */
+ if (range == 0)
+ return false;
- if (threshold == 0)
- threshold = targetm.case_values_threshold ();
+ unsigned HOST_WIDE_INT comparison_count = 0;
+ for (unsigned i = start; i <= end; i++)
+ {
+ simple_cluster *sc = static_cast<simple_cluster *> (clusters[i]);
+ comparison_count += sc->m_range_p ? 2 : 1;
+ }
- return threshold;
+ return range <= max_ratio * comparison_count;
}
-/* Reset the aux field of all outgoing edges of basic block BB. */
+/* Return true if cluster starting at START and ending at END (inclusive)
+ is profitable transformation. */
-static inline void
-reset_out_edges_aux (basic_block bb)
+bool
+jump_table_cluster::is_beneficial (const vec<cluster *> &,
+ unsigned start, unsigned end)
{
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->aux = (void *) 0;
+ return end - start + 1 >= case_values_threshold ();
}
-/* Compute the number of case labels that correspond to each outgoing edge of
- STMT. Record this information in the aux field of the edge. */
+/* Return true when RANGE of case values with UNIQ labels
+ can build a bit test. */
-static inline void
-compute_cases_per_edge (gswitch *stmt)
+bool
+bit_test_cluster::can_be_handled (unsigned HOST_WIDE_INT range,
+ unsigned int uniq)
{
- basic_block bb = gimple_bb (stmt);
- reset_out_edges_aux (bb);
- int ncases = gimple_switch_num_labels (stmt);
- for (int i = ncases - 1; i >= 1; --i)
+ /* Check overflow. */
+ if (range == 0)
+ return 0;
+
+ if (range >= GET_MODE_BITSIZE (word_mode))
+ return false;
+
+ return uniq <= 3;
+}
+
+/* Return true when cluster starting at START and ending at END (inclusive)
+ can build a bit test. */
+
+bool
+bit_test_cluster::can_be_handled (const vec<cluster *> &clusters,
+ unsigned start, unsigned end)
+{
+ unsigned HOST_WIDE_INT range = get_range (clusters[start]->get_low (),
+ clusters[end]->get_high ());
+ auto_bitmap dest_bbs;
+
+ for (unsigned i = start; i <= end; i++)
{
- tree elt = gimple_switch_label (stmt, i);
- tree lab = CASE_LABEL (elt);
- basic_block case_bb = label_to_block_fn (cfun, lab);
- edge case_edge = find_edge (bb, case_bb);
- case_edge->aux = (void *) ((intptr_t) (case_edge->aux) + 1);
+ simple_cluster *sc = static_cast<simple_cluster *> (clusters[i]);
+ bitmap_set_bit (dest_bbs, sc->m_case_bb->index);
}
-}
-/* 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.
+ return can_be_handled (range, bitmap_count_bits (dest_bbs));
+}
- LABEL is the case label to be inserted. LOW and HIGH are the bounds
- against which the index is compared to jump to LABEL and PROB is the
- estimated probability LABEL is reached from the switch statement. */
+/* Return true when COUNT of cases of UNIQ labels is beneficial for bit test
+ transformation. */
-static case_node *
-add_case_node (case_node *head, tree low, tree high, basic_block case_bb,
- tree case_label, profile_probability prob,
- object_allocator<case_node> &case_node_pool)
+bool
+bit_test_cluster::is_beneficial (unsigned count, unsigned uniq)
{
- case_node *r;
-
- gcc_checking_assert (low);
- gcc_checking_assert (high && (TREE_TYPE (low) == TREE_TYPE (high)));
-
- /* Add this label to the chain. */
- r = case_node_pool.allocate ();
- r->low = low;
- r->high = high;
- r->case_bb = case_bb;
- r->case_label = case_label;
- r->parent = r->left = NULL;
- r->prob = prob;
- r->subtree_prob = prob;
- r->right = head;
- return r;
+ return (((uniq == 1 && count >= 3)
+ || (uniq == 2 && count >= 5)
+ || (uniq == 3 && count >= 6)));
}
-/* Dump ROOT, a list or tree of case nodes, to file. */
+/* Return true if cluster starting at START and ending at END (inclusive)
+ is profitable transformation. */
-static void
-dump_case_nodes (FILE *f, case_node *root, int indent_step, int indent_level)
+bool
+bit_test_cluster::is_beneficial (const vec<cluster *> &clusters,
+ unsigned start, unsigned end)
{
- if (root == 0)
- return;
- indent_level++;
-
- dump_case_nodes (f, root->left, indent_step, indent_level);
+ auto_bitmap dest_bbs;
- fputs (";; ", f);
- fprintf (f, "%*s", indent_step * indent_level, "");
- print_dec (wi::to_wide (root->low), f, TYPE_SIGN (TREE_TYPE (root->low)));
- if (!tree_int_cst_equal (root->low, root->high))
+ for (unsigned i = start; i <= end; i++)
{
- fprintf (f, " ... ");
- print_dec (wi::to_wide (root->high), f,
- TYPE_SIGN (TREE_TYPE (root->high)));
+ simple_cluster *sc = static_cast<simple_cluster *> (clusters[i]);
+ bitmap_set_bit (dest_bbs, sc->m_case_bb->index);
}
- fputs ("\n", f);
- dump_case_nodes (f, root->right, indent_step, indent_level);
+ unsigned uniq = bitmap_count_bits (dest_bbs);
+ unsigned count = end - start + 1;
+ return is_beneficial (count, uniq);
}
-/* Take an ordered list of case nodes
- and transform them into a near optimal binary tree,
- on the assumption that any target code selection value is as
- likely as any other.
+/* Comparison function for qsort to order bit tests by decreasing
+ probability of execution. */
- The transformation is performed by splitting the ordered
- list into two equal sections plus a pivot. The parts are
- then attached to the pivot as left and right branches. Each
- branch is then transformed recursively. */
+int
+case_bit_test::cmp (const void *p1, const void *p2)
+{
+ const struct case_bit_test *const d1 = (const struct case_bit_test *) p1;
+ const struct case_bit_test *const d2 = (const struct case_bit_test *) p2;
+
+ if (d2->bits != d1->bits)
+ return d2->bits - d1->bits;
+
+ /* Stabilize the sort. */
+ return (LABEL_DECL_UID (CASE_LABEL (d2->label))
+ - LABEL_DECL_UID (CASE_LABEL (d1->label)));
+}
+
+/* Expand a switch statement by a short sequence of bit-wise
+ comparisons. "switch(x)" is effectively converted into
+ "if ((1 << (x-MINVAL)) & CST)" where CST and MINVAL are
+ integer constants.
+
+ INDEX_EXPR is the value being switched on.
+
+ MINVAL is the lowest case value of in the case nodes,
+ and RANGE is highest value minus MINVAL. MINVAL and RANGE
+ are not guaranteed to be of the same type as INDEX_EXPR
+ (the gimplifier doesn't change the type of case label values,
+ and MINVAL and RANGE are derived from those values).
+ MAXVAL is MINVAL + RANGE.
-static void
-balance_case_nodes (case_node_ptr *head, case_node_ptr parent)
+ There *MUST* be max_case_bit_tests or less unique case
+ node targets. */
+
+void
+bit_test_cluster::emit (tree index_expr, tree index_type,
+ tree, basic_block default_bb)
{
- case_node_ptr np;
+ struct case_bit_test test[m_max_case_bit_tests] = { {} };
+ unsigned int i, j, k;
+ unsigned int count;
- np = *head;
- if (np)
- {
- int i = 0;
- int ranges = 0;
- case_node_ptr *npp;
- case_node_ptr left;
+ tree unsigned_index_type = unsigned_type_for (index_type);
- /* Count the number of entries on branch. Also count the ranges. */
+ gimple_stmt_iterator gsi;
+ gassign *shift_stmt;
- while (np)
- {
- if (!tree_int_cst_equal (np->low, np->high))
- ranges++;
+ tree idx, tmp, csui;
+ tree word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
+ tree word_mode_zero = fold_convert (word_type_node, integer_zero_node);
+ tree word_mode_one = fold_convert (word_type_node, integer_one_node);
+ int prec = TYPE_PRECISION (word_type_node);
+ wide_int wone = wi::one (prec);
- i++;
- np = np->right;
- }
+ tree minval = get_low ();
+ tree maxval = get_high ();
+ tree range = int_const_binop (MINUS_EXPR, maxval, minval);
- if (i > 2)
+ /* Go through all case labels, and collect the case labels, profile
+ counts, and other information we need to build the branch tests. */
+ count = 0;
+ for (i = 0; i < m_cases.length (); i++)
+ {
+ unsigned int lo, hi;
+ simple_cluster *n = static_cast<simple_cluster *> (m_cases[i]);
+ for (k = 0; k < count; k++)
+ if (n->m_case_bb == test[k].target_bb)
+ break;
+
+ if (k == count)
{
- /* Split this list if it is long enough for that to help. */
- npp = head;
- left = *npp;
+ gcc_checking_assert (count < m_max_case_bit_tests);
+ test[k].mask = wi::zero (prec);
+ test[k].target_bb = n->m_case_bb;
+ test[k].label = n->m_case_label_expr;
+ test[k].bits = 1;
+ count++;
+ }
+ else
+ test[k].bits++;
- /* If there are just three nodes, split at the middle one. */
- if (i == 3)
- npp = &(*npp)->right;
- else
- {
- /* Find the place in the list that bisects the list's total cost,
- where ranges count as 2.
- Here I gets half the total cost. */
- i = (i + ranges + 1) / 2;
- while (1)
- {
- /* Skip nodes while their cost does not reach that amount. */
- if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
- i--;
- i--;
- if (i <= 0)
- break;
- npp = &(*npp)->right;
- }
- }
- *head = np = *npp;
- *npp = 0;
- np->parent = parent;
- np->left = left;
+ lo = tree_to_uhwi (int_const_binop (MINUS_EXPR, n->get_low (), minval));
+ if (n->get_high () == NULL_TREE)
+ hi = lo;
+ else
+ hi = tree_to_uhwi (int_const_binop (MINUS_EXPR, n->get_high (),
+ minval));
- /* Optimize each of the two split parts. */
- balance_case_nodes (&np->left, np);
- balance_case_nodes (&np->right, np);
- np->subtree_prob = np->prob;
- np->subtree_prob += np->left->subtree_prob;
- np->subtree_prob += np->right->subtree_prob;
+ for (j = lo; j <= hi; j++)
+ test[k].mask |= wi::lshift (wone, j);
+ }
+
+ qsort (test, count, sizeof (*test), case_bit_test::cmp);
+
+ /* If all values are in the 0 .. BITS_PER_WORD-1 range, we can get rid of
+ the minval subtractions, but it might make the mask constants more
+ expensive. So, compare the costs. */
+ if (compare_tree_int (minval, 0) > 0
+ && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
+ {
+ int cost_diff;
+ HOST_WIDE_INT m = tree_to_uhwi (minval);
+ rtx reg = gen_raw_REG (word_mode, 10000);
+ bool speed_p = optimize_insn_for_speed_p ();
+ cost_diff = set_rtx_cost (gen_rtx_PLUS (word_mode, reg,
+ GEN_INT (-m)), speed_p);
+ for (i = 0; i < count; i++)
+ {
+ rtx r = immed_wide_int_const (test[i].mask, word_mode);
+ cost_diff += set_src_cost (gen_rtx_AND (word_mode, reg, r),
+ word_mode, speed_p);
+ r = immed_wide_int_const (wi::lshift (test[i].mask, m), word_mode);
+ cost_diff -= set_src_cost (gen_rtx_AND (word_mode, reg, r),
+ word_mode, speed_p);
}
- else
+ if (cost_diff > 0)
{
- /* Else leave this branch as one level,
- but fill in `parent' fields. */
- np = *head;
- np->parent = parent;
- np->subtree_prob = np->prob;
- for (; np->right; np = np->right)
- {
- np->right->parent = np;
- (*head)->subtree_prob += np->right->subtree_prob;
- }
+ for (i = 0; i < count; i++)
+ test[i].mask = wi::lshift (test[i].mask, m);
+ minval = build_zero_cst (TREE_TYPE (minval));
+ range = maxval;
}
}
-}
-/* Return true if a switch should be expanded as a decision tree.
- RANGE is the difference between highest and lowest case.
- UNIQ is number of unique case node targets, not counting the default case.
- COUNT is the number of comparisons needed, not counting the default case. */
+ /* Now build the test-and-branch code. */
+
+ gsi = gsi_last_bb (m_case_bb);
+
+ /* idx = (unsigned)x - minval. */
+ idx = fold_convert (unsigned_index_type, index_expr);
+ idx = fold_build2 (MINUS_EXPR, unsigned_index_type, idx,
+ fold_convert (unsigned_index_type, minval));
+ idx = force_gimple_operand_gsi (&gsi, idx,
+ /*simple=*/true, NULL_TREE,
+ /*before=*/true, GSI_SAME_STMT);
+
+ /* if (idx > range) goto default */
+ range = force_gimple_operand_gsi (&gsi,
+ fold_convert (unsigned_index_type, range),
+ /*simple=*/true, NULL_TREE,
+ /*before=*/true, GSI_SAME_STMT);
+ tmp = fold_build2 (GT_EXPR, boolean_type_node, idx, range);
+ basic_block new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_bb);
+ gsi = gsi_last_bb (new_bb);
+
+ /* csui = (1 << (word_mode) idx) */
+ csui = make_ssa_name (word_type_node);
+ tmp = fold_build2 (LSHIFT_EXPR, word_type_node, word_mode_one,
+ fold_convert (word_type_node, idx));
+ tmp = force_gimple_operand_gsi (&gsi, tmp,
+ /*simple=*/false, NULL_TREE,
+ /*before=*/true, GSI_SAME_STMT);
+ shift_stmt = gimple_build_assign (csui, tmp);
+ gsi_insert_before (&gsi, shift_stmt, GSI_SAME_STMT);
+ update_stmt (shift_stmt);
+
+ /* for each unique set of cases:
+ if (const & csui) goto target */
+ for (k = 0; k < count; k++)
+ {
+ tmp = wide_int_to_tree (word_type_node, test[k].mask);
+ tmp = fold_build2 (BIT_AND_EXPR, word_type_node, csui, tmp);
+ tmp = force_gimple_operand_gsi (&gsi, tmp,
+ /*simple=*/true, NULL_TREE,
+ /*before=*/true, GSI_SAME_STMT);
+ tmp = fold_build2 (NE_EXPR, boolean_type_node, tmp, word_mode_zero);
+ new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, test[k].target_bb);
+ gsi = gsi_last_bb (new_bb);
+ }
-static bool
-expand_switch_as_decision_tree_p (tree range,
- unsigned int uniq ATTRIBUTE_UNUSED,
- unsigned int count)
-{
- int max_ratio;
+ /* We should have removed all edges now. */
+ gcc_assert (EDGE_COUNT (gsi_bb (gsi)->succs) == 0);
- /* If neither casesi or tablejump is available, or flag_jump_tables
- over-ruled us, we really have no choice. */
- if (!targetm.have_casesi () && !targetm.have_tablejump ())
- return true;
- if (!flag_jump_tables)
- return true;
-#ifndef ASM_OUTPUT_ADDR_DIFF_ELT
- if (flag_pic)
- return true;
-#endif
+ /* If nothing matched, go to the default label. */
+ make_edge (gsi_bb (gsi), default_bb, EDGE_FALLTHRU);
+}
- /* If the switch is relatively small such that the cost of one
- indirect jump on the target are higher than the cost of a
- decision tree, go with the decision tree.
+/* Split the basic block at the statement pointed to by GSIP, and insert
+ a branch to the target basic block of E_TRUE conditional on tree
+ expression COND.
- If range of values is much bigger than number of values,
- or if it is too large to represent in a HOST_WIDE_INT,
- make a sequence of conditional branches instead of a dispatch.
+ It is assumed that there is already an edge from the to-be-split
+ basic block to E_TRUE->dest block. This edge is removed, and the
+ profile information on the edge is re-used for the new conditional
+ jump.
- The definition of "much bigger" depends on whether we are
- optimizing for size or for speed. If the former, the maximum
- ratio range/count = 3, because this was found to be the optimal
- ratio for size on i686-pc-linux-gnu, see PR11823. The ratio
- 10 is much older, and was probably selected after an extensive
- benchmarking investigation on numerous platforms. Or maybe it
- just made sense to someone at some point in the history of GCC,
- who knows... */
- max_ratio = optimize_insn_for_size_p () ? 3 : 10;
- if (count < case_values_threshold () || !tree_fits_uhwi_p (range)
- || compare_tree_int (range, max_ratio * count) > 0)
- return true;
+ The CFG is updated. The dominator tree will not be valid after
+ this transformation, but the immediate dominators are updated if
+ UPDATE_DOMINATORS is true.
- return false;
-}
+ Returns the newly created basic block. */
-static void
-fix_phi_operands_for_edge (edge e, hash_map<tree, tree> *phi_mapping)
+basic_block
+bit_test_cluster::hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
+ tree cond, basic_block case_bb)
{
- basic_block bb = e->dest;
- gphi_iterator gsi;
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
+ tree tmp;
+ gcond *cond_stmt;
+ edge e_false;
+ basic_block new_bb, split_bb = gsi_bb (*gsip);
- tree *definition = phi_mapping->get (gimple_phi_result (phi));
- if (definition)
- add_phi_arg (phi, *definition, e, UNKNOWN_LOCATION);
- }
-}
+ edge e_true = make_edge (split_bb, case_bb, EDGE_TRUE_VALUE);
+ gcc_assert (e_true->src == split_bb);
+ tmp = force_gimple_operand_gsi (gsip, cond, /*simple=*/true, NULL,
+ /*before=*/true, GSI_SAME_STMT);
+ cond_stmt = gimple_build_cond_from_tree (tmp, NULL_TREE, NULL_TREE);
+ gsi_insert_before (gsip, cond_stmt, GSI_SAME_STMT);
-/* Add an unconditional jump to CASE_BB that happens in basic block BB. */
+ e_false = split_block (split_bb, cond_stmt);
+ new_bb = e_false->dest;
+ redirect_edge_pred (e_true, split_bb);
-static void
-emit_jump (basic_block bb, basic_block case_bb,
- hash_map<tree, tree> *phi_mapping)
-{
- edge e = single_succ_edge (bb);
- redirect_edge_succ (e, case_bb);
- fix_phi_operands_for_edge (e, phi_mapping);
+ e_false->flags &= ~EDGE_FALLTHRU;
+ e_false->flags |= EDGE_FALSE_VALUE;
+ e_false->probability = e_true->probability.invert ();
+ new_bb->count = e_false->count ();
+
+ return new_bb;
}
-/* Generate a decision tree, switching on INDEX_EXPR and jumping to
- one of the labels in CASE_LIST or to the DEFAULT_LABEL.
- DEFAULT_PROB is the estimated probability that it jumps to
- DEFAULT_LABEL.
+/* Compute the number of case labels that correspond to each outgoing edge of
+ switch statement. Record this information in the aux field of the edge. */
- We generate a binary decision tree to select the appropriate target
- code. */
+void
+switch_decision_tree::compute_cases_per_edge ()
+{
+ basic_block bb = gimple_bb (m_switch);
+ reset_out_edges_aux ();
+ int ncases = gimple_switch_num_labels (m_switch);
+ for (int i = ncases - 1; i >= 1; --i)
+ {
+ tree elt = gimple_switch_label (m_switch, i);
+ tree lab = CASE_LABEL (elt);
+ basic_block case_bb = label_to_block_fn (cfun, lab);
+ edge case_edge = find_edge (bb, case_bb);
+ case_edge->aux = (void *) ((intptr_t) (case_edge->aux) + 1);
+ }
+}
+
+/* Analyze switch statement and return true when the statement is expanded
+ as decision tree. */
-static void
-emit_case_decision_tree (gswitch *s, tree index_expr, tree index_type,
- case_node_ptr case_list, basic_block default_bb,
- tree default_label, profile_probability default_prob,
- hash_map<tree, tree> *phi_mapping)
+bool
+switch_decision_tree::analyze_switch_statement ()
{
- balance_case_nodes (&case_list, NULL);
+ unsigned l = gimple_switch_num_labels (m_switch);
+ basic_block bb = gimple_bb (m_switch);
+ auto_vec<cluster *> clusters;
+ clusters.create (l - 1);
+
+ tree default_label = CASE_LABEL (gimple_switch_default_label (m_switch));
+ basic_block default_bb = label_to_block_fn (cfun, default_label);
+ m_case_bbs.reserve (l);
+ m_case_bbs.quick_push (default_bb);
+
+ compute_cases_per_edge ();
+
+ for (unsigned i = 1; i < l; i++)
+ {
+ tree elt = gimple_switch_label (m_switch, i);
+ tree lab = CASE_LABEL (elt);
+ basic_block case_bb = label_to_block_fn (cfun, lab);
+ edge case_edge = find_edge (bb, case_bb);
+ tree low = CASE_LOW (elt);
+ tree high = CASE_HIGH (elt);
+
+ profile_probability p
+ = case_edge->probability.apply_scale (1, (intptr_t) (case_edge->aux));
+ clusters.quick_push (new simple_cluster (low, high, elt, case_bb, p));
+ m_case_bbs.quick_push (case_bb);
+ }
+
+ reset_out_edges_aux ();
+
+ vec<cluster *> output;
+ output.create (1);
+
+ /* Find whether the switch statement can be expanded with a method
+ different from decision tree. */
+ unsigned end = clusters.length () - 1;
+ if (jump_table_cluster::can_be_handled (clusters, 0, end)
+ && jump_table_cluster::is_beneficial (clusters, 0, end))
+ output.safe_push (new jump_table_cluster (clusters, 0, end));
+ else if (bit_test_cluster::can_be_handled (clusters, 0, end)
+ && bit_test_cluster::is_beneficial (clusters, 0, end))
+ output.safe_push (new bit_test_cluster (clusters, 0, end));
+ else
+ output = clusters;
if (dump_file)
- dump_function_to_file (current_function_decl, dump_file, dump_flags);
- if (dump_file && (dump_flags & TDF_DETAILS))
{
- int indent_step = ceil_log2 (TYPE_PRECISION (index_type)) + 2;
- fprintf (dump_file, ";; Expanding GIMPLE switch as decision tree:\n");
- dump_case_nodes (dump_file, case_list, indent_step, 0);
+ fprintf (dump_file, ";; GIMPLE switch case clusters: ");
+ for (unsigned i = 0; i < output.length (); i++)
+ output[i]->dump (dump_file, dump_flags & TDF_DETAILS);
+ fprintf (dump_file, "\n");
+ }
+
+ bool expanded = try_switch_expansion (output);
+
+ for (unsigned i = 0; i < output.length (); i++)
+ delete output[i];
+
+ return expanded;
+}
+
+/* Attempt to expand CLUSTERS as a decision tree. Return true when
+ expanded. */
+
+bool
+switch_decision_tree::try_switch_expansion (vec<cluster *> &clusters)
+{
+ tree index_expr = gimple_switch_index (m_switch);
+ tree index_type = TREE_TYPE (index_expr);
+ basic_block bb = gimple_bb (m_switch);
+
+ if (gimple_switch_num_labels (m_switch) == 1)
+ return false;
+
+ /* Find the default case target label. */
+ tree default_label_expr = CASE_LABEL (gimple_switch_default_label (m_switch));
+ m_default_bb = label_to_block_fn (cfun, default_label_expr);
+ edge default_edge = find_edge (bb, m_default_bb);
+
+ /* Do the insertion of a case label into m_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. */
+
+ for (int i = clusters.length () - 1; i >= 0; i--)
+ {
+ case_tree_node *r = m_case_list;
+ m_case_list = m_case_node_pool.allocate ();
+ m_case_list->m_right = r;
+ m_case_list->m_c = clusters[i];
}
- basic_block bb = gimple_bb (s);
+ record_phi_operand_mapping ();
+
+ /* Split basic block that contains the gswitch statement. */
gimple_stmt_iterator gsi = gsi_last_bb (bb);
edge e;
if (gsi_end_p (gsi))
}
bb = split_edge (e);
- bb = emit_case_nodes (bb, index_expr, case_list, default_bb, default_label,
- default_prob, index_type, phi_mapping);
+ /* Create new basic blocks for non-case clusters where specific expansion
+ needs to happen. */
+ for (unsigned i = 0; i < clusters.length (); i++)
+ if (clusters[i]->get_type () != SIMPLE_CASE)
+ {
+ clusters[i]->m_case_bb = create_empty_bb (bb);
+ clusters[i]->m_case_bb->loop_father = bb->loop_father;
+ }
- if (bb)
- emit_jump (bb, default_bb, phi_mapping);
+ /* Do not do an extra work for a single cluster. */
+ if (clusters.length () == 1
+ && clusters[0]->get_type () != SIMPLE_CASE)
+ clusters[0]->emit (index_expr, index_type,
+ gimple_switch_default_label (m_switch), m_default_bb);
+ else
+ {
+ emit (bb, index_expr, default_edge->probability, index_type);
+
+ /* Emit cluster-specific switch handling. */
+ for (unsigned i = 0; i < clusters.length (); i++)
+ if (clusters[i]->get_type () != SIMPLE_CASE)
+ clusters[i]->emit (index_expr, index_type,
+ gimple_switch_default_label (m_switch),
+ m_default_bb);
+ }
- /* Remove all edges and do just an edge that will reach default_bb. */
- gsi = gsi_last_bb (gimple_bb (s));
- gsi_remove (&gsi, true);
+ fix_phi_operands_for_edges ();
+
+ return true;
}
-static void
-record_phi_operand_mapping (const vec<basic_block> bbs, basic_block switch_bb,
- hash_map <tree, tree> *map)
+/* Before switch transformation, record all SSA_NAMEs defined in switch BB
+ and used in a label basic block. */
+
+void
+switch_decision_tree::record_phi_operand_mapping ()
{
+ basic_block switch_bb = gimple_bb (m_switch);
/* Record all PHI nodes that have to be fixed after conversion. */
- for (unsigned i = 0; i < bbs.length (); i++)
+ for (unsigned i = 0; i < m_case_bbs.length (); i++)
{
- basic_block bb = bbs[i];
-
gphi_iterator gsi;
+ basic_block bb = m_case_bbs[i];
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gphi *phi = gsi.phi ();
{
tree def = gimple_phi_arg_def (phi, i);
tree result = gimple_phi_result (phi);
- map->put (result, def);
+ m_phi_mapping.put (result, def);
break;
}
}
}
}
-/* Attempt to expand gimple switch STMT to a decision tree. */
+/* Append new operands to PHI statements that were introduced due to
+ addition of new edges to case labels. */
-static bool
-try_switch_expansion (gswitch *stmt)
+void
+switch_decision_tree::fix_phi_operands_for_edges ()
{
- tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
- basic_block default_bb;
- unsigned int count, uniq;
- int i;
- int ncases = gimple_switch_num_labels (stmt);
- tree index_expr = gimple_switch_index (stmt);
- tree index_type = TREE_TYPE (index_expr);
- tree elt;
- basic_block bb = gimple_bb (stmt);
+ gphi_iterator gsi;
- hash_map<tree, tree> phi_mapping;
- auto_vec<basic_block> case_bbs;
+ for (unsigned i = 0; i < m_case_bbs.length (); i++)
+ {
+ basic_block bb = m_case_bbs[i];
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ for (unsigned j = 0; j < gimple_phi_num_args (phi); j++)
+ {
+ tree def = gimple_phi_arg_def (phi, j);
+ if (def == NULL_TREE)
+ {
+ edge e = gimple_phi_arg_edge (phi, j);
+ tree *definition
+ = m_phi_mapping.get (gimple_phi_result (phi));
+ gcc_assert (definition);
+ add_phi_arg (phi, *definition, e, UNKNOWN_LOCATION);
+ }
+ }
+ }
+ }
+}
- /* A list of case labels; it is first built as a list and it may then
- be rearranged into a nearly balanced binary tree. */
- case_node *case_list = 0;
+/* Generate a decision tree, switching on INDEX_EXPR and jumping to
+ one of the labels in CASE_LIST or to the DEFAULT_LABEL.
- /* A pool for case nodes. */
- object_allocator<case_node> case_node_pool ("struct case_node pool");
+ We generate a binary decision tree to select the appropriate target
+ code. */
- /* cleanup_tree_cfg removes all SWITCH_EXPR with their index
- expressions being INTEGER_CST. */
- gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
+void
+switch_decision_tree::emit (basic_block bb, tree index_expr,
+ profile_probability default_prob, tree index_type)
+{
+ balance_case_nodes (&m_case_list, NULL);
- if (ncases == 1)
- return false;
+ if (dump_file)
+ dump_function_to_file (current_function_decl, dump_file, dump_flags);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ int indent_step = ceil_log2 (TYPE_PRECISION (index_type)) + 2;
+ fprintf (dump_file, ";; Expanding GIMPLE switch as decision tree:\n");
+ gcc_assert (m_case_list != NULL);
+ dump_case_nodes (dump_file, m_case_list, indent_step, 0);
+ }
- /* Find the default case target label. */
- tree default_label = CASE_LABEL (gimple_switch_default_label (stmt));
- default_bb = label_to_block_fn (cfun, default_label);
- edge default_edge = find_edge (bb, default_bb);
- profile_probability default_prob = default_edge->probability;
- case_bbs.safe_push (default_bb);
-
- /* Get upper and lower bounds of case values. */
- elt = gimple_switch_label (stmt, 1);
- minval = fold_convert (index_type, CASE_LOW (elt));
- elt = gimple_switch_label (stmt, ncases - 1);
- if (CASE_HIGH (elt))
- maxval = fold_convert (index_type, CASE_HIGH (elt));
- else
- maxval = fold_convert (index_type, CASE_LOW (elt));
+ bb = emit_case_nodes (bb, index_expr, m_case_list, default_prob, index_type);
- /* Compute span of values. */
- range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
+ if (bb)
+ emit_jump (bb, m_default_bb);
- /* Listify the labels queue and gather some numbers to decide
- how to expand this switch. */
- uniq = 0;
- count = 0;
- hash_set<tree> seen_labels;
- compute_cases_per_edge (stmt);
+ /* Remove all edges and do just an edge that will reach default_bb. */
+ bb = gimple_bb (m_switch);
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gsi_remove (&gsi, true);
- for (i = ncases - 1; i >= 1; --i)
+ delete_basic_block (bb);
+}
+
+/* Take an ordered list of case nodes
+ and transform them into a near optimal binary tree,
+ on the assumption that any target code selection value is as
+ likely as any other.
+
+ The transformation is performed by splitting the ordered
+ list into two equal sections plus a pivot. The parts are
+ then attached to the pivot as left and right branches. Each
+ branch is then transformed recursively. */
+
+void
+switch_decision_tree::balance_case_nodes (case_tree_node **head,
+ case_tree_node *parent)
+{
+ case_tree_node *np;
+
+ np = *head;
+ if (np)
{
- elt = gimple_switch_label (stmt, i);
- tree low = CASE_LOW (elt);
- gcc_assert (low);
- tree high = CASE_HIGH (elt);
- gcc_assert (!high || tree_int_cst_lt (low, high));
- tree lab = CASE_LABEL (elt);
+ int i = 0;
+ int ranges = 0;
+ case_tree_node **npp;
+ case_tree_node *left;
- /* Count the elements.
- A range counts double, since it requires two compares. */
- count++;
- if (high)
- count++;
-
- /* If we have not seen this label yet, then increase the
- number of unique case node targets seen. */
- if (!seen_labels.add (lab))
- uniq++;
-
- /* The bounds on the case range, LOW and HIGH, have to be converted
- to case's index type TYPE. Note that the original type of the
- case index in the source code is usually "lost" during
- gimplification due to type promotion, but the case labels retain the
- original type. Make sure to drop overflow flags. */
- low = fold_convert (index_type, low);
- if (TREE_OVERFLOW (low))
- low = wide_int_to_tree (index_type, wi::to_wide (low));
-
- /* The canonical from of a case label in GIMPLE is that a simple case
- has an empty CASE_HIGH. For the casesi and tablejump expanders,
- the back ends want simple cases to have high == low. */
- if (!high)
- high = low;
- high = fold_convert (index_type, high);
- if (TREE_OVERFLOW (high))
- high = wide_int_to_tree (index_type, wi::to_wide (high));
+ /* Count the number of entries on branch. Also count the ranges. */
- basic_block case_bb = label_to_block_fn (cfun, lab);
- edge case_edge = find_edge (bb, case_bb);
- case_list = add_case_node (
- case_list, low, high, case_bb, lab,
- case_edge->probability.apply_scale (1, (intptr_t) (case_edge->aux)),
- case_node_pool);
+ while (np)
+ {
+ if (!tree_int_cst_equal (np->m_c->get_low (), np->m_c->get_high ()))
+ ranges++;
- case_bbs.safe_push (case_bb);
- }
- reset_out_edges_aux (bb);
- record_phi_operand_mapping (case_bbs, bb, &phi_mapping);
+ i++;
+ np = np->m_right;
+ }
- /* cleanup_tree_cfg removes all SWITCH_EXPR with a single
- destination, such as one with a default case only.
- It also removes cases that are out of range for the switch
- type, so we should never get a zero here. */
- gcc_assert (count > 0);
+ if (i > 2)
+ {
+ /* Split this list if it is long enough for that to help. */
+ npp = head;
+ left = *npp;
- /* Decide how to expand this switch.
- The two options at this point are a dispatch table (casesi or
- tablejump) or a decision tree. */
+ /* If there are just three nodes, split at the middle one. */
+ if (i == 3)
+ npp = &(*npp)->m_right;
+ else
+ {
+ /* Find the place in the list that bisects the list's total cost,
+ where ranges count as 2.
+ Here I gets half the total cost. */
+ i = (i + ranges + 1) / 2;
+ while (1)
+ {
+ /* Skip nodes while their cost does not reach that amount. */
+ if (!tree_int_cst_equal ((*npp)->m_c->get_low (),
+ (*npp)->m_c->get_high ()))
+ i--;
+ i--;
+ if (i <= 0)
+ break;
+ npp = &(*npp)->m_right;
+ }
+ }
+ *head = np = *npp;
+ *npp = 0;
+ np->m_parent = parent;
+ np->m_left = left;
- if (expand_switch_as_decision_tree_p (range, uniq, count))
- {
- emit_case_decision_tree (stmt, index_expr, index_type, case_list,
- default_bb, default_label, default_prob,
- &phi_mapping);
- return true;
+ /* Optimize each of the two split parts. */
+ balance_case_nodes (&np->m_left, np);
+ balance_case_nodes (&np->m_right, np);
+ np->m_c->m_subtree_prob = np->m_c->m_prob;
+ np->m_c->m_subtree_prob += np->m_left->m_c->m_subtree_prob;
+ np->m_c->m_subtree_prob += np->m_right->m_c->m_subtree_prob;
+ }
+ else
+ {
+ /* Else leave this branch as one level,
+ but fill in `parent' fields. */
+ np = *head;
+ np->m_parent = parent;
+ np->m_c->m_subtree_prob = np->m_c->m_prob;
+ for (; np->m_right; np = np->m_right)
+ {
+ np->m_right->m_parent = np;
+ (*head)->m_c->m_subtree_prob += np->m_right->m_c->m_subtree_prob;
+ }
+ }
}
+}
+
+/* Dump ROOT, a list or tree of case nodes, to file. */
- return false;
+void
+switch_decision_tree::dump_case_nodes (FILE *f, case_tree_node *root,
+ int indent_step, int indent_level)
+{
+ if (root == 0)
+ return;
+ indent_level++;
+
+ dump_case_nodes (f, root->m_left, indent_step, indent_level);
+
+ fputs (";; ", f);
+ fprintf (f, "%*s", indent_step * indent_level, "");
+ root->m_c->dump (f);
+ root->m_c->m_prob.dump (f);
+ fputs ("\n", f);
+
+ dump_case_nodes (f, root->m_right, indent_step, indent_level);
+}
+
+
+/* Add an unconditional jump to CASE_BB that happens in basic block BB. */
+
+void
+switch_decision_tree::emit_jump (basic_block bb, basic_block case_bb)
+{
+ edge e = single_succ_edge (bb);
+ redirect_edge_succ (e, case_bb);
+}
+
+/* Generate code to compare OP0 with OP1 so that the condition codes are
+ set and to jump to LABEL_BB if the condition is true.
+ COMPARISON is the GIMPLE comparison (EQ, NE, GT, etc.).
+ PROB is the probability of jumping to LABEL_BB. */
+
+basic_block
+switch_decision_tree::emit_cmp_and_jump_insns (basic_block bb, tree op0,
+ tree op1, tree_code comparison,
+ basic_block label_bb,
+ profile_probability prob)
+{
+ // TODO: it's once called with lhs != index.
+ op1 = fold_convert (TREE_TYPE (op0), op1);
+
+ gcond *cond = gimple_build_cond (comparison, op0, op1, NULL_TREE, NULL_TREE);
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gsi_insert_after (&gsi, cond, GSI_NEW_STMT);
+
+ gcc_assert (single_succ_p (bb));
+
+ /* Make a new basic block where false branch will take place. */
+ edge false_edge = split_block (bb, cond);
+ false_edge->flags = EDGE_FALSE_VALUE;
+ false_edge->probability = prob.invert ();
+
+ edge true_edge = make_edge (bb, label_bb, EDGE_TRUE_VALUE);
+ true_edge->probability = prob;
+
+ return false_edge->dest;
+}
+
+/* Emit step-by-step code to select a case for the value of INDEX.
+ The thus generated decision tree follows the form of the
+ case-node binary tree NODE, whose nodes represent test conditions.
+ DEFAULT_PROB is probability of cases leading to default BB.
+ INDEX_TYPE is the type of the index of the switch. */
+
+basic_block
+switch_decision_tree::emit_case_nodes (basic_block bb, tree index,
+ case_tree_node *node,
+ profile_probability default_prob,
+ tree index_type)
+{
+ /* If node is null, we are done. */
+ if (node == NULL)
+ return bb;
+
+ /* Branch to a label where we will handle it later. */
+ basic_block test_bb = split_edge (single_succ_edge (bb));
+ redirect_edge_succ (single_pred_edge (test_bb),
+ single_succ_edge (bb)->dest);
+
+ profile_probability probability
+ = (node->m_right
+ ? node->m_right->m_c->m_subtree_prob : profile_probability::never ());
+ probability = ((probability + default_prob.apply_scale (1, 2))
+ / (node->m_c->m_subtree_prob + default_prob));
+ bb = emit_cmp_and_jump_insns (bb, index, node->m_c->get_high (), GT_EXPR,
+ test_bb, probability);
+ default_prob = default_prob.apply_scale (1, 2);
+
+ /* Value belongs to this node or to the left-hand subtree. */
+ probability = node->m_c->m_prob /
+ (node->m_c->m_subtree_prob + default_prob);
+ bb = emit_cmp_and_jump_insns (bb, index, node->m_c->get_low (), GE_EXPR,
+ node->m_c->m_case_bb, probability);
+
+ /* Handle the left-hand subtree. */
+ bb = emit_case_nodes (bb, index, node->m_left,
+ default_prob, index_type);
+
+ /* If the left-hand subtree fell through,
+ don't let it fall into the right-hand subtree. */
+ if (m_default_bb)
+ emit_jump (bb, m_default_bb);
+
+ bb = emit_case_nodes (test_bb, index, node->m_right,
+ default_prob, index_type);
+
+ return bb;
+}
+
+/* The main function of the pass scans statements for switches and invokes
+ process_switch on them. */
+
+namespace {
+
+const pass_data pass_data_convert_switch =
+{
+ GIMPLE_PASS, /* type */
+ "switchconv", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_SWITCH_CONVERSION, /* tv_id */
+ ( PROP_cfg | PROP_ssa ), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_convert_switch : public gimple_opt_pass
+{
+public:
+ pass_convert_switch (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_convert_switch, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_tree_switch_conversion != 0; }
+ virtual unsigned int execute (function *);
+
+}; // class pass_convert_switch
+
+unsigned int
+pass_convert_switch::execute (function *fun)
+{
+ basic_block bb;
+ bool cfg_altered = false;
+
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ gimple *stmt = last_stmt (bb);
+ if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+ {
+ if (dump_file)
+ {
+ expanded_location loc = expand_location (gimple_location (stmt));
+
+ fprintf (dump_file, "beginning to process the following "
+ "SWITCH statement (%s:%d) : ------- \n",
+ loc.file, loc.line);
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ putc ('\n', dump_file);
+ }
+
+ switch_conversion sconv;
+ sconv.expand (as_a <gswitch *> (stmt));
+ cfg_altered |= sconv.m_cfg_altered;
+ if (!sconv.m_reason)
+ {
+ if (dump_file)
+ {
+ fputs ("Switch converted\n", dump_file);
+ fputs ("--------------------------------\n", dump_file);
+ }
+
+ /* Make no effort to update the post-dominator tree.
+ It is actually not that hard for the transformations
+ we have performed, but it is not supported
+ by iterate_fix_dominators. */
+ free_dominance_info (CDI_POST_DOMINATORS);
+ }
+ else
+ {
+ if (dump_file)
+ {
+ fputs ("Bailing out - ", dump_file);
+ fputs (sconv.m_reason, dump_file);
+ fputs ("\n--------------------------------\n", dump_file);
+ }
+ }
+ }
+ }
+
+ return cfg_altered ? TODO_cleanup_cfg : 0;;
+}
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_convert_switch (gcc::context *ctxt)
+{
+ return new pass_convert_switch (ctxt);
}
/* The main function of the pass scans statements for switches and invokes
basic_block bb;
bool expanded = false;
+ auto_vec<gimple *> switch_statements;
+ switch_statements.create (1);
+
FOR_EACH_BB_FN (bb, fun)
{
gimple *stmt = last_stmt (bb);
if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+ switch_statements.safe_push (stmt);
+ }
+
+ for (unsigned i = 0; i < switch_statements.length (); i++)
+ {
+ gimple *stmt = switch_statements[i];
+ if (dump_file)
{
- if (dump_file)
- {
- expanded_location loc = expand_location (gimple_location (stmt));
+ expanded_location loc = expand_location (gimple_location (stmt));
- fprintf (dump_file, "beginning to process the following "
- "SWITCH statement (%s:%d) : ------- \n",
- loc.file, loc.line);
- print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
- putc ('\n', dump_file);
- }
+ fprintf (dump_file, "beginning to process the following "
+ "SWITCH statement (%s:%d) : ------- \n",
+ loc.file, loc.line);
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ putc ('\n', dump_file);
+ }
- expanded |= try_switch_expansion (as_a<gswitch *> (stmt));
+ gswitch *swtch = dyn_cast<gswitch *> (stmt);
+ if (swtch)
+ {
+ switch_decision_tree dt (swtch);
+ expanded |= dt.analyze_switch_statement ();
}
}
return new pass_lower_switch<false> (ctxt);
}
-/* Generate code to compare X with Y so that the condition codes are
- set and to jump to LABEL if the condition is true. If X is a
- constant and Y is not a constant, then the comparison is swapped to
- ensure that the comparison RTL has the canonical form.
- UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
- need to be widened. UNSIGNEDP is also used to select the proper
- branch condition code.
-
- If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y.
-
- MODE is the mode of the inputs (in case they are const_int).
-
- COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
- It will be potentially converted into an unsigned variant based on
- UNSIGNEDP to select a proper jump instruction.
-
- PROB is the probability of jumping to LABEL. */
-
-static basic_block
-emit_cmp_and_jump_insns (basic_block bb, tree op0, tree op1,
- tree_code comparison, basic_block label_bb,
- profile_probability prob,
- hash_map<tree, tree> *phi_mapping)
-{
- gcond *cond = gimple_build_cond (comparison, op0, op1, NULL_TREE, NULL_TREE);
- gimple_stmt_iterator gsi = gsi_last_bb (bb);
- gsi_insert_after (&gsi, cond, GSI_NEW_STMT);
-
- gcc_assert (single_succ_p (bb));
-
- /* Make a new basic block where false branch will take place. */
- edge false_edge = split_block (bb, cond);
- false_edge->flags = EDGE_FALSE_VALUE;
- false_edge->probability = prob.invert ();
-
- edge true_edge = make_edge (bb, label_bb, EDGE_TRUE_VALUE);
- fix_phi_operands_for_edge (true_edge, phi_mapping);
- true_edge->probability = prob;
-
- return false_edge->dest;
-}
-
-/* Computes the conditional probability of jumping to a target if the branch
- instruction is executed.
- TARGET_PROB is the estimated probability of jumping to a target relative
- to some basic block BB.
- BASE_PROB is the probability of reaching the branch instruction relative
- to the same basic block BB. */
-
-static inline profile_probability
-conditional_probability (profile_probability target_prob,
- profile_probability base_prob)
-{
- return target_prob / base_prob;
-}
-
-/* Emit step-by-step code to select a case for the value of INDEX.
- The thus generated decision tree follows the form of the
- case-node binary tree NODE, whose nodes represent test conditions.
- INDEX_TYPE is the type of the index of the switch. */
-
-static basic_block
-emit_case_nodes (basic_block bb, tree index, case_node_ptr node,
- basic_block default_bb, tree default_label,
- profile_probability default_prob, tree index_type,
- hash_map<tree, tree> *phi_mapping)
-{
- /* If node is null, we are done. */
- if (node == NULL)
- return bb;
-
- /* Branch to a label where we will handle it later. */
- basic_block test_bb = split_edge (single_succ_edge (bb));
- redirect_edge_succ (single_pred_edge (test_bb),
- single_succ_edge (bb)->dest);
-
- profile_probability probability
- = node->right ? node->right->subtree_prob : profile_probability::never ();
- probability
- = conditional_probability (probability + default_prob.apply_scale (1, 2),
- node->subtree_prob + default_prob);
- bb = emit_cmp_and_jump_insns (bb, index, node->high, GT_EXPR,
- test_bb, probability, phi_mapping);
- default_prob = default_prob.apply_scale (1, 2);
-
- /* Value belongs to this node or to the left-hand subtree. */
- probability
- = conditional_probability (node->prob, node->subtree_prob + default_prob);
- bb = emit_cmp_and_jump_insns (bb, index, node->low, GE_EXPR,
- node->case_bb, probability,
- phi_mapping);
-
- /* Handle the left-hand subtree. */
- bb = emit_case_nodes (bb, index, node->left, default_bb,
- default_label, default_prob, index_type,
- phi_mapping);
-
- /* If the left-hand subtree fell through,
- don't let it fall into the right-hand subtree. */
- if (default_bb)
- emit_jump (bb, default_bb, phi_mapping);
-
- bb = emit_case_nodes (test_bb, index, node->right, default_bb,
- default_label, default_prob, index_type,
- phi_mapping);
-
- return bb;
-}
namespace tree_switch_conversion {
+/* Type of cluster. */
+
+enum cluster_type
+{
+ SIMPLE_CASE,
+ JUMP_TABLE,
+ BIT_TEST
+};
+
+#define PRINT_CASE(f,c) print_generic_expr (f, c)
+
+/* Abstract base class for representing a cluster of cases. */
+
+struct cluster
+{
+ /* Constructor. */
+ cluster (tree case_label_expr, basic_block case_bb, profile_probability prob,
+ profile_probability subtree_prob);
+
+ /* Destructor. */
+ virtual ~cluster ()
+ {}
+
+ /* Return type. */
+ virtual cluster_type get_type () = 0;
+
+ /* Get low value covered by a cluster. */
+ virtual tree get_low () = 0;
+
+ /* Get high value covered by a cluster. */
+ virtual tree get_high () = 0;
+
+ /* Debug content of a cluster. */
+ virtual void debug () = 0;
+
+ /* Dump content of a cluster. */
+ virtual void dump (FILE *f, bool details = false) = 0;
+
+ /* Emit GIMPLE code to handle the cluster. */
+ virtual void emit (tree, tree, tree, basic_block) = 0;
+
+ /* Return range of a cluster. If value would overflow in type of LOW,
+ then return 0. */
+ static unsigned HOST_WIDE_INT get_range (tree low, tree high)
+ {
+ tree r = fold_build2 (MINUS_EXPR, TREE_TYPE (low), high, low);
+ if (!tree_fits_uhwi_p (r))
+ return 0;
+
+ return tree_to_uhwi (r) + 1;
+ }
+
+ /* Case label. */
+ tree m_case_label_expr;
+
+ /* Basic block of the case. */
+ basic_block m_case_bb;
+
+ /* Probability of taking this cluster. */
+ profile_probability m_prob;
+
+ /* Probability of reaching subtree rooted at this node. */
+ profile_probability m_subtree_prob;
+
+protected:
+ /* Default constructor. */
+ cluster () {}
+};
+
+cluster::cluster (tree case_label_expr, basic_block case_bb,
+ profile_probability prob, profile_probability subtree_prob):
+ m_case_label_expr (case_label_expr), m_case_bb (case_bb), m_prob (prob),
+ m_subtree_prob (subtree_prob)
+{
+}
+
+/* Subclass of cluster representing a simple contiguous range
+ from [low..high]. */
+
+struct simple_cluster: public cluster
+{
+ /* Constructor. */
+ simple_cluster (tree low, tree high, tree case_label_expr,
+ basic_block case_bb, profile_probability prob);
+
+ /* Destructor. */
+ ~simple_cluster ()
+ {}
+
+ cluster_type
+ get_type ()
+ {
+ return SIMPLE_CASE;
+ }
+
+ tree
+ get_low ()
+ {
+ return m_low;
+ }
+
+ tree
+ get_high ()
+ {
+ return m_high;
+ }
+
+ void
+ debug ()
+ {
+ dump (stderr);
+ }
+
+ void
+ dump (FILE *f, bool details ATTRIBUTE_UNUSED = false)
+ {
+ PRINT_CASE (f, get_low ());
+ if (get_low () != get_high ())
+ {
+ fprintf (f, "-");
+ PRINT_CASE (f, get_high ());
+ }
+ fprintf (f, " ");
+ }
+
+ void emit (tree, tree, tree, basic_block)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Low value of the case. */
+ tree m_low;
+
+ /* High value of the case. */
+ tree m_high;
+
+ /* True if case is a range. */
+ bool m_range_p;
+};
+
+simple_cluster::simple_cluster (tree low, tree high, tree case_label_expr,
+ basic_block case_bb, profile_probability prob):
+ cluster (case_label_expr, case_bb, prob, prob),
+ m_low (low), m_high (high)
+{
+ m_range_p = m_high != NULL;
+ if (m_high == NULL)
+ m_high = m_low;
+}
+
+/* Abstract subclass of jump table and bit test cluster,
+ handling a collection of simple_cluster instances. */
+
+struct group_cluster: public cluster
+{
+ /* Constructor. */
+ group_cluster (vec<cluster *> &clusters, unsigned start, unsigned end);
+
+ /* Destructor. */
+ ~group_cluster ();
+
+ tree
+ get_low ()
+ {
+ return m_cases[0]->get_low ();
+ }
+
+ tree
+ get_high ()
+ {
+ return m_cases[m_cases.length () - 1]->get_high ();
+ }
+
+ void
+ debug ()
+ {
+ dump (stderr);
+ }
+
+ void dump (FILE *f, bool details = false);
+
+ /* List of simple clusters handled by the group. */
+ vec<simple_cluster *> m_cases;
+};
+
+/* Concrete subclass of group_cluster representing a collection
+ of cases to be implemented as a jump table.
+ The "emit" vfunc gernerates a nested switch statement which
+ is later lowered to a jump table. */
+
+struct jump_table_cluster: public group_cluster
+{
+ /* Constructor. */
+ jump_table_cluster (vec<cluster *> &clusters, unsigned start, unsigned end)
+ : group_cluster (clusters, start, end)
+ {}
+
+ cluster_type
+ get_type ()
+ {
+ return JUMP_TABLE;
+ }
+
+ void emit (tree index_expr, tree index_type,
+ tree default_label_expr, basic_block default_bb);
+
+ /* Return true when cluster starting at START and ending at END (inclusive)
+ can build a jump-table. */
+ static bool can_be_handled (const vec<cluster *> &clusters, unsigned start,
+ unsigned end);
+
+ /* Return true if cluster starting at START and ending at END (inclusive)
+ is profitable transformation. */
+ static bool is_beneficial (const vec<cluster *> &clusters, unsigned start,
+ unsigned end);
+
+ /* Return the smallest number of different values for which it is best
+ to use a jump-table instead of a tree of conditional branches. */
+ static inline unsigned int case_values_threshold (void);
+};
+
+/* A GIMPLE switch statement can be expanded to a short sequence of bit-wise
+comparisons. "switch(x)" is converted into "if ((1 << (x-MINVAL)) & CST)"
+where CST and MINVAL are integer constants. This is better than a series
+of compare-and-banch insns in some cases, e.g. we can implement:
+
+ if ((x==4) || (x==6) || (x==9) || (x==11))
+
+as a single bit test:
+
+ if ((1<<x) & ((1<<4)|(1<<6)|(1<<9)|(1<<11)))
+
+This transformation is only applied if the number of case targets is small,
+if CST constains at least 3 bits, and "1 << x" is cheap. The bit tests are
+performed in "word_mode".
+
+The following example shows the code the transformation generates:
+
+ int bar(int x)
+ {
+ switch (x)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F':
+ return 1;
+ }
+ return 0;
+ }
+
+==>
+
+ bar (int x)
+ {
+ tmp1 = x - 48;
+ if (tmp1 > (70 - 48)) goto L2;
+ tmp2 = 1 << tmp1;
+ tmp3 = 0b11111100000001111111111;
+ if ((tmp2 & tmp3) != 0) goto L1 ; else goto L2;
+ L1:
+ return 1;
+ L2:
+ return 0;
+ }
+
+TODO: There are still some improvements to this transformation that could
+be implemented:
+
+* A narrower mode than word_mode could be used if that is cheaper, e.g.
+ for x86_64 where a narrower-mode shift may result in smaller code.
+
+* The compounded constant could be shifted rather than the one. The
+ test would be either on the sign bit or on the least significant bit,
+ depending on the direction of the shift. On some machines, the test
+ for the branch would be free if the bit to test is already set by the
+ shift operation.
+
+This transformation was contributed by Roger Sayle, see this e-mail:
+ http://gcc.gnu.org/ml/gcc-patches/2003-01/msg01950.html
+*/
+
+struct bit_test_cluster: public group_cluster
+{
+ /* Constructor. */
+ bit_test_cluster (vec<cluster *> &clusters, unsigned start, unsigned end)
+ :group_cluster (clusters, start, end)
+ {}
+
+ cluster_type
+ get_type ()
+ {
+ return BIT_TEST;
+ }
+
+/* Expand a switch statement by a short sequence of bit-wise
+ comparisons. "switch(x)" is effectively converted into
+ "if ((1 << (x-MINVAL)) & CST)" where CST and MINVAL are
+ integer constants.
+
+ INDEX_EXPR is the value being switched on.
+
+ MINVAL is the lowest case value of in the case nodes,
+ and RANGE is highest value minus MINVAL. MINVAL and RANGE
+ are not guaranteed to be of the same type as INDEX_EXPR
+ (the gimplifier doesn't change the type of case label values,
+ and MINVAL and RANGE are derived from those values).
+ MAXVAL is MINVAL + RANGE.
+
+ There *MUST* be max_case_bit_tests or less unique case
+ node targets. */
+ void emit (tree index_expr, tree index_type,
+ tree default_label_expr, basic_block default_bb);
+
+ /* Return true when RANGE of case values with UNIQ labels
+ can build a bit test. */
+ static bool can_be_handled (unsigned HOST_WIDE_INT range, unsigned uniq);
+
+ /* Return true when cluster starting at START and ending at END (inclusive)
+ can build a bit test. */
+ static bool can_be_handled (const vec<cluster *> &clusters, unsigned start,
+ unsigned end);
+
+ /* Return true when COUNT of cases of UNIQ labels is beneficial for bit test
+ transformation. */
+ static bool is_beneficial (unsigned count, unsigned uniq);
+
+ /* Return true if cluster starting at START and ending at END (inclusive)
+ is profitable transformation. */
+ static bool is_beneficial (const vec<cluster *> &clusters, unsigned start,
+ unsigned end);
+
+/* Split the basic block at the statement pointed to by GSIP, and insert
+ a branch to the target basic block of E_TRUE conditional on tree
+ expression COND.
+
+ It is assumed that there is already an edge from the to-be-split
+ basic block to E_TRUE->dest block. This edge is removed, and the
+ profile information on the edge is re-used for the new conditional
+ jump.
+
+ The CFG is updated. The dominator tree will not be valid after
+ this transformation, but the immediate dominators are updated if
+ UPDATE_DOMINATORS is true.
+
+ Returns the newly created basic block. */
+ static basic_block hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
+ tree cond,
+ basic_block case_bb);
+
+ /* Maximum number of different basic blocks that can be handled by
+ a bit test. */
+ static const int m_max_case_bit_tests = 3;
+};
+
+/* Helper struct to find minimal clusters. */
+
+struct min_cluster_item
+{
+ /* Constructor. */
+ min_cluster_item (unsigned count, unsigned start, unsigned non_jt_cases):
+ m_count (count), m_start (start), m_non_jt_cases (non_jt_cases)
+ {}
+
+ /* Count of clusters. */
+ unsigned m_count;
+
+ /* Index where is cluster boundary. */
+ unsigned m_start;
+
+ /* Total number of cases that will not be in a jump table. */
+ unsigned m_non_jt_cases;
+};
+
+/* Helper struct to represent switch decision tree. */
+
+struct case_tree_node
+{
+ /* Empty Constructor. */
+ case_tree_node ();
+
+ /* Left son in binary tree. */
+ case_tree_node *m_left;
+
+ /* Right son in binary tree; also node chain. */
+ case_tree_node *m_right;
+
+ /* Parent of node in binary tree. */
+ case_tree_node *m_parent;
+
+ /* Cluster represented by this tree node. */
+ cluster *m_c;
+};
+
+inline
+case_tree_node::case_tree_node ():
+ m_left (NULL), m_right (NULL), m_parent (NULL), m_c (NULL)
+{
+}
+
+unsigned int
+jump_table_cluster::case_values_threshold (void)
+{
+ unsigned int threshold = PARAM_VALUE (PARAM_CASE_VALUES_THRESHOLD);
+
+ if (threshold == 0)
+ threshold = targetm.case_values_threshold ();
+
+ return threshold;
+}
+
+/* A case_bit_test represents a set of case nodes that may be
+ selected from using a bit-wise comparison. HI and LO hold
+ the integer to be tested against, TARGET_EDGE contains the
+ edge to the basic block to jump to upon success and BITS
+ counts the number of case nodes handled by this test,
+ typically the number of bits set in HI:LO. The LABEL field
+ is used to quickly identify all cases in this set without
+ looking at label_to_block for every case label. */
+
+struct case_bit_test
+{
+ wide_int mask;
+ basic_block target_bb;
+ tree label;
+ int bits;
+
+ /* Comparison function for qsort to order bit tests by decreasing
+ probability of execution. */
+ static int cmp (const void *p1, const void *p2);
+};
+
+struct switch_decision_tree
+{
+ /* Constructor. */
+ switch_decision_tree (gswitch *swtch): m_switch (swtch), m_phi_mapping (),
+ m_case_bbs (), m_case_node_pool ("struct case_node pool"),
+ m_case_list (NULL)
+ {
+ }
+
+ /* Analyze switch statement and return true when the statement is expanded
+ as decision tree. */
+ bool analyze_switch_statement ();
+
+ /* Attempt to expand CLUSTERS as a decision tree. Return true when
+ expanded. */
+ bool try_switch_expansion (vec<cluster *> &clusters);
+
+ /* Reset the aux field of all outgoing edges of switch basic block. */
+ inline void reset_out_edges_aux ();
+
+ /* Compute the number of case labels that correspond to each outgoing edge of
+ switch statement. Record this information in the aux field of the edge.
+ */
+ void compute_cases_per_edge ();
+
+ /* Before switch transformation, record all SSA_NAMEs defined in switch BB
+ and used in a label basic block. */
+ void record_phi_operand_mapping ();
+
+ /* Append new operands to PHI statements that were introduced due to
+ addition of new edges to case labels. */
+ void fix_phi_operands_for_edges ();
+
+ /* Generate a decision tree, switching on INDEX_EXPR and jumping to
+ one of the labels in CASE_LIST or to the DEFAULT_LABEL.
+
+ We generate a binary decision tree to select the appropriate target
+ code. */
+ void emit (basic_block bb, tree index_expr,
+ profile_probability default_prob, tree index_type);
+
+ /* Emit step-by-step code to select a case for the value of INDEX.
+ The thus generated decision tree follows the form of the
+ case-node binary tree NODE, whose nodes represent test conditions.
+ DEFAULT_PROB is probability of cases leading to default BB.
+ INDEX_TYPE is the type of the index of the switch. */
+ basic_block emit_case_nodes (basic_block bb, tree index,
+ case_tree_node *node,
+ profile_probability default_prob,
+ tree index_type);
+
+ /* Take an ordered list of case nodes
+ and transform them into a near optimal binary tree,
+ on the assumption that any target code selection value is as
+ likely as any other.
+
+ The transformation is performed by splitting the ordered
+ list into two equal sections plus a pivot. The parts are
+ then attached to the pivot as left and right branches. Each
+ branch is then transformed recursively. */
+ static void balance_case_nodes (case_tree_node **head,
+ case_tree_node *parent);
+
+ /* Dump ROOT, a list or tree of case nodes, to file F. */
+ static void dump_case_nodes (FILE *f, case_tree_node *root, int indent_step,
+ int indent_level);
+
+ /* Add an unconditional jump to CASE_BB that happens in basic block BB. */
+ static void emit_jump (basic_block bb, basic_block case_bb);
+
+ /* Generate code to compare OP0 with OP1 so that the condition codes are
+ set and to jump to LABEL_BB if the condition is true.
+ COMPARISON is the GIMPLE comparison (EQ, NE, GT, etc.).
+ PROB is the probability of jumping to LABEL_BB. */
+ static basic_block emit_cmp_and_jump_insns (basic_block bb, tree op0,
+ tree op1, tree_code comparison,
+ basic_block label_bb,
+ profile_probability prob);
+
+ /* Switch statement. */
+ gswitch *m_switch;
+
+ /* Map of PHI nodes that have to be fixed after expansion. */
+ hash_map<tree, tree> m_phi_mapping;
+
+ /* List of basic blocks that belong to labels of the switch. */
+ auto_vec<basic_block> m_case_bbs;
+
+ /* Basic block with default label. */
+ basic_block m_default_bb;
+
+ /* A pool for case nodes. */
+ object_allocator<case_tree_node> m_case_node_pool;
+
+ /* Balanced tree of case nodes. */
+ case_tree_node *m_case_list;
+};
+
/*
Switch initialization conversion
labels. */
bool m_default_case_nonstandard;
+ /* Number of uniq labels for non-default edges. */
+ unsigned int m_uniq;
+
/* Count is number of non-default edges. */
unsigned int m_count;
bool m_cfg_altered;
};
+void
+switch_decision_tree::reset_out_edges_aux ()
+{
+ basic_block bb = gimple_bb (m_switch);
+ edge e;
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ e->aux = (void *) 0;
+}
+
} // tree_switch_conversion namespace
#endif // TREE_SWITCH_CONVERSION_H