Blame view

lib/find_bit.c 5.07 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
8f6f19dd5   Yury Norov   lib: move find_la...
2
  /* bit search implementation
1da177e4c   Linus Torvalds   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   Yury Norov   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   Yury Norov   lib: find_*_bit r...
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
   */
  
  #include <linux/bitops.h>
8f6f19dd5   Yury Norov   lib: move find_la...
16
  #include <linux/bitmap.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
17
  #include <linux/export.h>
2c57a0e23   Yury Norov   lib: find_*_bit r...
18
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

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

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

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

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

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

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

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

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

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

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

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

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

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

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