stmt.c (emit_case_bit_tests): Remove.

gcc/
	* stmt.c (emit_case_bit_tests): Remove.
	(expand_case): Remove expand_switch_using_bit_tests_p code.
	* tree-switch-conversion.c (hoist_edge_and_branch_if_true): New.
	(MAX_CASE_BIT_TESTS): Moved from stmt.c to here.
	(lshift_cheap_p): Likewise.
	(expand_switch_using_bit_tests_p): Likewise.
	(struct case_bit_test): Likewise.
	(case_bit_test_cmp): Likewise.
	(emit_case_bit_tests): New implementation for GIMPLE.
	(gen_inbound_check): Do not release post-dominator info here.
	(process_switch): Reorder code.  Expand as bit tests if it
	looks like a win.
	(do_switchconv): Release post-dominator info here if something
	changed.
	(struct gimple_opt_pass): Verify more.
	* tree.h (expand_switch_using_bit_tests_p): Remove prototype.

testsuite/
	* gcc.dg/tree-ssa/pr36881.c: Fix test case to not expand as bit tests.

From-SVN: r189173
This commit is contained in:
Steven Bosscher 2012-07-02 18:50:51 +00:00
parent 8153b03d4b
commit 531b10fcb0
6 changed files with 526 additions and 240 deletions

View File

@ -1,3 +1,22 @@
2012-07-02 Steven Bosscher <steven@gcc.gnu.org>
* stmt.c (emit_case_bit_tests): Remove.
(expand_case): Remove expand_switch_using_bit_tests_p code.
* tree-switch-conversion.c (hoist_edge_and_branch_if_true): New.
(MAX_CASE_BIT_TESTS): Moved from stmt.c to here.
(lshift_cheap_p): Likewise.
(expand_switch_using_bit_tests_p): Likewise.
(struct case_bit_test): Likewise.
(case_bit_test_cmp): Likewise.
(emit_case_bit_tests): New implementation for GIMPLE.
(gen_inbound_check): Do not release post-dominator info here.
(process_switch): Reorder code. Expand as bit tests if it
looks like a win.
(do_switchconv): Release post-dominator info here if something
changed.
(struct gimple_opt_pass): Verify more.
* tree.h (expand_switch_using_bit_tests_p): Remove prototype.
2012-07-02 Martin Jambor <mjambor@suse.cz>
PR middle-end/38474

View File

