Hello, The attached patch re-organizes some code in tree-switch-conversion.c. All information about a GIMPLE_SWITCH is now collected by one function, so that my switch lowering code can use the same switch_conv_info. Bootstrapped&tested on x86_64-unknown-linux-gnu. OK for trunk?
Ciao! Steven
* 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. Index: tree-switch-conversion.c =================================================================== *** tree-switch-conversion.c (revision 186586) --- tree-switch-conversion.c (working copy) *************** provided. For example, the following co *** 48,53 **** --- 48,54 ---- 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> *************** is changed into: *** 69,76 **** a_7 = 16; b_7 = 1; } ! 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 --- 70,77 ---- a_7 = 16; b_7 = 1; } ! 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 *************** eight) times the number of the actual sw *** 99,123 **** /* 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; --- 100,137 ---- /* The main structure of the pass. */ struct switch_conv_info { ! /* The expression used to decide the switch branch. */ tree index_expr; ! /* 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. 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 GIMPLE_SWITCH. */ basic_block switch_bb; ! /* 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; *************** struct switch_conv_info *** 135,149 **** 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; --- 149,154 ---- *************** struct switch_conv_info *** 157,197 **** /* 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]; }; ! /* 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, struct switch_conv_info *info) { - 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 first 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); gcc_assert (info->range_size); if (!host_integerp (info->range_size, 1)) { --- 162,265 ---- /* Parameters for expand_switch_using_bit_tests. Should be computed the same way as in expand_case. */ ! unsigned int uniq; ! unsigned int count; }; ! /* Collect information about GIMPLE_SWITCH statement SWTCH into INFO. */ ! static void ! collect_switch_conv_info (gimple swtch, struct switch_conv_info *info) { unsigned int branch_num = gimple_switch_num_labels (swtch); ! 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); ! /* 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; ! /* 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) ! info->range_max = CASE_HIGH (max_case); else ! info->range_max = CASE_LOW (max_case); ! ! info->range_size = ! int_const_binop (MINUS_EXPR, info->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)) { *************** check_range (gimple swtch, struct switch *** 200,206 **** } 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"; return false; --- 268,274 ---- } if ((unsigned HOST_WIDE_INT) tree_low_cst (info->range_size, 1) ! > ((unsigned) info->count * SWITCH_CONVERSION_BRANCH_RATIO)) { info->reason = "the maximum range-branch ratio exceeded"; return false; *************** check_range (gimple swtch, struct switch *** 209,294 **** 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, struct switch_conv_info *info) { - 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 ! { ! 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) ! { ! info->reason = "bad case - a non-final BB has two predecessors"; ! 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"; 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; --- 277,300 ---- return true; } ! /* Checks whether all but the FINAL_BB basic blocks are empty. */ static bool ! check_all_empty_except_final (struct switch_conv_info *info) { edge e; + edge_iterator ei; ! FOR_EACH_EDGE (e, ei, info->switch_bb->succs) { ! if (e->dest == info->final_bb) ! continue; ! if (!empty_block_p (e->dest)) { info->reason = "bad case - a non-final BB not empty"; return false; } } return true; *************** gen_inbound_check (gimple swtch, struct *** 879,914 **** 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"; /* Check the case label values are within reasonable range: */ ! if (!check_range (swtch, &info)) { gcc_assert (info.reason); return info.reason; --- 885,914 ---- static const char * process_switch (gimple swtch) { struct switch_conv_info info; ! /* 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 (&info)) { gcc_assert (info.reason); return info.reason; *************** process_switch (gimple swtch) *** 916,941 **** /* 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) { ! 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"; ! } } - if (!check_final_bb (&info)) { gcc_assert (info.reason); --- 916,926 ---- /* For all the cases, see whether they are empty, the assignments they represent constant and so on... */ ! if (! check_all_empty_except_final (&info)) { ! gcc_assert (info.reason); ! return info.reason; } if (!check_final_bb (&info)) { gcc_assert (info.reason);