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> 2012-04-27 Marc Glisse <marc.glisse@inria.fr>
PR middle-end/27139 PR middle-end/27139
......
...@@ -48,6 +48,7 @@ provided. For example, the following code: ...@@ -48,6 +48,7 @@ provided. For example, the following code:
default: default:
a_4 = 16; a_4 = 16;
b_4 = 1; b_4 = 1;
break;
} }
a_5 = PHI <a_1, a_2, a_3, a_4> a_5 = PHI <a_1, a_2, a_3, a_4>
b_5 = PHI <b_1, b_2, b_3, b_4> b_5 = PHI <b_1, b_2, b_3, b_4>
...@@ -69,8 +70,8 @@ is changed into: ...@@ -69,8 +70,8 @@ is changed into:
a_7 = 16; a_7 = 16;
b_7 = 1; b_7 = 1;
} }
a_5 = PHI <a_6, a_7> a_5 = PHI <a_6, a_7>
b_b = PHI <b_6, b_7> b_b = PHI <b_6, b_7>
There are further constraints. Specifically, the range of values across all There are further constraints. Specifically, the range of values across all
case labels must not be bigger than SWITCH_CONVERSION_BRANCH_RATIO (default 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. */ ...@@ -99,25 +100,38 @@ eight) times the number of the actual switch branches. */
/* The main structure of the pass. */ /* The main structure of the pass. */
struct switch_conv_info struct switch_conv_info
{ {
/* The expression used to decide the switch branch. (It is subsequently used /* The expression used to decide the switch branch. */
as the index to the created array.) */
tree index_expr; tree index_expr;
/* The following integer constants store the minimum value covered by the /* The following integer constants store the minimum and maximum value
cases. */ covered by the case labels. */
tree range_min; tree range_min;
tree range_max;
/* The difference between the above two numbers, i.e. The size of the array /* The difference between the above two numbers. Stored here because it
that would have to be created by the transformation. */ 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; tree range_size;
/* Basic block that contains the actual SWITCH_EXPR. */ /* Basic block that contains the actual GIMPLE_SWITCH. */
basic_block switch_bb; basic_block switch_bb;
/* All branches of the switch statement must have a single successor stored in /* Basic block that is the target of the default case. */
the following variable. */ 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; 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). */ /* Number of phi nodes in the final bb (that we'll be replacing). */
int phi_count; int phi_count;
...@@ -135,15 +149,6 @@ struct switch_conv_info ...@@ -135,15 +149,6 @@ struct switch_conv_info
switch expression is out of range. */ switch expression is out of range. */
tree *target_outbound_names; 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. /* The first load statement that loads a temporary from a new static array.
*/ */
gimple arr_ref_first; gimple arr_ref_first;
...@@ -157,41 +162,104 @@ struct switch_conv_info ...@@ -157,41 +162,104 @@ struct switch_conv_info
/* Parameters for expand_switch_using_bit_tests. Should be computed /* Parameters for expand_switch_using_bit_tests. Should be computed
the same way as in expand_case. */ the same way as in expand_case. */
unsigned int bit_test_uniq; unsigned int uniq;
unsigned int bit_test_count; unsigned int count;
basic_block bit_test_bb[2];
}; };
/* Checks whether the range given by individual case statements of the SWTCH /* Collect information about GIMPLE_SWITCH statement SWTCH into INFO. */
switch statement isn't too big and whether the number of branches actually
satisfies the size of the new array. */
static bool static void
check_range (gimple swtch, struct switch_conv_info *info) 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); 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 /* The gimplifier has already sorted the cases by CASE_LOW and ensured there
is a default label which is the first in the vector. */ 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); /* Collect the bits we can deduce from the CFG. */
info->range_min = CASE_LOW (min_case); 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); /* See if there is one common successor block for all branch
gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE); 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); max_case = gimple_switch_label (swtch, branch_num - 1);
info->range_min = CASE_LOW (min_case);
if (CASE_HIGH (max_case) != NULL_TREE) if (CASE_HIGH (max_case) != NULL_TREE)
range_max = CASE_HIGH (max_case); info->range_max = CASE_HIGH (max_case);
else else
range_max = CASE_LOW (max_case); info->range_max = CASE_LOW (max_case);
gcc_assert (info->range_min); info->range_size =
gcc_assert (range_max); 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); gcc_assert (info->range_size);
if (!host_integerp (info->range_size, 1)) if (!host_integerp (info->range_size, 1))
{ {
...@@ -200,7 +268,7 @@ check_range (gimple swtch, struct switch_conv_info *info) ...@@ -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) 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"; info->reason = "the maximum range-branch ratio exceeded";
return false; return false;
...@@ -209,86 +277,24 @@ check_range (gimple swtch, struct switch_conv_info *info) ...@@ -209,86 +277,24 @@ check_range (gimple swtch, struct switch_conv_info *info)
return true; return true;
} }
/* Checks the given CS switch case whether it is suitable for conversion /* Checks whether all but the FINAL_BB basic blocks are empty. */
(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. */
static bool 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 e;
edge_iterator ei;
ldecl = CASE_LABEL (cs); FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
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))
{ {
if (info->final_bb && info->final_bb != label_bb) if (e->dest == info->final_bb)
{ continue;
info->reason = "bad case - a non-final BB has two predecessors";
return false; /* sth complex going on in this branch */
}
following_bb = label_bb; if (!empty_block_p (e->dest))
}
else
{
if (!empty_block_p (label_bb))
{ {
info->reason = "bad case - a non-final BB not empty"; info->reason = "bad case - a non-final BB not empty";
return false; 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; return true;
...@@ -878,36 +884,30 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info) ...@@ -878,36 +884,30 @@ gen_inbound_check (gimple swtch, struct switch_conv_info *info)
static const char * static const char *
process_switch (gimple swtch) process_switch (gimple swtch)
{ {
unsigned int i, branch_num = gimple_switch_num_labels (swtch);
tree index_type;
struct switch_conv_info info; struct switch_conv_info info;
/* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */ /* Degenerate case with only a default label should never happen. */
if (branch_num < 2) gcc_checking_assert (gimple_switch_num_labels (swtch) > 1);
return "switch has no labels";
collect_switch_conv_info (swtch, &info);
info.reason = NULL;
info.final_bb = NULL; /* No error markers should reach here (they should be filtered out
info.switch_bb = gimple_bb (swtch); during gimplification). */
info.index_expr = gimple_switch_index (swtch); gcc_checking_assert (TREE_TYPE (info.index_expr) != error_mark_node);
info.arr_ref_first = NULL;
info.arr_ref_last = NULL; /* If there is no common successor, we cannot do the transformation. */
info.default_prob = 0; if (! info.final_bb)
info.default_count = 0; return "no common successor to all case label target blocks found";
info.other_count = 0;
info.bit_test_uniq = 0; if (info.uniq <= 2)
info.bit_test_count = 0; {
info.bit_test_bb[0] = NULL; if (expand_switch_using_bit_tests_p (info.index_expr, info.range_size,
info.bit_test_bb[1] = NULL; info.uniq, info.count))
return "expanding as bit test is preferable";
/* 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";
/* Check the case label values are within reasonable range: */ /* Check the case label values are within reasonable range: */
if (!check_range (swtch, &info)) if (!check_range (&info))
{ {
gcc_assert (info.reason); gcc_assert (info.reason);
return info.reason; return info.reason;
...@@ -915,26 +915,11 @@ process_switch (gimple swtch) ...@@ -915,26 +915,11 @@ process_switch (gimple swtch)
/* For all the cases, see whether they are empty, the assignments they /* For all the cases, see whether they are empty, the assignments they
represent constant and so on... */ represent constant and so on... */
for (i = 0; i < branch_num; i++) if (! check_all_empty_except_final (&info))
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)
{ {
rtl_profile_for_bb (gimple_bb (swtch)); gcc_assert (info.reason);
if (expand_switch_using_bit_tests_p (gimple_switch_index (swtch), return info.reason;
info.range_size, info.bit_test_uniq,
info.bit_test_count))
{
return "expanding as bit test is preferable";
}
} }
if (!check_final_bb (&info)) if (!check_final_bb (&info))
{ {
gcc_assert (info.reason); 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