https://gcc.gnu.org/g:3a067ae712e98d5ead1d565ad3b3dd32dc6ac37a
commit 3a067ae712e98d5ead1d565ad3b3dd32dc6ac37a Author: David Balek <davca.ba...@gmail.com> Date: Tue Sep 23 14:14:26 2025 +0200 Fixes merged switch creation Diff: --- gcc/gimple-flatten-switch.cc | 173 +++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 89 deletions(-) diff --git a/gcc/gimple-flatten-switch.cc b/gcc/gimple-flatten-switch.cc index 3d3e5c8a7695..133e87593dc8 100644 --- a/gcc/gimple-flatten-switch.cc +++ b/gcc/gimple-flatten-switch.cc @@ -28,27 +28,17 @@ #include <vector> #include <algorithm> -/* The struct holding the info about outer switch and all inner switches it - points to. */ +/* The struct holding the info about outer and inenr switch pair. */ struct switch_info { - switch_info(gswitch *outer_switch, gswitch *inner_switch) : - m_outer_switch(outer_switch), m_inner_switches() - { - m_inner_switches.create (1); - m_inner_switches.safe_push (inner_switch); - } + switch_info (gswitch *outer_switch, gswitch *inner_switch) : + m_outer_switch (outer_switch), m_inner_switch (inner_switch) + {} - void add_inner_switch (gswitch *inner_switch); gswitch *m_outer_switch; - auto_vec<gswitch*> m_inner_switches; + gswitch *m_inner_switch; }; -void -switch_info::add_inner_switch (gswitch *inner_switch) -{ - m_inner_switches.safe_push(inner_switch); -} void print_nested_switches (basic_block bb, gswitch *sw1, gswitch *sw2) @@ -591,58 +581,40 @@ repair_cfg (case_informations &merged_case_infos, basic_block merged_switch_bb) make_edge (info->m_this_bb, info->m_dest_bb, 0); } - /* Add the missing phi arguments */ - for (auto info : merged_case_infos) - { - edge e = (info->m_forwarder_bb == NULL) - ? find_edge(info->m_this_bb, info->m_dest_bb) - : find_edge(info->m_forwarder_bb, info->m_dest_bb); - - for (auto item : info->m_phi_mapping) - { - add_phi_arg (item.first, item.second, e, UNKNOWN_LOCATION); - } - } + /* Add the missing phi arguments */ + for (auto info : merged_case_infos) + { + edge e = (info->m_forwarder_bb == NULL) + ? find_edge(info->m_this_bb, info->m_dest_bb) + : find_edge(info->m_forwarder_bb, info->m_dest_bb); + + for (auto item : info->m_phi_mapping) + add_phi_arg (item.first, item.second, e, UNKNOWN_LOCATION); + } } /* Adjusts the outer switch to be merged switch */ static void -change_outer_switch_to_merged_switch (gswitch *outer, - case_informations &merged_case_infos) +create_merged_switch (gswitch *outer, + case_informations &merged_case_infos) { gcc_assert (merged_case_infos.size () > 0); gcc_assert (merged_case_infos[0]->is_default ()); - gimple_switch_set_num_labels (outer, merged_case_infos.size ()); - for (unsigned i = 0; i < merged_case_infos.size (); ++i) + gimple_stmt_iterator gsi = gsi_for_stmt (outer); + auto_vec<tree> labels; + for (unsigned i = 1; i < merged_case_infos.size (); ++i) { case_info_ptr info = merged_case_infos[i]; tree label = info->build_case (); - gimple_switch_set_label (outer, i, label); + labels.safe_push (label); } -} -/* Merges nested switches */ -static void -merge_nested_switches (function *fun, switch_info *info) -{ - gswitch* outer = info->m_outer_switch; - for (gswitch* inner : info->m_inner_switches) - { - case_informations outer_case_info{}, inner_case_info{}; - outer_switch_case_informations (fun, outer, inner, outer_case_info); - inner_switch_case_informations (fun, inner, inner_case_info); - - if (!check_if_switches_mergeable (outer_case_info, inner_case_info)) - continue; - - case_informations merged_case_info{}; - dump_function_to_file (fun->decl, stderr, TDF_DETAILS); - merge_case_infos (outer_case_info, inner_case_info, merged_case_info); - repair_cfg (merged_case_info, outer->bb); - change_outer_switch_to_merged_switch (outer, merged_case_info); - delete_basic_block (inner->bb); - } + gswitch *s = gimple_build_switch (gimple_switch_index(outer), + merged_case_infos[0]->build_case (), + labels); + gsi_remove (&gsi, true); + gsi_insert_before (&gsi, s, GSI_NEW_STMT); } @@ -666,18 +638,17 @@ bb_only_labels_and_switch (basic_block bb) return true; } -/* Finds the pairs of outer and inner switches */ -static void -find_nested_switches (hash_map<basic_block, switch_info *> *switch_in_bb, - basic_block bb) +/* Finds the pair of outer and inner switch */ +static switch_info * +find_nested_switch (basic_block bb) { gimple_stmt_iterator gsi = gsi_last_nondebug_bb(bb); if (gsi_end_p(gsi)) - return; + return NULL; gswitch *outer_switch = dyn_cast<gswitch *>(gsi_stmt(gsi)); if (outer_switch == NULL) - return; + return NULL; edge e; edge_iterator ei; @@ -705,18 +676,51 @@ find_nested_switches (hash_map<basic_block, switch_info *> *switch_in_bb, continue; print_nested_switches(bb, outer_switch, inner_switch); - - switch_info** info = switch_in_bb->get(bb); - if (info == NULL) - { - switch_info *new_info = new switch_info (outer_switch, inner_switch); - switch_in_bb->put(bb, new_info); - continue; - } - (*info)->add_inner_switch(inner_switch); + return new switch_info (outer_switch, inner_switch); } + + return NULL; } + +/* Merges nested switches and returns if any were even found */ +static bool +merge_nested_switches (function *fun, basic_block bb) +{ + switch_info *info = find_nested_switch (bb); + if (info == NULL) + return false; + + do { + gswitch* outer = info->m_outer_switch; + gswitch* inner = info->m_inner_switch; + case_informations outer_case_info{}, inner_case_info{}; + outer_switch_case_informations (fun, outer, inner, outer_case_info); + inner_switch_case_informations (fun, inner, inner_case_info); + + if (!check_if_switches_mergeable (outer_case_info, inner_case_info)) + { + delete info; + info = find_nested_switch (bb); + continue; + } + + + case_informations merged_case_info{}; + dump_function_to_file (fun->decl, stderr, TDF_DETAILS); + merge_case_infos (outer_case_info, inner_case_info, merged_case_info); + repair_cfg (merged_case_info, outer->bb); + create_merged_switch (outer, merged_case_info); + delete_basic_block (inner->bb); + delete info; + info = find_nested_switch (bb); + } while (info); + + return true; +} + + + namespace { const pass_data pass_data_flatten_switch = @@ -747,20 +751,12 @@ namespace unsigned int pass_flatten_switch::execute(function *fun) { - hash_map<basic_block, switch_info *> switches_in_bbs; - - basic_block bb; - FOR_EACH_BB_FN (bb, fun) - find_nested_switches (&switches_in_bbs, bb); - - - if (switches_in_bbs.is_empty ()) - return 0; - + //* int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun)); unsigned n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, false); + bool seen_nested_switch = false; auto_bitmap seen_bbs; for (int i = n - 1; i >= 0; --i) { @@ -769,24 +765,23 @@ namespace continue; bitmap_set_bit (seen_bbs, bb->index); - switch_info **info = switches_in_bbs.get (bb); - if (info == NULL) - continue; - merge_nested_switches(fun, *info); + seen_nested_switch |= merge_nested_switches(fun, bb); } free (rpo); - - - for (hash_map<basic_block, switch_info *>::iterator it - = switches_in_bbs.begin (); it != switches_in_bbs.end (); ++it) - delete (*it).second; + if (!seen_nested_switch) + return 0; free_dominance_info (CDI_DOMINATORS); dump_function_to_file (fun->decl, stderr, TDF_DETAILS); - return 0; + /*/ + + if (dump_file) + fprintf (dump_file, "there are %d bbs\n", n_basic_blocks_for_fn(fun)); + //*/ + return 0; }