@ -107,9 +107,6 @@ static bool check_unique_operand_names (tree, tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree, tree);
static void expand_null_return_1 (void);
static void expand_value_return (rtx);
static bool lshift_cheap_p (void);
static int case_bit_test_cmp (const void *, const void *);
static void emit_case_bit_tests (tree, tree, tree, tree, case_node_ptr, rtx);
static void balance_case_nodes (case_node_ptr *, case_node_ptr);
static int node_has_low_bound (case_node_ptr, tree);
static int node_has_high_bound (case_node_ptr, tree);
@ -1719,151 +1716,6 @@ add_case_node (struct case_node *head, tree type, tree low, tree high,
return r;
}
/* Maximum number of case bit tests. */
#define MAX_CASE_BIT_TESTS 3
/* 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, LABEL contains the label
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. */
struct case_bit_test
{
HOST_WIDE_INT hi;
HOST_WIDE_INT lo;
rtx label;
int bits;
};
/* Determine whether "1 << x" is relatively cheap in word_mode. */
static
bool lshift_cheap_p (void)
{
static bool init[2] = {false, false};
static bool cheap[2] = {true, true};
bool speed_p = optimize_insn_for_speed_p ();
if (!init[speed_p])
{
rtx reg = gen_rtx_REG (word_mode, 10000);
int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
speed_p);
cheap[speed_p] = cost < COSTS_N_INSNS (3);
init[speed_p] = true;
}
return cheap[speed_p];
}
/* Comparison function for qsort to order bit tests by decreasing
number of case nodes, i.e. the node with the most cases gets
tested first. */
static 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 CODE_LABEL_NUMBER (d2->label) - CODE_LABEL_NUMBER (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, which is of
type INDEX_TYPE. MINVAL is the lowest case value of in
the case nodes, of INDEX_TYPE type, and RANGE is highest
value minus MINVAL, also of type INDEX_TYPE. NODES is
the set of case nodes, and DEFAULT_LABEL is the label to
branch to should none of the cases match.
There *MUST* be MAX_CASE_BIT_TESTS or less unique case
node targets. */
static void
emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
tree range, case_node_ptr nodes, rtx default_label)
{
struct case_bit_test test[MAX_CASE_BIT_TESTS];
enum machine_mode mode;
rtx expr, index, label;
unsigned int i,j,lo,hi;
struct case_node *n;
unsigned int count;
count = 0;
for (n = nodes; n; n = n->right)
{
label = label_rtx (n->code_label);
for (i = 0; i < count; i++)
if (label == test[i].label)
break;
if (i == count)
{
gcc_assert (count < MAX_CASE_BIT_TESTS);
test[i].hi = 0;
test[i].lo = 0;
test[i].label = label;
test[i].bits = 1;
count++;
}
else
test[i].bits++;
lo = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
n->low, minval), 1);
hi = tree_low_cst (fold_build2 (MINUS_EXPR, index_type,
n->high, minval), 1);
for (j = lo; j <= hi; j++)
if (j >= HOST_BITS_PER_WIDE_INT)
test[i].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
else
test[i].lo |= (HOST_WIDE_INT) 1 << j;
}
qsort (test, count, sizeof(*test), case_bit_test_cmp);
index_expr = fold_build2 (MINUS_EXPR, index_type,
fold_convert (index_type, index_expr),
fold_convert (index_type, minval));
index = expand_normal (index_expr);
do_pending_stack_adjust ();
mode = TYPE_MODE (index_type);
expr = expand_normal (range);
if (default_label)
emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
default_label);
index = convert_to_mode (word_mode, index, 0);
index = expand_binop (word_mode, ashl_optab, const1_rtx,
index, NULL_RTX, 1, OPTAB_WIDEN);
for (i = 0; i < count; i++)
{
expr = immed_double_const (test[i].lo, test[i].hi, word_mode);
expr = expand_binop (word_mode, and_optab, index, expr,
NULL_RTX, 1, OPTAB_WIDEN);
emit_cmp_and_jump_insns (expr, const0_rtx, NE, NULL_RTX,
word_mode, 1, test[i].label);
}
if (default_label)
emit_jump (default_label);
}
#ifndef HAVE_casesi
#define HAVE_casesi 0
#endif
@ -1872,27 +1724,6 @@ emit_case_bit_tests (tree index_type, tree index_expr, tree minval,
#define HAVE_tablejump 0
#endif
/* Return true if a switch should be expanded as a bit test.
INDEX_EXPR is the index expression, RANGE is the difference between
highest and lowest case, UNIQ is number of unique case node targets
not counting the default case and COUNT is the number of comparisons
needed, not counting the default case. */
bool
expand_switch_using_bit_tests_p (tree index_expr, tree range,
unsigned int uniq, unsigned int count)
{
if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
return false;
return (! TREE_CONSTANT (index_expr)
&& compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
&& compare_tree_int (range, 0) > 0
&& lshift_cheap_p ()
&& ((uniq == 1 && count >= 3)
|| (uniq == 2 && count >= 5)
|| (uniq == 3 && count >= 6)));
}
/* Return the smallest number of different values for which it is best to use a
jump-table instead of a tree of conditional branches. */
@ -2035,40 +1866,22 @@ expand_case (gimple stmt)
/* Compute span of values. */
range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
/* Try implementing this switch statement by a short sequence of
bit-wise comparisons. However, we let the binary-tree case
below handle constant index expressions. */
if (expand_switch_using_bit_tests_p (index_expr, range, uniq, count))
{
/* Optimize the case where all the case values fit in a
word without having to subtract MINVAL. In this case,
we can optimize away the subtraction. */
if (compare_tree_int (minval, 0) > 0
&& compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0)
{
minval = build_int_cst (index_type, 0);
range = maxval;
}
emit_case_bit_tests (index_type, index_expr, minval, range,
case_list, default_label);
}
/* If range of values is much bigger than number of values,
make a sequence of conditional branches instead of a dispatch.
If the switch-index is a constant, do it this way
because we can optimize it. */
else if (count < case_values_threshold ()
|| compare_tree_int (range,
(optimize_insn_for_size_p () ? 3 : 10) * count) > 0
/* RANGE may be signed, and really large ranges will show up
as negative numbers. */
|| compare_tree_int (range, 0) < 0
|| !flag_jump_tables
|| TREE_CONSTANT (index_expr)
/* If neither casesi or tablejump is available, we can
only go this way. */
|| (!HAVE_casesi && !HAVE_tablejump))
if (count < case_values_threshold ()
|| compare_tree_int (range,
(optimize_insn_for_size_p () ? 3 : 10) * count) > 0
/* RANGE may be signed, and really large ranges will show up
as negative numbers. */
|| compare_tree_int (range, 0) < 0
|| !flag_jump_tables
|| TREE_CONSTANT (index_expr)
/* If neither casesi or tablejump is available, we can
only go this way. */
|| (!HAVE_casesi && !HAVE_tablejump))
{
index = expand_normal (index_expr);

View File

@ -1,3 +1,7 @@
2012-07-02 Steven Bosscher <steven@gcc.gnu.org>
* gcc.dg/tree-ssa/pr36881.c: Fix test case to not expand as bit tests.
2012-07-01 Wei Guozhi <carrot@google.com>
PR target/53447

View File

@ -13,7 +13,10 @@ const char *foo (int i)
case 7: p = "abc"; break;
case 2:
case 8: p = "def"; break;
default: p = "ghi"; break;
case 9: p = "ghi"; break;
case 5: p = "jkl"; break;
case 3: p = "mno"; break;
default: p = "prq"; break;
}
return p;
}

