Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
14e968ba VG |
2 | /* |
3 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | |
14e968ba VG |
4 | */ |
5 | ||
6 | #ifndef _ASM_BITOPS_H | |
7 | #define _ASM_BITOPS_H | |
8 | ||
9 | #ifndef _LINUX_BITOPS_H | |
10 | #error only <linux/bitops.h> can be included directly | |
11 | #endif | |
12 | ||
14e968ba VG |
13 | #ifndef __ASSEMBLY__ |
14 | ||
15 | #include <linux/types.h> | |
16 | #include <linux/compiler.h> | |
14e968ba | 17 | |
1f6ccfff VG |
18 | #ifdef CONFIG_ISA_ARCOMPACT |
19 | ||
14e968ba VG |
20 | /* |
21 | * Count the number of zeros, starting from MSB | |
22 | * Helper for fls( ) friends | |
23 | * This is a pure count, so (1-32) or (0-31) doesn't apply | |
24 | * It could be 0 to 32, based on num of 0's in there | |
25 | * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31 | |
26 | */ | |
27 | static inline __attribute__ ((const)) int clz(unsigned int x) | |
28 | { | |
29 | unsigned int res; | |
30 | ||
31 | __asm__ __volatile__( | |
32 | " norm.f %0, %1 \n" | |
33 | " mov.n %0, 0 \n" | |
34 | " add.p %0, %0, 1 \n" | |
35 | : "=r"(res) | |
36 | : "r"(x) | |
37 | : "cc"); | |
38 | ||
39 | return res; | |
40 | } | |
41 | ||
3fc2579e | 42 | static inline int constant_fls(unsigned int x) |
14e968ba VG |
43 | { |
44 | int r = 32; | |
45 | ||
46 | if (!x) | |
47 | return 0; | |
48 | if (!(x & 0xffff0000u)) { | |
49 | x <<= 16; | |
50 | r -= 16; | |
51 | } | |
52 | if (!(x & 0xff000000u)) { | |
53 | x <<= 8; | |
54 | r -= 8; | |
55 | } | |
56 | if (!(x & 0xf0000000u)) { | |
57 | x <<= 4; | |
58 | r -= 4; | |
59 | } | |
60 | if (!(x & 0xc0000000u)) { | |
61 | x <<= 2; | |
62 | r -= 2; | |
63 | } | |
78aec9bb | 64 | if (!(x & 0x80000000u)) |
14e968ba | 65 | r -= 1; |
14e968ba VG |
66 | return r; |
67 | } | |
68 | ||
69 | /* | |
70 | * fls = Find Last Set in word | |
71 | * @result: [1-32] | |
72 | * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 | |
73 | */ | |
3fc2579e | 74 | static inline __attribute__ ((const)) int fls(unsigned int x) |
14e968ba VG |
75 | { |
76 | if (__builtin_constant_p(x)) | |
77 | return constant_fls(x); | |
78 | ||
79 | return 32 - clz(x); | |
80 | } | |
81 | ||
82 | /* | |
83 | * __fls: Similar to fls, but zero based (0-31) | |
84 | */ | |
a1db7ad3 | 85 | static inline __attribute__ ((const)) unsigned long __fls(unsigned long x) |
14e968ba VG |
86 | { |
87 | if (!x) | |
88 | return 0; | |
89 | else | |
90 | return fls(x) - 1; | |
91 | } | |
92 | ||
93 | /* | |
94 | * ffs = Find First Set in word (LSB to MSB) | |
95 | * @result: [1-32], 0 if all 0's | |
96 | */ | |
97 | #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) | |
98 | ||
99 | /* | |
100 | * __ffs: Similar to ffs, but zero based (0-31) | |
101 | */ | |
4e868f84 | 102 | static inline __attribute__ ((const)) unsigned long __ffs(unsigned long word) |
14e968ba VG |
103 | { |
104 | if (!word) | |
105 | return word; | |
106 | ||
107 | return ffs(word) - 1; | |
108 | } | |
109 | ||
1f6ccfff VG |
110 | #else /* CONFIG_ISA_ARCV2 */ |
111 | ||
112 | /* | |
113 | * fls = Find Last Set in word | |
114 | * @result: [1-32] | |
115 | * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 | |
116 | */ | |
9d011e12 | 117 | static inline __attribute__ ((const)) int fls(unsigned int x) |
1f6ccfff VG |
118 | { |
119 | int n; | |
120 | ||
121 | asm volatile( | |
122 | " fls.f %0, %1 \n" /* 0:31; 0(Z) if src 0 */ | |
123 | " add.nz %0, %0, 1 \n" /* 0:31 -> 1:32 */ | |
124 | : "=r"(n) /* Early clobber not needed */ | |
125 | : "r"(x) | |
126 | : "cc"); | |
127 | ||
128 | return n; | |
129 | } | |
130 | ||
131 | /* | |
132 | * __fls: Similar to fls, but zero based (0-31). Also 0 if no bit set | |
133 | */ | |
a1db7ad3 | 134 | static inline __attribute__ ((const)) unsigned long __fls(unsigned long x) |
1f6ccfff VG |
135 | { |
136 | /* FLS insn has exactly same semantics as the API */ | |
137 | return __builtin_arc_fls(x); | |
138 | } | |
139 | ||
140 | /* | |
141 | * ffs = Find First Set in word (LSB to MSB) | |
142 | * @result: [1-32], 0 if all 0's | |
143 | */ | |
9d011e12 | 144 | static inline __attribute__ ((const)) int ffs(unsigned int x) |
1f6ccfff VG |
145 | { |
146 | int n; | |
147 | ||
148 | asm volatile( | |
149 | " ffs.f %0, %1 \n" /* 0:31; 31(Z) if src 0 */ | |
150 | " add.nz %0, %0, 1 \n" /* 0:31 -> 1:32 */ | |
151 | " mov.z %0, 0 \n" /* 31(Z)-> 0 */ | |
152 | : "=r"(n) /* Early clobber not needed */ | |
153 | : "r"(x) | |
154 | : "cc"); | |
155 | ||
156 | return n; | |
157 | } | |
158 | ||
159 | /* | |
160 | * __ffs: Similar to ffs, but zero based (0-31) | |
161 | */ | |
4e868f84 | 162 | static inline __attribute__ ((const)) unsigned long __ffs(unsigned long x) |
1f6ccfff | 163 | { |
4e868f84 | 164 | unsigned long n; |
1f6ccfff VG |
165 | |
166 | asm volatile( | |
167 | " ffs.f %0, %1 \n" /* 0:31; 31(Z) if src 0 */ | |
168 | " mov.z %0, 0 \n" /* 31(Z)-> 0 */ | |
169 | : "=r"(n) | |
170 | : "r"(x) | |
171 | : "cc"); | |
172 | ||
173 | return n; | |
174 | ||
175 | } | |
176 | ||
177 | #endif /* CONFIG_ISA_ARCOMPACT */ | |
178 | ||
14e968ba VG |
179 | /* |
180 | * ffz = Find First Zero in word. | |
181 | * @return:[0-31], 32 if all 1's | |
182 | */ | |
183 | #define ffz(x) __ffs(~(x)) | |
184 | ||
14e968ba VG |
185 | #include <asm-generic/bitops/hweight.h> |
186 | #include <asm-generic/bitops/fls64.h> | |
187 | #include <asm-generic/bitops/sched.h> | |
188 | #include <asm-generic/bitops/lock.h> | |
cea43147 VG |
189 | #include <asm-generic/bitops/atomic.h> |
190 | #include <asm-generic/bitops/non-atomic.h> | |
14e968ba | 191 | |
14e968ba VG |
192 | #include <asm-generic/bitops/le.h> |
193 | #include <asm-generic/bitops/ext2-atomic-setbit.h> | |
194 | ||
195 | #endif /* !__ASSEMBLY__ */ | |
196 | ||
14e968ba | 197 | #endif |