1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <xen/bitops.h>
4 #include <xen/init.h>
5 #include <xen/self-tests.h>
6
7 /* Mask of type UL with the upper x bits set. */
8 #define UPPER_MASK(x) (~0UL << (BITS_PER_LONG - (x)))
9
generic_flsl(unsigned long x)10 unsigned int generic_flsl(unsigned long x)
11 {
12 unsigned int r = BITS_PER_LONG;
13
14 if ( !x )
15 return 0;
16
17 BUILD_BUG_ON(BITS_PER_LONG > 64); /* Extend me when necessary. */
18
19 #if BITS_PER_LONG > 32
20 if ( !(x & UPPER_MASK(32)) )
21 {
22 x <<= 32;
23 r -= 32;
24 }
25 #endif
26 if ( !(x & UPPER_MASK(16)) )
27 {
28 x <<= 16;
29 r -= 16;
30 }
31 if ( !(x & UPPER_MASK(8)) )
32 {
33 x <<= 8;
34 r -= 8;
35 }
36 if ( !(x & UPPER_MASK(4)) )
37 {
38 x <<= 4;
39 r -= 4;
40 }
41 if ( !(x & UPPER_MASK(2)) )
42 {
43 x <<= 2;
44 r -= 2;
45 }
46 if ( !(x & UPPER_MASK(1)) )
47 {
48 x <<= 1;
49 r -= 1;
50 }
51
52 return r;
53 }
54
55 #ifdef CONFIG_SELF_TESTS
test_generic_flsl(void)56 static void __init __constructor test_generic_flsl(void)
57 {
58 RUNTIME_CHECK(generic_flsl, 0, 0);
59 RUNTIME_CHECK(generic_flsl, 1, 1);
60 RUNTIME_CHECK(generic_flsl, 3, 2);
61 RUNTIME_CHECK(generic_flsl, 7, 3);
62 RUNTIME_CHECK(generic_flsl, 6, 3);
63
64 RUNTIME_CHECK(generic_flsl, 1 | (1UL << (BITS_PER_LONG - 1)), BITS_PER_LONG);
65 #if BITS_PER_LONG > 32
66 RUNTIME_CHECK(generic_flsl, 1 | (1UL << 32), 33);
67 RUNTIME_CHECK(generic_flsl, 1 | (1UL << 63), 64);
68 #endif
69 }
70 #endif /* CONFIG_SELF_TESTS */
71