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