Blame view
lib/find_bit.c
5.28 KB
8f6f19dd5 lib: move find_la... |
1 |
/* bit search implementation |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 |
* * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * |
8f6f19dd5 lib: move find_la... |
6 7 8 9 |
* 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... |
10 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 16 17 18 19 |
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/bitops.h> |
8f6f19dd5 lib: move find_la... |
20 |
#include <linux/bitmap.h> |
8bc3bcc93 lib: reduce the u... |
21 |
#include <linux/export.h> |
2c57a0e23 lib: find_*_bit r... |
22 |
#include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
0ade34c37 lib: optimize cpu... |
24 25 |
#if !defined(find_next_bit) || !defined(find_next_zero_bit) || \ !defined(find_next_and_bit) |
c7f612cdf [PATCH] bitops: g... |
26 |
|
64970b68d x86, generic: opt... |
27 |
/* |
0ade34c37 lib: optimize cpu... |
28 29 30 31 32 |
* 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... |
33 |
*/ |
0ade34c37 lib: optimize cpu... |
34 35 36 |
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 |
37 |
{ |
1da177e4c Linux-2.6.12-rc2 |
38 |
unsigned long tmp; |
e4afd2e55 lib/find_bit.c: m... |
39 |
if (unlikely(start >= nbits)) |
2c57a0e23 lib: find_*_bit r... |
40 |
return nbits; |
0ade34c37 lib: optimize cpu... |
41 42 43 44 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
2c57a0e23 lib: find_*_bit r... |
45 46 47 48 49 50 51 52 53 |
/* 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... |
54 55 56 57 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
1da177e4c Linux-2.6.12-rc2 |
58 |
} |
2c57a0e23 lib: find_*_bit r... |
59 |
return min(start + __ffs(tmp), nbits); |
c7f612cdf [PATCH] bitops: g... |
60 |
} |
19de85ef5 bitops: add #ifnd... |
61 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
2c57a0e23 lib: find_*_bit r... |
63 |
#ifndef find_next_bit |
c7f612cdf [PATCH] bitops: g... |
64 |
/* |
2c57a0e23 lib: find_*_bit r... |
65 |
* Find the next set bit in a memory region. |
c7f612cdf [PATCH] bitops: g... |
66 |
*/ |
2c57a0e23 lib: find_*_bit r... |
67 68 69 |
unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { |
0ade34c37 lib: optimize cpu... |
70 |
return _find_next_bit(addr, NULL, size, offset, 0UL); |
2c57a0e23 lib: find_*_bit r... |
71 72 73 74 75 |
} EXPORT_SYMBOL(find_next_bit); #endif #ifndef find_next_zero_bit |
fee4b19fb bitops: remove "o... |
76 77 |
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) |
c7f612cdf [PATCH] bitops: g... |
78 |
{ |
0ade34c37 lib: optimize cpu... |
79 |
return _find_next_bit(addr, NULL, size, offset, ~0UL); |
1da177e4c Linux-2.6.12-rc2 |
80 |
} |
fee4b19fb bitops: remove "o... |
81 |
EXPORT_SYMBOL(find_next_zero_bit); |
19de85ef5 bitops: add #ifnd... |
82 |
#endif |
77b9bd9c4 x86: generic vers... |
83 |
|
0ade34c37 lib: optimize cpu... |
84 85 86 87 88 89 90 91 92 |
#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... |
93 |
#ifndef find_first_bit |
77b9bd9c4 x86: generic vers... |
94 95 96 |
/* * Find the first set bit in a memory region. */ |
fee4b19fb bitops: remove "o... |
97 |
unsigned long find_first_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c4 x86: generic vers... |
98 |
{ |
2c57a0e23 lib: find_*_bit r... |
99 |
unsigned long idx; |
77b9bd9c4 x86: generic vers... |
100 |
|
2c57a0e23 lib: find_*_bit r... |
101 102 103 |
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... |
104 |
} |
77b9bd9c4 x86: generic vers... |
105 |
|
2c57a0e23 lib: find_*_bit r... |
106 |
return size; |
77b9bd9c4 x86: generic vers... |
107 |
} |
fee4b19fb bitops: remove "o... |
108 |
EXPORT_SYMBOL(find_first_bit); |
19de85ef5 bitops: add #ifnd... |
109 |
#endif |
77b9bd9c4 x86: generic vers... |
110 |
|
19de85ef5 bitops: add #ifnd... |
111 |
#ifndef find_first_zero_bit |
77b9bd9c4 x86: generic vers... |
112 113 114 |
/* * Find the first cleared bit in a memory region. */ |
fee4b19fb bitops: remove "o... |
115 |
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) |
77b9bd9c4 x86: generic vers... |
116 |
{ |
2c57a0e23 lib: find_*_bit r... |
117 |
unsigned long idx; |
77b9bd9c4 x86: generic vers... |
118 |
|
2c57a0e23 lib: find_*_bit r... |
119 120 121 |
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... |
122 |
} |
77b9bd9c4 x86: generic vers... |
123 |
|
2c57a0e23 lib: find_*_bit r... |
124 |
return size; |
77b9bd9c4 x86: generic vers... |
125 |
} |
fee4b19fb bitops: remove "o... |
126 |
EXPORT_SYMBOL(find_first_zero_bit); |
19de85ef5 bitops: add #ifnd... |
127 |
#endif |
930ae745f [PATCH] bitops: g... |
128 |
|
8f6f19dd5 lib: move find_la... |
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
#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... |
148 149 150 |
#ifdef __BIG_ENDIAN /* include/linux/byteorder does not support "unsigned long" type */ |
930ae745f [PATCH] bitops: g... |
151 152 153 154 155 156 157 158 159 160 |
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... |
161 |
#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) |
0ade34c37 lib: optimize cpu... |
162 163 164 |
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... |
165 |
{ |
930ae745f [PATCH] bitops: g... |
166 |
unsigned long tmp; |
e4afd2e55 lib/find_bit.c: m... |
167 |
if (unlikely(start >= nbits)) |
2c57a0e23 lib: find_*_bit r... |
168 |
return nbits; |
0ade34c37 lib: optimize cpu... |
169 170 171 172 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
2c57a0e23 lib: find_*_bit r... |
173 174 175 176 |
/* Handle 1st word. */ tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); start = round_down(start, BITS_PER_LONG); |
930ae745f [PATCH] bitops: g... |
177 |
|
2c57a0e23 lib: find_*_bit r... |
178 179 180 181 |
while (!tmp) { start += BITS_PER_LONG; if (start >= nbits) return nbits; |
0ade34c37 lib: optimize cpu... |
182 183 184 185 |
tmp = addr1[start / BITS_PER_LONG]; if (addr2) tmp &= addr2[start / BITS_PER_LONG]; tmp ^= invert; |
930ae745f [PATCH] bitops: g... |
186 |
} |
930ae745f [PATCH] bitops: g... |
187 |
|
2c57a0e23 lib: find_*_bit r... |
188 189 190 191 192 193 194 195 |
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... |
196 |
return _find_next_bit_le(addr, NULL, size, offset, ~0UL); |
930ae745f [PATCH] bitops: g... |
197 |
} |
c4945b9ed asm-generic: rena... |
198 |
EXPORT_SYMBOL(find_next_zero_bit_le); |
19de85ef5 bitops: add #ifnd... |
199 |
#endif |
930ae745f [PATCH] bitops: g... |
200 |
|
19de85ef5 bitops: add #ifnd... |
201 |
#ifndef find_next_bit_le |
a56560b3b asm-generic: chan... |
202 |
unsigned long find_next_bit_le(const void *addr, unsigned |
aa02ad67d ext4: Add ext4_fi... |
203 204 |
long size, unsigned long offset) { |
0ade34c37 lib: optimize cpu... |
205 |
return _find_next_bit_le(addr, NULL, size, offset, 0UL); |
aa02ad67d ext4: Add ext4_fi... |
206 |
} |
c4945b9ed asm-generic: rena... |
207 |
EXPORT_SYMBOL(find_next_bit_le); |
19de85ef5 bitops: add #ifnd... |
208 |
#endif |
0664996b7 bitops: introduce... |
209 |
|
930ae745f [PATCH] bitops: g... |
210 |
#endif /* __BIG_ENDIAN */ |