Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv: Avoid code duplication with generic bitops implementation

There's code duplication between the fallback implementation for bitops
__ffs/__fls/ffs/fls API and the generic C implementation in
include/asm-generic/bitops/. To avoid this duplication, this patch renames
the generic C implementation by adding a "generic_" prefix to them, then we
can use these generic APIs as fallback.

Suggested-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Xiao Wang <xiao.w.wang@intel.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Link: https://lore.kernel.org/r/20231112094421.4014931-1-xiao.w.wang@intel.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>

authored by

Xiao Wang and committed by
Palmer Dabbelt
cb4ede92 05d450aa

+48 -122
+24 -114
arch/riscv/include/asm/bitops.h
··· 22 22 #include <asm-generic/bitops/fls.h> 23 23 24 24 #else 25 + #define __HAVE_ARCH___FFS 26 + #define __HAVE_ARCH___FLS 27 + #define __HAVE_ARCH_FFS 28 + #define __HAVE_ARCH_FLS 29 + 30 + #include <asm-generic/bitops/__ffs.h> 31 + #include <asm-generic/bitops/__fls.h> 32 + #include <asm-generic/bitops/ffs.h> 33 + #include <asm-generic/bitops/fls.h> 34 + 25 35 #include <asm/alternative-macros.h> 26 36 #include <asm/hwcap.h> 27 37 ··· 47 37 48 38 static __always_inline unsigned long variable__ffs(unsigned long word) 49 39 { 50 - int num; 51 - 52 40 asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 53 41 RISCV_ISA_EXT_ZBB, 1) 54 42 : : : : legacy); ··· 60 52 return word; 61 53 62 54 legacy: 63 - num = 0; 64 - #if BITS_PER_LONG == 64 65 - if ((word & 0xffffffff) == 0) { 66 - num += 32; 67 - word >>= 32; 68 - } 69 - #endif 70 - if ((word & 0xffff) == 0) { 71 - num += 16; 72 - word >>= 16; 73 - } 74 - if ((word & 0xff) == 0) { 75 - num += 8; 76 - word >>= 8; 77 - } 78 - if ((word & 0xf) == 0) { 79 - num += 4; 80 - word >>= 4; 81 - } 82 - if ((word & 0x3) == 0) { 83 - num += 2; 84 - word >>= 2; 85 - } 86 - if ((word & 0x1) == 0) 87 - num += 1; 88 - return num; 55 + return generic___ffs(word); 89 56 } 90 57 91 58 /** ··· 76 93 77 94 static __always_inline unsigned long variable__fls(unsigned long word) 78 95 { 79 - int num; 80 - 81 96 asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 82 97 RISCV_ISA_EXT_ZBB, 1) 83 98 : : : : legacy); ··· 89 108 return BITS_PER_LONG - 1 - word; 90 109 91 110 legacy: 92 - num = BITS_PER_LONG - 1; 93 - #if BITS_PER_LONG == 64 94 - if (!(word & (~0ul << 32))) { 95 - num -= 32; 96 - word <<= 32; 97 - } 98 - #endif 99 - if (!(word & (~0ul << (BITS_PER_LONG - 16)))) { 100 - num -= 16; 101 - word <<= 16; 102 - } 103 - if (!(word & (~0ul << (BITS_PER_LONG - 8)))) { 104 - num -= 8; 105 - word <<= 8; 106 - } 107 - if (!(word & (~0ul << (BITS_PER_LONG - 4)))) { 108 - num -= 4; 109 - word <<= 4; 110 - } 111 - if (!(word & (~0ul << (BITS_PER_LONG - 2)))) { 112 - num -= 2; 113 - word <<= 2; 114 - } 115 - if (!(word & (~0ul << (BITS_PER_LONG - 1)))) 116 - num -= 1; 117 - return num; 111 + return generic___fls(word); 118 112 } 119 113 120 114 /** ··· 105 149 106 150 static __always_inline int variable_ffs(int x) 107 151 { 108 - int r; 109 - 110 - if (!x) 111 - return 0; 112 - 113 152 asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 114 153 RISCV_ISA_EXT_ZBB, 1) 115 154 : : : : legacy); 155 + 156 + if (!x) 157 + return 0; 116 158 117 159 asm volatile (".option push\n" 118 160 ".option arch,+zbb\n" 119 161 CTZW "%0, %1\n" 120 162 ".option pop\n" 121 - : "=r" (r) : "r" (x) :); 163 + : "=r" (x) : "r" (x) :); 122 164 123 - return r + 1; 165 + return x + 1; 124 166 125 167 legacy: 126 - r = 1; 127 - if (!(x & 0xffff)) { 128 - x >>= 16; 129 - r += 16; 130 - } 131 - if (!(x & 0xff)) { 132 - x >>= 8; 133 - r += 8; 134 - } 135 - if (!(x & 0xf)) { 136 - x >>= 4; 137 - r += 4; 138 - } 139 - if (!(x & 3)) { 140 - x >>= 2; 141 - r += 2; 142 - } 143 - if (!(x & 1)) { 144 - x >>= 1; 145 - r += 1; 146 - } 147 - return r; 168 + return generic_ffs(x); 148 169 } 149 170 150 171 /** ··· 137 204 138 205 static __always_inline int variable_fls(unsigned int x) 139 206 { 140 - int r; 141 - 142 - if (!x) 143 - return 0; 144 - 145 207 asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 146 208 RISCV_ISA_EXT_ZBB, 1) 147 209 : : : : legacy); 210 + 211 + if (!x) 212 + return 0; 148 213 149 214 asm volatile (".option push\n" 150 215 ".option arch,+zbb\n" 151 216 CLZW "%0, %1\n" 152 217 ".option pop\n" 153 - : "=r" (r) : "r" (x) :); 218 + : "=r" (x) : "r" (x) :); 154 219 155 - return 32 - r; 220 + return 32 - x; 156 221 157 222 legacy: 158 - r = 32; 159 - if (!(x & 0xffff0000u)) { 160 - x <<= 16; 161 - r -= 16; 162 - } 163 - if (!(x & 0xff000000u)) { 164 - x <<= 8; 165 - r -= 8; 166 - } 167 - if (!(x & 0xf0000000u)) { 168 - x <<= 4; 169 - r -= 4; 170 - } 171 - if (!(x & 0xc0000000u)) { 172 - x <<= 2; 173 - r -= 2; 174 - } 175 - if (!(x & 0x80000000u)) { 176 - x <<= 1; 177 - r -= 1; 178 - } 179 - return r; 223 + return generic_fls(x); 180 224 } 181 225 182 226 /**
+6 -2
include/asm-generic/bitops/__ffs.h
··· 5 5 #include <asm/types.h> 6 6 7 7 /** 8 - * __ffs - find first bit in word. 8 + * generic___ffs - find first bit in word. 9 9 * @word: The word to search 10 10 * 11 11 * Undefined if no bit exists, so code should check against 0 first. 12 12 */ 13 - static __always_inline unsigned long __ffs(unsigned long word) 13 + static __always_inline unsigned long generic___ffs(unsigned long word) 14 14 { 15 15 int num = 0; 16 16 ··· 40 40 num += 1; 41 41 return num; 42 42 } 43 + 44 + #ifndef __HAVE_ARCH___FFS 45 + #define __ffs(word) generic___ffs(word) 46 + #endif 43 47 44 48 #endif /* _ASM_GENERIC_BITOPS___FFS_H_ */
+6 -2
include/asm-generic/bitops/__fls.h
··· 5 5 #include <asm/types.h> 6 6 7 7 /** 8 - * __fls - find last (most-significant) set bit in a long word 8 + * generic___fls - find last (most-significant) set bit in a long word 9 9 * @word: the word to search 10 10 * 11 11 * Undefined if no set bit exists, so code should check against 0 first. 12 12 */ 13 - static __always_inline unsigned long __fls(unsigned long word) 13 + static __always_inline unsigned long generic___fls(unsigned long word) 14 14 { 15 15 int num = BITS_PER_LONG - 1; 16 16 ··· 40 40 num -= 1; 41 41 return num; 42 42 } 43 + 44 + #ifndef __HAVE_ARCH___FLS 45 + #define __fls(word) generic___fls(word) 46 + #endif 43 47 44 48 #endif /* _ASM_GENERIC_BITOPS___FLS_H_ */
+6 -2
include/asm-generic/bitops/ffs.h
··· 3 3 #define _ASM_GENERIC_BITOPS_FFS_H_ 4 4 5 5 /** 6 - * ffs - find first bit set 6 + * generic_ffs - find first bit set 7 7 * @x: the word to search 8 8 * 9 9 * This is defined the same way as 10 10 * the libc and compiler builtin ffs routines, therefore 11 11 * differs in spirit from ffz (man ffs). 12 12 */ 13 - static inline int ffs(int x) 13 + static inline int generic_ffs(int x) 14 14 { 15 15 int r = 1; 16 16 ··· 38 38 } 39 39 return r; 40 40 } 41 + 42 + #ifndef __HAVE_ARCH_FFS 43 + #define ffs(x) generic_ffs(x) 44 + #endif 41 45 42 46 #endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
+6 -2
include/asm-generic/bitops/fls.h
··· 3 3 #define _ASM_GENERIC_BITOPS_FLS_H_ 4 4 5 5 /** 6 - * fls - find last (most-significant) bit set 6 + * generic_fls - find last (most-significant) bit set 7 7 * @x: the word to search 8 8 * 9 9 * This is defined the same way as ffs. 10 10 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 11 11 */ 12 12 13 - static __always_inline int fls(unsigned int x) 13 + static __always_inline int generic_fls(unsigned int x) 14 14 { 15 15 int r = 32; 16 16 ··· 38 38 } 39 39 return r; 40 40 } 41 + 42 + #ifndef __HAVE_ARCH_FLS 43 + #define fls(x) generic_fls(x) 44 + #endif 41 45 42 46 #endif /* _ASM_GENERIC_BITOPS_FLS_H_ */