cpyte 2.3.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cpyte-2.4.0/MANIFEST.in +1 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/PKG-INFO +1 -1
- {cpyte-2.3.0 → cpyte-2.4.0}/pyproject.toml +1 -1
- cpyte-2.4.0/source/cpyte/bignum.c +469 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/bytecoding.py +57 -29
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/compiling.py +195 -1
- cpyte-2.4.0/source/cpyte/gc_runtime.c +322 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/mainpie.py +15 -6
- cpyte-2.4.0/source/cpyte/runtime.c +63 -0
- cpyte-2.4.0/source/cpyte/runtime_scorpion.c +197 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/PKG-INFO +1 -1
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/SOURCES.txt +5 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/readme.md +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/setup.cfg +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/__init__.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/__main__.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/_bignum_bc.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/_gc_bc.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/_runtime_bc.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/astparse.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/clib.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/extension_hooks.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/generate_bc.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/lexar.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/linker.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/lsp_server.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/package_manifest.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte/semantic_analasis.py +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/dependency_links.txt +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/entry_points.txt +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/requires.txt +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/source/cpyte.egg-info/top_level.txt +0 -0
- {cpyte-2.3.0 → cpyte-2.4.0}/test/test_bignum_jit.py +0 -0
cpyte-2.4.0/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include source/cpyte/*.c
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <stdint.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include <unistd.h>
|
|
6
|
+
|
|
7
|
+
// --- Minimal bignum implementation ---
|
|
8
|
+
// Each bignum is a 64-bit limb array (little-endian), dynamically allocated.
|
|
9
|
+
|
|
10
|
+
typedef struct {
|
|
11
|
+
uint64_t* limbs;
|
|
12
|
+
size_t len;
|
|
13
|
+
size_t used;
|
|
14
|
+
int negative;
|
|
15
|
+
} BigNum;
|
|
16
|
+
|
|
17
|
+
static void _bn_fail(const char* msg) {
|
|
18
|
+
write(2, msg, strlen(msg));
|
|
19
|
+
write(2, "\n", 1);
|
|
20
|
+
exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static BigNum* _bn_alloc(void) {
|
|
24
|
+
BigNum* b = malloc(sizeof(BigNum));
|
|
25
|
+
if (!b) _bn_fail("bigint: alloc failed");
|
|
26
|
+
b->limbs = NULL;
|
|
27
|
+
b->len = 0;
|
|
28
|
+
b->used = 0;
|
|
29
|
+
b->negative = 0;
|
|
30
|
+
return b;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static void _bn_reserve(BigNum* b, size_t n) {
|
|
34
|
+
if (n > b->len) {
|
|
35
|
+
size_t new_len = n < 4 ? 4 : n;
|
|
36
|
+
uint64_t* p = realloc(b->limbs, new_len * sizeof(uint64_t));
|
|
37
|
+
if (!p) _bn_fail("bigint: realloc failed");
|
|
38
|
+
b->limbs = p;
|
|
39
|
+
b->len = new_len;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static void _bn_trim(BigNum* b) {
|
|
44
|
+
if (b->used == 0) return;
|
|
45
|
+
while (b->used > 1 && b->limbs[b->used - 1] == 0)
|
|
46
|
+
b->used--;
|
|
47
|
+
if (b->used == 1 && b->limbs[0] == 0)
|
|
48
|
+
b->negative = 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void _bn_set_uint64(BigNum* b, uint64_t v) {
|
|
52
|
+
_bn_reserve(b, 1);
|
|
53
|
+
b->limbs[0] = v;
|
|
54
|
+
b->used = 1;
|
|
55
|
+
b->negative = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static int _bn_cmp_mag(const BigNum* a, const BigNum* b) {
|
|
59
|
+
if (a->used != b->used) return a->used < b->used ? -1 : 1;
|
|
60
|
+
for (size_t i = a->used; i > 0; i--) {
|
|
61
|
+
size_t idx = i - 1;
|
|
62
|
+
if (a->limbs[idx] != b->limbs[idx])
|
|
63
|
+
return a->limbs[idx] < b->limbs[idx] ? -1 : 1;
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void* bigint_new(void) {
|
|
69
|
+
BigNum* b = _bn_alloc();
|
|
70
|
+
_bn_reserve(b, 1);
|
|
71
|
+
b->limbs[0] = 0;
|
|
72
|
+
b->used = 1;
|
|
73
|
+
b->negative = 0;
|
|
74
|
+
return b;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
void bigint_free(void* p) {
|
|
78
|
+
if (!p) return;
|
|
79
|
+
BigNum* b = (BigNum*)p;
|
|
80
|
+
free(b->limbs);
|
|
81
|
+
free(b);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void* bigint_from_int(int64_t val) {
|
|
85
|
+
BigNum* b = _bn_alloc();
|
|
86
|
+
if (val < 0) {
|
|
87
|
+
_bn_set_uint64(b, (uint64_t)(-(val + 1)) + 1);
|
|
88
|
+
b->negative = 1;
|
|
89
|
+
} else {
|
|
90
|
+
_bn_set_uint64(b, (uint64_t)val);
|
|
91
|
+
}
|
|
92
|
+
return b;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
void* bigint_from_uint64(uint64_t val) {
|
|
96
|
+
BigNum* b = _bn_alloc();
|
|
97
|
+
_bn_set_uint64(b, val);
|
|
98
|
+
return b;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void* bigint_from_str(const char* str) {
|
|
102
|
+
if (!str || str[0] == '\0') return bigint_from_int(0);
|
|
103
|
+
BigNum* b = _bn_alloc();
|
|
104
|
+
const char* p = str;
|
|
105
|
+
int neg = 0;
|
|
106
|
+
if (*p == '-') { neg = 1; p++; }
|
|
107
|
+
else if (*p == '+') { p++; }
|
|
108
|
+
|
|
109
|
+
while (*p == '0') p++;
|
|
110
|
+
|
|
111
|
+
size_t digits = strlen(p);
|
|
112
|
+
if (digits == 0 || *p == '\0') {
|
|
113
|
+
_bn_reserve(b, 1);
|
|
114
|
+
b->limbs[0] = 0;
|
|
115
|
+
b->used = 1;
|
|
116
|
+
return b;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_bn_reserve(b, (digits / 19) + 2);
|
|
120
|
+
b->used = 1;
|
|
121
|
+
b->limbs[0] = 0;
|
|
122
|
+
|
|
123
|
+
while (*p) {
|
|
124
|
+
uint64_t carry = 0;
|
|
125
|
+
for (size_t i = 0; i < b->used; i++) {
|
|
126
|
+
__uint128_t v = (__uint128_t)b->limbs[i] * 10 + carry;
|
|
127
|
+
b->limbs[i] = (uint64_t)v;
|
|
128
|
+
carry = (uint64_t)(v >> 64);
|
|
129
|
+
}
|
|
130
|
+
if (carry) {
|
|
131
|
+
_bn_reserve(b, b->used + 1);
|
|
132
|
+
b->limbs[b->used++] = carry;
|
|
133
|
+
}
|
|
134
|
+
uint64_t d = (uint64_t)(*p - '0');
|
|
135
|
+
carry = d;
|
|
136
|
+
for (size_t i = 0; i < b->used && carry; i++) {
|
|
137
|
+
__uint128_t v = (__uint128_t)b->limbs[i] + carry;
|
|
138
|
+
b->limbs[i] = (uint64_t)v;
|
|
139
|
+
carry = (uint64_t)(v >> 64);
|
|
140
|
+
}
|
|
141
|
+
if (carry) {
|
|
142
|
+
_bn_reserve(b, b->used + 1);
|
|
143
|
+
b->limbs[b->used++] = carry;
|
|
144
|
+
}
|
|
145
|
+
p++;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_bn_trim(b);
|
|
149
|
+
b->negative = neg;
|
|
150
|
+
return b;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void* bigint_add(void* a, void* b) {
|
|
154
|
+
BigNum* x = (BigNum*)a;
|
|
155
|
+
if (!x) return b ? bigint_add(b, a) : bigint_from_int(0);
|
|
156
|
+
if (!b) return a;
|
|
157
|
+
BigNum* y = (BigNum*)b;
|
|
158
|
+
BigNum* r = _bn_alloc();
|
|
159
|
+
|
|
160
|
+
if (x->negative == y->negative) {
|
|
161
|
+
size_t max_used = x->used > y->used ? x->used : y->used;
|
|
162
|
+
_bn_reserve(r, max_used + 1);
|
|
163
|
+
uint64_t carry = 0;
|
|
164
|
+
size_t i = 0;
|
|
165
|
+
for (; i < x->used && i < y->used; i++) {
|
|
166
|
+
__uint128_t v = (__uint128_t)x->limbs[i] + y->limbs[i] + carry;
|
|
167
|
+
r->limbs[i] = (uint64_t)v;
|
|
168
|
+
carry = (uint64_t)(v >> 64);
|
|
169
|
+
}
|
|
170
|
+
for (; i < x->used; i++) {
|
|
171
|
+
__uint128_t v = (__uint128_t)x->limbs[i] + carry;
|
|
172
|
+
r->limbs[i] = (uint64_t)v;
|
|
173
|
+
carry = (uint64_t)(v >> 64);
|
|
174
|
+
}
|
|
175
|
+
for (; i < y->used; i++) {
|
|
176
|
+
__uint128_t v = (__uint128_t)y->limbs[i] + carry;
|
|
177
|
+
r->limbs[i] = (uint64_t)v;
|
|
178
|
+
carry = (uint64_t)(v >> 64);
|
|
179
|
+
}
|
|
180
|
+
if (carry)
|
|
181
|
+
r->limbs[i++] = carry;
|
|
182
|
+
r->used = i;
|
|
183
|
+
r->negative = x->negative;
|
|
184
|
+
} else {
|
|
185
|
+
int cmp = _bn_cmp_mag(x, y);
|
|
186
|
+
const BigNum* bigger = (cmp >= 0) ? x : y;
|
|
187
|
+
const BigNum* smaller = (cmp >= 0) ? y : x;
|
|
188
|
+
_bn_reserve(r, bigger->used);
|
|
189
|
+
uint64_t borrow = 0;
|
|
190
|
+
size_t i = 0;
|
|
191
|
+
for (; i < smaller->used; i++) {
|
|
192
|
+
__uint128_t v = (__uint128_t)bigger->limbs[i] - smaller->limbs[i] - borrow;
|
|
193
|
+
r->limbs[i] = (uint64_t)v;
|
|
194
|
+
borrow = (uint64_t)((v >> 64) & 1);
|
|
195
|
+
}
|
|
196
|
+
for (; i < bigger->used; i++) {
|
|
197
|
+
__uint128_t v = (__uint128_t)bigger->limbs[i] - borrow;
|
|
198
|
+
r->limbs[i] = (uint64_t)v;
|
|
199
|
+
borrow = (uint64_t)((v >> 64) & 1);
|
|
200
|
+
}
|
|
201
|
+
r->used = bigger->used;
|
|
202
|
+
_bn_trim(r);
|
|
203
|
+
r->negative = (bigger == x) ? x->negative : y->negative;
|
|
204
|
+
}
|
|
205
|
+
return r;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
void* bigint_neg(void* a) {
|
|
209
|
+
if (!a) return bigint_from_int(0);
|
|
210
|
+
BigNum* x = (BigNum*)a;
|
|
211
|
+
BigNum* r = _bn_alloc();
|
|
212
|
+
_bn_reserve(r, x->used);
|
|
213
|
+
memcpy(r->limbs, x->limbs, x->used * sizeof(uint64_t));
|
|
214
|
+
r->used = x->used;
|
|
215
|
+
r->negative = !x->negative;
|
|
216
|
+
if (r->used == 1 && r->limbs[0] == 0) r->negative = 0;
|
|
217
|
+
return r;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
void* bigint_sub(void* a, void* b) {
|
|
221
|
+
if (!a) return b ? bigint_neg(b) : bigint_from_int(0);
|
|
222
|
+
if (!b) return a;
|
|
223
|
+
BigNum* y = (BigNum*)b;
|
|
224
|
+
int orig_neg = y->negative;
|
|
225
|
+
y->negative = !y->negative;
|
|
226
|
+
void* r = bigint_add(a, b);
|
|
227
|
+
y->negative = orig_neg;
|
|
228
|
+
return r;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void* bigint_mul(void* a, void* b) {
|
|
232
|
+
if (!a || !b) return bigint_from_int(0);
|
|
233
|
+
BigNum* x = (BigNum*)a;
|
|
234
|
+
BigNum* y = (BigNum*)b;
|
|
235
|
+
BigNum* r = _bn_alloc();
|
|
236
|
+
|
|
237
|
+
size_t n = x->used + y->used;
|
|
238
|
+
_bn_reserve(r, n);
|
|
239
|
+
memset(r->limbs, 0, n * sizeof(uint64_t));
|
|
240
|
+
r->used = n;
|
|
241
|
+
|
|
242
|
+
for (size_t i = 0; i < x->used; i++) {
|
|
243
|
+
uint64_t carry = 0;
|
|
244
|
+
for (size_t j = 0; j < y->used; j++) {
|
|
245
|
+
__uint128_t v = (__uint128_t)x->limbs[i] * y->limbs[j]
|
|
246
|
+
+ r->limbs[i + j] + carry;
|
|
247
|
+
r->limbs[i + j] = (uint64_t)v;
|
|
248
|
+
carry = (uint64_t)(v >> 64);
|
|
249
|
+
}
|
|
250
|
+
if (carry)
|
|
251
|
+
r->limbs[i + y->used] += carry;
|
|
252
|
+
}
|
|
253
|
+
_bn_trim(r);
|
|
254
|
+
r->negative = x->negative ^ y->negative;
|
|
255
|
+
if (r->used == 1 && r->limbs[0] == 0) r->negative = 0;
|
|
256
|
+
return r;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
void* bigint_div(void* a, void* b) {
|
|
260
|
+
if (!a || !b) return bigint_from_int(0);
|
|
261
|
+
BigNum* x = (BigNum*)a;
|
|
262
|
+
BigNum* y = (BigNum*)b;
|
|
263
|
+
if (y->used == 1 && y->limbs[0] == 0)
|
|
264
|
+
return bigint_from_int(0);
|
|
265
|
+
BigNum* r = _bn_alloc();
|
|
266
|
+
|
|
267
|
+
if (_bn_cmp_mag(y, x) > 0) {
|
|
268
|
+
_bn_reserve(r, 1);
|
|
269
|
+
r->limbs[0] = 0;
|
|
270
|
+
r->used = 1;
|
|
271
|
+
r->negative = 0;
|
|
272
|
+
return r;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Schoolbook division for single-limb divisor (fast path)
|
|
276
|
+
if (y->used == 1) {
|
|
277
|
+
uint64_t div = y->limbs[0];
|
|
278
|
+
_bn_reserve(r, x->used);
|
|
279
|
+
r->used = x->used;
|
|
280
|
+
uint64_t rem = 0;
|
|
281
|
+
for (size_t i = x->used; i > 0; i--) {
|
|
282
|
+
__uint128_t v = ((__uint128_t)rem << 64) | x->limbs[i - 1];
|
|
283
|
+
r->limbs[i - 1] = (uint64_t)(v / div);
|
|
284
|
+
rem = (uint64_t)(v % div);
|
|
285
|
+
}
|
|
286
|
+
_bn_trim(r);
|
|
287
|
+
r->negative = x->negative ^ y->negative;
|
|
288
|
+
if (r->used == 1 && r->limbs[0] == 0) r->negative = 0;
|
|
289
|
+
return r;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// General case: long division (Knuth Algorithm D)
|
|
293
|
+
// Normalize divisor by shifting
|
|
294
|
+
int norm_shift = __builtin_clzll(y->limbs[y->used - 1]);
|
|
295
|
+
BigNum* u = _bn_alloc(); // normalized dividend
|
|
296
|
+
BigNum* v = _bn_alloc(); // normalized divisor
|
|
297
|
+
_bn_reserve(u, x->used + 1);
|
|
298
|
+
_bn_reserve(v, y->used);
|
|
299
|
+
|
|
300
|
+
if (norm_shift > 0) {
|
|
301
|
+
uint64_t carry = 0;
|
|
302
|
+
for (size_t i = 0; i < y->used; i++) {
|
|
303
|
+
uint64_t val = (carry) | (y->limbs[i] << norm_shift);
|
|
304
|
+
v->limbs[i] = val;
|
|
305
|
+
carry = y->limbs[i] >> (64 - norm_shift);
|
|
306
|
+
}
|
|
307
|
+
v->used = y->used;
|
|
308
|
+
|
|
309
|
+
carry = 0;
|
|
310
|
+
for (size_t i = 0; i < x->used; i++) {
|
|
311
|
+
uint64_t val = (carry) | (x->limbs[i] << norm_shift);
|
|
312
|
+
u->limbs[i] = val;
|
|
313
|
+
carry = x->limbs[i] >> (64 - norm_shift);
|
|
314
|
+
}
|
|
315
|
+
u->limbs[x->used] = carry;
|
|
316
|
+
u->used = x->used + (carry ? 1 : 0);
|
|
317
|
+
} else {
|
|
318
|
+
memcpy(v->limbs, y->limbs, y->used * sizeof(uint64_t));
|
|
319
|
+
v->used = y->used;
|
|
320
|
+
memcpy(u->limbs, x->limbs, x->used * sizeof(uint64_t));
|
|
321
|
+
u->used = x->used;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
size_t q_len = u->used - v->used + 1;
|
|
325
|
+
_bn_reserve(r, q_len);
|
|
326
|
+
memset(r->limbs, 0, q_len * sizeof(uint64_t));
|
|
327
|
+
r->used = q_len;
|
|
328
|
+
|
|
329
|
+
uint64_t v_top = v->limbs[v->used - 1];
|
|
330
|
+
|
|
331
|
+
for (size_t j = q_len; j > 0; j--) {
|
|
332
|
+
size_t idx = j - 1;
|
|
333
|
+
size_t u_idx = idx + v->used;
|
|
334
|
+
|
|
335
|
+
// Estimate quotient digit
|
|
336
|
+
__uint128_t u_hi;
|
|
337
|
+
if (u_idx >= u->used) {
|
|
338
|
+
if (u->used > 0) {
|
|
339
|
+
u_hi = ((__uint128_t)u->limbs[u->used - 1] << 64) |
|
|
340
|
+
(u->used > 1 ? u->limbs[u->used - 2] : 0);
|
|
341
|
+
} else {
|
|
342
|
+
u_hi = 0;
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
u_hi = ((__uint128_t)u->limbs[u_idx] << 64) |
|
|
346
|
+
(u_idx > 0 ? u->limbs[u_idx - 1] : 0);
|
|
347
|
+
}
|
|
348
|
+
__uint128_t q_est = u_hi / v_top;
|
|
349
|
+
if (q_est > 0xFFFFFFFFFFFFFFFFULL)
|
|
350
|
+
q_est = 0xFFFFFFFFFFFFFFFFULL;
|
|
351
|
+
|
|
352
|
+
// Subtract q_est * v from u
|
|
353
|
+
uint64_t borrow = 0;
|
|
354
|
+
for (size_t i = 0; i < v->used; i++) {
|
|
355
|
+
__uint128_t prod = q_est * v->limbs[i];
|
|
356
|
+
__uint128_t sub = (__uint128_t)u->limbs[idx + i] - (uint64_t)prod - borrow;
|
|
357
|
+
u->limbs[idx + i] = (uint64_t)sub;
|
|
358
|
+
borrow = (uint64_t)(prod >> 64) - (uint64_t)(sub >> 64);
|
|
359
|
+
}
|
|
360
|
+
__uint128_t final_sub = (__uint128_t)u->limbs[u_idx] - borrow;
|
|
361
|
+
u->limbs[u_idx] = (uint64_t)final_sub;
|
|
362
|
+
|
|
363
|
+
if ((uint64_t)(final_sub >> 64) != 0) {
|
|
364
|
+
// Quotient was too large, add back
|
|
365
|
+
q_est--;
|
|
366
|
+
uint64_t carry = 0;
|
|
367
|
+
for (size_t i = 0; i < v->used; i++) {
|
|
368
|
+
__uint128_t sum = (__uint128_t)u->limbs[idx + i] + v->limbs[i] + carry;
|
|
369
|
+
u->limbs[idx + i] = (uint64_t)sum;
|
|
370
|
+
carry = (uint64_t)(sum >> 64);
|
|
371
|
+
}
|
|
372
|
+
u->limbs[u_idx] += carry;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
r->limbs[idx] = (uint64_t)q_est;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
_bn_trim(r);
|
|
379
|
+
bigint_free(u);
|
|
380
|
+
bigint_free(v);
|
|
381
|
+
|
|
382
|
+
r->negative = x->negative ^ y->negative;
|
|
383
|
+
if (r->used == 1 && r->limbs[0] == 0) r->negative = 0;
|
|
384
|
+
return r;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
void* bigint_mod(void* a, void* b) {
|
|
388
|
+
if (!a || !b) return bigint_from_int(0);
|
|
389
|
+
BigNum* x = (BigNum*)a;
|
|
390
|
+
void* q = bigint_div(a, b);
|
|
391
|
+
BigNum* qt = (BigNum*)q;
|
|
392
|
+
void* prod = bigint_mul(q, b);
|
|
393
|
+
BigNum* pt = (BigNum*)prod;
|
|
394
|
+
pt->negative = 0;
|
|
395
|
+
qt->negative = 0;
|
|
396
|
+
|
|
397
|
+
BigNum* r = _bn_alloc();
|
|
398
|
+
int cmp = _bn_cmp_mag(x, pt);
|
|
399
|
+
const BigNum* bigger = (cmp >= 0) ? (BigNum*)a : pt;
|
|
400
|
+
const BigNum* smaller = (cmp >= 0) ? pt : (BigNum*)a;
|
|
401
|
+
_bn_reserve(r, bigger->used);
|
|
402
|
+
uint64_t borrow = 0;
|
|
403
|
+
size_t i = 0;
|
|
404
|
+
for (; i < smaller->used; i++) {
|
|
405
|
+
__uint128_t v = (__uint128_t)bigger->limbs[i] - smaller->limbs[i] - borrow;
|
|
406
|
+
r->limbs[i] = (uint64_t)v;
|
|
407
|
+
borrow = (uint64_t)((v >> 64) & 1);
|
|
408
|
+
}
|
|
409
|
+
for (; i < bigger->used; i++) {
|
|
410
|
+
__uint128_t v = (__uint128_t)bigger->limbs[i] - borrow;
|
|
411
|
+
r->limbs[i] = (uint64_t)v;
|
|
412
|
+
borrow = (uint64_t)((v >> 64) & 1);
|
|
413
|
+
}
|
|
414
|
+
r->used = bigger->used;
|
|
415
|
+
_bn_trim(r);
|
|
416
|
+
r->negative = 0;
|
|
417
|
+
|
|
418
|
+
bigint_free(q);
|
|
419
|
+
bigint_free(prod);
|
|
420
|
+
return r;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
int bigint_cmp(void* a, void* b) {
|
|
424
|
+
BigNum* x = (BigNum*)a;
|
|
425
|
+
BigNum* y = (BigNum*)b;
|
|
426
|
+
if (!x && !y) return 0;
|
|
427
|
+
if (!x) return y->negative ? 1 : -1;
|
|
428
|
+
if (!y) return x->negative ? -1 : 1;
|
|
429
|
+
if (x->negative != y->negative)
|
|
430
|
+
return x->negative ? -1 : 1;
|
|
431
|
+
int cmp = _bn_cmp_mag(x, y);
|
|
432
|
+
return x->negative ? -cmp : cmp;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void bigint_print(void* p) {
|
|
436
|
+
BigNum* b = (BigNum*)p;
|
|
437
|
+
if (!b) { printf("(null)"); return; }
|
|
438
|
+
if (b->negative) putchar('-');
|
|
439
|
+
if (b->used == 1 && b->limbs[0] == 0) {
|
|
440
|
+
putchar('0');
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
size_t max_digits = b->used * 20 + 1;
|
|
444
|
+
char* buf = malloc(max_digits);
|
|
445
|
+
if (!buf) _bn_fail("bigint_print: alloc failed");
|
|
446
|
+
|
|
447
|
+
BigNum tmp;
|
|
448
|
+
tmp.limbs = malloc(b->used * sizeof(uint64_t));
|
|
449
|
+
memcpy(tmp.limbs, b->limbs, b->used * sizeof(uint64_t));
|
|
450
|
+
tmp.used = b->used;
|
|
451
|
+
tmp.len = b->used;
|
|
452
|
+
tmp.negative = 0;
|
|
453
|
+
|
|
454
|
+
size_t pos = max_digits;
|
|
455
|
+
buf[--pos] = '\0';
|
|
456
|
+
while (!(tmp.used == 1 && tmp.limbs[0] == 0)) {
|
|
457
|
+
uint64_t carry = 0;
|
|
458
|
+
for (size_t i = tmp.used; i > 0; i--) {
|
|
459
|
+
__uint128_t v = (__uint128_t)carry << 64 | tmp.limbs[i - 1];
|
|
460
|
+
tmp.limbs[i - 1] = (uint64_t)(v / 10);
|
|
461
|
+
carry = (uint64_t)(v % 10);
|
|
462
|
+
}
|
|
463
|
+
buf[--pos] = (char)('0' + carry);
|
|
464
|
+
_bn_trim(&tmp);
|
|
465
|
+
}
|
|
466
|
+
free(tmp.limbs);
|
|
467
|
+
printf("%s", buf + pos);
|
|
468
|
+
free(buf);
|
|
469
|
+
}
|
|
@@ -172,12 +172,17 @@ class LLVM:
|
|
|
172
172
|
return val
|
|
173
173
|
return self.builder.call(fn, [val])
|
|
174
174
|
|
|
175
|
-
def __init__(self, no_userspace=False, enable_extensions=True):
|
|
175
|
+
def __init__(self, no_userspace=False, enable_extensions=True, target_triple=None, no_gc=False):
|
|
176
176
|
self.module = ir.Module("main")
|
|
177
|
+
self.no_gc = no_gc
|
|
178
|
+
self._target_triple = target_triple
|
|
177
179
|
try:
|
|
178
180
|
import llvmlite.binding as _binding
|
|
179
181
|
_binding.initialize_native_target()
|
|
180
|
-
|
|
182
|
+
if target_triple:
|
|
183
|
+
_target = _binding.Target.from_triple(target_triple)
|
|
184
|
+
else:
|
|
185
|
+
_target = _binding.Target.from_default_triple()
|
|
181
186
|
_tm = _target.create_target_machine()
|
|
182
187
|
self.module.triple = _tm.triple
|
|
183
188
|
self.module.data_layout = _tm.target_data.get_data_layout()
|
|
@@ -200,6 +205,7 @@ class LLVM:
|
|
|
200
205
|
self._free_fn = None
|
|
201
206
|
self._gc_alloc_fn = None
|
|
202
207
|
self._gc_write_barrier_fn = None
|
|
208
|
+
self._sizeof_cache = {}
|
|
203
209
|
self._strlen_fn = None
|
|
204
210
|
self._memcpy_fn = None
|
|
205
211
|
self.no_userspace = no_userspace
|
|
@@ -252,18 +258,19 @@ class LLVM:
|
|
|
252
258
|
self.functions[name] = fn
|
|
253
259
|
|
|
254
260
|
# Concurrent tri-color GC runtime functions (ugc-based)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
261
|
+
if not self.no_gc:
|
|
262
|
+
gc_fns = [
|
|
263
|
+
('gc_init', _void, []),
|
|
264
|
+
('gc_malloc', _i8ptr, [_i64]),
|
|
265
|
+
('gc_write_barrier', _void, [_i8ptr, _i8ptr]),
|
|
266
|
+
('gc_collect', _void, []),
|
|
267
|
+
('gc_start_thread', _void, []),
|
|
268
|
+
('gc_stop_thread', _void, []),
|
|
269
|
+
('gc_shutdown', _void, []),
|
|
270
|
+
]
|
|
271
|
+
for name, ret, args in gc_fns:
|
|
272
|
+
fn = ir.Function(self.module, ir.FunctionType(ret, args), name=name)
|
|
273
|
+
self.functions[name] = fn
|
|
267
274
|
|
|
268
275
|
# Exception handling globals
|
|
269
276
|
self._exc_buf_ptr = ir.GlobalVariable(self.module, _i8ptr, "_exc_buf_ptr")
|
|
@@ -509,19 +516,20 @@ class LLVM:
|
|
|
509
516
|
|
|
510
517
|
if wrapper_builder is not None:
|
|
511
518
|
self.builder = wrapper_builder
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
+
if not self.no_gc:
|
|
520
|
+
# Initialize concurrent tri-color GC and start background thread
|
|
521
|
+
gc_init_fn = self.functions.get('gc_init')
|
|
522
|
+
if gc_init_fn:
|
|
523
|
+
self.builder.call(gc_init_fn, [])
|
|
524
|
+
gc_start_fn = self.functions.get('gc_start_thread')
|
|
525
|
+
if gc_start_fn:
|
|
526
|
+
self.builder.call(gc_start_fn, [])
|
|
519
527
|
for node in toplevel:
|
|
520
528
|
self.emit(node)
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
529
|
+
if not self.no_gc:
|
|
530
|
+
gc_shutdown_fn = self.functions.get('gc_shutdown')
|
|
531
|
+
if gc_shutdown_fn:
|
|
532
|
+
self.builder.call(gc_shutdown_fn, [])
|
|
525
533
|
self.builder.ret(ir.Constant(ir.IntType(32), 0))
|
|
526
534
|
|
|
527
535
|
return self.module, self.import_src_files
|
|
@@ -757,6 +765,19 @@ class LLVM:
|
|
|
757
765
|
return ptr
|
|
758
766
|
|
|
759
767
|
def _get_malloc_fn(self):
|
|
768
|
+
if self.no_gc:
|
|
769
|
+
# Bare-metal: use plain malloc
|
|
770
|
+
fn = self._malloc_fn
|
|
771
|
+
if fn is not None:
|
|
772
|
+
return fn
|
|
773
|
+
for f in self.module.functions:
|
|
774
|
+
if f.name == 'malloc':
|
|
775
|
+
self._malloc_fn = f
|
|
776
|
+
return f
|
|
777
|
+
fnty = ir.FunctionType(_i8ptr, [_i64])
|
|
778
|
+
fn = ir.Function(self.module, fnty, 'malloc')
|
|
779
|
+
self._malloc_fn = fn
|
|
780
|
+
return fn
|
|
760
781
|
# Concurrent tri-color GC allocator
|
|
761
782
|
fn = self._gc_alloc_fn
|
|
762
783
|
if fn is not None:
|
|
@@ -787,6 +808,8 @@ class LLVM:
|
|
|
787
808
|
def _emit_write_barrier(self, parent_ptr, child_ptr):
|
|
788
809
|
"""Insert a write barrier call when storing a pointer value into a heap object.
|
|
789
810
|
parent_ptr and child_ptr must be i8* typed LLVM values."""
|
|
811
|
+
if self.no_gc:
|
|
812
|
+
return
|
|
790
813
|
if parent_ptr.type != _i8ptr:
|
|
791
814
|
parent_ptr = self.builder.bitcast(parent_ptr, _i8ptr)
|
|
792
815
|
if child_ptr.type != _i8ptr:
|
|
@@ -845,8 +868,13 @@ class LLVM:
|
|
|
845
868
|
return (4, 4)
|
|
846
869
|
|
|
847
870
|
def _sizeof_type(self, ty):
|
|
871
|
+
key = id(ty)
|
|
872
|
+
if key in self._sizeof_cache:
|
|
873
|
+
return self._sizeof_cache[key]
|
|
848
874
|
sz, _ = self._type_abi_info(ty)
|
|
849
|
-
|
|
875
|
+
c = ir.Constant(ir.IntType(32), sz)
|
|
876
|
+
self._sizeof_cache[key] = c
|
|
877
|
+
return c
|
|
850
878
|
|
|
851
879
|
def emit_deref(self, node: Deref):
|
|
852
880
|
ptr = self.emit(node.operand)
|
|
@@ -1042,7 +1070,7 @@ class LLVM:
|
|
|
1042
1070
|
self.builder.position_at_end(entry)
|
|
1043
1071
|
|
|
1044
1072
|
# Initialize concurrent tri-color GC in main function
|
|
1045
|
-
if node.name == 'main':
|
|
1073
|
+
if node.name == 'main' and not self.no_gc:
|
|
1046
1074
|
gc_init_fn = self.functions.get('gc_init')
|
|
1047
1075
|
if gc_init_fn:
|
|
1048
1076
|
self.builder.call(gc_init_fn, [])
|
|
@@ -1066,7 +1094,7 @@ class LLVM:
|
|
|
1066
1094
|
|
|
1067
1095
|
if not self.builder.block.is_terminated:
|
|
1068
1096
|
# Shutdown GC before main returns
|
|
1069
|
-
if node.name == 'main':
|
|
1097
|
+
if node.name == 'main' and not self.no_gc:
|
|
1070
1098
|
gc_shutdown_fn = self.functions.get('gc_shutdown')
|
|
1071
1099
|
if gc_shutdown_fn:
|
|
1072
1100
|
self.builder.call(gc_shutdown_fn, [])
|
|
@@ -1086,7 +1114,7 @@ class LLVM:
|
|
|
1086
1114
|
return None
|
|
1087
1115
|
# Shutdown GC before main returns
|
|
1088
1116
|
fn_name = self.builder.function.name
|
|
1089
|
-
if fn_name == 'main':
|
|
1117
|
+
if fn_name == 'main' and not self.no_gc:
|
|
1090
1118
|
gc_shutdown_fn = self.functions.get('gc_shutdown')
|
|
1091
1119
|
if gc_shutdown_fn:
|
|
1092
1120
|
self.builder.call(gc_shutdown_fn, [])
|