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