Blame view

lib/find_bit.c 5.28 KB
8f6f19dd5   Yury Norov   lib: move find_la...
1
  /* bit search implementation
1da177e4c   Linus Torvalds   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   Yury Norov   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   Yury Norov   lib: find_*_bit r...
10
11
12
   * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
   * size and improve performance, 2015.
   *
1da177e4c   Linus Torvalds   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   Yury Norov   lib: move find_la...
20
  #include <linux/bitmap.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
21
  #include <linux/export.h>
2c57a0e23   Yury Norov   lib: find_*_bit r...
22
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

0ade34c37   Clement Courbet   lib: optimize cpu...
24
25
  #if !defined(find_next_bit) || !defined(find_next_zero_bit) || \
  		!defined(find_next_and_bit)
c7f612cdf   Akinobu Mita   [PATCH] bitops: g...
26

64970b68d   Alexander van Heukelum   x86, generic: opt...
27
  /*
0ade34c37   Clement Courbet   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   Akinobu Mita   [PATCH] bitops: g...
33
   */
0ade34c37   Clement Courbet   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   Linus Torvalds   Linux-2.6.12-rc2
37
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  	unsigned long tmp;
e4afd2e55   Matthew Wilcox   lib/find_bit.c: m...
39
  	if (unlikely(start >= nbits))
2c57a0e23   Yury Norov   lib: find_*_bit r...
40
  		return nbits;
0ade34c37   Clement Courbet   lib: optimize cpu...
41
42
43
44
  	tmp = addr1[start / BITS_PER_LONG];
  	if (addr2)
  		tmp &= addr2[start / BITS_PER_LONG];
  	tmp ^= invert;
2c57a0e23   Yury Norov   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   Clement Courbet   lib: optimize cpu...
54
55
56
57
  		tmp = addr1[start / BITS_PER_LONG];
  		if (addr2)
  			tmp &= addr2[start / BITS_PER_LONG];
  		tmp ^= invert;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	}
2c57a0e23   Yury Norov   lib: find_*_bit r...
59
  	return min(start + __ffs(tmp), nbits);
c7f612cdf   Akinobu Mita   [PATCH] bitops: g...
60
  }
19de85ef5   Akinobu Mita   bitops: add #ifnd...
61
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

2c57a0e23   Yury Norov   lib: find_*_bit r...
63
  #ifndef find_next_bit
c7f612cdf   Akinobu Mita   [PATCH] bitops: g...
64
  /*
2c57a0e23   Yury Norov   lib: find_*_bit r...
65
   * Find the next set bit in a memory region.
c7f612cdf   Akinobu Mita   [PATCH] bitops: g...
66
   */
2c57a0e23   Yury Norov   lib: find_*_bit r...
67
68
69
  unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
  			    unsigned long offset)
  {
0ade34c37   Clement Courbet   lib: optimize cpu...
70
  	return _find_next_bit(addr, NULL, size, offset, 0UL);
2c57a0e23   Yury Norov   lib: find_*_bit r...
71
72
73
74
75
  }
  EXPORT_SYMBOL(find_next_bit);
  #endif
  
  #ifndef find_next_zero_bit
fee4b19fb   Thomas Gleixner   bitops: remove "o...
76
77
  unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
  				 unsigned long offset)
c7f612cdf   Akinobu Mita   [PATCH] bitops: g...
78
  {
0ade34c37   Clement Courbet   lib: optimize cpu...
79
  	return _find_next_bit(addr, NULL, size, offset, ~0UL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  }
fee4b19fb   Thomas Gleixner   bitops: remove "o...
81
  EXPORT_SYMBOL(find_next_zero_bit);
19de85ef5   Akinobu Mita   bitops: add #ifnd...
82
  #endif
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
83

0ade34c37   Clement Courbet   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   Akinobu Mita   bitops: add #ifnd...
93
  #ifndef find_first_bit
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
94
95
96
  /*
   * Find the first set bit in a memory region.
   */
fee4b19fb   Thomas Gleixner   bitops: remove "o...
97
  unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
98
  {
2c57a0e23   Yury Norov   lib: find_*_bit r...
99
  	unsigned long idx;
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
100

2c57a0e23   Yury Norov   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   Alexander van Heukelum   x86: generic vers...
104
  	}
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
105

2c57a0e23   Yury Norov   lib: find_*_bit r...
106
  	return size;
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
107
  }
fee4b19fb   Thomas Gleixner   bitops: remove "o...
108
  EXPORT_SYMBOL(find_first_bit);
