int ret;
if (__builtin_constant_p(x))
- return generic_fls(x);
+ return generic_flsl(x);
asm("clz\t%"__OP32"0, %"__OP32"1" : "=r" (ret) : "r" (x));
return 32 - ret;
}
#define flsl(x) generic_flsl(x)
-#define fls(x) generic_fls(x)
+#define fls(x) generic_flsl(x)
#define ffs(x) ({ unsigned int t_ = (x); fls(t_ & -t_); })
#define ffsl(x) ({ unsigned long t_ = (x); flsl(t_ & -t_); })
(((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LLONG - 1 - (h))))
/*
- * ffs: find first bit set. 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 generic_ffs(unsigned int x)
-{
- int r = 1;
-
- if (!x)
- return 0;
- if (!(x & 0xffff)) {
- x >>= 16;
- r += 16;
- }
- if (!(x & 0xff)) {
- x >>= 8;
- r += 8;
- }
- if (!(x & 0xf)) {
- x >>= 4;
- r += 4;
- }
- if (!(x & 3)) {
- x >>= 2;
- r += 2;
- }
- if (!(x & 1)) {
- x >>= 1;
- r += 1;
- }
- return r;
-}
-
-/*
- * fls: find last bit set.
+ * Find First/Last Set bit (all forms).
+ *
+ * Bits are labelled from 1. Returns 0 if given 0.
*/
-
-static inline int generic_fls(unsigned int x)
-{
- int 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;
-}
-
-#if BITS_PER_LONG == 64
-
-static inline int generic_ffsl(unsigned long x)
-{
- return !x || (u32)x ? generic_ffs(x) : generic_ffs(x >> 32) + 32;
-}
-
-static inline int generic_flsl(unsigned long x)
-{
- u32 h = x >> 32;
-
- return h ? generic_fls(h) + 32 : generic_fls(x);
-}
-
-#else
-# define generic_ffsl generic_ffs
-# define generic_flsl generic_fls
-#endif
+unsigned int __pure generic_ffsl(unsigned long x);
+unsigned int __pure generic_flsl(unsigned long x);
/*
* Include this here because some architectures need generic_ffs/fls in
lib-y += ctors.o
lib-y += ctype.o
lib-y += find-next-bit.o
+lib-y += generic-ffsl.o
+lib-y += generic-flsl.o
lib-y += list-sort.o
lib-y += memchr.o
lib-y += memchr_inv.o
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/bitops.h>
+#include <xen/init.h>
+#include <xen/self-tests.h>
+
+unsigned int generic_ffsl(unsigned long x)
+{
+ unsigned int r = 1;
+
+ if ( !x )
+ return 0;
+
+ BUILD_BUG_ON(BITS_PER_LONG > 64); /* Extend me when necessary. */
+
+#if BITS_PER_LONG > 32
+ if ( !(x & 0xffffffffU) )
+ {
+ x >>= 32;
+ r += 32;
+ }
+#endif
+ if ( !(x & 0xffff) )
+ {
+ x >>= 16;
+ r += 16;
+ }
+ if ( !(x & 0xff) )
+ {
+ x >>= 8;
+ r += 8;
+ }
+ if ( !(x & 0xf) )
+ {
+ x >>= 4;
+ r += 4;
+ }
+ if ( !(x & 3) )
+ {
+ x >>= 2;
+ r += 2;
+ }
+ if ( !(x & 1) )
+ {
+ x >>= 1;
+ r += 1;
+ }
+
+ return r;
+}
+
+#ifdef CONFIG_SELF_TESTS
+static void __init __constructor test_generic_ffsl(void)
+{
+ RUNTIME_CHECK(generic_ffsl, 0, 0);
+ RUNTIME_CHECK(generic_ffsl, 1, 1);
+ RUNTIME_CHECK(generic_ffsl, 3, 1);
+ RUNTIME_CHECK(generic_ffsl, 7, 1);
+ RUNTIME_CHECK(generic_ffsl, 6, 2);
+
+ RUNTIME_CHECK(generic_ffsl, 1UL << (BITS_PER_LONG - 1), BITS_PER_LONG);
+#if BITS_PER_LONG > 32
+ RUNTIME_CHECK(generic_ffsl, 1UL << 32, 33);
+ RUNTIME_CHECK(generic_ffsl, 1UL << 63, 64);
+#endif
+}
+#endif /* CONFIG_SELF_TESTS */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/bitops.h>
+#include <xen/init.h>
+#include <xen/self-tests.h>
+
+/* Mask of type UL with the upper x bits set. */
+#define UPPER_MASK(x) (~0UL << (BITS_PER_LONG - (x)))
+
+unsigned int generic_flsl(unsigned long x)
+{
+ unsigned int r = BITS_PER_LONG;
+
+ if ( !x )
+ return 0;
+
+ BUILD_BUG_ON(BITS_PER_LONG > 64); /* Extend me when necessary. */
+
+#if BITS_PER_LONG > 32
+ if ( !(x & UPPER_MASK(32)) )
+ {
+ x <<= 32;
+ r -= 32;
+ }
+#endif
+ if ( !(x & UPPER_MASK(16)) )
+ {
+ x <<= 16;
+ r -= 16;
+ }
+ if ( !(x & UPPER_MASK(8)) )
+ {
+ x <<= 8;
+ r -= 8;
+ }
+ if ( !(x & UPPER_MASK(4)) )
+ {
+ x <<= 4;
+ r -= 4;
+ }
+ if ( !(x & UPPER_MASK(2)) )
+ {
+ x <<= 2;
+ r -= 2;
+ }
+ if ( !(x & UPPER_MASK(1)) )
+ {
+ x <<= 1;
+ r -= 1;
+ }
+
+ return r;
+}
+
+#ifdef CONFIG_SELF_TESTS
+static void __init __constructor test_generic_flsl(void)
+{
+ RUNTIME_CHECK(generic_flsl, 0, 0);
+ RUNTIME_CHECK(generic_flsl, 1, 1);
+ RUNTIME_CHECK(generic_flsl, 3, 2);
+ RUNTIME_CHECK(generic_flsl, 7, 3);
+ RUNTIME_CHECK(generic_flsl, 6, 3);
+
+ RUNTIME_CHECK(generic_flsl, 1 | (1UL << (BITS_PER_LONG - 1)), BITS_PER_LONG);
+#if BITS_PER_LONG > 32
+ RUNTIME_CHECK(generic_flsl, 1 | (1UL << 32), 33);
+ RUNTIME_CHECK(generic_flsl, 1 | (1UL << 63), 64);
+#endif
+}
+#endif /* CONFIG_SELF_TESTS */