[PATCH 16/37] MIPS: bitops: Use generic builtin ffs/fls; drop cpu_has_clo_clz

From: Paul Burton
Date: Mon Sep 30 2019 - 19:09:45 EST


The MIPS-specific implementations of __ffs(), ffs(), __fls() & fls()
make use of the MIPS clz instruction where possible. They do this via
inline asm, but in any configuration in which the kernel is built for a
MIPS32 or MIPS64 release 1 or higher instruction set we know that these
instructions are available & can be emitted using the __builtin_clz()
function & other associated builtins which are provided by all currently
supported versions of gcc.

When targeting an older instruction set GCC will generate a longer code
sequence similar to the fallback cases we have in our implementations.

As such, remove our custom implementations of these functions & use the
generic versions built atop compiler builtins. This allows us to drop a
significant chunk of code, along with the cpu_has_clo_clz feature macro
which was only used by these functions.

The only thing we lose here is the ability for kernels built to target a
pre-r1 ISA to opportunistically make use of clz when running on a CPU
that implements it. This seems like a small cost, and well worth paying
to simplify the code.

Signed-off-by: Paul Burton <paul.burton@xxxxxxxx>
---

arch/mips/include/asm/bitops.h | 146 +-----------------
arch/mips/include/asm/cpu-features.h | 10 --
.../asm/mach-malta/cpu-feature-overrides.h | 2 -
3 files changed, 4 insertions(+), 154 deletions(-)

diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
index 985d6a02f9ea..4b618afbfa5b 100644
--- a/arch/mips/include/asm/bitops.h
+++ b/arch/mips/include/asm/bitops.h
@@ -491,149 +491,11 @@ static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *
nudge_writes();
}

-/*
- * Return the bit position (0..63) of the most significant 1 bit in a word
- * Returns -1 if no 1 bit exists
- */
-static __always_inline unsigned long __fls(unsigned long word)
-{
- int num;
-
- if (BITS_PER_LONG == 32 && !__builtin_constant_p(word) &&
- __builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
- __asm__(
- " .set push \n"
- " .set "MIPS_ISA_LEVEL" \n"
- " clz %0, %1 \n"
- " .set pop \n"
- : "=r" (num)
- : "r" (word));
-
- return 31 - num;
- }
-
- if (BITS_PER_LONG == 64 && !__builtin_constant_p(word) &&
- __builtin_constant_p(cpu_has_mips64) && cpu_has_mips64) {
- __asm__(
- " .set push \n"
- " .set "MIPS_ISA_LEVEL" \n"
- " dclz %0, %1 \n"
- " .set pop \n"
- : "=r" (num)
- : "r" (word));
-
- return 63 - num;
- }
-
- num = BITS_PER_LONG - 1;
-
-#if BITS_PER_LONG == 64
- if (!(word & (~0ul << 32))) {
- num -= 32;
- word <<= 32;
- }
-#endif
- if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
- num -= 16;
- word <<= 16;
- }
- if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
- num -= 8;
- word <<= 8;
- }
- if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
- num -= 4;
- word <<= 4;
- }
- if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
- num -= 2;
- word <<= 2;
- }
- if (!(word & (~0ul << (BITS_PER_LONG-1))))
- num -= 1;
- return num;
-}
-
-/*
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Returns 0..SZLONG-1
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static __always_inline unsigned long __ffs(unsigned long word)
-{
- return __fls(word & -word);
-}
-
-/*
- * fls - find last bit set.
- * @word: The word to search
- *
- * This is defined the same way as ffs.
- * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
- */
-static inline int fls(unsigned int x)
-{
- int r;
-
- if (!__builtin_constant_p(x) &&
- __builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
- __asm__(
- " .set push \n"
- " .set "MIPS_ISA_LEVEL" \n"
- " clz %0, %1 \n"
- " .set pop \n"
- : "=r" (x)
- : "r" (x));
-
- return 32 - x;
- }
-
- r = 32;
- if (!x)
- return 0;
- if (!(x & 0xffff0000u)) {
- x <<= 16;
- r -= 16;
- }
- if (!(x & 0xff000000u)) {
- x <<= 8;
- r -= 8;
- }
- if (!(x & 0xf0000000u)) {
- x <<= 4;
- r -= 4;
- }
- if (!(x & 0xc0000000u)) {
- x <<= 2;
- r -= 2;
- }
- if (!(x & 0x80000000u)) {
- x <<= 1;
- r -= 1;
- }
- return r;
-}
-
+#include <asm-generic/bitops/builtin-__ffs.h>
+#include <asm-generic/bitops/builtin-ffs.h>
+#include <asm-generic/bitops/builtin-__fls.h>
+#include <asm-generic/bitops/builtin-fls.h>
#include <asm-generic/bitops/fls64.h>
-
-/*
- * ffs - find first bit set.
- * @word: The word to search
- *
- * This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-static inline int ffs(int word)
-{
- if (!word)
- return 0;
-
- return fls(word & -word);
-}
-
#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/find.h>

diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 983a6a7f43a1..274a35ae15af 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -362,16 +362,6 @@
})
#endif

-/*
- * MIPS32, MIPS64, VR5500, IDT32332, IDT32334 and maybe a few other
- * pre-MIPS32/MIPS64 processors have CLO, CLZ. The IDT RC64574 is 64-bit and
- * has CLO and CLZ but not DCLO nor DCLZ. For 64-bit kernels
- * cpu_has_clo_clz also indicates the availability of DCLO and DCLZ.
- */
-#ifndef cpu_has_clo_clz
-#define cpu_has_clo_clz cpu_has_mips_r
-#endif
-
/*
* MIPS32 R2, MIPS64 R2, Loongson 3A and Octeon have WSBH.
* MIPS64 R2, Loongson 3A and Octeon have WSBH, DSBH and DSHD.
diff --git a/arch/mips/include/asm/mach-malta/cpu-feature-overrides.h b/arch/mips/include/asm/mach-malta/cpu-feature-overrides.h
index de3b66a3723e..193c0912d38e 100644
--- a/arch/mips/include/asm/mach-malta/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-malta/cpu-feature-overrides.h
@@ -32,7 +32,6 @@
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
-#define cpu_has_clo_clz 1
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
@@ -59,7 +58,6 @@
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
-#define cpu_has_clo_clz 1
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
--
2.23.0