My Project
Chargement...
Recherche...
Aucune correspondance
arith64.c
Aller à la documentation de ce fichier.
1// GCC 32/64-bit integer arithmetic support for 32-bit systems that can't link
2// to libgcc.
3
4// Function prototypes and descriptions are taken from
5// https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html.
6
7// This file may be #include'd by another file, so we try not to pollute the
8// namespace and we don't import any headers.
9
10// All functions must be resolvable by the linker and therefore can't be inline
11// or static, even if they're #included into the file where they'll be used.
12
13// For best performance we try to avoid branching. This makes the code a little
14// weird in places.
15
16// See https://github.com/glitchub/arith64 for more information.
17// This software is released as-is into the public domain, as described at
18// https://unlicense.org. Do whatever you like with it.
19
20#include <manux/arith64.h>
21
22// Return the absolute value of a.
23// Note LLINT_MIN cannot be negated.
24static arith64_s64 __absvdi2(arith64_s64 a)
25{
26 return arith64_abs(a);
27}
28
29// Return the result of shifting a left by b bits.
30static arith64_s64 __ashldi3(arith64_s64 a, int b)
31{
32 arith64_word w = {.s64 = a};
33
34 b &= 63;
35
36 if (b >= 32)
37 {
38 w.u32.hi = w.u32.lo << (b - 32);
39 w.u32.lo = 0;
40 } else if (b)
41 {
42 w.u32.hi = (w.u32.lo >> (32 - b)) | (w.u32.hi << b);
43 w.u32.lo <<= b;
44 }
45 return w.s64;
46}
47
48// Return the result of arithmetically shifting a right by b bits.
49static arith64_s64 __ashrdi3(arith64_s64 a, int b)
50{
51 arith64_word w = {.s64 = a};
52
53 b &= 63;
54
55 if (b >= 32)
56 {
57 w.s32.lo = w.s32.hi >> (b - 32);
58 w.s32.hi >>= 31; // 0xFFFFFFFF or 0
59 } else if (b)
60 {
61 w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
62 w.s32.hi >>= b;
63 }
64 return w.s64;
65}
66
67// These functions return the number of leading 0-bits in a, starting at the
68// most significant bit position. If a is zero, the result is undefined.
69static int __clzsi2(arith64_u32 a)
70{
71 int b, n = 0;
72 b = !(a & 0xffff0000) << 4; n += b; a <<= b;
73 b = !(a & 0xff000000) << 3; n += b; a <<= b;
74 b = !(a & 0xf0000000) << 2; n += b; a <<= b;
75 b = !(a & 0xc0000000) << 1; n += b; a <<= b;
76 return n + !(a & 0x80000000);
77}
78
79static int __clzdi2(arith64_u64 a)
80{
81 int b, n = 0;
82 b = !(a & 0xffffffff00000000ULL) << 5; n += b; a <<= b;
83 b = !(a & 0xffff000000000000ULL) << 4; n += b; a <<= b;
84 b = !(a & 0xff00000000000000ULL) << 3; n += b; a <<= b;
85 b = !(a & 0xf000000000000000ULL) << 2; n += b; a <<= b;
86 b = !(a & 0xc000000000000000ULL) << 1; n += b; a <<= b;
87 return n + !(a & 0x8000000000000000ULL);
88}
89
90// These functions return the number of trailing 0-bits in a, starting at the
91// least significant bit position. If a is zero, the result is undefined.
92static int __ctzsi2(arith64_u32 a)
93{
94 int b, n = 0;
95 b = !(a & 0x0000ffff) << 4; n += b; a >>= b;
96 b = !(a & 0x000000ff) << 3; n += b; a >>= b;
97 b = !(a & 0x0000000f) << 2; n += b; a >>= b;
98 b = !(a & 0x00000003) << 1; n += b; a >>= b;
99 return n + !(a & 0x00000001);
100}
101
102static int __ctzdi2(arith64_u64 a)
103{
104 int b, n = 0;
105 b = !(a & 0x00000000ffffffffULL) << 5; n += b; a >>= b;
106 b = !(a & 0x000000000000ffffULL) << 4; n += b; a >>= b;
107 b = !(a & 0x00000000000000ffULL) << 3; n += b; a >>= b;
108 b = !(a & 0x000000000000000fULL) << 2; n += b; a >>= b;
109 b = !(a & 0x0000000000000003ULL) << 1; n += b; a >>= b;
110 return n + !(a & 0x0000000000000001ULL);
111}
112
113// Calculate both the quotient and remainder of the unsigned division of a and
114// b. The return value is the quotient, and the remainder is placed in variable
115// pointed to by c (if it's not NULL).
116static arith64_u64 __divmoddi4(arith64_u64 a, arith64_u64 b, arith64_u64 *c)
117{
118 if (b > a) // divisor > numerator?
119 {
120 if (c) *c = a; // remainder = numerator
121 return 0; // quotient = 0
122 }
123 if (!arith64_hi(b)) // divisor is 32-bit
124 {
125 if (b == 0) // divide by 0
126 {
127 volatile char x = 0; x = 1 / x; // force an exception
128 }
129 if (b == 1) // divide by 1
130 {
131 if (c) *c = 0; // remainder = 0
132 return a; // quotient = numerator
133 }
134 if (!arith64_hi(a)) // numerator is also 32-bit
135 {
136 if (c) // use generic 32-bit operators
137 *c = arith64_lo(a) % arith64_lo(b);
138 return arith64_lo(a) / arith64_lo(b);
139 }
140 }
141
142 // let's do long division
143 char bits = __clzdi2(b) - __clzdi2(a) + 1; // number of bits to iterate (a and b are non-zero)
144 arith64_u64 rem = a >> bits; // init remainder
145 a <<= 64 - bits; // shift numerator to the high bit
146 arith64_u64 wrap = 0; // start with wrap = 0
147 while (bits-- > 0) // for each bit
148 {
149 rem = (rem << 1) | (a >> 63); // shift numerator MSB to remainder LSB
150 a = (a << 1) | (wrap & 1); // shift out the numerator, shift in wrap
151 wrap = ((arith64_s64)(b - rem - 1) >> 63); // wrap = (b > rem) ? 0 : 0xffffffffffffffff (via sign extension)
152 rem -= b & wrap; // if (wrap) rem -= b
153 }
154 if (c) *c = rem; // maybe set remainder
155 return (a << 1) | (wrap & 1); // return the quotient
156}
157
158// Return the quotient of the signed division of a and b.
160{
161 arith64_u64 q = __divmoddi4(arith64_abs(a), arith64_abs(b), (void *)0);
162 return arith64_neg(q, a^b); // negate q if a and b signs are different
163}
164
165// Return the index of the least significant 1-bit in a, or the value zero if a
166// is zero. The least significant bit is index one.
167static int __ffsdi2(arith64_u64 a)
168{
169 return a ? __ctzdi2(a) + 1 : 0;
170}
171
172// Return the result of logically shifting a right by b bits.
173static arith64_u64 __lshrdi3(arith64_u64 a, int b)
174{
175 arith64_word w = {.u64 = a};
176
177 b &= 63;
178
179 if (b >= 32)
180 {
181 w.u32.lo = w.u32.hi >> (b - 32);
182 w.u32.hi = 0;
183 } else if (b)
184 {
185 w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
186 w.u32.hi >>= b;
187 }
188 return w.u64;
189}
190
191// Return the remainder of the signed division of a and b.
193{
194 arith64_u64 r;
195 __divmoddi4(arith64_abs(a), arith64_abs(b), &r);
196 return arith64_neg(r, a); // negate remainder if numerator is negative
197}
198
199// Return the number of bits set in a.
200static int __popcountsi2(arith64_u32 a)
201{
202 // collect sums into two low bytes
203 a = a - ((a >> 1) & 0x55555555);
204 a = ((a >> 2) & 0x33333333) + (a & 0x33333333);
205 a = (a + (a >> 4)) & 0x0F0F0F0F;
206 a = (a + (a >> 16));
207 // add the bytes, return bottom 6 bits
208 return (a + (a >> 8)) & 63;
209}
210
211// Return the number of bits set in a.
212static int __popcountdi2(arith64_u64 a)
213{
214 // collect sums into two low bytes
215 a = a - ((a >> 1) & 0x5555555555555555ULL);
216 a = ((a >> 2) & 0x3333333333333333ULL) + (a & 0x3333333333333333ULL);
217 a = (a + (a >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
218 a = (a + (a >> 32));
219 a = (a + (a >> 16));
220 // add the bytes, return bottom 7 bits
221 return (a + (a >> 8)) & 127;
222}
223
224// Return the quotient of the unsigned division of a and b.
225static arith64_u64 __udivdi3(arith64_u64 a, arith64_u64 b)
226{
227 return __divmoddi4(a, b, (void *)0);
228}
229
230// Return the remainder of the unsigned division of a and b.
231static arith64_u64 __umoddi3(arith64_u64 a, arith64_u64 b)
232{
233 arith64_u64 r;
234 __divmoddi4(a, b, &r);
235 return r;
236}
arith64_s64 __divdi3(arith64_s64 a, arith64_s64 b)
Definition arith64.c:159
arith64_s64 __moddi3(arith64_s64 a, arith64_s64 b)
Definition arith64.c:192
#define arith64_lo(n)
Definition arith64.h:35
#define arith64_u32
Definition arith64.h:8
#define arith64_hi(n)
Definition arith64.h:34
#define arith64_abs(a)
Definition arith64.h:39
#define arith64_s64
Definition arith64.h:7
#define arith64_u64
Definition arith64.h:6
#define arith64_neg(a, b)
Definition arith64.h:38
uint16_t b
uint16_t a
Exemple de fonction de mise-à-jour d'un paramètre dans un registre.
uint16_t c
struct arith64_word::@1 s32
struct arith64_word::@0 u32
arith64_u64 u64
Definition arith64.h:13
arith64_u32 lo
Definition arith64.h:18
arith64_s64 s64
Definition arith64.h:14
arith64_u32 hi
Definition arith64.h:18