19de85ef5   Akinobu Mita   bitops: add #ifnd...
109
  #endif
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
110

19de85ef5   Akinobu Mita   bitops: add #ifnd...
111
  #ifndef find_first_zero_bit
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
112
113
114
  /*
   * Find the first cleared bit in a memory region.
   */
fee4b19fb   Thomas Gleixner   bitops: remove "o...
115
  unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
116
  {
2c57a0e23   Yury Norov   lib: find_*_bit r...
117
  	unsigned long idx;
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
118

2c57a0e23   Yury Norov   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   Alexander van Heukelum   x86: generic vers...
122
  	}
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
123

2c57a0e23   Yury Norov   lib: find_*_bit r...
124
  	return size;
77b9bd9c4   Alexander van Heukelum   x86: generic vers...
125
  }
fee4b19fb   Thomas Gleixner   bitops: remove "o...
126
  EXPORT_SYMBOL(find_first_zero_bit);
19de85ef5   Akinobu Mita   bitops: add #ifnd...
127
  #endif
930ae745f   Akinobu Mita   [PATCH] bitops: g...
128

8f6f19dd5   Yury Norov   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   Akinobu Mita   [PATCH] bitops: g...
148
149
150
  #ifdef __BIG_ENDIAN
  
  /* include/linux/byteorder does not support "unsigned long" type */
930ae745f   Akinobu Mita   [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   Yury Norov   lib: find_*_bit r...
161
  #if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le)
0ade34c37   Clement Courbet   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   Akinobu Mita   [PATCH] bitops: g...
165
  {
930ae745f   Akinobu Mita   [PATCH] bitops: g...
166
  	unsigned long tmp;
e4afd2e55   Matthew Wilcox   lib/find_bit.c: m...
167
  	if (unlikely(start >= nbits))
2c57a0e23   Yury Norov   lib: find_*_bit r...
168
  		return nbits;
0ade34c37   Clement Courbet   lib: optimize cpu...
169
170
171
172
  	tmp = addr1[start / BITS_PER_LONG];
  	if (addr2)
  		tmp &= addr2[start / BITS_PER_LONG];
  	tmp ^= invert;
2c57a0e23   Yury Norov   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   Akinobu Mita   [PATCH] bitops: g...
177

2c57a0e23   Yury Norov   lib: find_*_bit r...
178
179
180
181
  	while (!tmp) {
  		start += BITS_PER_LONG;
  		if (start >= nbits)
  			return nbits;
0ade34c37   Clement Courbet   lib: optimize cpu...
182
183
184
185
  		tmp = addr1[start / BITS_PER_LONG];
  		if (addr2)
  			tmp &= addr2[start / BITS_PER_LONG];
  		tmp ^= invert;
930ae745f   Akinobu Mita   [PATCH] bitops: g...
186
  	}
930ae745f   Akinobu Mita   [PATCH] bitops: g...
187

2c57a0e23   Yury Norov   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   Clement Courbet   lib: optimize cpu...
196
  	return _find_next_bit_le(addr, NULL, size, offset, ~0UL);
930ae745f   Akinobu Mita   [PATCH] bitops: g...
197
  }
c4945b9ed   Akinobu Mita   asm-generic: rena...
198
  EXPORT_SYMBOL(find_next_zero_bit_le);
19de85ef5   Akinobu Mita   bitops: add #ifnd...
199
  #endif
930ae745f   Akinobu Mita   [PATCH] bitops: g...
200

19de85ef5   Akinobu Mita   bitops: add #ifnd...
201
  #ifndef find_next_bit_le
a56560b3b   Akinobu Mita   asm-generic: chan...
202
  unsigned long find_next_bit_le(const void *addr, unsigned
aa02ad67d   Aneesh Kumar K.V   ext4: Add ext4_fi...
203
204
  		long size, unsigned long offset)
  {
0ade34c37   Clement Courbet   lib: optimize cpu...
205
  	return _find_next_bit_le(addr, NULL, size, offset, 0UL);
aa02ad67d   Aneesh Kumar K.V   ext4: Add ext4_fi...
206
  }
c4945b9ed   Akinobu Mita   asm-generic: rena...
207
  EXPORT_SYMBOL(find_next_bit_le);
19de85ef5   Akinobu Mita   bitops: add #ifnd...
208
  #endif
0664996b7   Akinobu Mita   bitops: introduce...
209

930ae745f   Akinobu Mita   [PATCH] bitops: g...
210
  #endif /* __BIG_ENDIAN */