Blame view
lib/find_bit.c
5.07 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
8f6f19dd5 lib: move find_la... |
2 |
/* bit search implementation |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 |
* * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * |
8f6f19dd5 lib: move find_la... |
7 8 9 10 |
* Copyright (C) 2008 IBM Corporation * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au> * (Inspired by David Howell's find_next_bit implementation) * |
2c57a0e23 lib: find_*_bit r... |
11 12 |
* Rewritten by Yury Norov <yury.norov@gmail.com> to decrease * size and improve performance, 2015. |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 |
*/ #include <linux/bitops.h> |
8f6f19dd5 lib: move find_la... |
16 |
#include <linux/bitmap.h> |
8bc3bcc93 lib: reduce the u... |
17 |
#include <linux/export.h> |
2c57a0e23 lib: find_*_bit r... |
18 |
#include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
19 |
|
0ade34c37 lib: optimize cpu... |
20 21 |
#if !defined(find_next_bit) || !defined(find_next_zero_bit) || \ !defined(find_next_and_bit) |
c7f612cdf [PATCH] bitops: g... |
22 |
|
64970b68d x86, generic: opt... |
23 |
/* |
0ade34c37 lib: optimize cpu... |
24 25 26 27 28 |
* This is a common helper function for find_next_bit, find_next_zero_bit, and * find_next_and_bit. The differences are: * - The "invert" argument, which is XORed with each fetched word before * searching it for one bits. * - The optional "addr2", which is anded with "addr1" if present. |
c7f612cdf [PATCH] bitops: g... |
29 |
*/ |
0ade34c37 lib: optimize cpu... |
30 31 32 |
static inline unsigned long _find_next_bit(const unsigned long *addr1, const unsigned long *addr2, unsigned long nbits, unsigned long start, unsigned long invert) |
1da177e4c Linux-2.6.12-rc2 |
33 |
{ |
1da177e4c Linux-2.6.12-rc2 |
34 |
unsigned long tmp; |
e4afd2e55 lib/find_bit.c: m... |
35 |
if (unlikely(start >= nbits)) |
2c57a0e23 lib: find_*_bit r... |
36 |
return nbits; |
0ade34c37 lib: optimize cpu... |
37 38 39 40 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
2c57a0e23 lib: find_*_bit r... |
41 42 43 44 45 46 47 48 49 |
/* Handle 1st word. */ tmp &= BITMAP_FIRST_WORD_MASK(start); start = round_down(start, BITS_PER_LONG); while (!tmp) { start += BITS_PER_LONG; if (start >= nbits) return nbits; |
0ade34c37 lib: optimize cpu... |
50 51 52 53 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
1da177e4c Linux-2.6.12-rc2 |
54 |
} |
2c57a0e23 lib: find_*_bit r... |
55 |
return min(start + __ffs(tmp), nbits); |
c7f612cdf [PATCH] bitops: g... |
56 |
} |
19de85ef5 bitops: add #ifnd... |
57 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
58 |
|
2c57a0e23 lib: find_*_bit r... |
59 |
#ifndef find_next_bit |
c7f612cdf [PATCH] bitops: g... |
60 |
/* |
2c57a0e23 lib: find_*_bit r... |
61 |
* Find the next set bit in a memory region. |
c7f612cdf [PATCH] bitops: g... |
62 |
*/ |
2c57a0e23 lib: find_*_bit r... |
63 64 65 |
unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { |
0ade34c37 lib: optimize cpu... |
66 |
return _find_next_bit(addr, NULL, size, offset, 0UL); |
2c57a0e23 lib: find_*_bit r... |
67 68 69 70 71 |
} EXPORT_SYMBOL(find_next_bit); #endif #ifndef find_next_zero_bit |
fee4b19fb bitops: remove "o... |
72 73 |
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) |
c7f612cdf [PATCH] bitops: g... |
74 |
{ |
0ade34c37 lib: optimize cpu... |
75 |
return _find_next_bit(addr, NULL, size, offset, ~0UL); |
1da177e4c Linux-2.6.12-rc2 |
76 |
} |
fee4b19fb bitops: remove "o... |
77 |
EXPORT_SYMBOL(find_next_zero_bit); |
19de85ef5 bitops: add #ifnd... |
78 |
#endif |
77b9bd9c4 x86: generic vers... |
79 |
|
0ade34c37 lib: optimize cpu... |
80 81 82 83 84 85 86 87 88 |
#if !defined(find_next_and_bit) unsigned long find_next_and_bit(const unsigned long *addr1, const unsigned long *addr2, unsigned long size, unsigned long offset) { return _find_next_bit(addr1, addr2, size, offset, 0UL); } EXPORT_SYMBOL(find_next_and_bit); #endif |
19de85ef5 bitops: add #ifnd... |
89 |
#ifndef find_first_bit |
77b9bd9c4 x86: generic vers... |
90 91 92 |
/* * Find the first set bit in a memory region. */ |
fee4b19fb bitops: remove "o... |
93 |
unsigned long find_first_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c4 x86: generic vers... |
94 |
{ |
2c57a0e23 lib: find_*_bit r... |
95 |
unsigned long idx; |
77b9bd9c4 x86: generic vers... |
96 |
|
2c57a0e23 lib: find_*_bit r... |
97 98 99 |
for (idx = 0; idx * BITS_PER_LONG < size; idx++) { if (addr[idx]) return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); |
77b9bd9c4 x86: generic vers... |
100 |
} |
77b9bd9c4 x86: generic vers... |
101 |
|
2c57a0e23 lib: find_*_bit r... |
102 |
return size; |
77b9bd9c4 x86: generic vers... |
103 |
} |
fee4b19fb bitops: remove "o... |
104 |
EXPORT_SYMBOL(find_first_bit); |
19de85ef5 bitops: add #ifnd... |
105 |
#endif |
77b9bd9c4 x86: generic vers... |
106 |
|
19de85ef5 bitops: add #ifnd... |
107 |
#ifndef find_first_zero_bit |
77b9bd9c4 x86: generic vers... |
108 109 110 |
/* * Find the first cleared bit in a memory region. */ |
fee4b19fb bitops: remove "o... |
111 |
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c4 x86: generic vers... |
112 |
{ |
2c57a0e23 lib: find_*_bit r... |
113 |
unsigned long idx; |
77b9bd9c4 x86: generic vers... |
114 |
|
2c57a0e23 lib: find_*_bit r... |
115 116 117 |
for (idx = 0; idx * BITS_PER_LONG < size; idx++) { if (addr[idx] != ~0UL) return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); |
77b9bd9c4 x86: generic vers... |
118 |
} |
77b9bd9c4 x86: generic vers... |
119 |
|
2c57a0e23 lib: find_*_bit r... |
120 |
return size; |
77b9bd9c4 x86: generic vers... |
121 |
} |
fee4b19fb bitops: remove "o... |
122 |
EXPORT_SYMBOL(find_first_zero_bit); |
19de85ef5 bitops: add #ifnd... |
123 |
#endif |
930ae745f [PATCH] bitops: g... |
124 |
|
8f6f19dd5 lib: move find_la... |
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
#ifndef find_last_bit unsigned long find_last_bit(const unsigned long *addr, unsigned long size) { if (size) { unsigned long val = BITMAP_LAST_WORD_MASK(size); unsigned long idx = (size-1) / BITS_PER_LONG; do { val &= addr[idx]; if (val) return idx * BITS_PER_LONG + __fls(val); val = ~0ul; } while (idx--); } return size; } EXPORT_SYMBOL(find_last_bit); #endif |
930ae745f [PATCH] bitops: g... |
144 145 146 |
#ifdef __BIG_ENDIAN /* include/linux/byteorder does not support "unsigned long" type */ |
930ae745f [PATCH] bitops: g... |
147 148 149 150 151 152 153 154 155 156 |
static inline unsigned long ext2_swab(const unsigned long y) { #if BITS_PER_LONG == 64 return (unsigned long) __swab64((u64) y); #elif BITS_PER_LONG == 32 return (unsigned long) __swab32((u32) y); #else #error BITS_PER_LONG not defined #endif } |
2c57a0e23 lib: find_*_bit r... |
157 |
#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) |
0ade34c37 lib: optimize cpu... |
158 159 160 |
static inline unsigned long _find_next_bit_le(const unsigned long *addr1, const unsigned long *addr2, unsigned long nbits, unsigned long start, unsigned long invert) |
930ae745f [PATCH] bitops: g... |
161 |
{ |
930ae745f [PATCH] bitops: g... |
162 |
unsigned long tmp; |
e4afd2e55 lib/find_bit.c: m... |
163 |
if (unlikely(start >= nbits)) |
2c57a0e23 lib: find_*_bit r... |
164 |
return nbits; |
0ade34c37 lib: optimize cpu... |
165 166 167 168 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
2c57a0e23 lib: find_*_bit r... |
169 170 171 172 |
/* Handle 1st word. */ tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); start = round_down(start, BITS_PER_LONG); |
930ae745f [PATCH] bitops: g... |
173 |
|
2c57a0e23 lib: find_*_bit r... |
174 175 176 177 |
while (!tmp) { start += BITS_PER_LONG; if (start >= nbits) return nbits; |
0ade34c37 lib: optimize cpu... |
178 179 180 181 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
930ae745f [PATCH] bitops: g... |
182 |
} |
930ae745f [PATCH] bitops: g... |
183 |
|
2c57a0e23 lib: find_*_bit r... |
184 185 186 187 188 189 190 191 |
return min(start + __ffs(ext2_swab(tmp)), nbits); } #endif #ifndef find_next_zero_bit_le unsigned long find_next_zero_bit_le(const void *addr, unsigned long size, unsigned long offset) { |
0ade34c37 lib: optimize cpu... |
192 |
return _find_next_bit_le(addr, NULL, size, offset, ~0UL); |
930ae745f [PATCH] bitops: g... |
193 |
} |
c4945b9ed asm-generic: rena... |
194 |
EXPORT_SYMBOL(find_next_zero_bit_le); |
19de85ef5 bitops: add #ifnd... |
195 |
#endif |
930ae745f [PATCH] bitops: g... |
196 |
|
19de85ef5 bitops: add #ifnd... |
197 |
#ifndef find_next_bit_le |
a56560b3b asm-generic: chan... |
198 |
unsigned long find_next_bit_le(const void *addr, unsigned |
aa02ad67d ext4: Add ext4_fi... |
199 200 |
long size, unsigned long offset) { |
0ade34c37 lib: optimize cpu... |
201 |
return _find_next_bit_le(addr, NULL, size, offset, 0UL); |
aa02ad67d ext4: Add ext4_fi... |
202 |
} |
c4945b9ed asm-generic: rena... |
203 |
EXPORT_SYMBOL(find_next_bit_le); |
19de85ef5 bitops: add #ifnd... |
204 |
#endif |
0664996b7 bitops: introduce... |
205 |
|
930ae745f [PATCH] bitops: g... |
206 |
#endif /* __BIG_ENDIAN */ |