| 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 | #if defined (__cplusplus)
|
|---|
| 10 | extern "C" {
|
|---|
| 11 | #endif
|
|---|
| 12 |
|
|---|
| 13 | static __inline__ signed char __cxchg (__volatile__ signed char *p,
|
|---|
| 14 | signed char v)
|
|---|
| 15 | {
|
|---|
| 16 | __asm__ __volatile__ ("xchgb %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
|
|---|
| 17 | return v;
|
|---|
| 18 | }
|
|---|
| 19 |
|
|---|
| 20 | static __inline__ short __sxchg (__volatile__ short *p, short v)
|
|---|
| 21 | {
|
|---|
| 22 | __asm__ __volatile__ ("xchgw %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
|
|---|
| 23 | return v;
|
|---|
| 24 | }
|
|---|
| 25 |
|
|---|
| 26 | static __inline__ int __lxchg (__volatile__ int *p, int v)
|
|---|
| 27 | {
|
|---|
| 28 | __asm__ __volatile__ ("xchgl %0, %1" : "=m"(*p), "=r"(v) : "1"(v));
|
|---|
| 29 | return v;
|
|---|
| 30 | }
|
|---|
| 31 |
|
|---|
| 32 | static __inline__ void __enable (void)
|
|---|
| 33 | {
|
|---|
| 34 | __asm__ __volatile__ ("sti");
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | static __inline__ void __disable (void)
|
|---|
| 38 | {
|
|---|
| 39 | __asm__ __volatile__ ("cli");
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | #define __ROTATE_FUN(F,I,T) \
|
|---|
| 43 | static __inline__ T F (T value, int shift) \
|
|---|
| 44 | { \
|
|---|
| 45 | __asm__ (I " %b2, %0" : "=g"(value) : "0"(value), "c"(shift) : "cc"); \
|
|---|
| 46 | return value; \
|
|---|
| 47 | } \
|
|---|
| 48 | static __inline__ T F##1 (T value) \
|
|---|
| 49 | { \
|
|---|
| 50 | __asm__ (I " $1, %0" : "=g"(value) : "0"(value) : "cc"); \
|
|---|
| 51 | return value; \
|
|---|
| 52 | }
|
|---|
| 53 |
|
|---|
| 54 | #define __ROTATE(V,S,F) ((__builtin_constant_p (S) && (int)(S) == 1) \
|
|---|
| 55 | ? F##1 (V) : F (V, S))
|
|---|
| 56 |
|
|---|
| 57 | __ROTATE_FUN (__crotr, "rorb", unsigned char)
|
|---|
| 58 | __ROTATE_FUN (__srotr, "rorw", unsigned short)
|
|---|
| 59 | __ROTATE_FUN (__lrotr, "rorl", unsigned long)
|
|---|
| 60 |
|
|---|
| 61 | __ROTATE_FUN (__crotl, "rolb", unsigned char)
|
|---|
| 62 | __ROTATE_FUN (__srotl, "rolw", unsigned short)
|
|---|
| 63 | __ROTATE_FUN (__lrotl, "roll", unsigned long)
|
|---|
| 64 |
|
|---|
| 65 | #define _crotr(V,S) __ROTATE (V, S, __crotr)
|
|---|
| 66 | #define _srotr(V,S) __ROTATE (V, S, __srotr)
|
|---|
| 67 | #define _lrotr(V,S) __ROTATE (V, S, __lrotr)
|
|---|
| 68 | #define _crotl(V,S) __ROTATE (V, S, __crotl)
|
|---|
| 69 | #define _srotl(V,S) __ROTATE (V, S, __srotl)
|
|---|
| 70 | #define _lrotl(V,S) __ROTATE (V, S, __lrotl)
|
|---|
| 71 |
|
|---|
| 72 | #define _rotr(V,S) _lrotr (V, S)
|
|---|
| 73 | #define _rotl(V,S) _lrotl (V, S)
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 | static __inline__ int __fls (int v)
|
|---|
| 77 | {
|
|---|
| 78 | int r;
|
|---|
| 79 |
|
|---|
| 80 | __asm__ __volatile__ ("bsrl %1, %0;"
|
|---|
| 81 | "jnz 1f;"
|
|---|
| 82 | "movl $-1, %0;"
|
|---|
| 83 | ".align 2, 0x90;"
|
|---|
| 84 | "1:"
|
|---|
| 85 | : "=r"(r) : "r"(v) : "cc");
|
|---|
| 86 | return r + 1;
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | /* Quick routines similar to div() and friends, but inline */
|
|---|
| 90 |
|
|---|
| 91 | static __inline__ long __ldivmod (long num, long den, long *rem)
|
|---|
| 92 | {
|
|---|
| 93 | long q, r;
|
|---|
| 94 | __asm__ ("cltd; idivl %2"
|
|---|
| 95 | : "=a" (q), "=&d" (r)
|
|---|
| 96 | : "r?m" (den), "a" (num));
|
|---|
| 97 | *rem = r;
|
|---|
| 98 | return q;
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | static __inline__ unsigned long __uldivmod (unsigned long num,
|
|---|
| 102 | unsigned long den, unsigned long *rem)
|
|---|
| 103 | {
|
|---|
| 104 | unsigned long q, r;
|
|---|
| 105 | __asm__ ("xorl %%edx,%%edx; divl %2"
|
|---|
| 106 | : "=a" (q), "=&d" (r)
|
|---|
| 107 | : "r?m" (den), "a" (num));
|
|---|
| 108 | *rem = r;
|
|---|
| 109 | return q;
|
|---|
| 110 | }
|
|---|
| 111 |
|
|---|
| 112 | /*
|
|---|
| 113 | Divide a 64-bit integer by a 32-bit one:
|
|---|
| 114 |
|
|---|
| 115 | A*2^32 + B A B + (A mod 32)
|
|---|
| 116 | ---------- = --- * 2^32 + ----------------
|
|---|
| 117 | C C C
|
|---|
| 118 | */
|
|---|
| 119 | static __inline__ long long __lldivmod (long long num, long den, long *rem)
|
|---|
| 120 | {
|
|---|
| 121 | long long q;
|
|---|
| 122 | long r;
|
|---|
| 123 | __asm__ (" movl %%eax,%%esi;"
|
|---|
| 124 | " movl %%edx,%%eax;"
|
|---|
| 125 | " pushl %%edx;"
|
|---|
| 126 | " cltd;"
|
|---|
| 127 | " idivl %2;"
|
|---|
| 128 | " ;"
|
|---|
| 129 | /* Now ensure remainder is smallest of possible two values (negative and
|
|---|
| 130 | positive). For this we compare the remainder with positive and negative
|
|---|
| 131 | denominator/2; if it is smaller than one and bigger than another we
|
|---|
| 132 | consider it optimal, otherwise it can be made smaller by adding or
|
|---|
| 133 | subtracting denominator to it. This is done to ensure no overflow
|
|---|
| 134 | will occur at next division. */
|
|---|
| 135 | " movl %2,%%ecx;"
|
|---|
| 136 | " sarl $1,%%ecx;" /* ecx = den/2 */
|
|---|
| 137 | " cmpl %%ecx,%%edx;"
|
|---|
| 138 | " setl %%bl;"
|
|---|
| 139 | " negl %%ecx;"
|
|---|
| 140 | " cmpl %%ecx,%%edx;"
|
|---|
| 141 | " setl %%bh;"
|
|---|
| 142 | " xorb %%bh,%%bl;"
|
|---|
| 143 | " jnz 1f;" /* Remainder is between -den/2...den/2 */
|
|---|
| 144 | " ;"
|
|---|
| 145 | /* If remainder has same sign as denominator, we have to do r -= den; q++;
|
|---|
| 146 | otherwise we have to do r += den; q--; */
|
|---|
| 147 | " movl %2,%%ebx;" /* ebx = den */
|
|---|
| 148 | " xorl %%edx,%%ebx;" /* r ^ den */
|
|---|
| 149 | " js 0f;" /* Different signs */
|
|---|
| 150 | " subl %2,%%edx;" /* r -= den */
|
|---|
| 151 | " addl $1,%%eax;" /* q++ */
|
|---|
| 152 | " adcl $0,%%edx;"
|
|---|
| 153 | " jmp 1f;"
|
|---|
| 154 | " ;"
|
|---|
| 155 | "0: addl %2,%%edx;" /* r += den */
|
|---|
| 156 | " subl $1,%%eax;" /* q-- */
|
|---|
| 157 | " sbbl $0,%%edx;"
|
|---|
| 158 | " ;"
|
|---|
| 159 | "1: xchgl %%eax,%%esi;"
|
|---|
| 160 | " idivl %2;"
|
|---|
| 161 | " ;"
|
|---|
| 162 | " movl %%edx,%1;"
|
|---|
| 163 | " cltd;"
|
|---|
| 164 | " addl %%esi,%%edx;"
|
|---|
| 165 | " ;"
|
|---|
| 166 | /* Check if numerator has the same sign as remainder; if they have different
|
|---|
| 167 | sign we should make the remainder have same sign as numerator to comply
|
|---|
| 168 | with ANSI standard, which says we always should truncate the quotient
|
|---|
| 169 | towards zero. */
|
|---|
| 170 | " popl %%ebx;" /* ebx = num >> 32 */
|
|---|
| 171 | " xorl %1,%%ebx;" /* sign(r) ^ sign(num) */
|
|---|
| 172 | " jns 3f;" /* jump if same sign */
|
|---|
| 173 | " ;"
|
|---|
| 174 | /* If remainder has same sign as denominator, we have to do r -= den; q++;
|
|---|
| 175 | otherwise we have to do r += den; q--; */
|
|---|
| 176 | " movl %2,%%ebx;"
|
|---|
| 177 | " xorl %1,%%ebx;" /* r ^ den */
|
|---|
| 178 | " js 2f;" /* Different signs */
|
|---|
| 179 | " subl %2,%1;" /* r -= den */
|
|---|
| 180 | " addl $1,%%eax;" /* q++ */
|
|---|
| 181 | " adcl $0,%%edx;"
|
|---|
| 182 | " jmp 3f;"
|
|---|
| 183 | " ;"
|
|---|
| 184 | "2: addl %2,%1;" /* r += den */
|
|---|
| 185 | " subl $1,%%eax;" /* q-- */
|
|---|
| 186 | " sbbl $0,%%edx;"
|
|---|
| 187 | " ;"
|
|---|
| 188 | "3: ;"
|
|---|
| 189 | : "=A" (q), "=&c" (r)
|
|---|
| 190 | : "r" (den), "A" (num)
|
|---|
| 191 | : "ebx", "esi");
|
|---|
| 192 | *rem = r;
|
|---|
| 193 | return q;
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | /*
|
|---|
| 197 | Same as __lldivmod except that if A < C, we can do just one division
|
|---|
| 198 | instead of two because the result is always a 32-bit integer.
|
|---|
| 199 | */
|
|---|
| 200 | static __inline__ unsigned long long __ulldivmod (unsigned long long num,
|
|---|
| 201 | unsigned long den, unsigned long *rem)
|
|---|
| 202 | {
|
|---|
| 203 | unsigned long long q;
|
|---|
| 204 | unsigned long r;
|
|---|
| 205 | __asm__ (" movl %%eax,%1;"
|
|---|
| 206 | " movl %%edx,%%eax;"
|
|---|
| 207 | " xorl %%edx,%%edx;"
|
|---|
| 208 | " divl %2;"
|
|---|
| 209 | " xchgl %%eax,%%ecx;"
|
|---|
| 210 | " divl %2;"
|
|---|
| 211 | " xchgl %%edx,%1;"
|
|---|
| 212 | : "=A" (q), "=c" (r)
|
|---|
| 213 | : "r?m" (den), "A" (num));
|
|---|
| 214 | *rem = r;
|
|---|
| 215 | return q;
|
|---|
| 216 | }
|
|---|
| 217 |
|
|---|
| 218 | #if defined (__cplusplus)
|
|---|
| 219 | }
|
|---|
| 220 | #endif
|
|---|
| 221 |
|
|---|
| 222 | #endif /* not _I386_BUILTIN_H */
|
|---|