xref: /openbmc/qemu/util/bitops.c (revision 6683d7bc)
1 /*
2  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
3  * Written by David Howells (dhowells@redhat.com)
4  * Copyright (C) 2008 IBM Corporation
5  * Written by Rusty Russell <rusty@rustcorp.com.au>
6  * (Inspired by David Howell's find_next_bit implementation)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version
11  * 2 of the License, or (at your option) any later version.
12  */
13 
14 #include "qemu/bitops.h"
15 
16 #define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
17 
18 /*
19  * Find the next set bit in a memory region.
20  */
21 unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
22 			    unsigned long offset)
23 {
24     const unsigned long *p = addr + BITOP_WORD(offset);
25     unsigned long result = offset & ~(BITS_PER_LONG-1);
26     unsigned long tmp;
27 
28     if (offset >= size) {
29         return size;
30     }
31     size -= result;
32     offset %= BITS_PER_LONG;
33     if (offset) {
34         tmp = *(p++);
35         tmp &= (~0UL << offset);
36         if (size < BITS_PER_LONG) {
37             goto found_first;
38         }
39         if (tmp) {
40             goto found_middle;
41         }
42         size -= BITS_PER_LONG;
43         result += BITS_PER_LONG;
44     }
45     while (size >= 4*BITS_PER_LONG) {
46         unsigned long d1, d2, d3;
47         tmp = *p;
48         d1 = *(p+1);
49         d2 = *(p+2);
50         d3 = *(p+3);
51         if (tmp) {
52             goto found_middle;
53         }
54         if (d1 | d2 | d3) {
55             break;
56         }
57         p += 4;
58         result += 4*BITS_PER_LONG;
59         size -= 4*BITS_PER_LONG;
60     }
61     while (size >= BITS_PER_LONG) {
62         if ((tmp = *(p++))) {
63             goto found_middle;
64         }
65         result += BITS_PER_LONG;
66         size -= BITS_PER_LONG;
67     }
68     if (!size) {
69         return result;
70     }
71     tmp = *p;
72 
73 found_first:
74     tmp &= (~0UL >> (BITS_PER_LONG - size));
75     if (tmp == 0UL) {		/* Are any bits set? */
76         return result + size;	/* Nope. */
77     }
78 found_middle:
79     return result + ctzl(tmp);
80 }
81 
82 /*
83  * This implementation of find_{first,next}_zero_bit was stolen from
84  * Linus' asm-alpha/bitops.h.
85  */
86 unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
87 				 unsigned long offset)
88 {
89     const unsigned long *p = addr + BITOP_WORD(offset);
90     unsigned long result = offset & ~(BITS_PER_LONG-1);
91     unsigned long tmp;
92 
93     if (offset >= size) {
94         return size;
95     }
96     size -= result;
97     offset %= BITS_PER_LONG;
98     if (offset) {
99         tmp = *(p++);
100         tmp |= ~0UL >> (BITS_PER_LONG - offset);
101         if (size < BITS_PER_LONG) {
102             goto found_first;
103         }
104         if (~tmp) {
105             goto found_middle;
106         }
107         size -= BITS_PER_LONG;
108         result += BITS_PER_LONG;
109     }
110     while (size & ~(BITS_PER_LONG-1)) {
111         if (~(tmp = *(p++))) {
112             goto found_middle;
113         }
114         result += BITS_PER_LONG;
115         size -= BITS_PER_LONG;
116     }
117     if (!size) {
118         return result;
119     }
120     tmp = *p;
121 
122 found_first:
123     tmp |= ~0UL << size;
124     if (tmp == ~0UL) {	/* Are any bits zero? */
125         return result + size;	/* Nope. */
126     }
127 found_middle:
128     return result + ctzl(~tmp);
129 }
130 
131 unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
132 {
133     unsigned long words;
134     unsigned long tmp;
135 
136     /* Start at final word. */
137     words = size / BITS_PER_LONG;
138 
139     /* Partial final word? */
140     if (size & (BITS_PER_LONG-1)) {
141         tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
142                                        - (size & (BITS_PER_LONG-1)))));
143         if (tmp) {
144             goto found;
145         }
146     }
147 
148     while (words) {
149         tmp = addr[--words];
150         if (tmp) {
151         found:
152             return words * BITS_PER_LONG + BITS_PER_LONG - 1 - clzl(tmp);
153         }
154     }
155 
156     /* Not found */
157     return size;
158 }
159