Merge from vendor branch NCURSES:
[dragonfly.git] / sys / vfs / gnu / ext2fs / alpha-bitops.h
1 /* $FreeBSD: src/sys/gnu/ext2fs/alpha-bitops.h,v 1.1.2.1 2001/08/14 18:03:19 gallatin Exp $ */
2 /* $DragonFly: src/sys/vfs/gnu/ext2fs/Attic/alpha-bitops.h,v 1.2 2003/06/17 04:28:33 dillon Exp $ */
3 #ifndef _ALPHA_BITOPS_H
4 #define _ALPHA_BITOPS_H
5
6 /*
7  * Copyright 1994, Linus Torvalds.
8  */
9
10 /*
11  * These have to be done with inline assembly: that way the bit-setting
12  * is guaranteed to be atomic. All bit operations return 0 if the bit
13  * was cleared before the operation and != 0 if it was not.
14  *
15  * To get proper branch prediction for the main line, we must branch
16  * forward to code at the end of this object's .text section, then
17  * branch back to restart the operation.
18  *
19  * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1).
20  */
21 static __inline unsigned int set_bit(unsigned long, volatile void *);
22 static __inline unsigned int clear_bit(unsigned long, volatile void *);
23 static __inline unsigned int change_bit(unsigned long, volatile void *);
24 static __inline unsigned int test_bit(int, volatile void *);
25 static __inline unsigned long ffz_b(unsigned long x);
26 static __inline unsigned long ffz(unsigned long);
27 /* static __inline int ffs(int); */
28 static __inline void * memscan(void *, int, size_t);
29 #ifdef __alpha_cix__
30 static __inline unsigned long hweight64(unsigned long);
31 #endif
32 static __inline unsigned long
33 find_next_zero_bit(void *, unsigned long, unsigned long);
34
35 static __inline unsigned int set_bit(unsigned long nr, volatile void * addr)
36 {
37         unsigned long oldbit;
38         unsigned long temp;
39         volatile unsigned int *m = ((volatile unsigned int *) addr) + (nr >> 5);
40
41         __asm__ __volatile__(
42         "1:     ldl_l %0,%1\n"
43         "       and %0,%3,%2\n"
44         "       bne %2,2f\n"
45         "       xor %0,%3,%0\n"
46         "       stl_c %0,%1\n"
47         "       beq %0,3f\n"
48         "2:\n"
49         ".section .text2,\"ax\"\n"
50         "3:     br 1b\n"
51         ".previous"
52         :"=&r" (temp), "=m" (*m), "=&r" (oldbit)
53         :"Ir" (1UL << (nr & 31)), "m" (*m));
54         return oldbit;
55 }
56
57 static __inline unsigned int clear_bit(unsigned long nr, volatile void * addr)
58 {
59         unsigned long oldbit;
60         unsigned long temp;
61         volatile unsigned int *m = ((volatile unsigned int *) addr) + (nr >> 5);
62
63         __asm__ __volatile__(
64         "1:     ldl_l %0,%1\n"
65         "       and %0,%3,%2\n"
66         "       beq %2,2f\n"
67         "       xor %0,%3,%0\n"
68         "       stl_c %0,%1\n"
69         "       beq %0,3f\n"
70         "2:\n"
71         ".section .text2,\"ax\"\n"
72         "3:     br 1b\n"
73         ".previous"
74         :"=&r" (temp), "=m" (*m), "=&r" (oldbit)
75         :"Ir" (1UL << (nr & 31)), "m" (*m));
76         return oldbit;
77 }
78
79 static __inline unsigned int change_bit(unsigned long nr, volatile void * addr)
80 {
81         unsigned long oldbit;
82         unsigned long temp;
83         volatile unsigned int *m = ((volatile unsigned int *) addr) + (nr >> 5);
84
85         __asm__ __volatile__(
86         "1:     ldl_l %0,%1\n"
87         "       xor %0,%2,%0\n"
88         "       stl_c %0,%1\n"
89         "       beq %0,3f\n"
90         ".section .text2,\"ax\"\n"
91         "3:     br 1b\n"
92         ".previous"
93         :"=&r" (temp), "=m" (*m), "=&r" (oldbit)
94         :"Ir" (1UL << (nr & 31)), "m" (*m));
95         return oldbit;
96 }
97
98 static __inline unsigned int test_bit(int nr, volatile void * addr)
99 {
100         return 1UL & (((volatile int *) addr)[nr >> 5] >> (nr & 31));
101 }
102
103 /*
104  * ffz = Find First Zero in word. Undefined if no zero exists,
105  * so code should check against ~0UL first..
106  *
107  * Do a binary search on the bits.  Due to the nature of large
108  * constants on the alpha, it is worthwhile to split the search.
109  */
110 static __inline unsigned long ffz_b(unsigned long x)
111 {
112         unsigned long sum = 0;
113
114         x = ~x & -~x;           /* set first 0 bit, clear others */
115         if (x & 0xF0) sum += 4;
116         if (x & 0xCC) sum += 2;
117         if (x & 0xAA) sum += 1;
118
119         return sum;
120 }
121
122 static __inline unsigned long ffz(unsigned long word)
123 {
124 #ifdef __alpha_cix__
125         /* Whee.  EV6 can calculate it directly.  */
126         unsigned long result;
127         __asm__("ctlz %1,%0" : "=r"(result) : "r"(~word));
128         return result;
129 #else
130         unsigned long bits, qofs, bofs;
131
132         __asm__("cmpbge %1,%2,%0" : "=r"(bits) : "r"(word), "r"(~0UL));
133         qofs = ffz_b(bits);
134         __asm__("extbl %1,%2,%0" : "=r"(bits) : "r"(word), "r"(qofs));
135         bofs = ffz_b(bits);
136
137         return qofs*8 + bofs;
138 #endif
139 }
140
141 #ifdef __KERNEL__
142 #if     0
143 /*
144  * ffs: find first bit set. This is defined the same way as
145  * the libc and compiler builtin ffs routines, therefore
146  * differs in spirit from the above ffz (man ffs).
147  */
148
149 static __inline int ffs(int word)
150 {
151         int result = ffz(~word);
152         return word ? result+1 : 0;
153 }
154 #endif
155
156 /*
157  * hweightN: returns the hamming weight (i.e. the number
158  * of bits set) of a N-bit word
159  */
160
161 #ifdef __alpha_cix__
162 /* Whee.  EV6 can calculate it directly.  */
163 static __inline unsigned long hweight64(unsigned long w)
164 {
165         unsigned long result;
166         __asm__("ctpop %1,%0" : "=r"(result) : "r"(w));
167         return result;
168 }
169
170 #define hweight32(x) hweight64((x) & 0xfffffffful)
171 #define hweight16(x) hweight64((x) & 0xfffful)
172 #define hweight8(x)  hweight64((x) & 0xfful)
173 #else
174 #define hweight32(x) generic_hweight32(x)
175 #define hweight16(x) generic_hweight16(x)
176 #define hweight8(x)  generic_hweight8(x)
177 #endif
178
179 #endif /* __alpha_cix__ */
180
181 /* from lib/string.c */
182 static __inline void * memscan(void * addr, int c, size_t size)
183 {
184         unsigned char * p = (unsigned char *) addr;
185
186         while (size) {
187                 if (*p == c)
188                         return (void *) p;
189                 p++;
190                 size--;
191         }
192         return (void *) p;
193 }
194
195
196 /*
197  * Find next zero bit in a bitmap reasonably efficiently..
198  */
199 static __inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
200 {
201         unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
202         unsigned long result = offset & ~63UL;
203         unsigned long tmp;
204
205         if (offset >= size)
206                 return size;
207         size -= result;
208         offset &= 63UL;
209         if (offset) {
210                 tmp = *(p++);
211                 tmp |= ~0UL >> (64-offset);
212                 if (size < 64)
213                         goto found_first;
214                 if (~tmp)
215                         goto found_middle;
216                 size -= 64;
217                 result += 64;
218         }
219         while (size & ~63UL) {
220                 if (~(tmp = *(p++)))
221                         goto found_middle;
222                 result += 64;
223                 size -= 64;
224         }
225         if (!size)
226                 return result;
227         tmp = *p;
228 found_first:
229         tmp |= ~0UL << size;
230 found_middle:
231         return result + ffz(tmp);
232 }
233
234 /*
235  * The optimizer actually does good code for this case..
236  */
237 #define find_first_zero_bit(addr, size) \
238         find_next_zero_bit((addr), (size), 0)
239
240 #ifdef __KERNEL__
241
242 #define ext2_set_bit                 test_and_set_bit
243 #define ext2_clear_bit               test_and_clear_bit
244 #define ext2_test_bit                test_bit
245 #define ext2_find_first_zero_bit     find_first_zero_bit
246 #define ext2_find_next_zero_bit      find_next_zero_bit
247
248 /* Bitmap functions for the minix filesystem.  */
249 #define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
250 #define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
251 #define minix_test_bit(nr,addr) test_bit(nr,addr)
252 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
253
254 #endif /* __KERNEL__ */
255
256 #endif /* _ALPHA_BITOPS_H */