View File

@ -1,7 +1,7 @@
/* Switch Conversion converts variable initializations based on switch
statements to initializations from a static array.
Copyright (C) 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Martin Jambor <jamborm@suse.cz>
/* Lower GIMPLE_SWITCH expressions to something more efficient than
a jump table.
Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GCC.
@ -20,6 +20,458 @@ along with GCC; see the file COPYING3. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* This file handles the lowering of GIMPLE_SWITCH to an indexed
load, or a series of bit-test-and-branch expressions. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "line-map.h"
#include "params.h"
#include "flags.h"
#include "tree.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "tree-flow-inline.h"
#include "tree-ssa-operands.h"
#include "tree-pass.h"
#include "gimple-pretty-print.h"
#include "tree-dump.h"
#include "timevar.h"
#include "langhooks.h"
/* Need to include expr.h and optabs.h for lshift_cheap_p. */
#include "expr.h"
#include "optabs.h"
/* Maximum number of case bit tests.
FIXME: This should be derived from PARAM_CASE_VALUES_THRESHOLD and
targetm.case_values_threshold(), or be its own param. */
#define MAX_CASE_BIT_TESTS 3
/* 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, edge e_true,
bool update_dominators)
{
tree tmp;
gimple cond_stmt;
edge e_false;
basic_block new_bb, split_bb = gsi_bb (*gsip);
bool dominated_e_true = false;
gcc_assert (e_true->src == split_bb);
if (update_dominators
&& get_immediate_dominator (CDI_DOMINATORS, e_true->dest) == split_bb)
dominated_e_true = true;
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);
e_false = split_block (split_bb, cond_stmt);
new_bb = e_false->dest;
redirect_edge_pred (e_true, split_bb);
e_true->flags &= ~EDGE_FALLTHRU;
e_true->flags |= EDGE_TRUE_VALUE;
e_false->flags &= ~EDGE_FALLTHRU;
e_false->flags |= EDGE_FALSE_VALUE;
e_false->probability = REG_BR_PROB_BASE - e_true->probability;
e_false->count = split_bb->count - e_true->count;
new_bb->count = e_false->count;
if (update_dominators)
{
if (dominated_e_true)
set_immediate_dominator (CDI_DOMINATORS, e_true->dest, split_bb);
set_immediate_dominator (CDI_DOMINATORS, e_false->dest, split_bb);
}
return new_bb;
}
/* Determine whether "1 << x" is relatively cheap in word_mode. */
/* FIXME: This is the function that we need rtl.h and optabs.h for.
This function (and similar RTL-related cost code in e.g. IVOPTS) should
be moved to some kind of interface file for GIMPLE/RTL interactions. */
static bool
lshift_cheap_p (void)
{
/* FIXME: This should be made target dependent via this "this_target"
mechanism, similar to e.g. can_copy_init_p in gcse.c. */
static bool init[2] = {false, false};
static bool cheap[2] = {true, true};
bool speed_p;
/* If the targer has no lshift in word_mode, the operation will most
probably not be cheap. ??? Does GCC even work for such targets? */
if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
return false;
speed_p = optimize_insn_for_speed_p ();
if (!init[speed_p])
{
rtx reg = gen_raw_REG (word_mode, 10000);
int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
speed_p);
cheap[speed_p] = cost < COSTS_N_INSNS (MAX_CASE_BIT_TESTS);
init[speed_p] = true;
}
return cheap[speed_p];
}
/* Return true if a switch should be expanded as a bit test.
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. */
static bool
expand_switch_using_bit_tests_p (tree range,
unsigned int uniq,
unsigned int count)
{
return (((uniq == 1 && count >= 3)
|| (uniq == 2 && count >= 5)
|| (uniq == 3 && count >= 6))
&& lshift_cheap_p ()
&& compare_tree_int (range, GET_MODE_BITSIZE (word_mode)) < 0
&& compare_tree_int (range, 0) > 0);
}
/* Implement switch statements with bit tests
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 "x << 1" 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
*/
/* 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
{
HOST_WIDE_INT hi;
HOST_WIDE_INT lo;
edge target_edge;
tree label;
int bits;
};
/* Comparison function for qsort to order bit tests by decreasing
probability of execution. Our best guess comes from a measured
profile. If the profile counts are equal, break even on the
number of case nodes, i.e. the node with the most cases gets
tested first.
TODO: Actually this currently runs before a profile is available.
Therefore the case-as-bit-tests transformation should be done
later in the pass pipeline, or something along the lines of
"Efficient and effective branch reordering using profile data"
(Yang et. al., 2002) should be implemented (although, how good
is a paper is called "Efficient and effective ..." when the
latter is implied by the former, but oh well...). */
static 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->target_edge->count != d1->target_edge->count)
return d2->target_edge->count - d1->target_edge->count;
if (d2->bits != d1->bits)
return d2->bits - d1->bits;
/* Stabilize the sort. */
return LABEL_DECL_UID (d2->label) - LABEL_DECL_UID (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).
There *MUST* be MAX_CASE_BIT_TESTS or less unique case
node targets. */
static void
emit_case_bit_tests (gimple swtch, tree index_expr,
tree minval, tree range)
{
struct case_bit_test test[MAX_CASE_BIT_TESTS];
unsigned int i, j, k;
unsigned int count;
basic_block switch_bb = gimple_bb (swtch);
basic_block default_bb, new_default_bb, new_bb;
edge default_edge;
bool update_dom = dom_info_available_p (CDI_DOMINATORS);
VEC (basic_block, heap) *bbs_to_fix_dom = NULL;
tree index_type = TREE_TYPE (index_expr);
tree unsigned_index_type = unsigned_type_for (index_type);
unsigned int branch_num = gimple_switch_num_labels (swtch);
gimple_stmt_iterator gsi;
gimple shift_stmt;
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);
memset (&test, 0, sizeof (test));
/* Get the edge for the default case. */
tmp = gimple_switch_label (swtch, 0);
default_bb = label_to_block (CASE_LABEL (tmp));
default_edge = find_edge (switch_bb, default_bb);
/* 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 = 1; i < branch_num; i++)
{
unsigned int lo, hi;
tree cs = gimple_switch_label (swtch, i);
tree label = CASE_LABEL (cs);
for (k = 0; k < count; k++)
if (label == test[k].label)
break;
if (k == count)
{
edge e = find_edge (switch_bb, label_to_block (label));
gcc_assert (e);
gcc_checking_assert (count < MAX_CASE_BIT_TESTS);
test[k].hi = 0;
test[k].lo = 0;
test[k].target_edge = e;
test[k].label = label;
test[k].bits = 1;
count++;
}
else
test[k].bits++;
lo = tree_low_cst (int_const_binop (MINUS_EXPR,
CASE_LOW (cs), minval),
1);
if (CASE_HIGH (cs) == NULL_TREE)
hi = lo;
else
hi = tree_low_cst (int_const_binop (MINUS_EXPR,
CASE_HIGH (cs), minval),
1);
for (j = lo; j <= hi; j++)
if (j >= HOST_BITS_PER_WIDE_INT)
test[k].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
else
test[k].lo |= (HOST_WIDE_INT) 1 << j;
}
qsort (test, count, sizeof(*test), case_bit_test_cmp);
/* We generate two jumps to the default case label.
Split the default edge, so that we don't have to do any PHI node
updating. */
new_default_bb = split_edge (default_edge);
if (update_dom)
{
bbs_to_fix_dom = VEC_alloc (basic_block, heap, 10);
VEC_quick_push (basic_block, bbs_to_fix_dom, switch_bb);
VEC_quick_push (basic_block, bbs_to_fix_dom, default_bb);
VEC_quick_push (basic_block, bbs_to_fix_dom, new_default_bb);
}
/* Now build the test-and-branch code. */
gsi = gsi_last_bb (switch_bb);
/* idx = (unsigned) (x - minval) */
idx = fold_build2 (MINUS_EXPR, index_type, index_expr,
fold_convert (index_type, minval));
idx = fold_convert (unsigned_index_type, idx);
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);
new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_edge, update_dom);
if (update_dom)
VEC_quick_push (basic_block, bbs_to_fix_dom, new_bb);
gcc_assert (gimple_bb (swtch) == new_bb);
gsi = gsi_last_bb (new_bb);
/* Any blocks dominated by the GIMPLE_SWITCH, but that are not successors
of NEW_BB, are still immediately dominated by SWITCH_BB. Make it so. */
if (update_dom)
{
VEC (basic_block, heap) *dom_bbs;
basic_block dom_son;
dom_bbs = get_dominated_by (CDI_DOMINATORS, new_bb);
FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, dom_son)
{
edge e = find_edge (new_bb, dom_son);
if (e && single_pred_p (e->dest))
continue;
set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb);
VEC_safe_push (basic_block, heap, bbs_to_fix_dom, dom_son);
}
VEC_free (basic_block, heap, dom_bbs);
}
/* csui = (1 << (word_mode) idx) */
tmp = create_tmp_var (word_type_node, "csui");
add_referenced_var (tmp);
csui = make_ssa_name (tmp, NULL);
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);
SSA_NAME_DEF_STMT (csui) = shift_stmt;
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 = build_int_cst_wide (word_type_node, test[k].lo, test[k].hi);
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_edge,
update_dom);
if (update_dom)
VEC_safe_push (basic_block, heap, bbs_to_fix_dom, new_bb);
gcc_assert (gimple_bb (swtch) == new_bb);
gsi = gsi_last_bb (new_bb);
}
/* We should have removed all edges now. */
gcc_assert (EDGE_COUNT (gsi_bb (gsi)->succs) == 0);
/* If nothing matched, go to the default label. */
make_edge (gsi_bb (gsi), new_default_bb, EDGE_FALLTHRU);
/* The GIMPLE_SWITCH is now redundant. */
gsi_remove (&gsi, true);
if (update_dom)
{
/* Fix up the dominator tree. */
iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
VEC_free (basic_block, heap, bbs_to_fix_dom);
}
}
/*
Switch initialization conversion
@ -75,26 +527,10 @@ is changed into:
There are further constraints. Specifically, the range of values across all
case labels must not be bigger than SWITCH_CONVERSION_BRANCH_RATIO (default
eight) times the number of the actual switch branches. */
eight) times the number of the actual switch branches.
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "line-map.h"
#include "params.h"
#include "flags.h"
#include "tree.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "tree-flow-inline.h"
#include "tree-ssa-operands.h"
#include "input.h"
#include "tree-pass.h"
#include "gimple-pretty-print.h"
#include "tree-dump.h"
#include "timevar.h"
#include "langhooks.h"
This transformation was contributed by Martin Jambor, see this e-mail:
http://gcc.gnu.org/ml/gcc-patches/2008-07/msg00011.html */
/* The main structure of the pass. */
struct switch_conv_info
@ -799,13 +1235,6 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
gcc_assert (info->default_values);
/* 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.
Freeing post-dominance info is dome early to avoid pointless work in
create_basic_block, which is called when we split SWITCH_BB. */
free_dominance_info (CDI_POST_DOMINATORS);
bb0 = gimple_bb (swtch);
tidx = gimple_assign_lhs (info->arr_ref_first);
@ -885,7 +1314,7 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
set_immediate_dominator (CDI_DOMINATORS, bb1, bb0);
set_immediate_dominator (CDI_DOMINATORS, bb2, bb0);
if (! get_immediate_dominator(CDI_DOMINATORS, bbf))
if (! get_immediate_dominator (CDI_DOMINATORS, bbf))
/* If bbD was the immediate dominator ... */
set_immediate_dominator (CDI_DOMINATORS, bbf, bb0);
@ -920,17 +1349,30 @@ process_switch (gimple swtch)
during gimplification). */
gcc_checking_assert (TREE_TYPE (info.index_expr) != error_mark_node);
/* A switch on a constant should have been optimized in tree-cfg-cleanup. */
gcc_checking_assert (! TREE_CONSTANT (info.index_expr));
if (info.uniq <= MAX_CASE_BIT_TESTS)
{
if (expand_switch_using_bit_tests_p (info.range_size,
info.uniq, info.count))
{
if (dump_file)
fputs (" expanding as bit test is preferable\n", dump_file);
emit_case_bit_tests (swtch, info.index_expr,
info.range_min, info.range_size);
return NULL;
}
if (info.uniq <= 2)
/* This will be expanded as a decision tree in stmt.c:expand_case. */
return " expanding as jumps is preferable";
}
/* If there is no common successor, we cannot do the transformation. */
if (! info.final_bb)
return "no common successor to all case label target blocks found";
if (info.uniq <= 2)
{
if (expand_switch_using_bit_tests_p (info.index_expr, info.range_size,
info.uniq, info.count))
return "expanding as bit test is preferable";
}
/* Check the case label values are within reasonable range: */
if (!check_range (&info))
{
@ -999,6 +1441,11 @@ do_switchconv (void)
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
{
@ -1039,6 +1486,8 @@ struct gimple_opt_pass pass_convert_switch =
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_update_ssa
| TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
| TODO_ggc_collect | TODO_verify_ssa
| TODO_verify_stmts
| TODO_verify_flow /* todo_flags_finish */
}
};

View File

@ -5728,8 +5728,6 @@ extern bool parse_input_constraint (const char **, int, int, int, int,
const char * const *, bool *, bool *);
extern void expand_asm_stmt (gimple);
extern tree resolve_asm_operand_names (tree, tree, tree, tree);
extern bool expand_switch_using_bit_tests_p (tree, tree, unsigned int,
unsigned int);
extern void expand_case (gimple);
#ifdef HARD_CONST
/* Silly ifdef to avoid having all includers depend on hard-reg-set.h. */