addi+and keeps a 32 bit object sign extended on rv64, bclr does not:
clearing bit 31 leaves 0xffffffff00000000, so the loop
(m = x; m; m &= m - 1) never terminates.
A sext.w would fix that, but ctzw+bclr+sext.w is no shorter than
ctzw+addiw+and and one instruction deeper, so leave the 32 bit case
alone.
Wrong code since r16-3984-g4f01f39d021; it hangs rte_softrss() in DPDK
built with -march=rva23u64.
gcc/
* config/riscv/riscv-bclr-lowest-set-bit.cc
(pass_bclr_lowest_set_bit::execute): Skip a decrement wrapped in
a SIGN_EXTEND.
gcc/testsuite/
* gcc.target/riscv/bclr-lowest-set-bit-1.c: Expect addi+and for
the unsigned int cases on rv64.
* gcc.target/riscv/bclr-lowest-set-bit-2.c: New test.
Signed-off-by: Sun Yuechi <[email protected]>
---
v2: skip the SIGN_EXTEND case instead of extending the result, and
update bclr-lowest-set-bit-1.c for rv64.
Regtested on riscv64-linux-gnu (16.1.0 tree), no regressions.
gcc/config/riscv/riscv-bclr-lowest-set-bit.cc | 6 ++--
.../gcc.target/riscv/bclr-lowest-set-bit-1.c | 6 ++--
.../gcc.target/riscv/bclr-lowest-set-bit-2.c | 31 +++++++++++++++++++
3 files changed, 38 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-2.c
diff --git a/gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
b/gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
index ecfa511a882..4907518e2ee 100644
--- a/gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
+++ b/gcc/config/riscv/riscv-bclr-lowest-set-bit.cc
@@ -193,10 +193,10 @@ pass_bclr_lowest_set_bit::execute (function *fn)
rtx dec_src = SET_SRC (dec_set);
rtx dec_dest = SET_DEST (dec_set);
- /* For a 32 bit object on rv64, the decrement will
- be wrapped by a SIGN_EXTEND. Strip it. */
+ /* For a 32 bit object on rv64 the decrement is wrapped by a
+ SIGN_EXTEND. bclr would not keep the result sign extended. */
if (GET_CODE (dec_src) == SIGN_EXTEND)
- dec_src = XEXP (dec_src, 0);
+ continue;
/* Verify it's res = x - 1, if not proceed to the next insn. */
if (!dec_set
diff --git a/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-1.c
b/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-1.c
index fa201cec359..211f3cb6a40 100644
--- a/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-1.c
+++ b/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-1.c
@@ -123,6 +123,8 @@ void foo12(unsigned long x)
foo12_res2 = tz;
}
-/* { dg-final { scan-assembler-not "\\sand\\s" } } */
-/* { dg-final { scan-assembler-times "\\sbclr\\s" 12 } } */
+/* { dg-final { scan-assembler-not "\\sand\\s" { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\sbclr\\s" 12 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\sand\\s" 6 { target rv64 } } } */
+/* { dg-final { scan-assembler-times "\\sbclr\\s" 6 { target rv64 } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-2.c
b/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-2.c
new file mode 100644
index 00000000000..0c36817c103
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bclr-lowest-set-bit-2.c
@@ -0,0 +1,31 @@
+/* { dg-do run { target { rv64 && riscv_b_ok } } } */
+/* { dg-options "-march=rv64gc_zbb_zbs -mabi=lp64d -O2 -save-temps" } */
+
+/* If bclr replaces the addiw+and, this loop never terminates. */
+
+extern void abort (void);
+
+__attribute__((noipa)) unsigned
+bit_walk (unsigned x)
+{
+ unsigned r = 0;
+ unsigned guard = 0;
+
+ for (unsigned m = x; m; m &= m - 1)
+ {
+ if (++guard > 32)
+ abort ();
+ r += (unsigned) __builtin_ctz (m);
+ }
+ return r;
+}
+
+int
+main (void)
+{
+ if (bit_walk (0x80000001u) != 31)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "\\sbclr\\s" } } */
base-commit: 919c0d16c91c930c374db6665f55595653511636
--
2.55.0