On Thu, May 30, 2024 at 5:09 AM Filip Kastl <fka...@suse.cz> wrote: > > Hi, > > This patch adds a transformation into the switch conversion pass -- > the "exponential index transform". This transformation can help switch > conversion convert switches it otherwise could not. The transformation is > intended for switches whose cases are all powers of 2. Here is a more > detailed > description of what and how this patch tries to address: > > > The problem > ----------- > > Consider this piece of C code > > switch (i) > { > case (1 << 0): return 0; > case (1 << 1): return 1; > case (1 << 2): return 2; > ... > case (1 << 30): return 30; > default: return 31; > } > > If i is a power of 2 (2^k), the switch just returns the exponent (k). This > can > be seen as taking the base 2 logarithm of i or as returning the position of > the > singular 1 bit in i. > > Currently, GCC fails to see this and doesn't optimize the switch in any way. > > Switch conversion is able to optimize similar switches to an array lookup. > This is not possible here because the range of cases is too wide. Another > optimization that switch conversion is able to do is the "linear > transformation" -- switch conversion is able to notice a linear relationship > between the index variable (variable i in the case) and the result value and > rewrite switch to just an assignment (or multiple assignments in case of > multiple result values). Sadly, linear transformation isn't applicable here > because the linear relationship is based on the exponent of i, not on i > itself. > > > The solution > ------------ > > The exponential index transformation does the following. When it recognises > that a switch only has case numbers that are powers of 2 it replaces them with > their exponents. It also replaces the index variable by its exponent. This > is > done by inserting a statement that takes the logarithm of i and using the > result as the new index variable. Actually we use the FFS operation for this > -- since we expect a power of two, we may just ask for the position of the > first 1 bit. > > We also need to insert a conditional that checks at runtime that the index > variable is a power of two. If it isn't, the resulting value should just be > the default case value (31 in the example above). > > With exponential index transform, switch conversion is able to simplify the > above example into something like this > > if (i is power of 2) > return log2(i); // actually implemented as ffs(i) - 1 > else > return 31; > > Switch conversion bails if the range of case numbers is too big. Exponential > index transform shrinks this range (exponentially). So even if there is no > linear relationship in the switch, exponential index transform can still help > convert the switch at least to an array lookup. > > > Limitations > ----------- > > Currently we only run the exponential index transform if the target has the > POPCOUNT (for checking a number is a power of 2) and FFS (for taking the > logarithm) instructions -- we check direct_internal_fn_supported_p () for > POPCOUNT and FFS internal functions. Otherwise maybe computing FFS could be > less efficient than just using a jump table. We try to avoid transforming a > switch into a less efficient form. Maybe this is too conservative and could > be > tweaked in the future. > > > Bootstrapped and regtested on x86_64 linux. I have additionally run bootstrap > and regtest on a version where I removed the check that the target has the > POPCOUNT and FFS instructions so that the transformation would be triggered > more often. That testing also went well. > > Are there any things I should tweak? Or is the patch ready to be applied? > > Cheers, > Filip Kastl > > > -- 8< -- > > > Sometimes a switch has case numbers that are powers of 2. Switch > conversion usually isn't able to optimize switches. This patch adds > "exponential index transformation" to switch conversion. After switch > conversion applies this transformation on the switch the index variable > of the switch becomes the exponent instead of the whole value. For > example: > > switch (i) > { > case (1 << 0): return 0; > case (1 << 1): return 1; > case (1 << 2): return 2; > ... > case (1 << 30): return 30; > default: return 31; > } > > gets transformed roughly into > > switch (log2(i)) > { > case 0: return 0; > case 1: return 1; > case 2: return 2; > ... > case 30: return 30; > default: return 31; > } > > This enables switch conversion to further optimize the switch. > > This patch only enables this transformation if there are optabs for > POPCOUNT and FFS so that the base 2 logarithm can be computed > efficiently at runtime. > > gcc/ChangeLog: > > * tree-switch-conversion.cc (switch_conversion::switch_conversion): > Track if the transformation happened. > (switch_conversion::is_exp_index_transform_viable): New function > to decide whether the transformation should be applied. > (switch_conversion::exp_index_transform): New function to > execute the transformation. > (switch_conversion::gen_inbound_check): Don't remove the default > BB if the transformation happened. > (switch_conversion::expand): Execute the transform if it is > viable. Skip test for sufficiently small case range if the > transformation is going to be executed. > * tree-switch-conversion.h: Add is_exp_index_transform viable > and exp_index_transform. > > gcc/testsuite/ChangeLog: > > * gcc.target/i386/switch-exp-transform-1.c: New test. > * gcc.target/i386/switch-exp-transform-2.c: New test. > * gcc.target/i386/switch-exp-transform-3.c: New test. > > Signed-off-by: Filip Kastl <fka...@suse.cz> > --- > .../gcc.target/i386/switch-exp-transform-1.c | 34 +++ > .../gcc.target/i386/switch-exp-transform-2.c | 36 +++ > .../gcc.target/i386/switch-exp-transform-3.c | 151 +++++++++ > gcc/tree-switch-conversion.cc | 289 +++++++++++++++++- > gcc/tree-switch-conversion.h | 18 ++ > 5 files changed, 523 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/switch-exp-transform-1.c > create mode 100644 gcc/testsuite/gcc.target/i386/switch-exp-transform-2.c > create mode 100644 gcc/testsuite/gcc.target/i386/switch-exp-transform-3.c > > diff --git a/gcc/testsuite/gcc.target/i386/switch-exp-transform-1.c > b/gcc/testsuite/gcc.target/i386/switch-exp-transform-1.c > new file mode 100644 > index 00000000000..d51dd110623 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/switch-exp-transform-1.c > @@ -0,0 +1,34 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-switchconv -march=znver3" } */ > + > +/* Checks that exponential index transform enables switch conversion to > convert > + this switch into an array lookup. Also checks that the "index variable > is a > + power of two" check has been generated. -march=znver3 because that > + microarchitecture supports POPCOUNT and FFS instructions and exponential > + index transform requires that. */ > + > +int foo(unsigned bar) > +{ > + switch (bar) > + { > + case (1 << 0): > + return 1; > + case (1 << 1): > + return 2; > + case (1 << 2): > + return 3; > + case (1 << 3): > + return 4; > + case (1 << 4): > + return 8; > + case (1 << 5): > + return 13; > + case (1 << 6): > + return 21; > + default: > + return 0; > + } > +} > + > +/* { dg-final { scan-tree-dump "CSWTCH" "switchconv" } } */ > +/* { dg-final { scan-tree-dump "POPCOUNT" "switchconv" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/switch-exp-transform-2.c > b/gcc/testsuite/gcc.target/i386/switch-exp-transform-2.c > new file mode 100644 > index 00000000000..9f2b536aa74 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/switch-exp-transform-2.c > @@ -0,0 +1,36 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-switchconv -march=znver3" } */ > + > +/* Checks that when exponential index transform is viable but switch > conversion > + decides that the switch cannot be converted, the exponential index > transform > + is not done. -march=znver3 because that microarchitecture supports > POPCOUNT > + and FFS instructions and exponential index transform requires that. */ > + > +int a; > + > +int foo(unsigned bar) > +{ > + switch (bar) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + a = 3; > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +/* { dg-final { scan-tree-dump "Exponential index transform viable" > "switchconv" } } */ > +/* { dg-final { scan-tree-dump-not "Applying exponential index transform" > "switchconv" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/switch-exp-transform-3.c > b/gcc/testsuite/gcc.target/i386/switch-exp-transform-3.c > new file mode 100644 > index 00000000000..e9665d4a38d > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/switch-exp-transform-3.c > @@ -0,0 +1,151 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-switchconv -march=znver3" } */ > + > +/* Checks that the exponential index transformation is done for all these > types > + of the index variable: > + - (unsigned) int > + - (unsigned) long > + - (unsigned) long long > + > + -march=znver3 because that microarchitecture supports POPCOUNT > + and FFS instructions and exponential index transform requires that. */ > + > +int unopt_int(int bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +int unopt_unsigned_int(unsigned int bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +int unopt_long(long bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +int unopt_unsigned_long(unsigned long bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +int unopt_long_long(long long bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +int unopt_unsigned_long_long(unsigned long long bit_position) > +{ > + switch (bit_position) > + { > + case (1 << 0): > + return 0; > + case (1 << 1): > + return 1; > + case (1 << 2): > + return 2; > + case (1 << 3): > + return 3; > + case (1 << 4): > + return 4; > + case (1 << 5): > + return 5; > + case (1 << 6): > + return 6; > + default: > + return 0; > + } > +} > + > +/* { dg-final { scan-tree-dump-times "Applying exponential index transform" > 6 "switchconv" } } */ > diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc > index 3a5b84c09e2..975888c0969 100644 > --- a/gcc/tree-switch-conversion.cc > +++ b/gcc/tree-switch-conversion.cc > @@ -52,6 +52,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, > Boston, MA > #include "omp-general.h" > #include "gimple-range.h" > #include "tree-cfgcleanup.h" > +#include "hwint.h" > +#include "internal-fn.h" > > /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode > type in the GIMPLE type system that is language-independent? */ > @@ -66,7 +68,8 @@ using namespace tree_switch_conversion; > switch_conversion::switch_conversion (): m_final_bb (NULL), > m_constructors (NULL), m_default_values (NULL), > m_arr_ref_first (NULL), m_arr_ref_last (NULL), > - m_reason (NULL), m_default_case_nonstandard (false), m_cfg_altered (false) > + m_reason (NULL), m_default_case_nonstandard (false), m_cfg_altered (false), > + m_exp_index_transform_applied (false) > { > } > > @@ -202,6 +205,267 @@ switch_conversion::collect (gswitch *swtch) > } > } > > +/* Check that the "exponential index transform" can be applied to this > switch. > + > + See comment of the exp_index_transform function for details about this > + transformation. > + > + We want: > + - This form of the switch is more efficient > + - Cases are powers of 2 > + > + Expects that SWTCH has at least one case. */ > + > +bool > +switch_conversion::is_exp_index_transform_viable (gswitch *swtch) > +{ > + tree index = gimple_switch_index (swtch); > + tree index_type = TREE_TYPE (index); > + basic_block swtch_bb = gimple_bb (swtch); > + unsigned num_labels = gimple_switch_num_labels (swtch); > + > + /* Check that we can efficiently compute logarithm of 2^k (using FFS) and > + test that a given number is 2^k for some k (using POPCOUNT). */ > + optimization_type opt_type = bb_optimization_type (swtch_bb); > + if (!direct_internal_fn_supported_p (IFN_FFS, index_type, opt_type) > + || !direct_internal_fn_supported_p (IFN_POPCOUNT, index_type, opt_type)) > + return false; > + > + /* Check that each case label corresponds only to one value > + (no case 1..3). */ > + unsigned i; > + for (i = 1; i < num_labels; i++) > + { > + tree label = gimple_switch_label (swtch, i); > + if (CASE_HIGH (label)) > + return false; > + } > + > + /* Check that each label is nonnegative. */ > + for (i = 1; i < num_labels; i++) > + { > + tree label = gimple_switch_label (swtch, i); > + if (!tree_fits_uhwi_p (CASE_LOW (label))) > + return false; > + } > + > + /* Check that each case is a power of 2. */ > + for (i = 1; i < num_labels; i++) > + { > + tree label = gimple_switch_label (swtch, i); > + unsigned HOST_WIDE_INT label_hwi = tree_to_uhwi (CASE_LOW (label));
I Know you check tree_fits_uhwi_p above but couldn't you use wide_int::exact_log2 here instead? That is I am not a fan of using tree_to_uhwi but rather using wide_int. Also the use of direct_internal_fn_supported_p seems too early since you could figure out the widest value in use and use that to see what mode/type to use. Thanks, Andrew > + if (!pow2p_hwi (label_hwi)) > + return false; > + } > + > + if (dump_file) > + fprintf (dump_file, "Exponential index transform viable\n"); > + > + return true; > +} > + > +/* Perform the "exponential index transform". > + > + Assume that cases of SWTCH are powers of 2. The transformation replaces > the > + cases by their exponents (2^k -> k). It also inserts a statement that > + computes the exponent of the original index variable (basically taking the > + logarithm) and then sets the result as the new index variable. > + > + The transformation also inserts a conditional statement checking that the > + incoming original index variable is a power of 2 with the false edge > leading > + to the default case. > + > + The exponential index transform shrinks the range of case numbers which > + helps switch conversion convert switches it otherwise could not. > + > + Consider for example: > + > + switch (i) > + { > + case (1 << 0): return 0; > + case (1 << 1): return 1; > + case (1 << 2): return 2; > + ... > + case (1 << 30): return 30; > + default: return 31; > + } > + > + First, exponential index transform gets applied. Since each case becomes > + case x: return x;, the rest of switch conversion is then able to get rid > of > + the switch statement. > + > + if (i is power of 2) > + return log2 (i); > + else > + return 31; > + > + */ > + > +void > +switch_conversion::exp_index_transform (gswitch *swtch) > +{ > + if (dump_file) > + fprintf (dump_file, "Applying exponential index transform\n"); > + > + tree index = gimple_switch_index (swtch); > + tree index_type = TREE_TYPE (index); > + basic_block swtch_bb = gimple_bb (swtch); > + unsigned num_labels = gimple_switch_num_labels (swtch); > + tree one = build_one_cst (index_type); > + > + /* Insert a cond stmt that checks if the index variable is a power of 2. > */ > + gimple_stmt_iterator gsi = gsi_for_stmt (swtch); > + gsi_prev (&gsi); > + gimple *foo = gsi_stmt (gsi); > + edge new_edge1 = split_block (swtch_bb, foo); > + > + swtch_bb = new_edge1->dest; > + basic_block cond_bb = new_edge1->src; > + new_edge1->flags |= EDGE_TRUE_VALUE; > + new_edge1->flags &= ~EDGE_FALLTHRU; > + new_edge1->probability = profile_probability::even (); > + > + basic_block default_bb = gimple_switch_default_bb (cfun, swtch); > + edge new_edge2 = make_edge (cond_bb, default_bb, EDGE_FALSE_VALUE); > + new_edge2->probability = profile_probability::even (); > + > + gsi = gsi_last_bb (cond_bb); > + > + tree tmp1 = make_ssa_name (index_type); > + gcall *stmt_popcount = gimple_build_call_internal (IFN_POPCOUNT, 2, index, > + one); > + gimple_call_set_lhs (stmt_popcount, tmp1); > + gsi_insert_after (&gsi, stmt_popcount, GSI_NEW_STMT); > + > + gcond *stmt_cond = gimple_build_cond (EQ_EXPR, tmp1, one, NULL, NULL); > + gsi_insert_after (&gsi, stmt_cond, GSI_NEW_STMT); > + > + /* We just added an edge going to default bb so fix PHI nodes in that bb: > + For each PHI add new PHI arg. It will be the same arg as when comming > to > + the default bb from the switch bb. */ > + edge default_edge = find_edge (swtch_bb, default_bb); > + for (gphi_iterator gsi = gsi_start_phis (default_bb); > + !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gphi *phi = gsi.phi (); > + tree arg = PHI_ARG_DEF_FROM_EDGE (phi, default_edge); > + location_t loc = gimple_phi_arg_location_from_edge (phi, default_edge); > + add_phi_arg (phi, arg, new_edge2, loc); > + } > + > + /* Insert a statement that takes the logarithm of the index variable. */ > + tree tmp2 = make_ssa_name (index_type); > + gsi = gsi_start_bb (swtch_bb); > + gcall *stmt_ffs = gimple_build_call_internal (IFN_FFS, 1, index); > + gimple_call_set_lhs (stmt_ffs, tmp2); > + gsi_insert_before (&gsi, stmt_ffs, GSI_SAME_STMT); > + > + tree tmp3 = make_ssa_name (index_type); > + gassign *stmt_minus_one = gimple_build_assign (tmp3, MINUS_EXPR, tmp2, > one); > + gsi_insert_before (&gsi, stmt_minus_one, GSI_SAME_STMT); > + > + /* Use the result of the logarithm as the new index variable. */ > + gimple_switch_set_index (swtch, tmp3); > + update_stmt (swtch); > + > + /* Replace each case number with its logarithm. */ > + unsigned i; > + for (i = 1; i < num_labels; i++) > + { > + tree label = gimple_switch_label (swtch, i); > + unsigned HOST_WIDE_INT label_hwi = tree_to_uhwi (CASE_LOW (label)); > + CASE_LOW (label) = build_int_cst (index_type, floor_log2 (label_hwi)); > + } > + > + /* Fix the dominator tree, if it is available. */ > + if (dom_info_available_p (CDI_DOMINATORS)) > + { > + /* Analysis of how dominators should look after we add the edge E going > + from the cond block to the default block. > + > + 1 For the blocks between the switch block and the final block > + (excluding the final block itself): They had the switch block as > + their immediate dominator. That shouldn't change. > + > + 2 The final block may now have the switch block or the cond block as > + its immediate dominator. There's no easy way of knowing (consider > + two cases where in both m_default_case_nonstandard = true, in one a > + path through default intersects the final block and in one all paths > + through default avoid the final block but intersect a successor of > the > + final block). > + > + 3 Other blocks that had the switch block as their immediate dominator > + should now have the cond block as their immediate dominator. > + > + 4 Immediate dominators of the rest of the blocks shouldn't change. > + > + Reasoning for 3 and 4: > + > + We'll only consider blocks that do not fall into 1 or 2. > + > + Consider a block X whose original imm dom was the switch block. All > + paths to X must also intersect the cond block since it's the only > + pred of the switch block. The final block doesn't dominate X so at > + least one path P must lead through the default block. Let P' be P > but > + instead of going through the switch block, take E. The switch block > + doesn't dominate X so its imm dom must now be the cond block. > + > + Consider a block X whose original imm dom was Y != the switch block. > + We only added an edge so all original paths to X are still present. > + So X gained no new dominators. Observe that Y still dominates X. > + There would have to be a path that avoids Y otherwise. But any block > + we can avoid now except for the switch block we were able to avoid > + before adding E. */ > + > + redirect_immediate_dominators (CDI_DOMINATORS, swtch_bb, cond_bb); > + > + /* FIXME: Since exponential transform is run only if we know that the > + switch will be converted, we know these blocks will be removed and we > + maybe don't have to bother updating their dominators. */ > + edge e; > + edge_iterator ei; > + FOR_EACH_EDGE (e, ei, swtch_bb->succs) > + { > + basic_block bb = e->dest; > + if (bb == m_final_bb || bb == default_bb) > + continue; > + set_immediate_dominator (CDI_DOMINATORS, bb, swtch_bb); > + } > + > + vec<basic_block> v; > + v.create (1); > + v.quick_push (m_final_bb); > + iterate_fix_dominators (CDI_DOMINATORS, v, true); > + } > + > + /* Update information about the switch statement. */ > + tree first_label = gimple_switch_label (swtch, 1); > + tree last_label = gimple_switch_label (swtch, num_labels - 1); > + > + m_range_min = CASE_LOW (first_label); > + m_range_max = CASE_LOW (last_label); > + m_index_expr = gimple_switch_index (swtch); > + m_switch_bb = swtch_bb; > + > + unsigned HOST_WIDE_INT range_size_hwi = tree_to_uhwi (m_range_max) > + - tree_to_uhwi (m_range_min); > + m_range_size = build_int_cst (index_type, range_size_hwi); > + > + m_cfg_altered = true; > + > + m_contiguous_range = true; > + unsigned HOST_WIDE_INT last_hwi = tree_to_uhwi (CASE_LOW (first_label)); > + for (i = 2; i < num_labels; i++) > + { > + tree label = gimple_switch_label (swtch, i); > + unsigned HOST_WIDE_INT label_hwi = tree_to_uhwi (CASE_LOW (label)); > + m_contiguous_range &= last_hwi + 1 == label_hwi; > + last_hwi = label_hwi; > + } > + > + m_exp_index_transform_applied = true; > +} > + > /* Checks whether the range given by individual case statements of the switch > switch statement isn't too big and whether the number of branches actually > satisfies the size of the new array. */ > @@ -973,8 +1237,9 @@ switch_conversion::gen_inbound_check () > bbf->count = e1f->count () + e2f->count (); > > /* Tidy blocks that have become unreachable. */ > - prune_bbs (bbd, m_final_bb, > - m_default_case_nonstandard ? m_default_bb : NULL); > + bool prune_default_bb = !m_default_case_nonstandard > + && !m_exp_index_transform_applied; > + prune_bbs (bbd, m_final_bb, prune_default_bb ? NULL : m_default_bb); > > /* Fixup the PHI nodes in bbF. */ > fix_phi_nodes (e1f, e2f, bbf); > @@ -1053,8 +1318,19 @@ switch_conversion::expand (gswitch *swtch) > return; > } > > - /* Check the case label values are within reasonable range: */ > - if (!check_range ()) > + /* Sometimes it is possible to use the "exponential index transform" to > help > + switch conversion convert switches which it otherwise could not convert. > + However, we want to do this transform only when we know that switch > + conversion will then really be able to convert the switch. So we first > + check if the transformation is applicable and then maybe later do the > + transformation. */ > + bool exp_transform_viable = is_exp_index_transform_viable (swtch); > + > + /* Check the case label values are within reasonable range. > + > + If we will be doing exponential index transform, the range will be > always > + reasonable. */ > + if (!exp_transform_viable && !check_range ()) > { > gcc_assert (m_reason); > return; > @@ -1076,6 +1352,9 @@ switch_conversion::expand (gswitch *swtch) > /* At this point all checks have passed and we can proceed with the > transformation. */ > > + if (exp_transform_viable) > + exp_index_transform (swtch); > + > create_temp_arrays (); > gather_default_values (m_default_case_nonstandard > ? gimple_switch_label (swtch, 1) > diff --git a/gcc/tree-switch-conversion.h b/gcc/tree-switch-conversion.h > index 6939eec6018..1a865f85f3a 100644 > --- a/gcc/tree-switch-conversion.h > +++ b/gcc/tree-switch-conversion.h > @@ -743,6 +743,19 @@ public: > /* Collection information about SWTCH statement. */ > void collect (gswitch *swtch); > > + /* Check that the 'exponential index transform' can be applied. > + > + See the comment at the function definition for more details. */ > + bool is_exp_index_transform_viable (gswitch *swtch); > + > + /* Perform the 'exponential index transform'. > + > + The exponential index transform shrinks the range of case numbers which > + helps switch conversion convert switches it otherwise could not. > + > + See the comment at the function definition for more details. */ > + void exp_index_transform (gswitch *swtch); > + > /* Checks whether the range given by individual case statements of the > switch > switch statement isn't too big and whether the number of branches > actually > satisfies the size of the new array. */ > @@ -900,6 +913,11 @@ public: > > /* True if CFG has been changed. */ > bool m_cfg_altered; > + > + /* True if exponential index transform has been applied. See the comment > at > + the definition of exp_index_transform for details about the > + transformation. */ > + bool m_exp_index_transform_applied; > }; > > void > -- > 2.45.0 > >