diff --git a/gcc/common.opt b/gcc/common.opt index d4cbb2f86a554fa2f87e52b2b6cbd1de27ddaa31..7d0e0d9c88a8a7b1f233cdbb422c2f7f38c67525 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1940,6 +1940,10 @@ fjump-tables Common Var(flag_jump_tables) Init(1) Optimization Use jump tables for sufficiently large switch statements. +fbit-tests +Common Var(flag_bit_tests) Init(1) Optimization +Use bit tests for sufficiently large switch statements. + fkeep-inline-functions Common Report Var(flag_keep_inline_functions) Generate code for functions even if they are fully inlined. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 32f90ef20229a1e0617e21fee89926f9cfff043e..271373c381bfc6b0630a55324448b5382e36ae68 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -638,7 +638,7 @@ Objective-C and Objective-C++ Dialects}. -fno-gnu-unique @gol -finhibit-size-directive -fcommon -fno-ident @gol -fpcc-struct-return -fpic -fPIC -fpie -fPIE -fno-plt @gol --fno-jump-tables @gol +-fno-jump-tables -fno-bit-tests @gol -frecord-gcc-switches @gol -freg-struct-return -fshort-enums -fshort-wchar @gol -fverbose-asm -fpack-struct[=@var{n}] @gol @@ -15989,6 +15989,12 @@ building code that forms part of a dynamic linker and cannot reference the address of a jump table. On some targets, jump tables do not require a GOT and this option is not needed. +@item -fno-bit-tests +@opindex fno-bit-tests +@opindex fbit-tests +Do not use bit tests for switch statements even where it would be +more efficient than other code generation strategies. + @item -ffixed-@var{reg} @opindex ffixed Treat the register named @var{reg} as a fixed register; generated code diff --git a/gcc/testsuite/gcc.dg/tree-ssa/switch-4.c b/gcc/testsuite/gcc.dg/tree-ssa/switch-4.c new file mode 100644 index 0000000000000000000000000000000000000000..5953ef34e9b5eb1da5f2cc5d9cb67050a6741870 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/switch-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target { { x86_64-*-* aarch64-*-* ia64-*-* powerpc64-*-* } && lp64 } } } */ +/* { dg-options "-O2 -fno-bit-tests -fdump-tree-switchlower1" } */ + +int global; + +int foo (int x) +{ + switch (x) { + case 0: + case 10: + return 1; + case 20: + case 30: + case 62: + return 2; + case 1000: + case 1010: + case 1025 ... 1030: + return 1; + default: + return 0; + } +} + +/* { dg-final { scan-tree-dump-not "BT:" "switchlower1" } } */ diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index 03a1fe632d0a20720be5176662c64593aa5875f1..426462e856bebea5646d4ae804b726ac1e846606 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -1310,6 +1310,9 @@ jump_table_cluster::is_beneficial (const vec<cluster *> &, vec<cluster *> bit_test_cluster::find_bit_tests (vec<cluster *> &clusters) { + if (!is_enabled ()) + return clusters.copy (); + unsigned l = clusters.length (); auto_vec<min_cluster_item> min; min.reserve (l + 1); diff --git a/gcc/tree-switch-conversion.h b/gcc/tree-switch-conversion.h index dbfd9eecba22c9091d0e3b6ebae8ec1912977283..7515e952eb361c855df686795f302c30b342b763 100644 --- a/gcc/tree-switch-conversion.h +++ b/gcc/tree-switch-conversion.h @@ -411,6 +411,12 @@ public: basic_block case_bb, profile_probability prob); + /* Return whether bit test expansion is allowed. */ + static inline bool is_enabled (void) + { + return flag_bit_tests; + } + /* True when the jump table handles an entire switch statement. */ bool m_handles_entire_switch;