source: trunk/src/emx/include/386/builtin.h@ 1876

Last change on this file since 1876 was 1876, checked in by bird, 21 years ago

Fixed atomic inc/dec inline functions.

  • Property cvs2svn:cvs-rev set to 1.10
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 15.2 KB
Line 
1/* 386/builtin.h (emx+gcc) */
2/** @file
3 * EMX 0.9d-fix04
4 */
5
6#ifndef _I386_BUILTIN_H
7#define _I386_BUILTIN_H
8
9#include <sys/cdefs.h>
10#include <stdint.h>
11
12__BEGIN_DECLS
13
14
15static __inline__ signed char __cxchg (__volatile__ signed char *p,
16 signed char v)
17{
18 __asm__ __volatile__ ("xchgb %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
19 return v;
20}
21
22static __inline__ short __sxchg (__volatile__ short *p, short v)
23{
24 __asm__ __volatile__ ("xchgw %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
25 return v;
26}
27
28static __inline__ int __lxchg (__volatile__ int *p, int v)
29{
30 __asm__ __volatile__ ("xchgl %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
31 return v;
32}
33
34static __inline__ void __enable (void)
35{
36 __asm__ __volatile__ ("sti");
37}
38
39static __inline__ void __disable (void)
40{
41 __asm__ __volatile__ ("cli");
42}
43
44
45/**
46 * Performs an atomical xchg on an unsigned int.
47 * @returns old value.
48 * @param pu Pointer to the value to update.
49 * @param u The new value.
50 */
51static __inline__ unsigned __atomic_xchg(__volatile__ unsigned *pu, unsigned u)
52{
53 __asm__ __volatile__ ("xchgl %0, %1" : "=m" (*pu), "=r" (u) : "1" (u));
54 return u;
55}
56
57/**
58 * Performs an atomical xchg on an 16-bit unsigned integer.
59 *
60 * @returns old value.
61 * @param pu16 Pointer to the value to update.
62 * @param u16 The new value.
63 */
64static inline uint16_t __atomic_xchg_word(volatile uint16_t *pu16, uint16_t u16)
65{
66 __asm__ __volatile__ ("xchgw %0, %1" : "=m" (*pu16), "=r" (u16) : "1" (u16));
67 return u16;
68}
69
70/**
71 * Atomically sets a bit and return the old one.
72 *
73 * @returns 1 if the bwit was set, 0 if it was clear.
74 * @param pv Pointer to base of bitmap.
75 * @param uBit Bit in question.
76 */
77static __inline__ int __atomic_set_bit(__volatile__ void *pv, unsigned uBit)
78{
79 __asm__ __volatile__("lock btsl %2, %1\n\t"
80 "sbbl %0,%0"
81 : "=r" (uBit),
82 "=m" (*(__volatile__ unsigned *)pv)
83 : "0" (uBit)
84 : "memory");
85 return uBit;
86}
87
88
89/**
90 * Atomically clears a bit.
91 *
92 * @param pv Pointer to base of bitmap.
93 * @param uBit Bit in question.
94 */
95static __inline__ void __atomic_clear_bit(__volatile__ void *pv, unsigned uBit)
96{
97 __asm__ __volatile__("lock btrl %1, %0"
98 : "=m" (*(__volatile__ unsigned *)pv)
99 : "r" (uBit));
100}
101
102
103/**
104 * Atomically (er?) tests if a bit is set.
105 *
106 * @returns non zero if the bit was set.
107 * @returns 0 if the bit was clear.
108 * @param pv Pointer to base of bitmap.
109 * @param uBit Bit in question.
110 */
111static __inline__ int __atomic_test_bit(const __volatile__ void *pv, unsigned uBit)
112{
113 __asm__ __volatile__("btl %0, %1\n\t"
114 "sbbl %0, %0\t\n"
115 : "=r" (uBit)
116 : "m" (*(const __volatile__ unsigned *)pv),
117 "0" (uBit));
118 return uBit;
119}
120
121
122/**
123 * Atomically add a 32-bit unsigned value to another.
124 *
125 * @param pu Pointer to the value to add to.
126 * @param uAdd The value to add to *pu.
127 */
128static __inline__ void __atomic_add(__volatile__ unsigned *pu, const unsigned uAdd)
129{
130 __asm__ __volatile__("lock addl %1, %0"
131 : "=m" (*pu)
132 : "nr" (uAdd),
133 "m" (*pu));
134}
135
136/**
137 * Atomically subtract a 32-bit unsigned value from another.
138 *
139 * @param pu Pointer to the value to subtract from.
140 * @param uAdd The value to subtract from *pu.
141 */
142static __inline__ void __atomic_sub(__volatile__ unsigned *pu, const unsigned uSub)
143{
144 __asm__ __volatile__("lock subl %1, %0"
145 : "=m" (*pu)
146 : "nr" (uSub),
147 "m" (*pu));
148}
149
150
151/**
152 * Atomically increments a 32-bit unsigned value.
153 *
154 * @param pu Pointer to the value to increment.
155 */
156static __inline__ void __atomic_increment(__volatile__ unsigned *pu)
157{
158 __asm__ __volatile__("lock incl %0"
159 : "=m" (*pu)
160 : "m" (*pu));
161}
162
163/**
164 * Atomically decrements a 32-bit unsigned value.
165 *
166 * @param pu Pointer to the value to decrement.
167 */
168static __inline__ void __atomic_decrement(__volatile__ unsigned *pu)
169{
170 __asm__ __volatile__("lock decl %0"
171 : "=m" (*pu)
172 : "m" (*pu));
173}
174
175/**
176 * Atomically increments a 32-bit unsigned value if less than max.
177 *
178 * @returns 0 if incremented.
179 * @returns uMax when not updated.
180 * @param pu Pointer to the value to increment.
181 * @param uMax *pu must not be above this value.
182 */
183static __inline__ int __atomic_increment_max(__volatile__ unsigned *pu, const unsigned uMax)
184{
185 unsigned rc;
186 __asm__ __volatile__("movl %2, %%eax\n\t"
187 "1:\n\t"
188 "movl %%eax, %0\n\t"
189 "cmpl %3, %0\n\t"
190 "jb 2f\n\t"
191 "jmp 4f\n"
192 "2:\n\t"
193 "incl %0\n\t"
194 "lock cmpxchgl %0, %1\n\t"
195 "jz 3f\n\t"
196 "jmp 1b\n"
197 "3:"
198 "xorl %0, %0\n\t"
199 "4:"
200 : "=b" (rc),
201 "=m" (*pu)
202 : "m" (*pu),
203 "nd" (uMax),
204 "0" (rc)
205 : "%eax");
206 return rc;
207}
208
209
210/**
211 * Atomically increments a 16-bit unsigned value if less than max.
212 *
213 * @returns New value.
214 * @returns Current value | 0xffff0000 if current value is less or equal to u16Min.
215 * @param pu16 Pointer to the value to increment.
216 * @param u16Max *pu16 must not be above this value after the incrementation.
217 */
218static inline unsigned __atomic_increment_word_max(volatile uint16_t *pu16, const uint16_t u16Max)
219{
220 unsigned rc = 0;
221 __asm__ __volatile__("movw %2, %%ax\n\t"
222 "1:\n\t"
223 "movw %%ax, %w0\n\t"
224 "cmpw %w3, %%ax\n\t"
225 "jb 2f\n\t"
226 "orl $0xffff0000, %0\n\t"
227 "jmp 3f\n"
228 "2:\n\t"
229 "incw %w0\n\t"
230 "lock cmpxchgw %w0, %2\n\t"
231 "jz 3f\n\t"
232 "jmp 1b\n\t"
233 "3:"
234 : "=r" (rc),
235 "=m" (*pu16)
236 : "m" (*pu16),
237 "nr" (u16Max),
238 "0" (rc)
239 : "%eax");
240 return rc;
241}
242
243
244/**
245 * Atomically decrements a 32-bit unsigned value if greater than a min.
246 *
247 * @returns 0 if decremented.
248 * @returns uMin when not updated.
249 * @param pu Pointer to the value to decrement.
250 * @param uMin *pu must not be below this value.
251 */
252static __inline__ int __atomic_decrement_min(__volatile__ unsigned *pu, const unsigned uMin)
253{
254 unsigned rc;
255 __asm__ __volatile__("movl %2, %%eax\n"
256 "1:\n\t"
257 "movl %%eax, %0\n\t"
258 "cmpl %3, %0\n\t"
259 "ja 2f\n\t"
260 "jmp 4f\n"
261 "2:\n\t"
262 "decl %0\n\t"
263 "lock cmpxchgl %0, %1\n\t"
264 "jz 3f\n\t"
265 "jmp 1b\n"
266 "3:"
267 "xorl %0, %0\n\t"
268 "4:"
269 : "=b" (rc),
270 "=m" (*pu)
271 : "m" (*pu),
272 "nr" (uMin),
273 "0" (rc)
274 : "%eax");
275 return rc;
276}
277
278
279/**
280 * Atomically decrements a 16-bit unsigned value if greater than a min.
281 *
282 * @returns New value.
283 * @returns Current value | 0xffff0000 if current value is less or equal to u16Min.
284 * @param pu16 Pointer to the value to decrement.
285 * @param u16Min *pu16 must not be below this value after the decrementation.
286 */
287static inline unsigned __atomic_decrement_word_min(volatile uint16_t *pu16, const uint16_t u16Min)
288{
289 unsigned rc = 0;
290 __asm__ __volatile__("movw %2, %%ax\n\t"
291 "1:\n\t"
292 "movw %%ax, %w0\n\t"
293 "cmpw %w3, %%ax\n\t"
294 "ja 2f\n\t"
295 "orl $0xffff0000, %0\n\t"
296 "jmp 3f\n"
297 "2:\n\t"
298 "decw %%bx\n\t"
299 "lock cmpxchgw %w0, %1\n\t"
300 "jz 3f\n\t"
301 "jmp 1b\n"
302 "3:"
303 : "=b" (rc),
304 "=m" (*pu16)
305 : "m" (*pu16),
306 "nr" (u16Min),
307 "0" (rc)
308 : "%eax");
309 return rc;
310}
311
312
313/**
314 * Atomically compare and exchange a 32-bit word.
315 *
316 * @returns 1 if changed, 0 if unchanged (i.e. boolean).
317 * @param pu32 Pointer to the value to compare & exchange.
318 * @param u32New The new value.
319 * @param u32Cur The current value. Only update if *pu32 equals this one.
320 */
321static inline unsigned __atomic_cmpxchg32(volatile uint32_t *pu32, uint32_t u32New, uint32_t u32Old)
322{
323 __asm__ __volatile__("lock cmpxchgl %2, %1\n\t"
324 "setz %%al\n\t"
325 "movzx %%al, %%eax\n\t"
326 : "=a" (u32Old),
327 "=m" (*pu32)
328 : "r" (u32New),
329 "0" (u32Old));
330 return (unsigned)u32Old;
331}
332
333
334#define __ROTATE_FUN(F,I,T) \
335 static __inline__ T F (T value, int shift) \
336 { \
337 __asm__ (I " %b2, %0" : "=g"(value) : "0"(value), "c"(shift) : "cc"); \
338 return value; \
339 } \
340 static __inline__ T F##1 (T value) \
341 { \
342 __asm__ (I " $1, %0" : "=g"(value) : "0"(value) : "cc"); \
343 return value; \
344 }
345
346#define __ROTATE(V,S,F) ((__builtin_constant_p (S) && (int)(S) == 1) \
347 ? F##1 (V) : F (V, S))
348
349__ROTATE_FUN (__crotr, "rorb", unsigned char)
350__ROTATE_FUN (__srotr, "rorw", unsigned short)
351__ROTATE_FUN (__lrotr, "rorl", unsigned long)
352
353__ROTATE_FUN (__crotl, "rolb", unsigned char)
354__ROTATE_FUN (__srotl, "rolw", unsigned short)
355__ROTATE_FUN (__lrotl, "roll", unsigned long)
356
357#define _crotr(V,S) __ROTATE (V, S, __crotr)
358#define _srotr(V,S) __ROTATE (V, S, __srotr)
359#define _lrotr(V,S) __ROTATE (V, S, __lrotr)
360#define _crotl(V,S) __ROTATE (V, S, __crotl)
361#define _srotl(V,S) __ROTATE (V, S, __srotl)
362#define _lrotl(V,S) __ROTATE (V, S, __lrotl)
363
364#define _rotr(V,S) _lrotr (V, S)
365#define _rotl(V,S) _lrotl (V, S)
366
367
368static __inline__ int __fls (int v)
369{
370 int r;
371
372 __asm__ __volatile__ ("bsrl %1, %0;"
373 "jnz 1f;"
374 "movl $-1, %0;"
375 ".align 2, 0x90;"
376 "1:"
377 : "=r"(r) : "r"(v) : "cc");
378 return r + 1;
379}
380
381/* Quick routines similar to div() and friends, but inline */
382
383static __inline__ long __ldivmod (long num, long den, long *rem)
384{
385 long q, r;
386 __asm__ ("cltd; idivl %2"
387 : "=a" (q), "=&d" (r)
388 : "r?m" (den), "a" (num));
389 *rem = r;
390 return q;
391}
392
393static __inline__ unsigned long __uldivmod (unsigned long num,
394 unsigned long den, unsigned long *rem)
395{
396 unsigned long q, r;
397 __asm__ ("xorl %%edx,%%edx; divl %2"
398 : "=a" (q), "=&d" (r)
399 : "r?m" (den), "a" (num));
400 *rem = r;
401 return q;
402}
403
404/*
405 Divide a 64-bit integer by a 32-bit one:
406
407 A*2^32 + B A B + (A mod 32)
408 ---------- = --- * 2^32 + ----------------
409 C C C
410*/
411static __inline__ long long __lldivmod (long long num, long den, long *rem)
412{
413 long long q;
414 long r;
415 __asm__ (" movl %%eax,%%esi;"
416 " movl %%edx,%%eax;"
417 " pushl %%edx;"
418 " cltd;"
419 " idivl %2;"
420 " ;"
421/* Now ensure remainder is smallest of possible two values (negative and
422 positive). For this we compare the remainder with positive and negative
423 denominator/2; if it is smaller than one and bigger than another we
424 consider it optimal, otherwise it can be made smaller by adding or
425 subtracting denominator to it. This is done to ensure no overflow
426 will occur at next division. */
427 " movl %2,%%ecx;"
428 " sarl $1,%%ecx;" /* ecx = den/2 */
429 " cmpl %%ecx,%%edx;"
430 " setl %%bl;"
431 " negl %%ecx;"
432 " cmpl %%ecx,%%edx;"
433 " setl %%bh;"
434 " xorb %%bh,%%bl;"
435 " jnz 1f;" /* Remainder is between -den/2...den/2 */
436 " ;"
437/* If remainder has same sign as denominator, we have to do r -= den; q++;
438 otherwise we have to do r += den; q--; */
439 " movl %2,%%ebx;" /* ebx = den */
440 " xorl %%edx,%%ebx;" /* r ^ den */
441 " js 0f;" /* Different signs */
442 " subl %2,%%edx;" /* r -= den */
443 " addl $1,%%eax;" /* q++ */
444 " adcl $0,%%edx;"
445 " jmp 1f;"
446 " ;"
447 "0: addl %2,%%edx;" /* r += den */
448 " subl $1,%%eax;" /* q-- */
449 " sbbl $0,%%edx;"
450 " ;"
451 "1: xchgl %%eax,%%esi;"
452 " idivl %2;"
453 " ;"
454 " movl %%edx,%1;"
455 " cltd;"
456 " addl %%esi,%%edx;"
457 " ;"
458/* Check if numerator has the same sign as remainder; if they have different
459 sign we should make the remainder have same sign as numerator to comply
460 with ANSI standard, which says we always should truncate the quotient
461 towards zero. */
462 " popl %%ebx;" /* ebx = num >> 32 */
463 " xorl %1,%%ebx;" /* sign(r) ^ sign(num) */
464 " jns 3f;" /* jump if same sign */
465 " ;"
466/* If remainder has same sign as denominator, we have to do r -= den; q++;
467 otherwise we have to do r += den; q--; */
468 " movl %2,%%ebx;"
469 " xorl %1,%%ebx;" /* r ^ den */
470 " js 2f;" /* Different signs */
471 " subl %2,%1;" /* r -= den */
472 " addl $1,%%eax;" /* q++ */
473 " adcl $0,%%edx;"
474 " jmp 3f;"
475 " ;"
476 "2: addl %2,%1;" /* r += den */
477 " subl $1,%%eax;" /* q-- */
478 " sbbl $0,%%edx;"
479 " ;"
480 "3: ;"
481 : "=A" (q), "=&c" (r)
482 : "r" (den), "A" (num)
483 : "ebx", "esi");
484 *rem = r;
485 return q;
486}
487
488/*
489 Same as __lldivmod except that if A < C, we can do just one division
490 instead of two because the result is always a 32-bit integer.
491*/
492static __inline__ unsigned long long __ulldivmod (unsigned long long num,
493 unsigned long den, unsigned long *rem)
494{
495 unsigned long long q;
496 unsigned long r;
497 __asm__ (" movl %%eax,%1;"
498 " movl %%edx,%%eax;"
499 " xorl %%edx,%%edx;"
500 " divl %2;"
501 " xchgl %%eax,%%ecx;"
502 " divl %2;"
503 " xchgl %%edx,%1;"
504 : "=A" (q), "=c" (r)
505 : "r?m" (den), "A" (num));
506 *rem = r;
507 return q;
508}
509
510__END_DECLS
511#endif /* not _I386_BUILTIN_H */
Note: See TracBrowser for help on using the repository browser.