From df62c1c110e8532b995b23540b7e3695729c0779 Mon Sep 17 00:00:00 2001 From: Jing Yu Date: Thu, 5 Nov 2009 15:11:04 -0800 Subject: Check in gcc sources for prebuilt toolchains in Eclair. --- gcc-4.4.0/gcc/tree-switch-conversion.c | 897 +++++++++++++++++++++++++++++++++ 1 file changed, 897 insertions(+) create mode 100644 gcc-4.4.0/gcc/tree-switch-conversion.c (limited to 'gcc-4.4.0/gcc/tree-switch-conversion.c') diff --git a/gcc-4.4.0/gcc/tree-switch-conversion.c b/gcc-4.4.0/gcc/tree-switch-conversion.c new file mode 100644 index 000000000..dba0c6f3d --- /dev/null +++ b/gcc-4.4.0/gcc/tree-switch-conversion.c @@ -0,0 +1,897 @@ +/* Switch Conversion converts variable initializations based on switch + statements to initializations from a static array. + Copyright (C) 2006, 2008 Free Software Foundation, Inc. + Contributed by Martin Jambor + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +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. */ + +/* + Switch initialization conversion + +The following pass changes simple initializations of scalars in a switch +statement into initializations from a static array. Obviously, the values must +be constant and known at compile time and a default branch must be +provided. For example, the following code: + + int a,b; + + switch (argc) + { + case 1: + case 2: + a_1 = 8; + b_1 = 6; + break; + case 3: + a_2 = 9; + b_2 = 5; + break; + case 12: + a_3 = 10; + b_3 = 4; + break; + default: + a_4 = 16; + b_4 = 1; + } + a_5 = PHI + b_5 = PHI + + +is changed into: + + static const int = CSWTCH01[] = {6, 6, 5, 1, 1, 1, 1, 1, 1, 1, 1, 4}; + static const int = CSWTCH02[] = {8, 8, 9, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 10}; + + if (((unsigned) argc) - 1 < 11) + { + a_6 = CSWTCH02[argc - 1]; + b_6 = CSWTCH01[argc - 1]; + } + else + { + a_7 = 16; + b_7 = 1; + } + a_5 = PHI + b_b = PHI + +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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include + +#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 "output.h" +#include "input.h" +#include "tree-pass.h" +#include "diagnostic.h" +#include "tree-dump.h" +#include "timevar.h" + +/* 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.) */ + tree index_expr; + + /* The following integer constants store the minimum value covered by the + cases. */ + tree range_min; + + /* The difference between the above two numbers, i.e. The size of the array + that would have to be created by the transformation. */ + tree range_size; + + /* Basic block that contains the actual SWITCH_EXPR. */ + basic_block switch_bb; + + /* All branches of the switch statement must have a single successor stored in + the following variable. */ + basic_block final_bb; + + /* Number of phi nodes in the final bb (that we'll be replacing). */ + int phi_count; + + /* Array of default values, in the same order as phi nodes. */ + tree *default_values; + + /* Constructors of new static arrays. */ + VEC (constructor_elt, gc) **constructors; + + /* Array of ssa names that are initialized with a value from a new static + array. */ + tree *target_inbound_names; + + /* Array of ssa names that are initialized with the default value if the + 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; + + /* The last load statement that loads a temporary from a new static array. */ + gimple arr_ref_last; + + /* String reason why the case wasn't a good candidate that is written to the + dump file, if there is one. */ + const char *reason; +}; + +/* Global pass info. */ +static struct switch_conv_info info; + + +/* 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 (gimple swtch) +{ + tree min_case, max_case; + unsigned int branch_num = gimple_switch_num_labels (swtch); + tree range_max; + + /* The gimplifier has already sorted the cases by CASE_LOW and ensured there + is a default label which is the last in the vector. */ + + min_case = gimple_switch_label (swtch, 1); + info.range_min = CASE_LOW (min_case); + + gcc_assert (branch_num > 1); + gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE); + max_case = gimple_switch_label (swtch, branch_num - 1); + if (CASE_HIGH (max_case) != NULL_TREE) + range_max = CASE_HIGH (max_case); + else + range_max = CASE_LOW (max_case); + + gcc_assert (info.range_min); + gcc_assert (range_max); + + info.range_size = int_const_binop (MINUS_EXPR, range_max, info.range_min, 0); + + gcc_assert (info.range_size); + if (!host_integerp (info.range_size, 1)) + { + info.reason = "index range way too large or otherwise unusable.\n"; + return false; + } + + if ((unsigned HOST_WIDE_INT) tree_low_cst (info.range_size, 1) + > ((unsigned) branch_num * SWITCH_CONVERSION_BRANCH_RATIO)) + { + info.reason = "the maximum range-branch ratio exceeded.\n"; + return false; + } + + 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. */ + +static bool +check_process_case (tree cs) +{ + tree ldecl; + basic_block label_bb, following_bb; + edge e; + + 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 + info.other_count += e->count; + + if (!label_bb) + { + info.reason = " Bad case - cs BB label is NULL\n"; + return false; + } + + if (!single_pred_p (label_bb)) + { + if (info.final_bb && info.final_bb != label_bb) + { + info.reason = " Bad case - a non-final BB has two predecessors\n"; + return false; /* sth complex going on in this branch */ + } + + following_bb = label_bb; + } + else + { + if (!empty_block_p (label_bb)) + { + info.reason = " Bad case - a non-final BB not empty\n"; + 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\n"; + return false; /* the only successor is not common for all the branches */ + } + + return true; +} + +/* This function checks whether all required values in phi nodes in final_bb + are constants. Required values are those that correspond to a basic block + which is a part of the examined switch statement. It returns true if the + phi nodes are OK, otherwise false. */ + +static bool +check_final_bb (void) +{ + gimple_stmt_iterator gsi; + + info.phi_count = 0; + for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + unsigned int i; + + info.phi_count++; + + for (i = 0; i < gimple_phi_num_args (phi); i++) + { + basic_block bb = gimple_phi_arg_edge (phi, i)->src; + + if (bb == info.switch_bb + || (single_pred_p (bb) && single_pred (bb) == info.switch_bb)) + { + tree reloc, val; + + val = gimple_phi_arg_def (phi, i); + if (!is_gimple_ip_invariant (val)) + { + info.reason = " Non-invariant value from a case\n"; + return false; /* Non-invariant argument. */ + } + reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); + if ((flag_pic && reloc != null_pointer_node) + || (!flag_pic && reloc == NULL_TREE)) + { + if (reloc) + info.reason + = " Value from a case would need runtime relocations\n"; + else + info.reason + = " Value from a case is not a valid initializer\n"; + return false; + } + } + } + } + + return true; +} + +/* The following function allocates default_values, target_{in,out}_names and + constructors arrays. The last one is also populated with pointers to + vectors that will become constructors of new arrays. */ + +static void +create_temp_arrays (void) +{ + int i; + + info.default_values = (tree *) xcalloc (info.phi_count, sizeof (tree)); + info.constructors = (VEC (constructor_elt, gc) **) xcalloc (info.phi_count, + sizeof (tree)); + info.target_inbound_names = (tree *) xcalloc (info.phi_count, sizeof (tree)); + info.target_outbound_names = (tree *) xcalloc (info.phi_count, + sizeof (tree)); + + for (i = 0; i < info.phi_count; i++) + info.constructors[i] + = 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 + created by that function are not freed here, however, because they have + already become constructors and must be preserved. */ + +static void +free_temp_arrays (void) +{ + free (info.constructors); + free (info.default_values); + free (info.target_inbound_names); + free (info.target_outbound_names); +} + +/* Populate the array of default values in the order of phi nodes. + DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. */ + +static void +gather_default_values (tree default_case) +{ + gimple_stmt_iterator gsi; + basic_block bb = label_to_block (CASE_LABEL (default_case)); + edge e; + int i = 0; + + gcc_assert (CASE_LOW (default_case) == NULL_TREE); + + if (bb == info.final_bb) + e = find_edge (info.switch_bb, bb); + else + e = single_succ_edge (bb); + + for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); + gcc_assert (val); + info.default_values[i++] = val; + } +} + +/* The following function populates the vectors in the constructors array with + future contents of the static arrays. The vectors are populated in the + order of phi nodes. SWTCH is the switch statement being converted. */ + +static void +build_constructors (gimple swtch) +{ + unsigned i, branch_num = gimple_switch_num_labels (swtch); + tree pos = info.range_min; + + for (i = 1; i < branch_num; i++) + { + tree cs = gimple_switch_label (swtch, i); + basic_block bb = label_to_block (CASE_LABEL (cs)); + edge e; + tree high; + gimple_stmt_iterator gsi; + int j; + + if (bb == info.final_bb) + e = find_edge (info.switch_bb, bb); + else + e = single_succ_edge (bb); + gcc_assert (e); + + while (tree_int_cst_lt (pos, CASE_LOW (cs))) + { + int k; + for (k = 0; k < info.phi_count; k++) + { + constructor_elt *elt; + + elt = VEC_quick_push (constructor_elt, + info.constructors[k], NULL); + elt->index = int_const_binop (MINUS_EXPR, pos, + info.range_min, 0); + elt->value = info.default_values[k]; + } + + pos = int_const_binop (PLUS_EXPR, pos, integer_one_node, 0); + } + gcc_assert (tree_int_cst_equal (pos, CASE_LOW (cs))); + + j = 0; + if (CASE_HIGH (cs)) + high = CASE_HIGH (cs); + else + high = CASE_LOW (cs); + for (gsi = gsi_start_phis (info.final_bb); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); + tree low = CASE_LOW (cs); + pos = CASE_LOW (cs); + + do + { + constructor_elt *elt; + + elt = VEC_quick_push (constructor_elt, + info.constructors[j], NULL); + elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min, 0); + elt->value = val; + + pos = int_const_binop (PLUS_EXPR, pos, integer_one_node, 0); + } while (!tree_int_cst_lt (high, pos) && tree_int_cst_lt (low, pos)); + j++; + } + } +} + +/* Create an appropriate array type and declaration and assemble a static array + variable. Also create a load statement that initializes the variable in + question with a value from the static array. SWTCH is the switch statement + being converted, NUM is the index to arrays of constructors, default values + and target SSA names for this particular array. ARR_INDEX_TYPE is the type + of the index of the new array, PHI is the phi node of the final BB that + corresponds to the value that will be loaded from the created array. TIDX + is a temporary variable holding the index for loads from the new array. */ + +static void +build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, + tree tidx) +{ + tree array_type, ctor, decl, value_type, name, fetch; + gimple load; + gimple_stmt_iterator gsi; + + gcc_assert (info.default_values[num]); + value_type = TREE_TYPE (info.default_values[num]); + array_type = build_array_type (value_type, arr_index_type); + + ctor = build_constructor (array_type, info.constructors[num]); + TREE_CONSTANT (ctor) = true; + + decl = build_decl (VAR_DECL, NULL_TREE, array_type); + TREE_STATIC (decl) = 1; + DECL_INITIAL (decl) = ctor; + + DECL_NAME (decl) = create_tmp_var_name ("CSWTCH"); + DECL_ARTIFICIAL (decl) = 1; + TREE_CONSTANT (decl) = 1; + add_referenced_var (decl); + varpool_mark_needed_node (varpool_node (decl)); + varpool_finalize_decl (decl); + mark_sym_for_renaming (decl); + + name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL); + info.target_inbound_names[num] = name; + + fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE, + NULL_TREE); + load = gimple_build_assign (name, fetch); + SSA_NAME_DEF_STMT (name) = load; + + gsi = gsi_for_stmt (swtch); + gsi_insert_before (&gsi, load, GSI_SAME_STMT); + mark_symbols_for_renaming (load); + + info.arr_ref_last = load; +} + +/* Builds and initializes static arrays initialized with values gathered from + the SWTCH switch statement. Also creates statements that load values from + them. */ + +static void +build_arrays (gimple swtch) +{ + tree arr_index_type; + tree tidx, sub; + gimple stmt; + gimple_stmt_iterator gsi; + int i; + + gsi = gsi_for_stmt (swtch); + + arr_index_type = build_index_type (info.range_size); + tidx = make_rename_temp (arr_index_type, "csti"); + sub = fold_build2 (MINUS_EXPR, TREE_TYPE (info.index_expr), info.index_expr, + fold_convert (TREE_TYPE (info.index_expr), + info.range_min)); + sub = force_gimple_operand_gsi (&gsi, fold_convert (arr_index_type, sub), + false, NULL, true, GSI_SAME_STMT); + stmt = gimple_build_assign (tidx, sub); + + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + mark_symbols_for_renaming (stmt); + info.arr_ref_first = stmt; + + for (gsi = gsi_start_phis (info.final_bb), i = 0; + !gsi_end_p (gsi); gsi_next (&gsi), i++) + build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx); +} + +/* Generates and appropriately inserts loads of default values at the position + given by BSI. Returns the last inserted statement. */ + +static gimple +gen_def_assigns (gimple_stmt_iterator *gsi) +{ + int i; + gimple assign = NULL; + + for (i = 0; i < info.phi_count; i++) + { + tree name + = make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]), NULL); + + info.target_outbound_names[i] = name; + assign = gimple_build_assign (name, info.default_values[i]); + SSA_NAME_DEF_STMT (name) = assign; + gsi_insert_before (gsi, assign, GSI_SAME_STMT); + find_new_referenced_vars (assign); + mark_symbols_for_renaming (assign); + } + return assign; +} + +/* Deletes the unused bbs and edges that now contain the switch statement and + its empty branch bbs. BBD is the now dead BB containing the original switch + statement, FINAL is the last BB of the converted switch statement (in terms + of succession). */ + +static void +prune_bbs (basic_block bbd, basic_block final) +{ + edge_iterator ei; + edge e; + + for (ei = ei_start (bbd->succs); (e = ei_safe_edge (ei)); ) + { + basic_block bb; + bb = e->dest; + remove_edge (e); + if (bb != final) + delete_basic_block (bb); + } + delete_basic_block (bbd); +} + +/* Add values to phi nodes in final_bb for the two new edges. E1F is the edge + from the basic block loading values from an array and E2F from the basic + block loading default values. BBF is the last switch basic block (see the + bbf description in the comment below). */ + +static void +fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) +{ + gimple_stmt_iterator gsi; + int i; + + for (gsi = gsi_start_phis (bbf), i = 0; + !gsi_end_p (gsi); gsi_next (&gsi), i++) + { + gimple phi = gsi_stmt (gsi); + add_phi_arg (phi, info.target_inbound_names[i], e1f); + add_phi_arg (phi, info.target_outbound_names[i], e2f); + } + +} + +/* Creates a check whether the switch expression value actually falls into the + range given by all the cases. If it does not, the temporaries are loaded + with default values instead. SWTCH is the switch statement being converted. + + bb0 is the bb with the switch statement, however, we'll end it with a + condition instead. + + bb1 is the bb to be used when the range check went ok. It is derived from + the switch BB + + bb2 is the bb taken when the expression evaluated outside of the range + covered by the created arrays. It is populated by loads of default + values. + + bbF is a fall through for both bb1 and bb2 and contains exactly what + originally followed the switch statement. + + bbD contains the switch statement (in the end). It is unreachable but we + still need to strip off its edges. +*/ + +static void +gen_inbound_check (gimple swtch) +{ + tree label_decl1 = create_artificial_label (); + tree label_decl2 = create_artificial_label (); + tree label_decl3 = create_artificial_label (); + gimple label1, label2, label3; + + tree utype; + tree tmp_u; + tree cast; + gimple cast_assign, minus_assign; + tree ulb, minus; + tree bound; + + gimple cond_stmt; + + gimple last_assign; + gimple_stmt_iterator gsi; + basic_block bb0, bb1, bb2, bbf, bbd; + edge e01, e02, e21, e1d, e1f, e2f; + + gcc_assert (info.default_values); + bb0 = gimple_bb (swtch); + + /* Make sure we do not generate arithmetics in a subrange. */ + if (TREE_TYPE (TREE_TYPE (info.index_expr))) + utype = unsigned_type_for (TREE_TYPE (TREE_TYPE (info.index_expr))); + else + utype = unsigned_type_for (TREE_TYPE (info.index_expr)); + + /* (end of) block 0 */ + gsi = gsi_for_stmt (info.arr_ref_first); + tmp_u = make_rename_temp (utype, "csui"); + + cast = fold_convert (utype, info.index_expr); + cast_assign = gimple_build_assign (tmp_u, cast); + find_new_referenced_vars (cast_assign); + gsi_insert_before (&gsi, cast_assign, GSI_SAME_STMT); + mark_symbols_for_renaming (cast_assign); + + ulb = fold_convert (utype, info.range_min); + minus = fold_build2 (MINUS_EXPR, utype, tmp_u, ulb); + minus = force_gimple_operand_gsi (&gsi, minus, false, NULL, true, + GSI_SAME_STMT); + minus_assign = gimple_build_assign (tmp_u, minus); + find_new_referenced_vars (minus_assign); + gsi_insert_before (&gsi, minus_assign, GSI_SAME_STMT); + mark_symbols_for_renaming (minus_assign); + + bound = fold_convert (utype, info.range_size); + + cond_stmt = gimple_build_cond (LE_EXPR, tmp_u, bound, NULL_TREE, NULL_TREE); + + find_new_referenced_vars (cond_stmt); + gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT); + mark_symbols_for_renaming (cond_stmt); + + /* block 2 */ + gsi = gsi_for_stmt (info.arr_ref_first); + label2 = gimple_build_label (label_decl2); + gsi_insert_before (&gsi, label2, GSI_SAME_STMT); + last_assign = gen_def_assigns (&gsi); + + /* block 1 */ + gsi = gsi_for_stmt (info.arr_ref_first); + label1 = gimple_build_label (label_decl1); + gsi_insert_before (&gsi, label1, GSI_SAME_STMT); + + /* block F */ + gsi = gsi_start_bb (info.final_bb); + label3 = gimple_build_label (label_decl3); + gsi_insert_before (&gsi, label3, GSI_SAME_STMT); + + /* cfg fix */ + e02 = split_block (bb0, cond_stmt); + bb2 = e02->dest; + + e21 = split_block (bb2, last_assign); + bb1 = e21->dest; + remove_edge (e21); + + e1d = split_block (bb1, info.arr_ref_last); + bbd = e1d->dest; + remove_edge (e1d); + + /* flags and profiles of the edge for in-range values */ + e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE); + e01->probability = REG_BR_PROB_BASE - info.default_prob; + e01->count = info.other_count; + + /* flags and profiles of the edge taking care of out-of-range values */ + e02->flags &= ~EDGE_FALLTHRU; + e02->flags |= EDGE_FALSE_VALUE; + e02->probability = info.default_prob; + e02->count = info.default_count; + + bbf = info.final_bb; + + e1f = make_edge (bb1, bbf, EDGE_FALLTHRU); + e1f->probability = REG_BR_PROB_BASE; + e1f->count = info.other_count; + + e2f = make_edge (bb2, bbf, EDGE_FALLTHRU); + e2f->probability = REG_BR_PROB_BASE; + e2f->count = info.default_count; + + /* frequencies of the new BBs */ + bb1->frequency = EDGE_FREQUENCY (e01); + bb2->frequency = EDGE_FREQUENCY (e02); + bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f); + + prune_bbs (bbd, info.final_bb); /* To keep calc_dfs_tree() in dominance.c + happy. */ + + fix_phi_nodes (e1f, e2f, bbf); + + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); +} + +/* 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 + one after another until one fails or the conversion is completed. */ + +static bool +process_switch (gimple swtch) +{ + unsigned int i, branch_num = gimple_switch_num_labels (swtch); + tree index_type; + + /* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */ + if (branch_num < 2) + { + info.reason = "switch has no labels\n"; + return false; + } + + info.final_bb = NULL; + info.switch_bb = gimple_bb (swtch); + info.index_expr = gimple_switch_index (swtch); + index_type = TREE_TYPE (info.index_expr); + info.arr_ref_first = NULL; + info.arr_ref_last = NULL; + info.default_prob = 0; + info.default_count = 0; + info.other_count = 0; + + /* An ERROR_MARK occurs for various reasons including invalid data type. + (comment from stmt.c) */ + if (index_type == error_mark_node) + { + info.reason = "index error.\n"; + return false; + } + + /* Check the case label values are within reasonable range: */ + if (!check_range (swtch)) + return false; + + /* 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))) + { + if (dump_file) + fprintf (dump_file, "Processing of case %i failed\n", i); + return false; + } + + if (!check_final_bb ()) + return false; + + /* At this point all checks have passed and we can proceed with the + transformation. */ + + create_temp_arrays (); + gather_default_values (gimple_switch_label (swtch, 0)); + build_constructors (swtch); + + build_arrays (swtch); /* Build the static arrays and assignments. */ + gen_inbound_check (swtch); /* Build the bounds check. */ + + /* Cleanup: */ + free_temp_arrays (); + return true; +} + +/* The main function of the pass scans statements for switches and invokes + process_switch on them. */ + +static unsigned int +do_switchconv (void) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + gimple stmt = last_stmt (bb); + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + { + if (dump_file) + { + expanded_location loc = expand_location (gimple_location (stmt)); + + fprintf (dump_file, "beginning to process the following " + "SWITCH statement (%s:%d) : ------- \n", + loc.file, loc.line); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + info.reason = NULL; + if (process_switch (stmt)) + { + if (dump_file) + { + fprintf (dump_file, "Switch converted\n"); + fprintf (dump_file, "--------------------------------\n"); + } + } + else + { + if (dump_file) + { + gcc_assert (info.reason); + fprintf (dump_file, "Bailing out - "); + fprintf (dump_file, info.reason); + fprintf (dump_file, "--------------------------------\n"); + } + } + } + } + + return 0; +} + +/* The pass gate. */ + +static bool +switchconv_gate (void) +{ + return flag_tree_switch_conversion != 0; +} + +struct gimple_opt_pass pass_convert_switch = +{ + { + GIMPLE_PASS, + "switchconv", /* name */ + switchconv_gate, /* gate */ + do_switchconv, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_SWITCH_CONVERSION, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa | TODO_dump_func + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ + } +}; -- cgit v1.2.3