In platforms where can_open_code_p might return false for bitreverse we
still allow emitting it, if expand_bitreverse can emit code for it.
This usually requires bswap to exist.  This fixes some minor regressions
where bswap was recognized but bitreverse is not available.

gcc/ChangeLog:

        * gimple-ssa-store-merging.cc (can_open_bitreverse_p): New.
        (pass_optimize_bswap::execute): Use can_open_bitreverse_p.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/builtin-bitreverse-2.c: New test.

Signed-off-by: David Guillen Fandos <[email protected]>
---
 gcc/gimple-ssa-store-merging.cc               | 30 ++++++++++++++++---
 .../gcc.target/i386/builtin-bitreverse-2.c    | 16 ++++++++++
 2 files changed, 42 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/builtin-bitreverse-2.c

diff --git a/gcc/gimple-ssa-store-merging.cc b/gcc/gimple-ssa-store-merging.cc
index 43b08ded1d8..465b1d13861 100644
--- a/gcc/gimple-ssa-store-merging.cc
+++ b/gcc/gimple-ssa-store-merging.cc
@@ -275,6 +275,28 @@ sym_is_range_zero (const uint8_t *n, unsigned int start, 
unsigned int count)
   return true;
 }
 
+/* Return true if we can implement bitreverse for mode MODE.  This is true
+   if there are instructions for it or a libfunc call.  Also true if
+   expand_bitreverse can emit code (this requires bswap).
+*/
+
+static bool
+can_open_bitreverse_p (machine_mode mode)
+{
+  if (can_implement_p (bitreverse_optab, mode))
+    return true;
+
+  scalar_int_mode int_mode;
+  if (is_a<scalar_int_mode> (mode, &int_mode))
+    {
+      int precision = GET_MODE_BITSIZE (int_mode);
+      if (precision < 16 || can_open_code_p (bswap_optab, mode))
+       return true;
+    }
+
+  return false;
+}
+
 /* Perform a SHIFT or ROTATE operation by COUNT bits on symbolic
    number N.  Return false if the requested operation is not permitted
    on a symbolic number.  */
@@ -1642,13 +1664,13 @@ pass_optimize_bswap::execute (function *fun)
               && can_open_code_p (bswap_optab, DImode));
 
   bitrev8_p = (builtin_decl_explicit_p (BUILT_IN_BITREVERSE8)
-               && can_open_code_p (bitreverse_optab, QImode));
+               && can_open_bitreverse_p (QImode));
   bitrev16_p = (builtin_decl_explicit_p (BUILT_IN_BITREVERSE16)
-               && can_open_code_p (bitreverse_optab, HImode));
+               && can_open_bitreverse_p (HImode));
   bitrev32_p = (builtin_decl_explicit_p (BUILT_IN_BITREVERSE32)
-               && can_open_code_p (bitreverse_optab, SImode));
+               && can_open_bitreverse_p (SImode));
   bitrev64_p = (builtin_decl_explicit_p (BUILT_IN_BITREVERSE64)
-               && can_open_code_p (bitreverse_optab, DImode));
+               && can_open_bitreverse_p (DImode));
 
   /* Determine the argument type of the builtins.  The code later on
      assumes that the return and argument type are the same.  */
diff --git a/gcc/testsuite/gcc.target/i386/builtin-bitreverse-2.c 
b/gcc/testsuite/gcc.target/i386/builtin-bitreverse-2.c
new file mode 100644
index 00000000000..7c9596a8ec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-bitreverse-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-gfni" } */
+
+/* Check that bit reverse is still recognized and expanded using bswap.  */
+
+unsigned int
+bitr1(unsigned int x) {
+  x = (x & 0x55555555) <<  1 | (x & 0xAAAAAAAA) >>  1;
+  x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
+  x = (x & 0x33333333) <<  2 | (x & 0xCCCCCCCC) >>  2;
+  x = (x & 0x00FF00FF) <<  8 | (x & 0xFF00FF00) >>  8;
+  x = (x & 0x0F0F0F0F) <<  4 | (x & 0xF0F0F0F0) >>  4;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times "bswap" 1 } } */
-- 
2.55.0

Reply via email to