Commit 886cd84f by Steven Bosscher

tree-switch-conversion.c (struct switch_conv_info): Add range_max, reorganize…

tree-switch-conversion.c (struct switch_conv_info): Add range_max, reorganize some fields and update comments.

gcc/
	* tree-switch-conversion.c (struct switch_conv_info): Add range_max,
	reorganize some fields and update comments.  Rename bit_test_uniq
	and bit_test_count to uniq resp. count.  Remove bit_test_bb.
	(collect_switch_conv_info): New function, collects info about a
	GIMPLE_SWITCH into a struct switch_conv_info.
	(check_range): Simplify to use pre-recorded info.  Fix think-o in
	range-branch ratio check.
	(check_process_case): Remove function.
	(check_all_empty_except_final): New function, verifies that all
	non-final basic blocks are empty.
	(process_switch): Simplify to use pre-recorded info.  Call
	collect_switch_conv_info to do that.  Assert that degenerate switch
	statements have been cleaned up.

From-SVN: r186901
parent 07ab2b1b
2012-04-27 Steven Bosscher <steven@gcc.gnu.org>
* tree-switch-conversion.c (struct switch_conv_info): Add range_max,
reorganize some fields and update comments. Rename bit_test_uniq
and bit_test_count to uniq resp. count. Remove bit_test_bb.
(collect_switch_conv_info): New function, collects info about a
GIMPLE_SWITCH into a struct switch_conv_info.
(check_range): Simplify to use pre-recorded info. Fix think-o in
range-branch ratio check.
(check_process_case): Remove function.
(check_all_empty_except_final): New function, verifies that all
non-final basic blocks are empty.
(process_switch): Simplify to use pre-recorded info. Call
collect_switch_conv_info to do that. Assert that degenerate switch
statements have been cleaned up.
2012-04-27 Marc Glisse <marc.glisse@inria.fr>
PR middle-end/27139
......
......@@ -48,6 +48,7 @@ provided. For example, the following code:
default:
a_4 = 16;
b_4 = 1;
break;
}
a_5 = PHI <a_1, a_2, a_3, a_4>
b_5 = PHI <b_1, b_2, b_3, b_4>
......@@ -69,8 +70,8 @@ is changed into:
a_7 = 16;
b_7 = 1;
}
a_5 = PHI <a_6, a_7>
b_b = PHI <b_6, b_7>
a_5 = PHI <a_6, a_7>
b_b = PHI <b_6, b_7>
There are further constraints. Specifically, the range of values across all
case labels must not be bigger than SWITCH_CONVERSION_BRANCH_RATIO (default
......@@ -99,25 +100,38 @@ eight) times the number of the actual switch branches. */
/* The main structure of the pass. */
struct switch_conv_info
{
/* The expression used to decide the switch branch. (It is subsequently used
as the index to the created array.) */
/* The expression used to decide the switch branch. */
tree index_expr;
/* The following integer constants store the minimum value covered by the
cases. */
/* The following integer constants store the minimum and maximum value
covered by the case labels. */
tree range_min;
tree range_max;
/* The difference between the above two numbers, i.e. The size of the array
that would have to be created by the transformation. */
/* The difference between the above two numbers. Stored here because it
is used in all the conversion heuristics, as well as for some of the
transformation, and it is expensive to re-compute it all the time. */
tree range_size;
/* Basic block that contains the actual SWITCH_EXPR. */
/* Basic block that contains the actual GIMPLE_SWITCH. */
basic_block switch_bb;
/* All branches of the switch statement must have a single successor stored in
the following variable. */
/* Basic block that is the target of the default case. */
basic_block default_bb;
/* The single successor block of all branches out of the GIMPLE_SWITCH,
if such a block exists. Otherwise NULL. */
basic_block final_bb;
/* The probability of the default edge in the replaced switch. */
int default_prob;
/* The count of the default edge in the replaced switch. */
gcov_type default_count;
/* Combined count of all other (non-default) edges in the replaced switch. */
gcov_type other_count;
/* Number of phi nodes in the final bb (that we'll be replacing). */
int phi_count;
......@@ -135,15 +149,6 @@ struct switch_conv_info
switch expression is out of range. */
tree *target_outbound_names;
/* The probability of the default edge in the replaced switch. */
int default_prob;
/* The count of the default edge in the replaced switch. */
gcov_type default_count;
/* Combined count of all other (non-default) edges in the replaced switch. */
gcov_type other_count;
/* The first load statement that loads a temporary from a new static array.
*/
gimple arr_ref_first;
......@@ -157,41 +162,104 @@ struct switch_conv_info
/* Parameters for expand_switch_using_bit_tests. Should be computed
the same way as in expand_case. */
unsigned int bit_test_uniq;
unsigned int bit_test_count;
basic_block bit_test_bb[2];
unsigned int uniq;
unsigned int count;
};
/* Checks whether the range given by individual case statements of the SWTCH
switch statement isn't too big and whether the number of branches actually
satisfies the size of the new array. */
/* Collect information about GIMPLE_SWITCH statement SWTCH into INFO. */
static bool
check_range (gimple swtch, struct switch_conv_info *info)
static void
collect_switch_conv_info (gimple swtch, struct switch_conv_info *info)
{
tree min_case, max_case;
unsigned int branch_num = gimple_switch_num_labels (swtch);
tree range_max;
tree min_case, max_case;
unsigned int count, i;
edge e, e_default;
edge_iterator ei;
memset (info, 0, sizeof (*info));
/* The gimplifier has already sorted the cases by CASE_LOW and ensured there
is a default label which is the first in the vector. */
gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
min_case = gimple_switch_label (swtch, 1);
info->range_min = CASE_LOW (min_case);
/* Collect the bits we can deduce from the CFG. */
info->index_expr = gimple_switch_index (swtch);
info->switch_bb = gimple_bb (swtch);
info->default_bb =
label_to_block (CASE_LABEL (gimple_switch_label (swtch, 0)));
e_default = find_edge (info->switch_bb, info->default_bb);
info->default_prob = e_default->probability;
info->default_count = e_default->count;
FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
if (e != e_default)
info->other_count += e->count;
gcc_assert (branch_num > 1);
gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
/* See if there is one common successor block for all branch
targets. If it exists, record it in FINAL_BB. */
FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
{
if (! single_pred_p (e->dest))
{
info->final_bb = e->dest;
break;
}
}
if (info->final_bb)
FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
{
if (e->dest == info->final_bb)
continue;
if (single_pred_p (e->dest)
&& single_succ_p (e->dest)
&& single_succ (e->dest) == info->final_bb)
continue;
info->final_bb = NULL;
break;
}
/* Get upper and lower bounds of case values, and the covered range. */
min_case = gimple_switch_label (swtch, 1);
max_case = gimple_switch_label (swtch, branch_num - 1);
info->range_min = CASE_LOW (min_case);
if (CASE_HIGH (max_case) != NULL_TREE)
range_max = CASE_HIGH (max_case);
info->range_max = CASE_HIGH (max_case);
else
range_max = CASE_LOW (max_case);
info->range_max = CASE_LOW (max_case);
gcc_assert (info->range_min);
gcc_assert (range_max);
info->range_size =
int_const_binop (MINUS_EXPR, info->range_max, info->range_min);
info->range_size = int_const_binop (MINUS_EXPR, range_max, info->range_min);
/* Get a count of the number of case labels. Single-valued case labels
simply count as one, but a case range counts double, since it may
require two compares if it gets lowered as a branching tree. */
count = 0;
for (i = 1; i < branch_num; i++)
{
tree elt = gimple_switch_label (swtch, i);
count++;
if (CASE_HIGH (elt)
&& ! tree_int_cst_equal (CASE_LOW (elt), CASE_HIGH (elt)))
count++;
}
info->count = 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. */
info->uniq = EDGE_COUNT (gimple_bb (swtch)->succs) - 1;
}
/* Checks whether the range given by individual case statements of the SWTCH
switch statement isn't too big and whether the number of branches actually
satisfies the size of the new array. */
static bool
check_range (struct switch_conv_info *info)
{
gcc_assert (info->range_size);
if (!host_integerp (info->range_size, 1))
{
......@@ -200,7 +268,7 @@ check_range (gimple swtch, struct switch_conv_info *info)
}
if ((unsigned HOST_WIDE_INT) tree_low_cst (info->range_size, 1)
> ((unsigned) branch_num * SWITCH_CONVERSION_BRANCH_RATIO))
> ((unsigned) info->count * SWITCH_CONVERSION_BRANCH_RATIO))
{
info->reason = "the maximum range-branch ratio exceeded";
return false;
......@@ -209,86 +277,24 @@ check_range (gimple swtch, struct switch_conv_info *info)
return true;
}
/* Checks the given CS switch case whether it is suitable for conversion
(whether all but the default basic blocks are empty and so on). If it is,
adds the case to the branch list along with values for the defined variables
and returns true. Otherwise returns false. */
/* Checks whether all but the FINAL_BB basic blocks are empty. */
static bool
check_process_case (tree cs, struct switch_conv_info *info)
check_all_empty_except_final (struct switch_conv_info *info)
{
tree ldecl;
basic_block label_bb, following_bb;
edge e;
edge_iterator ei;
ldecl = CASE_LABEL (cs);
label_bb = label_to_block (ldecl);
e = find_edge (info->switch_bb, label_bb);
gcc_assert (e);
if (CASE_LOW (cs) == NULL_TREE)
{
/* Default branch. */
info->default_prob = e->probability;
info->default_count = e->count;
}
else
{
int i;
info->other_count += e->count;
for (i = 0; i < 2; i++)
if (info->bit_test_bb[i] == label_bb)
break;
else if (info->bit_test_bb[i] == NULL)
{
info->bit_test_bb[i] = label_bb;
info->bit_test_uniq++;
break;
}
if (i == 2)
info->bit_test_uniq = 3;
if (CASE_HIGH (cs) != NULL_TREE
&& ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs)))
info->bit_test_count += 2;
else
info->bit_test_count++;
}
if (!label_bb)
{
info->reason = "bad case - cs BB label is NULL";
return false;
}
if (!single_pred_p (label_bb))
FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
{
if (info->final_bb && info->final_bb != label_bb)
{
info->reason = "bad case - a non-final BB has two predecessors";
return false; /* sth complex going on in this branch */
}
if (e->dest == info->final_bb)
continue;
following_bb = label_bb;
}
else
{
if (!empty_block_p (label_bb))
if (!empty_block_p (e->dest))
{
info->reason = "bad case - a non-final BB not empty";
return false;
}
e = single_succ_edge (label_bb);
following_bb = single_succ (label_bb);
}
if (!info->final_bb)
info->final_bb = following_bb;
else if (info->final_bb != following_bb)
{
info->reason = "bad case - different final BB";
return false; /* the only successor is not common for all the branches */
}
return true;
......@@ -878,36 +884,30 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
static const char *
process_switch (gimple swtch)
{
unsigned int i, branch_num = gimple_switch_num_labels (swtch);
tree index_type;
struct switch_conv_info info;
/* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */
if (branch_num < 2)
return "switch has no labels";
info.reason = NULL;
info.final_bb = NULL;
info.switch_bb = gimple_bb (swtch);
info.index_expr = gimple_switch_index (swtch);
info.arr_ref_first = NULL;
info.arr_ref_last = NULL;
info.default_prob = 0;
info.default_count = 0;
info.other_count = 0;
info.bit_test_uniq = 0;
info.bit_test_count = 0;
info.bit_test_bb[0] = NULL;
info.bit_test_bb[1] = NULL;
/* An ERROR_MARK occurs for various reasons including invalid data type.
(comment from stmt.c) */
index_type = TREE_TYPE (info.index_expr);
if (index_type == error_mark_node)
return "index error\n";
/* Degenerate case with only a default label should never happen. */
gcc_checking_assert (gimple_switch_num_labels (swtch) > 1);
collect_switch_conv_info (swtch, &info);
/* No error markers should reach here (they should be filtered out
during gimplification). */
gcc_checking_assert (TREE_TYPE (info.index_expr) != error_mark_node);
/* 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 (swtch, &info))
if (!check_range (&info))
{
gcc_assert (info.reason);
return info.reason;
......@@ -915,26 +915,11 @@ process_switch (gimple swtch)
/* For all the cases, see whether they are empty, the assignments they
represent constant and so on... */
for (i = 0; i < branch_num; i++)
if (!check_process_case (gimple_switch_label (swtch, i), &info))
{
gcc_assert (info.reason);
if (dump_file)
fprintf (dump_file, "processing of case %i failed\n\t", i);
return info.reason;
}
if (info.bit_test_uniq <= 2)
if (! check_all_empty_except_final (&info))
{
rtl_profile_for_bb (gimple_bb (swtch));
if (expand_switch_using_bit_tests_p (gimple_switch_index (swtch),
info.range_size, info.bit_test_uniq,
info.bit_test_count))
{
return "expanding as bit test is preferable";
}
gcc_assert (info.reason);
return info.reason;
}
if (!check_final_bb (&info))
{
gcc_assert (info.reason);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment