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