[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260113122457.27507-3-jszhang@kernel.org>
Date: Tue, 13 Jan 2026 20:24:56 +0800
From: Jisheng Zhang <jszhang@...nel.org>
To: Paul Walmsley <pjw@...nel.org>,
Palmer Dabbelt <palmer@...belt.com>,
Albert Ou <aou@...s.berkeley.edu>,
Alexandre Ghiti <alex@...ti.fr>
Cc: linux-riscv@...ts.infradead.org,
linux-kernel@...r.kernel.org
Subject: [PATCH 2/3] riscv: word-at-a-time: improve find_zero() without Zbb
Previous commit improved the find_zero() performance for !RISCV_ISA_ZBB.
What about RISCV_ISA_ZBB=y but the HW doesn't support Zbb? We have the
same heavy generic fls64() issue.
Let's improve this situation by checking Zbb extension and fall back
to generic count_masked_bytes() if Zbb isn't supported.
To remove non-necessary zero bits couting on RV32, we also replace the
'fls64(mask) >> 3' with '!mask ? 0 : ((__fls(mask) + 1) >> 3);'
We will get similar performance improvement as previous commit for
RISCV_ISA_ZBB=y but HW doesn't support Zbb.
Signed-off-by: Jisheng Zhang <jszhang@...nel.org>
---
arch/riscv/include/asm/word-at-a-time.h | 29 ++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h
index 0c8a9b337f93..ca3d30741ed1 100644
--- a/arch/riscv/include/asm/word-at-a-time.h
+++ b/arch/riscv/include/asm/word-at-a-time.h
@@ -42,9 +42,36 @@ static inline unsigned long create_zero_mask(unsigned long bits)
return bits >> 7;
}
+#ifdef CONFIG_64BIT
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+ return mask*0x0001020304050608ul >> 56;
+}
+
+#else /* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+#endif
+
static inline unsigned long find_zero(unsigned long mask)
{
- return fls64(mask) >> 3;
+ if (riscv_has_extension_likely(RISCV_ISA_EXT_ZBB))
+ return !mask ? 0 : ((__fls(mask) + 1) >> 3);
+
+ return count_masked_bytes(mask);
}
/* The mask we created is directly usable as a bytemask */
--
2.51.0
Powered by blists - more mailing lists