Commit fade902a by Steven Bosscher

tree-switch-conversion.c (info): Remove global pass info.

	* tree-switch-conversion.c (info): Remove global pass info.
	(check_range, check_process_case, check_final_bb, create_temp_arrays,
	free_temp_arrays, gather_default_values, build_constructors,
	array_value_type, build_one_array, build_arrays, gen_def_assigns,
	fix_phi_nodes, gen_inbound_check): Pass info around from ...
	(process_switch): ... here.  Unify message format.  Return a const
	char pointer to the failure reason message.
	(do_switchconv): Unify message format.  Update process_switch usage.

From-SVN: r186576
parent 308e3ba6
2012-04-18 Steven Bosscher <steven@gcc.gnu.org> 2012-04-18 Steven Bosscher <steven@gcc.gnu.org>
* tree-switch-conversion.c (info): Remove global pass info.
(check_range, check_process_case, check_final_bb, create_temp_arrays,
free_temp_arrays, gather_default_values, build_constructors,
array_value_type, build_one_array, build_arrays, gen_def_assigns,
fix_phi_nodes, gen_inbound_check): Pass info around from ...
(process_switch): ... here. Unify message format. Return a const
char pointer to the failure reason message.
(do_switchconv): Unify message format. Update process_switch usage.
* tree.def (CASE_LABEL_EXPR): Fix documentation, mention all operands. * tree.def (CASE_LABEL_EXPR): Fix documentation, mention all operands.
* tree-cfg.c (edge_to_cases): Fix documentation. * tree-cfg.c (edge_to_cases): Fix documentation.
......
...@@ -24,8 +24,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -24,8 +24,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
Switch initialization conversion Switch initialization conversion
The following pass changes simple initializations of scalars in a switch The following pass changes simple initializations of scalars in a switch
statement into initializations from a static array. Obviously, the values must statement into initializations from a static array. Obviously, the values
be constant and known at compile time and a default branch must be must be constant and known at compile time and a default branch must be
provided. For example, the following code: provided. For example, the following code:
int a,b; int a,b;
...@@ -162,16 +162,12 @@ struct switch_conv_info ...@@ -162,16 +162,12 @@ struct switch_conv_info
basic_block bit_test_bb[2]; basic_block bit_test_bb[2];
}; };
/* Global pass info. */
static struct switch_conv_info info;
/* Checks whether the range given by individual case statements of the SWTCH /* 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 switch statement isn't too big and whether the number of branches actually
satisfies the size of the new array. */ satisfies the size of the new array. */
static bool static bool
check_range (gimple swtch) check_range (gimple swtch, struct switch_conv_info *info)
{ {
tree min_case, max_case; tree min_case, max_case;
unsigned int branch_num = gimple_switch_num_labels (swtch); unsigned int branch_num = gimple_switch_num_labels (swtch);
...@@ -181,7 +177,7 @@ check_range (gimple swtch) ...@@ -181,7 +177,7 @@ check_range (gimple swtch)
is a default label which is the first in the vector. */ is a default label which is the first in the vector. */
min_case = gimple_switch_label (swtch, 1); min_case = gimple_switch_label (swtch, 1);
info.range_min = CASE_LOW (min_case); info->range_min = CASE_LOW (min_case);
gcc_assert (branch_num > 1); gcc_assert (branch_num > 1);
gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE); gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE);
...@@ -191,22 +187,22 @@ check_range (gimple swtch) ...@@ -191,22 +187,22 @@ check_range (gimple swtch)
else else
range_max = CASE_LOW (max_case); range_max = CASE_LOW (max_case);
gcc_assert (info.range_min); gcc_assert (info->range_min);
gcc_assert (range_max); gcc_assert (range_max);
info.range_size = int_const_binop (MINUS_EXPR, range_max, info.range_min); info->range_size = int_const_binop (MINUS_EXPR, range_max, info->range_min);
gcc_assert (info.range_size); gcc_assert (info->range_size);
if (!host_integerp (info.range_size, 1)) if (!host_integerp (info->range_size, 1))
{ {
info.reason = "index range way too large or otherwise unusable.\n"; info->reason = "index range way too large or otherwise unusable";
return false; return false;
} }
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) branch_num * SWITCH_CONVERSION_BRANCH_RATIO))
{ {
info.reason = "the maximum range-branch ratio exceeded.\n"; info->reason = "the maximum range-branch ratio exceeded";
return false; return false;
} }
...@@ -219,7 +215,7 @@ check_range (gimple swtch) ...@@ -219,7 +215,7 @@ check_range (gimple swtch)
and returns true. Otherwise returns false. */ and returns true. Otherwise returns false. */
static bool static bool
check_process_case (tree cs) check_process_case (tree cs, struct switch_conv_info *info)
{ {
tree ldecl; tree ldecl;
basic_block label_bb, following_bb; basic_block label_bb, following_bb;
...@@ -228,48 +224,48 @@ check_process_case (tree cs) ...@@ -228,48 +224,48 @@ check_process_case (tree cs)
ldecl = CASE_LABEL (cs); ldecl = CASE_LABEL (cs);
label_bb = label_to_block (ldecl); label_bb = label_to_block (ldecl);
e = find_edge (info.switch_bb, label_bb); e = find_edge (info->switch_bb, label_bb);
gcc_assert (e); gcc_assert (e);
if (CASE_LOW (cs) == NULL_TREE) if (CASE_LOW (cs) == NULL_TREE)
{ {
/* Default branch. */ /* Default branch. */
info.default_prob = e->probability; info->default_prob = e->probability;
info.default_count = e->count; info->default_count = e->count;
} }
else else
{ {
int i; int i;
info.other_count += e->count; info->other_count += e->count;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
if (info.bit_test_bb[i] == label_bb) if (info->bit_test_bb[i] == label_bb)
break; break;
else if (info.bit_test_bb[i] == NULL) else if (info->bit_test_bb[i] == NULL)
{ {
info.bit_test_bb[i] = label_bb; info->bit_test_bb[i] = label_bb;
info.bit_test_uniq++; info->bit_test_uniq++;
break; break;
} }
if (i == 2) if (i == 2)
info.bit_test_uniq = 3; info->bit_test_uniq = 3;
if (CASE_HIGH (cs) != NULL_TREE if (CASE_HIGH (cs) != NULL_TREE
&& ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs))) && ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs)))
info.bit_test_count += 2; info->bit_test_count += 2;
else else
info.bit_test_count++; info->bit_test_count++;
} }
if (!label_bb) if (!label_bb)
{ {
info.reason = " Bad case - cs BB label is NULL\n"; info->reason = "bad case - cs BB label is NULL";
return false; return false;
} }
if (!single_pred_p (label_bb)) if (!single_pred_p (label_bb))
{ {
if (info.final_bb && info.final_bb != label_bb) if (info->final_bb && info->final_bb != label_bb)
{ {
info.reason = " Bad case - a non-final BB has two predecessors\n"; info->reason = "bad case - a non-final BB has two predecessors";
return false; /* sth complex going on in this branch */ return false; /* sth complex going on in this branch */
} }
...@@ -279,7 +275,7 @@ check_process_case (tree cs) ...@@ -279,7 +275,7 @@ check_process_case (tree cs)
{ {
if (!empty_block_p (label_bb)) if (!empty_block_p (label_bb))
{ {
info.reason = " Bad case - a non-final BB not empty\n"; info->reason = "bad case - a non-final BB not empty";
return false; return false;
} }
...@@ -287,11 +283,11 @@ check_process_case (tree cs) ...@@ -287,11 +283,11 @@ check_process_case (tree cs)
following_bb = single_succ (label_bb); following_bb = single_succ (label_bb);
} }
if (!info.final_bb) if (!info->final_bb)
info.final_bb = following_bb; info->final_bb = following_bb;
else if (info.final_bb != following_bb) else if (info->final_bb != following_bb)
{ {
info.reason = " Bad case - different final BB\n"; info->reason = "bad case - different final BB";
return false; /* the only successor is not common for all the branches */ return false; /* the only successor is not common for all the branches */
} }
...@@ -304,31 +300,31 @@ check_process_case (tree cs) ...@@ -304,31 +300,31 @@ check_process_case (tree cs)
phi nodes are OK, otherwise false. */ phi nodes are OK, otherwise false. */
static bool static bool
check_final_bb (void) check_final_bb (struct switch_conv_info *info)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
info.phi_count = 0; info->phi_count = 0;
for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
gimple phi = gsi_stmt (gsi); gimple phi = gsi_stmt (gsi);
unsigned int i; unsigned int i;
info.phi_count++; info->phi_count++;
for (i = 0; i < gimple_phi_num_args (phi); i++) for (i = 0; i < gimple_phi_num_args (phi); i++)
{ {
basic_block bb = gimple_phi_arg_edge (phi, i)->src; basic_block bb = gimple_phi_arg_edge (phi, i)->src;
if (bb == info.switch_bb if (bb == info->switch_bb
|| (single_pred_p (bb) && single_pred (bb) == info.switch_bb)) || (single_pred_p (bb) && single_pred (bb) == info->switch_bb))
{ {
tree reloc, val; tree reloc, val;
val = gimple_phi_arg_def (phi, i); val = gimple_phi_arg_def (phi, i);
if (!is_gimple_ip_invariant (val)) if (!is_gimple_ip_invariant (val))
{ {
info.reason = " Non-invariant value from a case\n"; info->reason = "non-invariant value from a case";
return false; /* Non-invariant argument. */ return false; /* Non-invariant argument. */
} }
reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); reloc = initializer_constant_valid_p (val, TREE_TYPE (val));
...@@ -336,11 +332,11 @@ check_final_bb (void) ...@@ -336,11 +332,11 @@ check_final_bb (void)
|| (!flag_pic && reloc == NULL_TREE)) || (!flag_pic && reloc == NULL_TREE))
{ {
if (reloc) if (reloc)
info.reason info->reason
= " Value from a case would need runtime relocations\n"; = "value from a case would need runtime relocations";
else else
info.reason info->reason
= " Value from a case is not a valid initializer\n"; = "value from a case is not a valid initializer";
return false; return false;
} }
} }
...@@ -355,17 +351,17 @@ check_final_bb (void) ...@@ -355,17 +351,17 @@ check_final_bb (void)
vectors that will become constructors of new arrays. */ vectors that will become constructors of new arrays. */
static void static void
create_temp_arrays (void) create_temp_arrays (struct switch_conv_info *info)
{ {
int i; int i;
info.default_values = XCNEWVEC (tree, info.phi_count * 3); info->default_values = XCNEWVEC (tree, info->phi_count * 3);
info.constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info.phi_count); info->constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info->phi_count);
info.target_inbound_names = info.default_values + info.phi_count; info->target_inbound_names = info->default_values + info->phi_count;
info.target_outbound_names = info.target_inbound_names + info.phi_count; info->target_outbound_names = info->target_inbound_names + info->phi_count;
for (i = 0; i < info.phi_count; i++) for (i = 0; i < info->phi_count; i++)
info.constructors[i] info->constructors[i]
= VEC_alloc (constructor_elt, gc, tree_low_cst (info.range_size, 1) + 1); = VEC_alloc (constructor_elt, gc, tree_low_cst (info->range_size, 1) + 1);
} }
/* Free the arrays created by create_temp_arrays(). The vectors that are /* Free the arrays created by create_temp_arrays(). The vectors that are
...@@ -373,17 +369,17 @@ create_temp_arrays (void) ...@@ -373,17 +369,17 @@ create_temp_arrays (void)
already become constructors and must be preserved. */ already become constructors and must be preserved. */
static void static void
free_temp_arrays (void) free_temp_arrays (struct switch_conv_info *info)
{ {
XDELETEVEC (info.constructors); XDELETEVEC (info->constructors);
XDELETEVEC (info.default_values); XDELETEVEC (info->default_values);
} }
/* Populate the array of default values in the order of phi nodes. /* Populate the array of default values in the order of phi nodes.
DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. */ DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. */
static void static void
gather_default_values (tree default_case) gather_default_values (tree default_case, struct switch_conv_info *info)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
basic_block bb = label_to_block (CASE_LABEL (default_case)); basic_block bb = label_to_block (CASE_LABEL (default_case));
...@@ -392,17 +388,17 @@ gather_default_values (tree default_case) ...@@ -392,17 +388,17 @@ gather_default_values (tree default_case)
gcc_assert (CASE_LOW (default_case) == NULL_TREE); gcc_assert (CASE_LOW (default_case) == NULL_TREE);
if (bb == info.final_bb) if (bb == info->final_bb)
e = find_edge (info.switch_bb, bb); e = find_edge (info->switch_bb, bb);
else else
e = single_succ_edge (bb); e = single_succ_edge (bb);
for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
gimple phi = gsi_stmt (gsi); gimple phi = gsi_stmt (gsi);
tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
gcc_assert (val); gcc_assert (val);
info.default_values[i++] = val; info->default_values[i++] = val;
} }
} }
...@@ -411,10 +407,10 @@ gather_default_values (tree default_case) ...@@ -411,10 +407,10 @@ gather_default_values (tree default_case)
order of phi nodes. SWTCH is the switch statement being converted. */ order of phi nodes. SWTCH is the switch statement being converted. */
static void static void
build_constructors (gimple swtch) build_constructors (gimple swtch, struct switch_conv_info *info)
{ {
unsigned i, branch_num = gimple_switch_num_labels (swtch); unsigned i, branch_num = gimple_switch_num_labels (swtch);
tree pos = info.range_min; tree pos = info->range_min;
for (i = 1; i < branch_num; i++) for (i = 1; i < branch_num; i++)
{ {
...@@ -425,8 +421,8 @@ build_constructors (gimple swtch) ...@@ -425,8 +421,8 @@ build_constructors (gimple swtch)
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
int j; int j;
if (bb == info.final_bb) if (bb == info->final_bb)
e = find_edge (info.switch_bb, bb); e = find_edge (info->switch_bb, bb);
else else
e = single_succ_edge (bb); e = single_succ_edge (bb);
gcc_assert (e); gcc_assert (e);
...@@ -434,15 +430,15 @@ build_constructors (gimple swtch) ...@@ -434,15 +430,15 @@ build_constructors (gimple swtch)
while (tree_int_cst_lt (pos, CASE_LOW (cs))) while (tree_int_cst_lt (pos, CASE_LOW (cs)))
{ {
int k; int k;
for (k = 0; k < info.phi_count; k++) for (k = 0; k < info->phi_count; k++)
{ {
constructor_elt *elt; constructor_elt *elt;
elt = VEC_quick_push (constructor_elt, elt = VEC_quick_push (constructor_elt,
info.constructors[k], NULL); info->constructors[k], NULL);
elt->index = int_const_binop (MINUS_EXPR, pos, elt->index = int_const_binop (MINUS_EXPR, pos,
info.range_min); info->range_min);
elt->value = info.default_values[k]; elt->value = info->default_values[k];
} }
pos = int_const_binop (PLUS_EXPR, pos, integer_one_node); pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
...@@ -454,7 +450,7 @@ build_constructors (gimple swtch) ...@@ -454,7 +450,7 @@ build_constructors (gimple swtch)
high = CASE_HIGH (cs); high = CASE_HIGH (cs);
else else
high = CASE_LOW (cs); high = CASE_LOW (cs);
for (gsi = gsi_start_phis (info.final_bb); for (gsi = gsi_start_phis (info->final_bb);
!gsi_end_p (gsi); gsi_next (&gsi)) !gsi_end_p (gsi); gsi_next (&gsi))
{ {
gimple phi = gsi_stmt (gsi); gimple phi = gsi_stmt (gsi);
...@@ -467,8 +463,8 @@ build_constructors (gimple swtch) ...@@ -467,8 +463,8 @@ build_constructors (gimple swtch)
constructor_elt *elt; constructor_elt *elt;
elt = VEC_quick_push (constructor_elt, elt = VEC_quick_push (constructor_elt,
info.constructors[j], NULL); info->constructors[j], NULL);
elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min); elt->index = int_const_binop (MINUS_EXPR, pos, info->range_min);
elt->value = val; elt->value = val;
pos = int_const_binop (PLUS_EXPR, pos, integer_one_node); pos = int_const_binop (PLUS_EXPR, pos, integer_one_node);
...@@ -505,9 +501,10 @@ constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec) ...@@ -505,9 +501,10 @@ constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec)
all the constants. */ all the constants. */
static tree static tree
array_value_type (gimple swtch, tree type, int num) array_value_type (gimple swtch, tree type, int num,
struct switch_conv_info *info)
{ {
unsigned int i, len = VEC_length (constructor_elt, info.constructors[num]); unsigned int i, len = VEC_length (constructor_elt, info->constructors[num]);
constructor_elt *elt; constructor_elt *elt;
enum machine_mode mode; enum machine_mode mode;
int sign = 0; int sign = 0;
...@@ -523,7 +520,7 @@ array_value_type (gimple swtch, tree type, int num) ...@@ -523,7 +520,7 @@ array_value_type (gimple swtch, tree type, int num)
if (len < (optimize_bb_for_size_p (gimple_bb (swtch)) ? 2 : 32)) if (len < (optimize_bb_for_size_p (gimple_bb (swtch)) ? 2 : 32))
return type; return type;
FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt) FOR_EACH_VEC_ELT (constructor_elt, info->constructors[num], i, elt)
{ {
double_int cst; double_int cst;
...@@ -585,37 +582,37 @@ array_value_type (gimple swtch, tree type, int num) ...@@ -585,37 +582,37 @@ array_value_type (gimple swtch, tree type, int num)
static void static void
build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
tree tidx) tree tidx, struct switch_conv_info *info)
{ {
tree name, cst; tree name, cst;
gimple load; gimple load;
gimple_stmt_iterator gsi = gsi_for_stmt (swtch); gimple_stmt_iterator gsi = gsi_for_stmt (swtch);
location_t loc = gimple_location (swtch); location_t loc = gimple_location (swtch);
gcc_assert (info.default_values[num]); gcc_assert (info->default_values[num]);
name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL); name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL);
info.target_inbound_names[num] = name; info->target_inbound_names[num] = name;
cst = constructor_contains_same_values_p (info.constructors[num]); cst = constructor_contains_same_values_p (info->constructors[num]);
if (cst) if (cst)
load = gimple_build_assign (name, cst); load = gimple_build_assign (name, cst);
else else
{ {
tree array_type, ctor, decl, value_type, fetch, default_type; tree array_type, ctor, decl, value_type, fetch, default_type;
default_type = TREE_TYPE (info.default_values[num]); default_type = TREE_TYPE (info->default_values[num]);
value_type = array_value_type (swtch, default_type, num); value_type = array_value_type (swtch, default_type, num, info);
array_type = build_array_type (value_type, arr_index_type); array_type = build_array_type (value_type, arr_index_type);
if (default_type != value_type) if (default_type != value_type)
{ {
unsigned int i; unsigned int i;
constructor_elt *elt; constructor_elt *elt;
FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt) FOR_EACH_VEC_ELT (constructor_elt, info->constructors[num], i, elt)
elt->value = fold_convert (value_type, elt->value); elt->value = fold_convert (value_type, elt->value);
} }
ctor = build_constructor (array_type, info.constructors[num]); ctor = build_constructor (array_type, info->constructors[num]);
TREE_CONSTANT (ctor) = true; TREE_CONSTANT (ctor) = true;
TREE_STATIC (ctor) = true; TREE_STATIC (ctor) = true;
...@@ -645,7 +642,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, ...@@ -645,7 +642,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
SSA_NAME_DEF_STMT (name) = load; SSA_NAME_DEF_STMT (name) = load;
gsi_insert_before (&gsi, load, GSI_SAME_STMT); gsi_insert_before (&gsi, load, GSI_SAME_STMT);
update_stmt (load); update_stmt (load);
info.arr_ref_last = load; info->arr_ref_last = load;
} }
/* Builds and initializes static arrays initialized with values gathered from /* Builds and initializes static arrays initialized with values gathered from
...@@ -653,7 +650,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, ...@@ -653,7 +650,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi,
them. */ them. */
static void static void
build_arrays (gimple swtch) build_arrays (gimple swtch, struct switch_conv_info *info)
{ {
tree arr_index_type; tree arr_index_type;
tree tidx, sub, tmp, utype; tree tidx, sub, tmp, utype;
...@@ -665,19 +662,19 @@ build_arrays (gimple swtch) ...@@ -665,19 +662,19 @@ build_arrays (gimple swtch)
gsi = gsi_for_stmt (swtch); gsi = gsi_for_stmt (swtch);
/* Make sure we do not generate arithmetics in a subrange. */ /* Make sure we do not generate arithmetics in a subrange. */
utype = TREE_TYPE (info.index_expr); utype = TREE_TYPE (info->index_expr);
if (TREE_TYPE (utype)) if (TREE_TYPE (utype))
utype = lang_hooks.types.type_for_mode (TYPE_MODE (TREE_TYPE (utype)), 1); utype = lang_hooks.types.type_for_mode (TYPE_MODE (TREE_TYPE (utype)), 1);
else else
utype = lang_hooks.types.type_for_mode (TYPE_MODE (utype), 1); utype = lang_hooks.types.type_for_mode (TYPE_MODE (utype), 1);
arr_index_type = build_index_type (info.range_size); arr_index_type = build_index_type (info->range_size);
tmp = create_tmp_var (utype, "csui"); tmp = create_tmp_var (utype, "csui");
add_referenced_var (tmp); add_referenced_var (tmp);
tidx = make_ssa_name (tmp, NULL); tidx = make_ssa_name (tmp, NULL);
sub = fold_build2_loc (loc, MINUS_EXPR, utype, sub = fold_build2_loc (loc, MINUS_EXPR, utype,
fold_convert_loc (loc, utype, info.index_expr), fold_convert_loc (loc, utype, info->index_expr),
fold_convert_loc (loc, utype, info.range_min)); fold_convert_loc (loc, utype, info->range_min));
sub = force_gimple_operand_gsi (&gsi, sub, sub = force_gimple_operand_gsi (&gsi, sub,
false, NULL, true, GSI_SAME_STMT); false, NULL, true, GSI_SAME_STMT);
stmt = gimple_build_assign (tidx, sub); stmt = gimple_build_assign (tidx, sub);
...@@ -685,29 +682,29 @@ build_arrays (gimple swtch) ...@@ -685,29 +682,29 @@ build_arrays (gimple swtch)
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
update_stmt (stmt); update_stmt (stmt);
info.arr_ref_first = stmt; info->arr_ref_first = stmt;
for (gsi = gsi_start_phis (info.final_bb), i = 0; for (gsi = gsi_start_phis (info->final_bb), i = 0;
!gsi_end_p (gsi); gsi_next (&gsi), i++) !gsi_end_p (gsi); gsi_next (&gsi), i++)
build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx); build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx, info);
} }
/* Generates and appropriately inserts loads of default values at the position /* Generates and appropriately inserts loads of default values at the position
given by BSI. Returns the last inserted statement. */ given by BSI. Returns the last inserted statement. */
static gimple static gimple
gen_def_assigns (gimple_stmt_iterator *gsi) gen_def_assigns (gimple_stmt_iterator *gsi, struct switch_conv_info *info)
{ {
int i; int i;
gimple assign = NULL; gimple assign = NULL;
for (i = 0; i < info.phi_count; i++) for (i = 0; i < info->phi_count; i++)
{ {
tree name tree name
= make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]), NULL); = make_ssa_name (SSA_NAME_VAR (info->target_inbound_names[i]), NULL);
info.target_outbound_names[i] = name; info->target_outbound_names[i] = name;
assign = gimple_build_assign (name, info.default_values[i]); assign = gimple_build_assign (name, info->default_values[i]);
SSA_NAME_DEF_STMT (name) = assign; SSA_NAME_DEF_STMT (name) = assign;
gsi_insert_before (gsi, assign, GSI_SAME_STMT); gsi_insert_before (gsi, assign, GSI_SAME_STMT);
update_stmt (assign); update_stmt (assign);
...@@ -743,7 +740,8 @@ prune_bbs (basic_block bbd, basic_block final) ...@@ -743,7 +740,8 @@ prune_bbs (basic_block bbd, basic_block final)
bbf description in the comment below). */ bbf description in the comment below). */
static void static void
fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) fix_phi_nodes (edge e1f, edge e2f, basic_block bbf,
struct switch_conv_info *info)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
int i; int i;
...@@ -752,10 +750,9 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) ...@@ -752,10 +750,9 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf)
!gsi_end_p (gsi); gsi_next (&gsi), i++) !gsi_end_p (gsi); gsi_next (&gsi), i++)
{ {
gimple phi = gsi_stmt (gsi); gimple phi = gsi_stmt (gsi);
add_phi_arg (phi, info.target_inbound_names[i], e1f, UNKNOWN_LOCATION); add_phi_arg (phi, info->target_inbound_names[i], e1f, UNKNOWN_LOCATION);
add_phi_arg (phi, info.target_outbound_names[i], e2f, UNKNOWN_LOCATION); add_phi_arg (phi, info->target_outbound_names[i], e2f, UNKNOWN_LOCATION);
} }
} }
/* Creates a check whether the switch expression value actually falls into the /* Creates a check whether the switch expression value actually falls into the
...@@ -780,7 +777,7 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) ...@@ -780,7 +777,7 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf)
*/ */
static void static void
gen_inbound_check (gimple swtch) gen_inbound_check (gimple swtch, struct switch_conv_info *info)
{ {
tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION); tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION);
tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION); tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION);
...@@ -797,17 +794,17 @@ gen_inbound_check (gimple swtch) ...@@ -797,17 +794,17 @@ gen_inbound_check (gimple swtch)
edge e01, e02, e21, e1d, e1f, e2f; edge e01, e02, e21, e1d, e1f, e2f;
location_t loc = gimple_location (swtch); location_t loc = gimple_location (swtch);
gcc_assert (info.default_values); gcc_assert (info->default_values);
bb0 = gimple_bb (swtch); bb0 = gimple_bb (swtch);
tidx = gimple_assign_lhs (info.arr_ref_first); tidx = gimple_assign_lhs (info->arr_ref_first);
utype = TREE_TYPE (tidx); utype = TREE_TYPE (tidx);
/* (end of) block 0 */ /* (end of) block 0 */
gsi = gsi_for_stmt (info.arr_ref_first); gsi = gsi_for_stmt (info->arr_ref_first);
gsi_next (&gsi); gsi_next (&gsi);
bound = fold_convert_loc (loc, utype, info.range_size); bound = fold_convert_loc (loc, utype, info->range_size);
cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE); cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE);
gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT); gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
update_stmt (cond_stmt); update_stmt (cond_stmt);
...@@ -815,14 +812,14 @@ gen_inbound_check (gimple swtch) ...@@ -815,14 +812,14 @@ gen_inbound_check (gimple swtch)
/* block 2 */ /* block 2 */
label2 = gimple_build_label (label_decl2); label2 = gimple_build_label (label_decl2);
gsi_insert_before (&gsi, label2, GSI_SAME_STMT); gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
last_assign = gen_def_assigns (&gsi); last_assign = gen_def_assigns (&gsi, info);
/* block 1 */ /* block 1 */
label1 = gimple_build_label (label_decl1); label1 = gimple_build_label (label_decl1);
gsi_insert_before (&gsi, label1, GSI_SAME_STMT); gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
/* block F */ /* block F */
gsi = gsi_start_bb (info.final_bb); gsi = gsi_start_bb (info->final_bb);
label3 = gimple_build_label (label_decl3); label3 = gimple_build_label (label_decl3);
gsi_insert_before (&gsi, label3, GSI_SAME_STMT); gsi_insert_before (&gsi, label3, GSI_SAME_STMT);
...@@ -834,40 +831,40 @@ gen_inbound_check (gimple swtch) ...@@ -834,40 +831,40 @@ gen_inbound_check (gimple swtch)
bb1 = e21->dest; bb1 = e21->dest;
remove_edge (e21); remove_edge (e21);
e1d = split_block (bb1, info.arr_ref_last); e1d = split_block (bb1, info->arr_ref_last);
bbd = e1d->dest; bbd = e1d->dest;
remove_edge (e1d); remove_edge (e1d);
/* flags and profiles of the edge for in-range values */ /* flags and profiles of the edge for in-range values */
e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE); e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE);
e01->probability = REG_BR_PROB_BASE - info.default_prob; e01->probability = REG_BR_PROB_BASE - info->default_prob;
e01->count = info.other_count; e01->count = info->other_count;
/* flags and profiles of the edge taking care of out-of-range values */ /* flags and profiles of the edge taking care of out-of-range values */
e02->flags &= ~EDGE_FALLTHRU; e02->flags &= ~EDGE_FALLTHRU;
e02->flags |= EDGE_FALSE_VALUE; e02->flags |= EDGE_FALSE_VALUE;
e02->probability = info.default_prob; e02->probability = info->default_prob;
e02->count = info.default_count; e02->count = info->default_count;
bbf = info.final_bb; bbf = info->final_bb;
e1f = make_edge (bb1, bbf, EDGE_FALLTHRU); e1f = make_edge (bb1, bbf, EDGE_FALLTHRU);
e1f->probability = REG_BR_PROB_BASE; e1f->probability = REG_BR_PROB_BASE;
e1f->count = info.other_count; e1f->count = info->other_count;
e2f = make_edge (bb2, bbf, EDGE_FALLTHRU); e2f = make_edge (bb2, bbf, EDGE_FALLTHRU);
e2f->probability = REG_BR_PROB_BASE; e2f->probability = REG_BR_PROB_BASE;
e2f->count = info.default_count; e2f->count = info->default_count;
/* frequencies of the new BBs */ /* frequencies of the new BBs */
bb1->frequency = EDGE_FREQUENCY (e01); bb1->frequency = EDGE_FREQUENCY (e01);
bb2->frequency = EDGE_FREQUENCY (e02); bb2->frequency = EDGE_FREQUENCY (e02);
bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f); bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f);
prune_bbs (bbd, info.final_bb); /* To keep calc_dfs_tree() in dominance.c prune_bbs (bbd, info->final_bb); /* To keep calc_dfs_tree() in dominance.c
happy. */ happy. */
fix_phi_nodes (e1f, e2f, bbf); fix_phi_nodes (e1f, e2f, bbf, info);
free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS);
...@@ -875,25 +872,25 @@ gen_inbound_check (gimple swtch) ...@@ -875,25 +872,25 @@ gen_inbound_check (gimple swtch)
/* The following function is invoked on every switch statement (the current one /* The following function is invoked on every switch statement (the current one
is given in SWTCH) and runs the individual phases of switch conversion on it is given in SWTCH) and runs the individual phases of switch conversion on it
one after another until one fails or the conversion is completed. */ one after another until one fails or the conversion is completed.
Returns NULL on success, or a pointer to a string with the reason why the
conversion failed. */
static bool static const char *
process_switch (gimple swtch) process_switch (gimple swtch)
{ {
unsigned int i, branch_num = gimple_switch_num_labels (swtch); unsigned int i, branch_num = gimple_switch_num_labels (swtch);
tree index_type; tree index_type;
struct switch_conv_info info;
/* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */ /* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */
if (branch_num < 2) if (branch_num < 2)
{ return "switch has no labels";
info.reason = "switch has no labels\n";
return false;
}
info.reason = NULL;
info.final_bb = NULL; info.final_bb = NULL;
info.switch_bb = gimple_bb (swtch); info.switch_bb = gimple_bb (swtch);
info.index_expr = gimple_switch_index (swtch); info.index_expr = gimple_switch_index (swtch);
index_type = TREE_TYPE (info.index_expr);
info.arr_ref_first = NULL; info.arr_ref_first = NULL;
info.arr_ref_last = NULL; info.arr_ref_last = NULL;
info.default_prob = 0; info.default_prob = 0;
...@@ -906,24 +903,26 @@ process_switch (gimple swtch) ...@@ -906,24 +903,26 @@ process_switch (gimple swtch)
/* An ERROR_MARK occurs for various reasons including invalid data type. /* An ERROR_MARK occurs for various reasons including invalid data type.
(comment from stmt.c) */ (comment from stmt.c) */
index_type = TREE_TYPE (info.index_expr);
if (index_type == error_mark_node) if (index_type == error_mark_node)
{ return "index error\n";
info.reason = "index error.\n";
return false;
}
/* Check the case label values are within reasonable range: */ /* Check the case label values are within reasonable range: */
if (!check_range (swtch)) if (!check_range (swtch, &info))
return false; {
gcc_assert (info.reason);
return info.reason;
}
/* 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++) for (i = 0; i < branch_num; i++)
if (!check_process_case (gimple_switch_label (swtch, i))) if (!check_process_case (gimple_switch_label (swtch, i), &info))
{ {
gcc_assert (info.reason);
if (dump_file) if (dump_file)
fprintf (dump_file, "Processing of case %i failed\n", i); fprintf (dump_file, "processing of case %i failed\n\t", i);
return false; return info.reason;
} }
if (info.bit_test_uniq <= 2) if (info.bit_test_uniq <= 2)
...@@ -933,27 +932,29 @@ process_switch (gimple swtch) ...@@ -933,27 +932,29 @@ process_switch (gimple swtch)
info.range_size, info.bit_test_uniq, info.range_size, info.bit_test_uniq,
info.bit_test_count)) info.bit_test_count))
{ {
info.reason = " Expanding as bit test is preferable\n"; return "expanding as bit test is preferable";
return false;
} }
} }
if (!check_final_bb ()) if (!check_final_bb (&info))
return false; {
gcc_assert (info.reason);
return info.reason;
}
/* At this point all checks have passed and we can proceed with the /* At this point all checks have passed and we can proceed with the
transformation. */ transformation. */
create_temp_arrays (); create_temp_arrays (&info);
gather_default_values (gimple_switch_label (swtch, 0)); gather_default_values (gimple_switch_label (swtch, 0), &info);
build_constructors (swtch); build_constructors (swtch, &info);
build_arrays (swtch); /* Build the static arrays and assignments. */ build_arrays (swtch, &info); /* Build the static arrays and assignments. */
gen_inbound_check (swtch); /* Build the bounds check. */ gen_inbound_check (swtch, &info); /* Build the bounds check. */
/* Cleanup: */ /* Cleanup: */
free_temp_arrays (); free_temp_arrays (&info);
return true; return NULL;
} }
/* The main function of the pass scans statements for switches and invokes /* The main function of the pass scans statements for switches and invokes
...@@ -966,6 +967,7 @@ do_switchconv (void) ...@@ -966,6 +967,7 @@ do_switchconv (void)
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
{ {
const char *failure_reason;
gimple stmt = last_stmt (bb); gimple stmt = last_stmt (bb);
if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
{ {
...@@ -980,8 +982,8 @@ do_switchconv (void) ...@@ -980,8 +982,8 @@ do_switchconv (void)
putc ('\n', dump_file); putc ('\n', dump_file);
} }
info.reason = NULL; failure_reason = process_switch (stmt);
if (process_switch (stmt)) if (! failure_reason)
{ {
if (dump_file) if (dump_file)
{ {
...@@ -993,10 +995,9 @@ do_switchconv (void) ...@@ -993,10 +995,9 @@ do_switchconv (void)
{ {
if (dump_file) if (dump_file)
{ {
gcc_assert (info.reason);
fputs ("Bailing out - ", dump_file); fputs ("Bailing out - ", dump_file);
fputs (info.reason, dump_file); fputs (failure_reason, dump_file);
fputs ("--------------------------------\n", dump_file); fputs ("\n--------------------------------\n", dump_file);
} }
} }
} }
......
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