]> gitweb.factorcode.org Git - factor.git/blob - vm/math.cpp
vm: Add messages about things that can allocate. Fix a gc bug in the primitive for...
[factor.git] / vm / math.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 void factor_vm::primitive_bignum_to_fixnum()
7 {
8         ctx->replace(tag_fixnum(bignum_to_fixnum(untag<bignum>(ctx->peek()))));
9 }
10
11 void factor_vm::primitive_float_to_fixnum()
12 {
13         ctx->replace(tag_fixnum(float_to_fixnum(ctx->peek())));
14 }
15
16 /* does not allocate, even though from_signed_cell can allocate */
17 /* Division can only overflow when we are dividing the most negative fixnum
18 by -1. */
19 void factor_vm::primitive_fixnum_divint()
20 {
21         fixnum y = untag_fixnum(ctx->pop()); \
22         fixnum x = untag_fixnum(ctx->peek());
23         fixnum result = x / y;
24         if(result == -fixnum_min)
25                 /* Does not allocate */
26                 ctx->replace(from_signed_cell(-fixnum_min));
27         else
28                 ctx->replace(tag_fixnum(result));
29 }
30
31 /* does not allocate, even though from_signed_cell can allocate */
32 void factor_vm::primitive_fixnum_divmod()
33 {
34         cell y = ((cell *)ctx->datastack)[0];
35         cell x = ((cell *)ctx->datastack)[-1];
36         if(y == tag_fixnum(-1) && x == tag_fixnum(fixnum_min))
37         {
38                 /* Does not allocate */
39                 ((cell *)ctx->datastack)[-1] = from_signed_cell(-fixnum_min);
40                 ((cell *)ctx->datastack)[0] = tag_fixnum(0);
41         }
42         else
43         {
44                 ((cell *)ctx->datastack)[-1] = tag_fixnum(untag_fixnum(x) / untag_fixnum(y));
45                 ((cell *)ctx->datastack)[0] = (fixnum)x % (fixnum)y;
46         }
47 }
48
49 /*
50  * If we're shifting right by n bits, we won't overflow as long as none of the
51  * high WORD_SIZE-TAG_BITS-n bits are set.
52  */
53 inline fixnum factor_vm::sign_mask(fixnum x)
54 {
55         return x >> (WORD_SIZE - 1);
56 }
57
58 inline fixnum factor_vm::branchless_max(fixnum x, fixnum y)
59 {
60         return (x - ((x - y) & sign_mask(x - y)));
61 }
62
63 inline fixnum factor_vm::branchless_abs(fixnum x)
64 {
65         return (x ^ sign_mask(x)) - sign_mask(x);
66 }
67
68 void factor_vm::primitive_fixnum_shift()
69 {
70         fixnum y = untag_fixnum(ctx->pop());
71         fixnum x = untag_fixnum(ctx->peek());
72
73         if(x == 0)
74                 return;
75         else if(y < 0)
76         {
77                 y = branchless_max(y,-WORD_SIZE + 1);
78                 ctx->replace(tag_fixnum(x >> -y));
79                 return;
80         }
81         else if(y < WORD_SIZE - TAG_BITS)
82         {
83                 fixnum mask = -((fixnum)1 << (WORD_SIZE - 1 - TAG_BITS - y));
84                 if(!(branchless_abs(x) & mask))
85                 {
86                         ctx->replace(tag_fixnum(x << y));
87                         return;
88                 }
89         }
90
91         ctx->replace(tag<bignum>(bignum_arithmetic_shift(
92                 fixnum_to_bignum(x),y)));
93 }
94
95 void factor_vm::primitive_fixnum_to_bignum()
96 {
97         ctx->replace(tag<bignum>(fixnum_to_bignum(untag_fixnum(ctx->peek()))));
98 }
99
100 void factor_vm::primitive_float_to_bignum()
101 {
102         ctx->replace(tag<bignum>(float_to_bignum(ctx->peek())));
103 }
104
105 #define POP_BIGNUMS(x,y) \
106         bignum * y = untag<bignum>(ctx->pop()); \
107         bignum * x = untag<bignum>(ctx->pop());
108
109 void factor_vm::primitive_bignum_eq()
110 {
111         POP_BIGNUMS(x,y);
112         ctx->push(tag_boolean(bignum_equal_p(x,y)));
113 }
114
115 void factor_vm::primitive_bignum_add()
116 {
117         POP_BIGNUMS(x,y);
118         ctx->push(tag<bignum>(bignum_add(x,y)));
119 }
120
121 void factor_vm::primitive_bignum_subtract()
122 {
123         POP_BIGNUMS(x,y);
124         ctx->push(tag<bignum>(bignum_subtract(x,y)));
125 }
126
127 void factor_vm::primitive_bignum_multiply()
128 {
129         POP_BIGNUMS(x,y);
130         ctx->push(tag<bignum>(bignum_multiply(x,y)));
131 }
132
133 void factor_vm::primitive_bignum_divint()
134 {
135         POP_BIGNUMS(x,y);
136         ctx->push(tag<bignum>(bignum_quotient(x,y)));
137 }
138
139 void factor_vm::primitive_bignum_divmod()
140 {
141         bignum *q, *r;
142         POP_BIGNUMS(x,y);
143         bignum_divide(x,y,&q,&r);
144         ctx->push(tag<bignum>(q));
145         ctx->push(tag<bignum>(r));
146 }
147
148 void factor_vm::primitive_bignum_mod()
149 {
150         POP_BIGNUMS(x,y);
151         ctx->push(tag<bignum>(bignum_remainder(x,y)));
152 }
153
154 void factor_vm::primitive_bignum_gcd()
155 {
156         POP_BIGNUMS(x,y);
157         ctx->push(tag<bignum>(bignum_gcd(x,y)));
158 }
159
160 void factor_vm::primitive_bignum_and()
161 {
162         POP_BIGNUMS(x,y);
163         ctx->push(tag<bignum>(bignum_bitwise_and(x,y)));
164 }
165
166 void factor_vm::primitive_bignum_or()
167 {
168         POP_BIGNUMS(x,y);
169         ctx->push(tag<bignum>(bignum_bitwise_ior(x,y)));
170 }
171
172 void factor_vm::primitive_bignum_xor()
173 {
174         POP_BIGNUMS(x,y);
175         ctx->push(tag<bignum>(bignum_bitwise_xor(x,y)));
176 }
177
178 void factor_vm::primitive_bignum_shift()
179 {
180         fixnum y = untag_fixnum(ctx->pop());
181         bignum* x = untag<bignum>(ctx->pop());
182         ctx->push(tag<bignum>(bignum_arithmetic_shift(x,y)));
183 }
184
185 void factor_vm::primitive_bignum_less()
186 {
187         POP_BIGNUMS(x,y);
188         ctx->push(tag_boolean(bignum_compare(x,y) == bignum_comparison_less));
189 }
190
191 void factor_vm::primitive_bignum_lesseq()
192 {
193         POP_BIGNUMS(x,y);
194         ctx->push(tag_boolean(bignum_compare(x,y) != bignum_comparison_greater));
195 }
196
197 void factor_vm::primitive_bignum_greater()
198 {
199         POP_BIGNUMS(x,y);
200         ctx->push(tag_boolean(bignum_compare(x,y) == bignum_comparison_greater));
201 }
202
203 void factor_vm::primitive_bignum_greatereq()
204 {
205         POP_BIGNUMS(x,y);
206         ctx->push(tag_boolean(bignum_compare(x,y) != bignum_comparison_less));
207 }
208
209 void factor_vm::primitive_bignum_not()
210 {
211         ctx->replace(tag<bignum>(bignum_bitwise_not(untag<bignum>(ctx->peek()))));
212 }
213
214 void factor_vm::primitive_bignum_bitp()
215 {
216         int bit = (int)to_fixnum(ctx->pop());
217         bignum *x = untag<bignum>(ctx->pop());
218         ctx->push(tag_boolean(bignum_logbitp(bit,x)));
219 }
220
221 void factor_vm::primitive_bignum_log2()
222 {
223         ctx->replace(tag<bignum>(bignum_integer_length(untag<bignum>(ctx->peek()))));
224 }
225
226 /* allocates memory */
227 cell factor_vm::unbox_array_size_slow()
228 {
229         if(tagged<object>(ctx->peek()).type() == BIGNUM_TYPE)
230         {
231                 bignum *zero = untag<bignum>(bignum_zero);
232                 GC_BIGNUM(zero);
233                 bignum *max = cell_to_bignum(array_size_max);
234                 bignum *n = untag<bignum>(ctx->peek());
235                 if(bignum_compare(n,zero) != bignum_comparison_less
236                         && bignum_compare(n,max) == bignum_comparison_less)
237                 {
238                         ctx->pop();
239                         return bignum_to_cell(n);
240                 }
241         }
242
243         general_error(ERROR_ARRAY_SIZE,ctx->pop(),tag_fixnum(array_size_max));
244         return 0; /* can't happen */
245 }
246
247 void factor_vm::primitive_fixnum_to_float()
248 {
249         ctx->replace(allot_float(fixnum_to_float(ctx->peek())));
250 }
251
252 void factor_vm::primitive_format_float()
253 {
254         byte_array *array = allot_byte_array(100);
255         char *format = alien_offset(ctx->pop());
256         double value = untag_float_check(ctx->pop());
257         SNPRINTF(array->data<char>(),99,format,value);
258         ctx->push(tag<byte_array>(array));
259 }
260
261 #define POP_FLOATS(x,y) \
262         double y = untag_float(ctx->pop()); \
263         double x = untag_float(ctx->pop());
264
265 void factor_vm::primitive_float_eq()
266 {
267         POP_FLOATS(x,y);
268         ctx->push(tag_boolean(x == y));
269 }
270
271 void factor_vm::primitive_float_add()
272 {
273         POP_FLOATS(x,y);
274         ctx->push(allot_float(x + y));
275 }
276
277 void factor_vm::primitive_float_subtract()
278 {
279         POP_FLOATS(x,y);
280         ctx->push(allot_float(x - y));
281 }
282
283 void factor_vm::primitive_float_multiply()
284 {
285         POP_FLOATS(x,y);
286         ctx->push(allot_float(x * y));
287 }
288
289 void factor_vm::primitive_float_divfloat()
290 {
291         POP_FLOATS(x,y);
292         ctx->push(allot_float(x / y));
293 }
294
295 void factor_vm::primitive_float_less()
296 {
297         POP_FLOATS(x,y);
298         ctx->push(tag_boolean(x < y));
299 }
300
301 void factor_vm::primitive_float_lesseq()
302 {
303         POP_FLOATS(x,y);
304         ctx->push(tag_boolean(x <= y));
305 }
306
307 void factor_vm::primitive_float_greater()
308 {
309         POP_FLOATS(x,y);
310         ctx->push(tag_boolean(x > y));
311 }
312
313 void factor_vm::primitive_float_greatereq()
314 {
315         POP_FLOATS(x,y);
316         ctx->push(tag_boolean(x >= y));
317 }
318
319 /* Allocates memory */
320 void factor_vm::primitive_float_bits()
321 {
322         ctx->push(from_unsigned_cell(float_bits((float)untag_float_check(ctx->pop()))));
323 }
324
325 /* Allocates memory */
326 void factor_vm::primitive_bits_float()
327 {
328         ctx->push(allot_float(bits_float((u32)to_cell(ctx->pop()))));
329 }
330
331 void factor_vm::primitive_double_bits()
332 {
333         ctx->push(from_unsigned_8(double_bits(untag_float_check(ctx->pop()))));
334 }
335
336 void factor_vm::primitive_bits_double()
337 {
338         ctx->push(allot_float(bits_double(to_unsigned_8(ctx->pop()))));
339 }
340
341 /* Cannot allocate */
342 fixnum factor_vm::to_fixnum(cell tagged)
343 {
344         switch(TAG(tagged))
345         {
346         case FIXNUM_TYPE:
347                 return untag_fixnum(tagged);
348         case BIGNUM_TYPE:
349                 return bignum_to_fixnum(untag<bignum>(tagged));
350         default:
351                 type_error(FIXNUM_TYPE,tagged);
352                 return 0; /* can't happen */
353         }
354 }
355
356 VM_C_API fixnum to_fixnum(cell tagged, factor_vm *parent)
357 {
358         return parent->to_fixnum(tagged);
359 }
360
361 cell factor_vm::to_cell(cell tagged)
362 {
363         return (cell)to_fixnum(tagged);
364 }
365
366 VM_C_API cell to_cell(cell tagged, factor_vm *parent)
367 {
368         return parent->to_cell(tagged);
369 }
370
371 /* Allocates memory */
372 VM_C_API cell from_signed_cell(fixnum integer, factor_vm *parent)
373 {
374         return parent->from_signed_cell(integer);
375 }
376
377 /* Allocates memory */
378 VM_C_API cell from_unsigned_cell(cell integer, factor_vm *parent)
379 {
380         return parent->from_unsigned_cell(integer);
381 }
382
383 /* Allocates memory */
384 cell factor_vm::from_signed_8(s64 n)
385 {
386         if(n < fixnum_min || n > fixnum_max)
387                 return tag<bignum>(long_long_to_bignum(n));
388         else
389                 return tag_fixnum((fixnum)n);
390 }
391
392 VM_C_API cell from_signed_8(s64 n, factor_vm *parent)
393 {
394         return parent->from_signed_8(n);
395 }
396
397 /* Cannot allocate */
398 s64 factor_vm::to_signed_8(cell obj)
399 {
400         switch(tagged<object>(obj).type())
401         {
402         case FIXNUM_TYPE:
403                 return untag_fixnum(obj);
404         case BIGNUM_TYPE:
405                 return bignum_to_long_long(untag<bignum>(obj));
406         default:
407                 type_error(BIGNUM_TYPE,obj);
408                 return 0;
409         }
410 }
411
412 VM_C_API s64 to_signed_8(cell obj, factor_vm *parent)
413 {
414         return parent->to_signed_8(obj);
415 }
416
417 cell factor_vm::from_unsigned_8(u64 n)
418 {
419         if(n > (u64)fixnum_max)
420                 return tag<bignum>(ulong_long_to_bignum(n));
421         else
422                 return tag_fixnum((fixnum)n);
423 }
424
425 VM_C_API cell from_unsigned_8(u64 n, factor_vm *parent)
426 {
427         return parent->from_unsigned_8(n);
428 }
429
430 /* Cannot allocate */
431 u64 factor_vm::to_unsigned_8(cell obj)
432 {
433         switch(tagged<object>(obj).type())
434         {
435         case FIXNUM_TYPE:
436                 return untag_fixnum(obj);
437         case BIGNUM_TYPE:
438                 return bignum_to_ulong_long(untag<bignum>(obj));
439         default:
440                 type_error(BIGNUM_TYPE,obj);
441                 return 0;
442         }
443 }
444
445 VM_C_API u64 to_unsigned_8(cell obj, factor_vm *parent)
446 {
447         return parent->to_unsigned_8(obj);
448 }
449  
450 /* Cannot allocate */
451 float factor_vm::to_float(cell value)
452 {
453         return (float)untag_float_check(value);
454 }
455
456 /* Cannot allocate */
457 double factor_vm::to_double(cell value)
458 {
459         return untag_float_check(value);
460 }
461
462 /* The fixnum+, fixnum- and fixnum* primitives are defined in cpu_*.S. On
463 overflow, they call these functions. */
464 inline void factor_vm::overflow_fixnum_add(fixnum x, fixnum y)
465 {
466         ctx->replace(tag<bignum>(fixnum_to_bignum(
467                 untag_fixnum(x) + untag_fixnum(y))));
468 }
469
470 VM_C_API void overflow_fixnum_add(fixnum x, fixnum y, factor_vm *parent)
471 {
472         parent->overflow_fixnum_add(x,y);
473 }
474
475 inline void factor_vm::overflow_fixnum_subtract(fixnum x, fixnum y)
476 {
477         ctx->replace(tag<bignum>(fixnum_to_bignum(
478                 untag_fixnum(x) - untag_fixnum(y))));
479 }
480
481 VM_C_API void overflow_fixnum_subtract(fixnum x, fixnum y, factor_vm *parent)
482 {
483         parent->overflow_fixnum_subtract(x,y);
484 }
485
486 inline void factor_vm::overflow_fixnum_multiply(fixnum x, fixnum y)
487 {
488         bignum *bx = fixnum_to_bignum(x);
489         GC_BIGNUM(bx);
490         bignum *by = fixnum_to_bignum(y);
491         GC_BIGNUM(by);
492         ctx->replace(tag<bignum>(bignum_multiply(bx,by)));
493 }
494
495 VM_C_API void overflow_fixnum_multiply(fixnum x, fixnum y, factor_vm *parent)
496 {
497         parent->overflow_fixnum_multiply(x,y);
498 }
499
500 }