1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2000-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway
6 ;;;; Filename: integers.lisp
7 ;;;; Description: Arithmetics.
8 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
9 ;;;; Created at: Wed Nov 8 18:44:57 2000
10 ;;;; Distribution: See the accompanying file COPYING.
12 ;;;; $Id: integers.lisp,v 1.124 2008/02/04 10:08:18 ffjeld Exp $
14 ;;;;------------------------------------------------------------------
16 (require :muerte
/basic-macros
)
17 (require :muerte
/typep
)
18 (require :muerte
/arithmetic-macros
)
19 (provide :muerte
/integers
)
23 (defconstant most-positive-fixnum
#.movitz
::+movitz-most-positive-fixnum
+)
24 (defconstant most-negative-fixnum
#.movitz
::+movitz-most-negative-fixnum
+)
28 (define-primitive-function fast-compare-two-reals
(n1 n2
)
29 "Compare two numbers (i.e. set EFLAGS accordingly)."
32 `(with-inline-assembly (:returns
:nothing
) ; unspecified
33 (:testb
,movitz
::+movitz-fixnum-zmask
+ :al
)
35 (:testb
,movitz
::+movitz-fixnum-zmask
+ :bl
)
36 (:jnz
'n2-not-fixnum-but-n1-is
)
37 (:cmpl
:ebx
:eax
) ; both were fixnum
39 n1-not-fixnum
; but we don't know about n2
40 (:testb
,movitz
::+movitz-fixnum-zmask
+ :bl
)
41 (:jnz
'neither-is-fixnum
)
43 (:locally
(:jmp
(:edi
(:edi-offset fast-compare-real-fixnum
))))
44 n2-not-fixnum-but-n1-is
45 (:locally
(:jmp
(:edi
(:edi-offset fast-compare-fixnum-real
))))
47 ;; Check that both numbers are bignums, and compare them.
48 (:leal
(:eax
,(- (movitz:tag
:other
))) :ecx
)
50 (:jnz
'(:sub-program
(go-complicated)
51 (:globally
(:movl
(:edi
(:edi-offset complicated-compare
)) :esi
))
52 (:jmp
(:esi
(:offset movitz-funobj code-vector%
2op
)))))
53 (:movl
(:eax
,movitz
:+other-type-offset
+) :ecx
)
54 (:cmpb
,(movitz:tag
:bignum
) :cl
)
55 (:jne
'go-complicated
)
57 (:cmpl
:eax
:ebx
) ; If they are EQ, they are certainly =
58 (:je
'(:sub-program
(n1-and-n2-are-eq)
61 (:leal
(:ebx
,(- (movitz:tag
:other
))) :ecx
)
63 (:jnz
'go-complicated
)
64 (:movl
(:ebx
,movitz
:+other-type-offset
+) :ecx
)
65 (:cmpb
,(movitz:tag
:bignum
) :cl
)
66 (:jne
'go-complicated
)
68 (:cmpb
:ch
(:eax
(:offset movitz-bignum sign
)))
69 (:jne
'(:sub-program
(different-signs)
70 ;; Comparing the sign-bytes sets up EFLAGS correctly!
73 (:jnz
'compare-negatives
)
74 ;; Both n1 and n2 are positive bignums.
77 (:movzxw
(:eax
(:offset movitz-bignum length
)) :edx
)
78 ;; (:cmpw :cx (:eax (:offset movitz-bignum length)))
80 (:jne
'(:sub-program
(positive-different-sizes)
83 ;; Both n1 and n2 are positive bignums of the same size, namely ECX.
84 ;; (:movl :ecx :edx) ; counter
86 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
87 (:jz
'positive-compare-lsb
)
88 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
)) :ecx
)
89 (:cmpl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
90 (:je
'positive-compare-loop
)
92 ;; Now we have to make the compare act as unsigned, which is why
93 ;; we compare zero-extended 16-bit quantities.
94 (:movzxw
(:ebx
:edx
(:offset movitz-bignum bigit0
2)) :ecx
) ; First compare upper 16 bits.
95 (:locally
(:movl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
96 (:movzxw
(:eax
:edx
(:offset movitz-bignum bigit0
2)) :ecx
)
97 (:locally
(:cmpl
(:edi
(:edi-offset raw-scratch0
)) :ecx
))
98 (:jne
'upper-16-decisive
)
99 (:movzxw
(:ebx
:edx
(:offset movitz-bignum bigit0
))
100 :ecx
) ; Then compare lower 16 bits.
101 (:locally
(:movl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
102 (:movzxw
(:eax
:edx
(:offset movitz-bignum bigit0
))
103 :ecx
) ; Then compare lower 16 bits.
104 (:locally
(:cmpl
(:edi
(:edi-offset raw-scratch0
)) :ecx
))
109 ;; Moth n1 and n2 are negative bignums.
112 (:cmpw
(:eax
(:offset movitz-bignum length
)) :cx
)
113 (:jne
'(:sub-program
(negative-different-sizes)
116 ;; Both n1 and n2 are negative bignums of the same size, namely ECX.
117 (:movl
:ecx
:edx
) ; counter
118 negative-compare-loop
119 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
120 (:jz
'negative-compare-lsb
)
121 (:movl
(:eax
:edx
(:offset movitz-bignum bigit0
)) :ecx
)
122 (:cmpl
:ecx
(:ebx
:edx
(:offset movitz-bignum bigit0
)))
123 (:je
'negative-compare-loop
)
125 negative-compare-lsb
; it's down to the LSB bigits.
126 ;; Now we have to make the compare act as unsigned, which is why
127 ;; we compare zero-extended 16-bit quantities.
128 (:movzxw
(:ebx
:edx
(:offset movitz-bignum bigit0
2))
129 :ecx
) ; First compare upper 16 bits.
130 (:locally
(:movl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
131 (:movzxw
(:eax
:edx
(:offset movitz-bignum bigit0
)) :ecx
)
132 (:locally
(:cmpl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
133 (:jne
'negative-upper-16-decisive
)
134 (:movzxw
(:ebx
:edx
(:offset movitz-bignum bigit0
))
135 :ecx
) ; Then compare lower 16 bits.
136 (:locally
(:movl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
137 (:movzxw
(:eax
:edx
(:offset movitz-bignum bigit0
))
138 :ecx
) ; Then compare lower 16 bits.
139 (:locally
(:cmpl
:ecx
(:edi
(:edi-offset raw-scratch0
))))
140 negative-upper-16-decisive
144 (defun complicated-eql (x y
)
147 `(with-inline-assembly (:returns
:multiple-values
) ; well..
148 (:compile-two-forms
(:eax
:ebx
) x y
)
149 (:cmpl
:eax
:ebx
) ; EQ?
151 (:leal
(:eax
,(- (movitz:tag
:other
))) :ecx
)
154 (:leal
(:ebx
,(- (movitz:tag
:other
))) :ecx
)
157 (:movl
(:eax
,movitz
:+other-type-offset
+) :ecx
)
158 (:cmpb
,(movitz:tag
:bignum
) :cl
)
160 (:cmpl
:ecx
(:ebx
,movitz
:+other-type-offset
+))
162 ;; Ok.. we have two bignums of identical sign and size.
164 (:leal
(:ecx
4) :edx
) ; counter
166 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
168 (:movl
(:eax
:edx
(:offset movitz-bignum bigit0 -
4)) :ecx
)
169 (:cmpl
:ecx
(:ebx
:edx
(:offset movitz-bignum bigit0 -
4)))
173 (:cmpb
,(movitz:tag
:ratio
) :cl
)
175 (:cmpl
:ecx
(:ebx
,movitz
:+other-type-offset
+))
177 (:movl
(:eax
(:offset movitz-ratio numerator
)) :eax
)
178 (:movl
(:ebx
(:offset movitz-ratio numerator
)) :ebx
)
179 (:call
(:esi
(:offset movitz-funobj code-vector%
2op
)))
181 (:compile-two-forms
(:eax
:ebx
) x y
)
182 (:movl
(:eax
(:offset movitz-ratio denominator
)) :eax
)
183 (:movl
(:ebx
(:offset movitz-ratio denominator
)) :ebx
)
184 (:call
(:esi
(:offset movitz-funobj code-vector%
2op
)))
194 (define-primitive-function fast-compare-fixnum-real
(n1 n2
)
195 "Compare (known) fixnum <n1> with real <n2>."
198 `(with-inline-assembly (:returns
:nothing
) ; unspecified
199 (:testb
,movitz
::+movitz-fixnum-zmask
+ :bl
)
200 (:jnz
'n2-not-fixnum
)
204 (:leal
(:ebx
,(- (movitz:tag
:other
))) :ecx
)
206 (:jnz
'(:sub-program
(go-complicated)
207 (:globally
(:movl
(:edi
(:edi-offset complicated-compare
)) :esi
))
208 (:jmp
(:esi
(:offset movitz-funobj code-vector%
2op
)))))
209 (:movl
(:ebx
,movitz
:+other-type-offset
+) :ecx
)
210 (:cmpw
,(movitz:tag
:bignum
0) :cx
)
211 (:jne
'not-plusbignum
)
212 ;; compare eax with something bigger
213 (:cmpl
#x10000000
:edi
)
216 (:cmpw
,(movitz:tag
:bignum
#xff
) :cx
)
217 (:jne
'go-complicated
)
218 ;; compare ebx with something bigger
219 (:cmpl
#x-10000000
:edi
)
223 (define-primitive-function fast-compare-real-fixnum
(n1 n2
)
224 "Compare real <n1> with fixnum <n2>."
225 (with-inline-assembly (:returns
:nothing
) ; unspecified
226 (:testb
#.movitz
::+movitz-fixnum-zmask
+ :al
)
231 (:leal
(:eax
#.
(cl:-
(movitz:tag
:other
))) :ecx
)
233 (:jnz
'(:sub-program
(go-complicated)
234 (:globally
(:movl
(:edi
(:edi-offset complicated-compare
)) :esi
))
235 (:jmp
(:esi
(:offset movitz-funobj code-vector%
2op
)))))
236 (:movl
(:eax
#.movitz
:+other-type-offset
+) :ecx
)
237 (:cmpw
#.
(movitz:tag
:bignum
0) :cx
)
238 (:jne
'not-plusbignum
)
239 ;; compare ebx with something bigger
240 (:cmpl
#x-10000000
:edi
)
243 (:cmpw
#.
(movitz:tag
:bignum
#xff
) :cx
)
244 (:jne
'go-complicated
)
245 ;; compare ebx with something bigger
246 (:cmpl
#x10000000
:edi
)
249 (defun complicated-compare (x y
)
250 (let ((ix (* (numerator x
) (denominator y
)))
251 (iy (* (numerator y
) (denominator x
))))
252 (with-inline-assembly (:returns
:multiple-values
)
253 (:compile-two-forms
(:eax
:ebx
) ix iy
)
254 (:call-global-pf fast-compare-two-reals
)
255 (:movl
1 :ecx
) ; The real result is in EFLAGS.
265 "Is x between 0 and max?"
266 (compiler-macro-call below x max
))
271 (define-compiler-macro =%
2op
(n1 n2
&environment env
)
274 ((movitz:movitz-constantp n1 env
)
275 (let ((n1 (movitz:movitz-eval n1 env
)))
278 `(do-result-mode-case ()
280 (with-inline-assembly (:returns
:boolean-zf
=1 :side-effects nil
)
281 (:compile-form
(:result-mode
:eax
) ,n2
)
283 (t (with-inline-assembly (:returns
:boolean-cf
=1 :side-effects nil
)
284 (:compile-form
(:result-mode
:eax
) ,n2
)
287 `(with-inline-assembly (:returns
:boolean-zf
=1 :side-effects nil
)
288 (:compile-two-forms
(:eax
:ebx
) ,n1
,n2
)
289 (:call-global-pf fast-compare-fixnum-real
)))
291 `(with-inline-assembly (:returns
:boolean-zf
=1 :side-effects nil
)
292 (:compile-two-forms
(:eax
:ebx
) ,n1
,n2
)
293 (:call-global-pf fast-compare-two-reals
))))))
295 ((movitz:movitz-constantp n2 env
)
299 (define-number-relational = =%
2op nil
:defun-p nil
)
301 (defun = (first-number &rest numbers
)
302 (declare (dynamic-extent numbers
))
303 (dolist (n numbers t
)
304 (unless (= first-number n
)
307 (define-compiler-macro /=%
2op
(n1 n2
)
310 (define-number-relational /= /=%
2op nil
:defun-p nil
)
312 (defun /= (&rest numbers
)
313 (declare (dynamic-extent numbers
))
314 (do ((p (cdr numbers
) (cdr p
)))
316 (do ((v numbers
(cdr v
)))
318 (when (= (car p
) (car v
))
319 (return-from /= nil
)))))
324 (deftype positive-fixnum
()
325 '(integer 0 #.movitz
:+movitz-most-positive-fixnum
+))
327 (deftype positive-bignum
()
328 `(integer #.
(cl:1+ movitz
:+movitz-most-positive-fixnum
+) *))
330 (deftype negative-fixnum
()
331 `(integer #.movitz
:+movitz-most-negative-fixnum
+ -
1))
333 (deftype negative-bignum
()
334 `(integer * #.
(cl:1- movitz
::+movitz-most-negative-fixnum
+)))
340 (compiler-macro-call evenp x
))
343 (compiler-macro-call oddp x
))
348 (defun %negatef
(x p0 p1
)
349 "Negate x. If x is not eq to p0 or p1, negate x destructively."
353 (if (or (eq x p0
) (eq x p1
))
355 (with-inline-assembly (:returns
:eax
)
356 (:compile-form
(:result-mode
:eax
) x
)
357 (:xorl
#xff00
(:eax
#.movitz
:+other-type-offset
+)))))))
361 (defun + (&rest terms
)
362 (declare (without-check-stack-limit))
368 `(number-double-dispatch (x y
)
370 (with-inline-assembly (:returns
:eax
)
371 (:compile-form
(:result-mode
:eax
) x
)
372 (:compile-form
(:result-mode
:ebx
) y
)
374 (:jo
'(:sub-program
(fix-fix-overflow)
376 (:jns
'fix-fix-negative
)
377 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
378 (:call-local-pf box-u32-ecx
)
381 (:jz
'fix-double-negative
)
383 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
384 (:call-local-pf box-u32-ecx
)
385 (:movl
,(dpb 4 (byte 16 16)
386 (movitz:tag
:bignum
#xff
))
387 (:eax
,movitz
:+other-type-offset
+))
390 (:compile-form
(:result-mode
:eax
)
391 ,(* 2 movitz
:+movitz-most-negative-fixnum
+))
394 ((positive-bignum positive-fixnum
)
396 ((positive-fixnum positive-bignum
)
397 (bignum-add-fixnum y x
))
398 ((positive-bignum negative-fixnum
)
400 ((negative-fixnum positive-bignum
)
401 (with-inline-assembly (:returns
:eax
:labels
(restart-addition
409 (:compile-two-forms
(:eax
:ebx
) y x
)
410 (:movzxw
(:eax
(:offset movitz-bignum length
)) :ecx
)
413 (:compile-form
(:result-mode
:ecx
) x
)
414 (:sarl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
415 (:addl
(:eax
(:offset movitz-bignum bigit0
)) :ecx
)
416 (:call-local-pf box-u32-ecx
)
417 (:jmp
'pfix-pbig-done
)
420 (:declare-label-set retry-jumper
(restart-addition))
421 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
422 (:pushl
'retry-jumper
)
423 ;; ..this allows us to detect recursive atomicallies.
424 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
429 (:compile-form
(:result-mode
:eax
) y
)
430 (:movzxw
(:eax
(:offset movitz-bignum length
)) :ecx
)
432 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
433 ;; Now inside atomically section.
435 (:leal
((:ecx
1) ,(* 1 movitz
:+movitz-fixnum-factor
+))
436 :eax
) ; Number of words
437 (:call-local-pf cons-pointer
)
438 (:load-lexical
(:lexical-binding y
) :ebx
) ; bignum
439 (:movzxw
(:ebx
(:offset movitz-bignum length
)) :ecx
)
440 (:leal
((:ecx
1) ,movitz
:+movitz-fixnum-factor
+)
443 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
444 (:movl
(:ebx
:edx
,movitz
:+other-type-offset
+) :ecx
)
445 (:movl
:ecx
(:eax
:edx
,movitz
:+other-type-offset
+))
446 (:jnz
'copy-bignum-loop
)
448 (:load-lexical
(:lexical-binding x
) :ecx
)
449 (:sarl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
450 (:xorl
:ebx
:ebx
) ; counter
452 (:subl
:ecx
(:eax
(:offset movitz-bignum bigit0
)))
453 (:jnc
'add-bignum-done
)
456 (:subl
1 (:eax
:ebx
(:offset movitz-bignum bigit0
)))
457 (:jc
'add-bignum-loop
)
459 (:movzxw
(:eax
(:offset movitz-bignum length
))
461 (:leal
((:ecx
1) ,movitz
:+movitz-fixnum-factor
+)
462 :ecx
) ; result bignum word-size
463 (:cmpl
0 (:eax
:ecx
(:offset movitz-bignum bigit0 -
8)))
465 (:subl
#x40000
(:eax
,movitz
:+other-type-offset
+))
466 (:subl
,movitz
:+movitz-fixnum-factor
+ :ecx
)
468 (:call-local-pf cons-commit-non-pointer
)
469 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
470 (:leal
(:esp
16) :esp
)
473 ((positive-bignum positive-bignum
)
474 (if (< (%bignum-bigits y
) (%bignum-bigits x
))
476 ;; Assume x is smallest.
477 (with-inline-assembly (:returns
:eax
:labels
(restart-addition
486 (:compile-two-forms
(:eax
:ebx
) y x
)
488 (:jz
'pfix-pbig-done
)
489 (:movzxw
(:eax
(:offset movitz-bignum length
)) :ecx
)
490 (:cmpl
,movitz
:+movitz-fixnum-factor
+ :ecx
)
492 (:movl
(:ebx
(:offset movitz-bignum bigit0
)) :ecx
)
493 (:addl
(:eax
(:offset movitz-bignum bigit0
)) :ecx
)
495 (:call-local-pf box-u32-ecx
)
496 (:jmp
'pfix-pbig-done
)
499 ;; Set up atomically continuation.
500 (:declare-label-set restart-jumper
(restart-addition))
501 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
502 (:pushl
'restart-jumper
)
503 ;; ..this allows us to detect recursive atomicallies.
504 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
509 (:compile-form
(:result-mode
:eax
) y
)
510 (:movzxw
(:eax
(:offset movitz-bignum length
)) :ecx
)
512 (:leal
((:ecx
1) ,(* 2 movitz
:+movitz-fixnum-factor
+))
513 :eax
) ; Number of words
515 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
516 ;; Now inside atomically section.
518 (:call-local-pf cons-non-pointer
)
519 (:load-lexical
(:lexical-binding y
) :ebx
) ; bignum
520 (:movzxw
(:ebx
(:offset movitz-bignum length
)) :ecx
)
521 (:leal
((:ecx
1) ,movitz
:+movitz-fixnum-factor
+)
523 (:movl
0 (:eax
:edx
,movitz
:+other-type-offset
+)) ; MSB
525 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
526 (:movl
(:ebx
:edx
,movitz
:+other-type-offset
+) :ecx
)
527 (:movl
:ecx
(:eax
:edx
,movitz
:+other-type-offset
+))
528 (:jnz
'copy-bignum-loop
)
530 (:load-lexical
(:lexical-binding x
) :ebx
)
531 (:xorl
:edx
:edx
) ; counter
532 (:xorl
:ecx
:ecx
) ; Carry
534 (:cmpw
:dx
(:ebx
(:offset movitz-bignum length
)))
535 (:jbe
'(:sub-program
(zero-padding-loop)
536 (:addl
:ecx
(:eax
:edx
(:offset movitz-bignum
539 (:negl
:ecx
) ; ECX = Add's Carry.
541 (:cmpw
:dx
(:eax
(:offset movitz-bignum length
)))
542 (:jae
'zero-padding-loop
)
543 (:jmp
'add-bignum-done
)))
544 (:addl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
546 (:jc
'(:sub-program
(term1-carry)
547 ;; The digit + carry carried over, ECX = 0
550 (:cmpw
:dx
(:eax
(:offset movitz-bignum length
)))
551 (:jae
'add-bignum-loop
)
552 (:jmp
'add-bignum-done
)))
553 (:addl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
555 (:negl
:ecx
) ; ECX = Add's Carry.
557 (:cmpw
:dx
(:eax
(:offset movitz-bignum length
)))
558 (:jae
'add-bignum-loop
)
560 (:movzxw
(:eax
(:offset movitz-bignum length
))
562 (:leal
((:ecx
1) ,movitz
:+movitz-fixnum-factor
+)
564 (:cmpl
0 (:eax
:ecx
(:offset movitz-bignum bigit0 -
4)))
566 (:addl
#x40000
(:eax
,movitz
:+other-type-offset
+))
567 (:addl
,movitz
:+movitz-fixnum-factor
+ :ecx
)
569 (:call-local-pf cons-commit-non-pointer
)
570 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
571 (:leal
(:esp
16) :esp
)
574 (((integer * -
1) (integer 0 *))
576 (((integer 0 *) (integer * -
1))
578 (((integer * -
1) (integer * -
1))
579 (%negatef
(+ (- x
) (- y
)) x y
))
581 (/ (+ (* (numerator x
) (denominator y
))
582 (* (numerator y
) (denominator x
)))
583 (* (denominator x
) (denominator y
))))
587 (declare (dynamic-extent terms
))
590 (reduce #'+ terms
)))))
600 (defun - (minuend &rest subtrahends
)
601 (declare (dynamic-extent subtrahends
))
608 `(with-inline-assembly (:returns
:eax
)
609 (:compile-form
(:result-mode
:eax
) x
)
611 (:jo
'(:sub-program
(fix-overflow)
612 (:compile-form
(:result-mode
:eax
)
613 ,(1+ movitz
:+movitz-most-positive-fixnum
+))
618 (%bignum-negate
(copy-bignum x
)))
620 (make-ratio (- (ratio-numerator x
)) (ratio-denominator x
)))))
621 (2 (minuend subtrahend
)
624 `(number-double-dispatch (minuend subtrahend
)
630 (with-inline-assembly (:returns
:eax
:labels
(done negative-result
))
631 (:compile-two-forms
(:eax
:ebx
) minuend subtrahend
)
634 (:jnc
'negative-result
)
636 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
637 (:orl
,(- movitz
:+movitz-most-negative-fixnum
+) :ecx
)
638 (:call-local-pf box-u32-ecx
)
643 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
644 (:call-local-pf box-u32-ecx
)
645 (:xorl
#xff00
(:eax
(:offset movitz-bignum type
)))
647 ((positive-bignum fixnum
)
648 (+ (- subtrahend
) minuend
))
649 ((fixnum positive-bignum
)
650 (%negatef
(+ subtrahend
(- minuend
))
652 ;;; ((positive-fixnum positive-bignum)
653 ;;; (bignum-canonicalize
655 ;;; (bignum-subf (copy-bignum subtrahend) minuend))))
656 ;;; ((negative-fixnum positive-bignum)
657 ;;; (bignum-canonicalize
658 ;;; (%negatef (bignum-add-fixnum subtrahend minuend)
659 ;;; subtrahend minuend)))
660 ((positive-bignum positive-bignum
)
662 ((= minuend subtrahend
)
664 ((< minuend subtrahend
)
665 (let ((x (- subtrahend minuend
)))
666 (%negatef x subtrahend minuend
)))
667 (t (bignum-canonicalize
668 (with-inline-assembly (:returns
:eax
)
669 (:compile-two-forms
(:eax
:ebx
) (copy-bignum minuend
) subtrahend
)
670 (:xorl
:edx
:edx
) ; counter
671 (:xorl
:ecx
:ecx
) ; carry
673 (:addl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
675 (:jc
'(:sub-program
(carry-overflow)
676 ;; Just propagate carry
679 (:cmpw
:dx
(:ebx
(:offset movitz-bignum length
)))
681 (:jmp
'bignum-sub-done
)))
682 (:subl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
686 (:cmpw
:dx
(:ebx
(:offset movitz-bignum length
)))
688 (:subl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
689 (:jnc
'bignum-sub-done
)
692 (:subl
1 (:eax
:edx
(:offset movitz-bignum bigit0
)))
693 (:jc
'propagate-carry
)
696 (((integer 0 *) (integer * -
1))
697 (+ minuend
(- subtrahend
)))
698 (((integer * -
1) (integer 0 *))
699 (%negatef
(+ (- minuend
) subtrahend
) minuend subtrahend
))
700 (((integer * -
1) (integer * -
1))
701 (+ minuend
(- subtrahend
)))
703 (/ (- (* (numerator minuend
) (denominator subtrahend
))
704 (* (numerator subtrahend
) (denominator minuend
)))
705 (* (denominator minuend
) (denominator subtrahend
))))
708 (t (minuend &rest subtrahends
)
709 (declare (dynamic-extent subtrahends
))
711 (reduce #'- subtrahends
:initial-value minuend
)
716 (defun zerop (number)
719 (defun plusp (number)
722 (defun minusp (number)
726 (compiler-macro-call abs x
))
736 (defun max (number1 &rest numbers
)
739 (compiler-macro-call max x y
))
740 (t (number1 &rest numbers
)
741 (declare (dynamic-extent numbers
))
743 (dolist (x numbers max
)
747 (defun min (number1 &rest numbers
)
750 (compiler-macro-call min x y
))
751 (t (number1 &rest numbers
)
752 (declare (dynamic-extent numbers
))
754 (dolist (x numbers min
)
760 (defun ash (integer count
)
765 ((typep count
'(integer 0 *))
766 (let ((result-length (+ (integer-length (if (minusp integer
) (1- integer
) integer
))
769 ((<= result-length
29)
770 (with-inline-assembly (:returns
:eax
)
771 (:compile-two-forms
(:eax
:ecx
) integer count
)
772 (:shrl
#.movitz
:+movitz-fixnum-shift
+ :ecx
)
774 ((typep integer
'positive-fixnum
)
775 (let ((result (%make-bignum
(ceiling result-length
32) 0)))
776 (setf (memref result
(movitz-type-slot-offset 'movitz-bignum
'bigit0
)
777 :type
:unsigned-byte32
)
779 (bignum-shift-leftf result count
)))
780 ((typep integer
'positive-bignum
)
781 (let ((result (%make-bignum
(ceiling result-length
32))))
782 (dotimes (i (* 2 (%bignum-bigits result
)))
783 (setf (memref result -
2 :index i
:type
:unsigned-byte16
)
784 (let ((pos (- (* i
16) count
)))
786 ((minusp (+ pos
16)) 0)
788 (ldb (byte 16 pos
) integer
))
789 (t (ash (ldb (byte (+ pos
16) 0) integer
)
791 (assert (or (plusp (memref result -
2
792 :index
(+ -
1 (* 2 (%bignum-bigits result
)))
793 :type
:unsigned-byte16
))
794 (plusp (memref result -
2
795 :index
(+ -
2 (* 2 (%bignum-bigits result
)))
796 :type
:unsigned-byte16
))))
797 (bignum-canonicalize result
)))
798 ((typep integer
'negative-fixnum
)
799 (let ((result (%make-bignum
(ceiling result-length
32) 0)))
800 (setf (memref result
(movitz-type-slot-offset 'movitz-bignum
'bigit0
)
801 :type
:unsigned-byte32
)
803 (%bignum-negate
(bignum-shift-leftf result count
))))
804 ((typep integer
'negative-bignum
)
805 (let ((result (%make-bignum
(ceiling result-length
32) 0)))
806 (dotimes (i (%bignum-bigits integer
))
807 (setf (memref result
(movitz-type-slot-offset 'movitz-bignum
'bigit0
)
808 :index i
:type
:unsigned-byte32
)
809 (memref integer
(movitz-type-slot-offset 'movitz-bignum
'bigit0
)
810 :index i
:type
:unsigned-byte32
)))
811 (%bignum-negate
(bignum-shift-leftf result count
))))
812 (t (error 'program-error
)))))
813 (t (let ((count (- count
)))
816 (with-inline-assembly (:returns
:eax
:type fixnum
)
817 (:compile-two-forms
(:eax
:ecx
) integer count
)
818 (:shrl
#.movitz
:+movitz-fixnum-shift
+ :ecx
)
824 (let ((result-length (- (integer-length integer
) count
)))
826 ((<= result-length
1)
827 result-length
) ; 1 or 0.
828 (t (multiple-value-bind (long short
)
830 (let ((result (%make-bignum
(1+ (ceiling result-length
32)))))
831 (let ((src-max-bigit (* 2 (%bignum-bigits integer
))))
832 (dotimes (i (* 2 (%bignum-bigits result
)))
834 (let ((src (+ i long
)))
835 (setf (memref result -
2 :index i
:type
:unsigned-byte16
)
836 (if (< src src-max-bigit
)
837 (memref integer -
2 :index src
:type
:unsigned-byte16
)
842 `(with-inline-assembly (:returns
:ebx
)
843 (:compile-two-forms
(:ecx
:ebx
) short result
)
844 (:xorl
:edx
:edx
) ; counter
845 (:xorl
:eax
:eax
) ; We need to use EAX for u32 storage.
846 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
850 (:cmpw
:dx
(:ebx
(:offset movitz-bignum length
)))
851 (:jbe
'end-shift-short-loop
)
852 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
855 (:ebx
:edx
(:offset movitz-bignum bigit0 -
4)))
856 (:jmp
'shift-short-loop
)
858 (:movl
:edx
:eax
) ; Safe EAX
859 (:shrl
:cl
(:ebx
:edx
(:offset movitz-bignum bigit0 -
4)))
865 (defun integer-length (integer)
871 `(with-inline-assembly (:returns
:eax
)
873 (:compile-form
(:result-mode
:ecx
) integer
)
880 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)
881 ,(* -
1 movitz
:+movitz-fixnum-factor
+))
888 `(with-inline-assembly (:returns
:eax
)
889 (:compile-form
(:result-mode
:ebx
) integer
)
890 (:movzxw
(:ebx
(:offset movitz-bignum length
))
896 (:cmpl
0 (:ebx
:edx
(:offset movitz-bignum bigit0
)))
897 (:jz
'bigit-scan-loop
)
898 ;; Now, EAX must be loaded with (+ (* EDX 32) bit-index 1).
899 (:leal
((:edx
8)) :eax
) ; Factor 8
900 (:bsrl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
902 (:leal
((:eax
4)) :eax
) ; Factor 4
903 (:leal
((:ecx
4) :eax
4) :eax
)
907 (let ((abs-length (bignum-integer-length integer
)))
908 (if (= 1 (bignum-logcount integer
))
914 (defun * (&rest factors
)
920 `(number-double-dispatch (x y
)
923 (with-inline-assembly (:returns
:eax
)
924 (:compile-two-forms
(:eax
:ecx
) x y
)
925 (:sarl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
927 (:imull
:ecx
:eax
:edx
)
928 (:jno
'fixnum-result
) ; most likely/optimized path.
929 (:cmpl
,movitz
::+movitz-fixnum-factor
+ :edx
)
931 (:cmpl
#xfffffffc
:edx
)
932 (:ja
'u32-negative-result
)
935 (:jnz
'u32-negative-result
)
936 ;; The result requires 2 bigits..
938 (:shll
,movitz
::+movitz-fixnum-shift
+ :edx
) ; guaranteed won't overflow.
940 (:store-lexical
(:lexical-binding d0
) :eax
:type fixnum
)
941 (:store-lexical
(:lexical-binding d1
) :edx
:type fixnum
)
942 (:compile-form
(:result-mode
:eax
) (%make-bignum
2))
943 (:movl
,(dpb (* 2 movitz
:+movitz-fixnum-factor
+)
944 (byte 16 16) (movitz:tag
:bignum
0))
945 (:eax
,movitz
:+other-type-offset
+))
946 (:load-lexical
(:lexical-binding d0
) :ecx
)
947 (:movl
:ecx
(:eax
(:offset movitz-bignum bigit0
)))
948 (:load-lexical
(:lexical-binding d1
) :ecx
)
949 (:sarl
,movitz
:+movitz-fixnum-shift
+
951 (:shrdl
,movitz
:+movitz-fixnum-shift
+ :ecx
952 (:eax
(:offset movitz-bignum bigit0
)))
953 (:sarl
,movitz
:+movitz-fixnum-shift
+
955 (:movl
:ecx
(:eax
(:offset movitz-bignum bigit0
4)))
957 ;; if result was negative, we must negate bignum
958 (:notl
(:eax
(:offset movitz-bignum bigit0
4)))
959 (:negl
(:eax
(:offset movitz-bignum bigit0
)))
961 (:adcl
0 (:eax
(:offset movitz-bignum bigit0
4)))
962 (:xorl
#xff00
(:eax
,movitz
:+other-type-offset
+))
967 (:shrdl
,movitz
::+movitz-fixnum-shift
+ :edx
:ecx
)
970 (:call-local-pf box-u32-ecx
)
975 (:shrdl
,movitz
::+movitz-fixnum-shift
+ :edx
:ecx
)
979 (:call-local-pf box-u32-ecx
)
980 (:xorl
#xff00
(:eax
,movitz
:+other-type-offset
+))
993 (with-inline-assembly (:returns
:eax
)
994 ;; Set up atomically continuation.
995 (:declare-label-set restart-jumper
(restart-multiplication))
996 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
997 (:pushl
'restart-jumper
)
998 ;; ..this allows us to detect recursive atomicallies:
999 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
1001 restart-multiplication
1004 (:compile-two-forms
(:eax
:ebx
) (integer-length x
) (integer-length y
))
1006 ;; Compute (1+ (ceiling (+ (len x) (len y)) 32)) ..
1008 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
1009 ;; Now inside atomically section.
1011 (:leal
(:eax
:ebx
,(* 4 (+ 31 32))) :eax
)
1012 (:andl
,(logxor #xffffffff
(* 31 4)) :eax
)
1014 (:call-local-pf cons-non-pointer
) ; New bignum into EAX
1016 (:load-lexical
(:lexical-binding y
) :ebx
) ; bignum
1017 (:movl
(:ebx
,movitz
:+other-type-offset
+) :ecx
)
1018 (:movl
:ecx
(:eax
,movitz
:+other-type-offset
+))
1019 (:store-lexical
(:lexical-binding r
) :eax
:type bignum
)
1021 (:movl
:eax
:ebx
) ; r into ebx
1022 (:xorl
:esi
:esi
) ; counter
1023 (:xorl
:edx
:edx
) ; initial carry
1024 (:std
) ; Make EAX, EDX, ESI non-GC-roots.
1025 (:compile-form
(:result-mode
:ecx
) x
)
1026 (:sarl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1027 (:jns
'multiply-loop
)
1028 (:negl
:ecx
) ; can't overflow
1030 (:movl
:edx
(:ebx
(:esi
1) ; new
1031 (:offset movitz-bignum bigit0
)))
1032 (:compile-form
(:result-mode
:ebx
) y
)
1033 (:movl
(:ebx
(:esi
1) (:offset movitz-bignum bigit0
))
1036 (:mull
:ecx
:eax
:edx
)
1037 (:compile-form
(:result-mode
:ebx
) r
)
1038 (:addl
:eax
(:ebx
:esi
(:offset movitz-bignum bigit0
)))
1041 (:cmpw
:si
(:ebx
(:offset movitz-bignum length
)))
1042 (:ja
'multiply-loop
)
1044 (:jz
'no-carry-expansion
)
1045 (:movl
:edx
(:ebx
:esi
(:offset movitz-bignum bigit0
)))
1047 (:movw
:si
(:ebx
(:offset movitz-bignum length
)))
1049 (:leal
(:esi
,movitz
:+movitz-fixnum-factor
+)
1050 :ecx
) ; Put bignum length into ECX
1051 (:movl
(:ebp -
4) :esi
)
1054 (:cld
) ; EAX, EDX, and ESI are GC roots again.
1055 (:call-local-pf cons-commit-non-pointer
)
1056 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
1057 (:leal
(:esp
16) :esp
)
1058 (:compile-form
(:result-mode
:ebx
) x
)
1060 (:jns
'positive-result
)
1061 ;; Negate the resulting bignum
1062 (:xorl
#xff00
(:eax
,movitz
:+other-type-offset
+))
1065 ((positive-bignum positive-bignum
)
1068 ;; X is the biggest factor.
1069 #-movitz-reference-code
1070 (do ((tmp (%make-bignum
(ceiling (+ (integer-length x
)
1073 (r (bignum-set-zerof (%make-bignum
(ceiling (+ (integer-length x
)
1076 (length (integer-length y
))
1078 ((>= i length
) (bignum-canonicalize r
))
1079 (bignum-set-zerof tmp
)
1080 (bignum-addf r
(bignum-shift-leftf (bignum-mulf (bignum-addf tmp x
)
1081 (ldb (byte 29 i
) y
))
1083 #+movitz-reference-code
1085 (length (integer-length y
))
1088 (incf r
(ash (* x
(ldb (byte 29 i
) y
)) i
)))))
1090 (make-rational (* (ratio-numerator x
) (ratio-numerator y
))
1091 (* (ratio-denominator x
) (ratio-denominator y
))))
1093 (make-rational (* y
(ratio-numerator x
))
1094 (ratio-denominator x
)))
1096 (make-rational (* x
(ratio-numerator y
))
1097 (ratio-denominator y
)))
1099 (%negatef
(* x
(- y
)) x y
))
1101 (%negatef
(* (- x
) y
) x y
))
1102 (((integer * -
1) (integer * -
1))
1106 (declare (dynamic-extent factors
))
1109 (reduce '* factors
)))))
1113 (defun truncate (number &optional
(divisor 1))
1116 (if (not (typep number
'ratio
))
1118 (multiple-value-bind (q r
)
1119 (truncate (%ratio-numerator number
)
1120 (%ratio-denominator number
))
1121 (values q
(make-rational r
(%ratio-denominator number
))))))
1123 (number-double-dispatch (number divisor
)
1125 (if (not (typep number
'ratio
))
1127 (multiple-value-bind (q r
)
1128 (truncate (%ratio-numerator number
)
1129 (%ratio-denominator number
))
1130 (values q
(make-rational r
(%ratio-denominator number
))))))
1132 (with-inline-assembly (:returns
:multiple-values
)
1133 (:compile-form
(:result-mode
:eax
) number
)
1134 (:compile-form
(:result-mode
:ebx
) divisor
)
1137 (:idivl
:ebx
:eax
:edx
)
1138 (:shll
#.movitz
::+movitz-fixnum-shift
+ :eax
)
1142 (:movb
2 :cl
) ; return values: qutient, remainder.
1144 ((positive-fixnum positive-bignum
)
1146 ((positive-bignum positive-fixnum
)
1150 (with-inline-assembly (:returns
:multiple-values
)
1151 (:compile-form
(:result-mode
:ebx
) number
)
1152 (:cmpw
,movitz
:+movitz-fixnum-factor
+
1153 (:ebx
(:offset movitz-bignum length
)))
1155 (:compile-form
(:result-mode
:ecx
) divisor
)
1156 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1158 (:movl
(:ebx
(:offset movitz-bignum bigit0
)) :eax
)
1160 (:divl
:ecx
:eax
:edx
)
1162 (:shll
,movitz
:+movitz-fixnum-shift
+ :edx
)
1166 (:call-local-pf box-u32-ecx
)
1171 ;; Set up atomically continuation.
1172 (:declare-label-set restart-jumper
(restart-truncation))
1173 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
1174 (:pushl
'restart-jumper
)
1175 ;; ..this allows us to detect recursive atomicallies.
1176 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
1182 (:compile-form
(:result-mode
:ebx
) number
)
1183 (:movw
(:ebx
(:offset movitz-bignum length
)) :ax
)
1186 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
1187 ;; Now inside atomically section.
1189 (:call-local-pf cons-non-pointer
) ; New bignum into EAX
1191 (:store-lexical
(:lexical-binding r
) :eax
:type bignum
) ; XXX breaks GC invariant!
1192 (:compile-form
(:result-mode
:ebx
) number
)
1193 (:movl
(:ebx
,movitz
:+other-type-offset
+) :ecx
)
1194 (:movl
:ecx
(:eax
,movitz
:+other-type-offset
+))
1197 (:jnz
'(:sub-program
() (:int
63)))
1200 (:xorl
:edx
:edx
) ; edx=hi-digit=0
1201 ; eax=lo-digit=msd(number)
1202 (:compile-form
(:result-mode
:ecx
) divisor
)
1203 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1207 (:load-lexical
(:lexical-binding number
) :ebx
)
1208 (:movl
(:ebx
:esi
(:offset movitz-bignum bigit0 -
4))
1210 (:divl
:ecx
:eax
:edx
)
1211 (:load-lexical
(:lexical-binding r
) :ebx
)
1212 (:movl
:eax
(:ebx
:esi
(:offset movitz-bignum bigit0 -
4)))
1215 (:movl
:edi
:eax
) ; safe value
1216 (:leal
((:edx
,movitz
:+movitz-fixnum-factor
+)) :edx
)
1218 (:movl
(:ebp -
4) :esi
)
1222 (:movzxw
(:eax
(:offset movitz-bignum length
))
1224 (:leal
((:ecx
1) ,movitz
:+movitz-fixnum-factor
+)
1226 (:cmpl
0 (:eax
:ecx
(:offset movitz-bignum bigit0 -
8)))
1227 (:jne
'no-more-shrinkage
)
1229 (:subw
4 (:eax
(:offset movitz-bignum length
)))
1230 (:subl
,movitz
:+movitz-fixnum-factor
+ :ecx
)
1231 (:cmpl
,(* 2 movitz
:+movitz-fixnum-factor
+) :ecx
)
1232 (:jne
'no-more-shrinkage
)
1233 (:cmpl
,movitz
:+movitz-most-positive-fixnum
+
1234 (:eax
(:offset movitz-bignum bigit0
)))
1235 (:jnc
'no-more-shrinkage
)
1236 (:movl
(:eax
(:offset movitz-bignum bigit0
))
1238 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :eax
)
1239 (:jmp
'fixnum-result
) ; don't commit the bignum
1241 (:call-local-pf cons-commit-non-pointer
)
1243 ;; Exit atomically block.
1244 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
1245 (:leal
(:esp
16) :esp
)
1250 ((positive-bignum positive-bignum
)
1252 ((= number divisor
) (values 1 0))
1253 ((< number divisor
) (values 0 number
))
1255 #-movitz-reference-code
1256 (let* ((divisor-length (integer-length divisor
))
1257 (guess-pos (- divisor-length
29))
1258 (msb (ldb (byte 29 guess-pos
) divisor
)))
1259 (when (eq msb most-positive-fixnum
)
1261 (setf msb
(ash msb -
1)))
1263 (do ((tmp (copy-bignum number
))
1264 (tmp2 (copy-bignum number
))
1265 (q (bignum-set-zerof (%make-bignum
(ceiling (1+ (- (integer-length number
)
1268 (r (copy-bignum number
)))
1269 ((%bignum
< r divisor
)
1270 (values (bignum-canonicalize q
)
1271 (bignum-canonicalize r
)))
1272 (let ((guess (bignum-shift-rightf
1273 (bignum-truncatef (bignum-addf (bignum-set-zerof tmp
)
1277 (if (%bignum-zerop guess
)
1278 (setf q
(bignum-addf-fixnum q
1)
1279 r
(bignum-subf r divisor
))
1280 (setf q
(bignum-addf q guess
)
1281 r
(do ((i 0 (+ i
29)))
1282 ((>= i divisor-length
) r
)
1283 (bignum-subf r
(bignum-shift-leftf
1284 (bignum-mulf (bignum-addf (bignum-set-zerof tmp2
) guess
)
1285 (ldb (byte 29 i
) divisor
))
1287 #+movitz-reference-code
1288 (let* ((guess-pos (- (integer-length divisor
) 29))
1289 (msb (ldb (byte 29 guess-pos
) divisor
)))
1290 (when (eq msb most-positive-fixnum
)
1292 (setf msb
(ash msb -
1)))
1294 (do ((shift (- guess-pos
))
1299 (let ((guess (ash (truncate r msb
) shift
)))
1304 r
(- r
(* guess divisor
))))))))))
1305 (((integer * -
1) (integer 0 *))
1306 (multiple-value-bind (q r
)
1307 (truncate (- number
) divisor
)
1308 (values (%negatef q number divisor
)
1309 (%negatef r number divisor
))))
1310 (((integer 0 *) (integer * -
1))
1311 (multiple-value-bind (q r
)
1312 (truncate number
(- divisor
))
1313 (values (%negatef q number divisor
)
1315 (((integer * -
1) (integer * -
1))
1316 (multiple-value-bind (q r
)
1317 (truncate (- number
) (- divisor
))
1318 (values q
(%negatef r number divisor
))))
1319 ((rational rational
)
1320 (multiple-value-bind (q r
)
1321 (truncate (* (numerator number
)
1322 (denominator divisor
))
1323 (* (denominator number
)
1324 (numerator divisor
)))
1325 (values q
(make-rational r
(* (denominator number
)
1326 (denominator divisor
))))))
1329 (defun / (number &rest denominators
)
1332 (if (not (typep x
'ratio
))
1334 (make-rational (%ratio-denominator x
)
1335 (%ratio-numerator x
))))
1337 (multiple-value-bind (q r
)
1342 (t (make-rational (* (numerator x
) (denominator y
))
1343 (* (denominator x
) (numerator y
)))))))
1344 (t (number &rest denominators
)
1345 (declare (dynamic-extent denominators
))
1347 ((null denominators
)
1348 (make-rational 1 number
))
1349 ((null (cdr denominators
))
1350 (multiple-value-bind (q r
)
1351 (truncate number
(first denominators
))
1354 (make-rational number
(first denominators
)))))
1355 (t (/ number
(reduce '* denominators
)))))))
1357 (defun round (number &optional
(divisor 1))
1358 "Mathematical rounding."
1359 (multiple-value-bind (quotient remainder
)
1360 (truncate number divisor
)
1361 (let ((rem2 (* 2 remainder
)))
1362 (case (+ (if (minusp number
) #b10
0)
1363 (if (minusp divisor
) #b01
0))
1366 (if (evenp quotient
)
1367 (values quotient remainder
)
1368 (values (1+ quotient
) (- remainder divisor
))))
1370 (values quotient remainder
))
1371 (t (values (1+ quotient
) (- remainder divisor
)))))
1374 (if (evenp quotient
)
1375 (values quotient remainder
)
1376 (values (1+ quotient
) (- remainder divisor
))))
1378 (values quotient remainder
))
1379 (t (values (1+ quotient
) (- remainder divisor
)))))
1381 ((= (- divisor
) rem2
)
1382 (if (evenp quotient
)
1383 (values quotient remainder
)
1384 (values (1- quotient
) (- remainder
))))
1386 (values quotient remainder
))
1387 (t (values (1+ quotient
) (- remainder divisor
)))))
1389 ((= (- divisor
) rem2
)
1390 (if (evenp quotient
)
1391 (values quotient remainder
)
1392 (values (1- quotient
) (- remainder
))))
1394 (values quotient remainder
))
1395 (t (values (1- quotient
) (- remainder
)))))))))
1397 (defun ceiling (number &optional
(divisor 1))
1398 (case (+ (if (minusp number
) #b10
0)
1399 (if (minusp divisor
) #b01
0))
1400 (#b00
(multiple-value-bind (q r
)
1401 (truncate (+ number divisor -
1) divisor
)
1402 (values q
(- r
(1- divisor
)))))
1403 (t (error "Don't know."))))
1405 (defun rem (dividend divisor
)
1406 (nth-value 1 (truncate dividend divisor
)))
1408 (defun mod (number divisor
)
1409 "Returns second result of FLOOR."
1410 (let ((rem (rem number divisor
)))
1411 (if (and (not (zerop rem
))
1412 (if (minusp divisor
)
1420 (defun byte (size position
)
1421 (check-type size positive-fixnum
)
1422 (let ((position (check-the (unsigned-byte 20) position
)))
1423 (+ position
(ash size
20))))
1425 (defun byte-size (bytespec)
1428 (defun byte-position (bytespec)
1429 (ldb (byte 20 0) bytespec
))
1431 (defun logbitp (index integer
)
1432 (check-type index positive-fixnum
)
1437 (with-inline-assembly (:returns
:boolean-cf
=1)
1438 (:compile-two-forms
(:ecx
:ebx
) index integer
)
1439 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
1440 (:addl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
1443 (with-inline-assembly (:returns
:boolean-cf
=1)
1444 (:compile-two-forms
(:ecx
:ebx
) index integer
)
1445 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
1446 (:btl
:ecx
(:ebx
(:offset movitz-bignum bigit0
))))))))
1449 (define-compiler-macro logbitp
(&whole form
&environment env index integer
)
1450 (if (not (movitz:movitz-constantp index env
))
1452 (let ((index (movitz:movitz-eval index env
)))
1453 (check-type index
(integer 0 *))
1456 `(with-inline-assembly (:returns
:boolean-cf
=1)
1457 (:compile-form
(:result-mode
:untagged-fixnum-ecx
) ,integer
)
1458 (:btl
,index
:ecx
)))
1462 (defun logand (&rest integers
)
1468 `(number-double-dispatch (x y
)
1470 (with-inline-assembly (:returns
:eax
)
1471 (:compile-two-forms
(:eax
:ebx
) x y
)
1473 ((positive-bignum positive-fixnum
)
1474 (with-inline-assembly (:returns
:eax
)
1475 (:compile-form
(:result-mode
:eax
) x
)
1476 (:call-global-pf unbox-u32
)
1477 (:compile-form
(:result-mode
:eax
) y
)
1478 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :ecx
)
1480 ((positive-fixnum positive-bignum
)
1481 (with-inline-assembly (:returns
:eax
)
1482 (:compile-form
(:result-mode
:eax
) y
)
1483 (:call-global-pf unbox-u32
)
1484 (:compile-form
(:result-mode
:eax
) x
)
1485 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :ecx
)
1487 ((fixnum positive-bignum
)
1488 (let ((result (copy-bignum y
)))
1489 (with-inline-assembly (:returns
:eax
)
1490 (:compile-two-forms
(:eax
:untagged-fixnum-ecx
) result x
)
1491 (:andl
:ecx
(:eax
(:offset movitz-bignum bigit0
))))))
1492 ((positive-bignum fixnum
)
1493 (let ((result (copy-bignum x
)))
1494 (with-inline-assembly (:returns
:eax
)
1495 (:compile-two-forms
(:eax
:untagged-fixnum-ecx
) result y
)
1496 (:andl
:ecx
(:eax
(:offset movitz-bignum bigit0
))))))
1497 ((positive-bignum positive-bignum
)
1498 (if (< (%bignum-bigits y
) (%bignum-bigits x
))
1500 (bignum-canonicalize
1501 (with-inline-assembly (:returns
:eax
)
1502 (:compile-two-forms
(:eax
:ebx
) (copy-bignum x
) y
)
1503 (:movzxw
(:eax
(:offset movitz-bignum length
))
1505 (:leal
((:ecx
1) -
4) :edx
)
1507 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
1510 (:eax
:edx
(:offset movitz-bignum bigit0
)))
1512 (:jnc
'pb-pb-and-loop
)))))
1513 ((negative-bignum fixnum
)
1514 (with-inline-assembly (:returns
:eax
)
1515 (:load-lexical
(:lexical-binding x
) :untagged-fixnum-ecx
)
1516 (:load-lexical
(:lexical-binding y
) :eax
)
1517 (:leal
((:ecx
4) -
4) :ecx
)
1520 ((negative-bignum positive-bignum
)
1522 ((<= (%bignum-bigits y
) (%bignum-bigits x
))
1523 (let ((r (copy-bignum y
)))
1524 (with-inline-assembly (:returns
:eax
)
1525 (:load-lexical
(:lexical-binding r
) :eax
)
1526 (:load-lexical
(:lexical-binding x
) :ebx
)
1528 (:movl
#xffffffff
:ecx
)
1530 (:addl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
1533 (:andl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
1540 (:cmpw
:dx
(:eax
(:offset movitz-bignum length
)))
1542 (t (error "Logand not implemented."))))
1546 (declare (dynamic-extent integers
))
1549 (reduce #'logand integers
)))))
1551 (defun logandc1 (integer1 integer2
)
1554 `(number-double-dispatch (integer1 integer2
)
1555 ((t positive-fixnum
)
1556 (with-inline-assembly (:returns
:eax
:type fixnum
)
1557 (:compile-form
(:result-mode
:eax
) integer1
)
1558 (:call-global-pf unbox-u32
)
1559 (:shll
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1560 (:compile-form
(:result-mode
:eax
) integer2
)
1563 (((eql 0) t
) integer2
)
1565 ((positive-fixnum positive-bignum
)
1566 (bignum-canonicalize
1567 (with-inline-assembly (:returns
:eax
)
1568 (:compile-two-forms
(:eax
:ecx
) (copy-bignum integer2
) integer1
)
1569 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1571 (:andl
:ecx
(:eax
(:offset movitz-bignum bigit0
))))))
1572 ((positive-bignum positive-bignum
)
1573 (bignum-canonicalize
1574 (with-inline-assembly (:returns
:eax
)
1575 (:compile-two-forms
(:eax
:ebx
) (copy-bignum integer2
) integer1
)
1576 (:movzxw
(:eax
(:offset movitz-bignum length
))
1578 (:leal
((:ecx
1) -
4) :edx
)
1580 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
1583 (:andl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
1585 (:jnc
'pb-pb-andc1-loop
)))))))
1589 (defun logandc2 (integer1 integer2
)
1590 (logandc1 integer2 integer1
))
1592 (defun logior (&rest integers
)
1596 (number-double-dispatch (x y
)
1598 (with-inline-assembly (:returns
:eax
)
1599 (:compile-two-forms
(:eax
:ebx
) x y
)
1601 ((positive-fixnum positive-bignum
)
1604 `(let ((r (copy-bignum y
)))
1605 (with-inline-assembly (:returns
:eax
)
1606 (:compile-two-forms
(:eax
:ecx
) r x
)
1607 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1608 (:orl
:ecx
(:eax
(:offset movitz-bignum bigit0
)))))))
1610 ((positive-bignum positive-fixnum
)
1613 `(let ((r (copy-bignum x
)))
1614 (with-inline-assembly (:returns
:eax
)
1615 (:compile-two-forms
(:eax
:ecx
) r y
)
1616 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1617 (:orl
:ecx
(:eax
(:offset movitz-bignum bigit0
)))))))
1619 ((positive-bignum positive-bignum
)
1620 (if (< (%bignum-bigits x
) (%bignum-bigits y
))
1622 (let ((r (copy-bignum x
)))
1625 `(with-inline-assembly (:returns
:eax
)
1626 (:compile-two-forms
(:eax
:ebx
) r y
)
1627 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1629 (:leal
((:ecx
1) ,(* -
1 movitz
:+movitz-fixnum-factor
+))
1630 :edx
) ; EDX is loop counter
1632 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
1635 (:eax
:edx
(:offset movitz-bignum bigit0
)))
1640 (declare (dynamic-extent integers
))
1643 (reduce #'logior integers
)))))
1645 (defun logxor (&rest integers
)
1649 (number-double-dispatch (x y
)
1651 (with-inline-assembly (:returns
:eax
)
1652 (:compile-two-forms
(:eax
:ebx
) x y
)
1656 ((positive-fixnum positive-bignum
)
1659 `(with-inline-assembly (:returns
:eax
)
1660 (:compile-two-forms
(:eax
:ecx
) (copy-bignum y
) x
)
1661 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1662 (:xorl
:ecx
(:eax
(:offset movitz-bignum bigit0
))))))
1664 ((positive-bignum positive-fixnum
)
1667 `(with-inline-assembly (:returns
:eax
)
1668 (:compile-two-forms
(:eax
:ecx
) (copy-bignum x
) y
)
1669 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1670 (:xorl
:ecx
(:eax
(:offset movitz-bignum bigit0
))))))
1672 ((positive-bignum positive-bignum
)
1673 (if (< (%bignum-bigits x
) (%bignum-bigits y
))
1675 (let ((r (copy-bignum x
)))
1678 `(bignum-canonicalize
1679 (with-inline-assembly (:returns
:eax
)
1680 (:compile-two-forms
(:eax
:ebx
) r y
)
1681 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1683 (:leal
((:ecx
1),(* -
1 movitz
:+movitz-fixnum-factor
+))
1684 :edx
) ; EDX is loop counter
1686 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
))
1688 (:xorl
:ecx
(:eax
:edx
(:offset movitz-bignum bigit0
)))
1694 (declare (dynamic-extent integers
))
1697 (reduce #'logxor integers
)))))
1699 (defun lognot (integer)
1702 (defun ldb%byte
(size position integer
)
1703 "This is LDB with explicit byte-size and position parameters."
1704 (check-type size positive-fixnum
)
1705 (check-type position positive-fixnum
)
1710 `(with-inline-assembly (:returns
:eax
)
1711 (:compile-two-forms
(:eax
:ecx
) integer position
)
1712 (:cmpl
,(* (1- movitz
:+movitz-fixnum-bits
+) movitz
:+movitz-fixnum-factor
+)
1714 (:ja
'(:sub-program
(outside-fixnum)
1715 (:addl
#x80000000
:eax
) ; sign into carry
1717 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :eax
)
1718 (:jmp
'mask-fixnum
)))
1719 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1720 (:std
) ; <================= STD
1721 (:sarl
:cl
:eax
) ; shift..
1722 (:andl
,(logxor #xffffffff movitz
:+movitz-fixnum-zmask
+) :eax
)
1723 (:cld
) ; =================> CLD
1725 (:compile-form
(:result-mode
:ecx
) size
)
1726 (:cmpl
,(* (1- movitz
:+movitz-fixnum-bits
+) movitz
:+movitz-fixnum-factor
+)
1728 (:jna
'fixnum-result
)
1731 ;; We need to generate a bignum..
1732 ;; ..filling in 1-bits since the integer is negative.
1733 (:pushl
:eax
) ; This will become the LSB bigit.
1735 ;; Set up atomically continuation.
1736 (:declare-label-set restart-jumper
(restart-ones-expanded-bignum))
1737 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
1738 (:pushl
'restart-jumper
)
1739 ;; ..this allows us to detect recursive atomicallies.
1740 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
1742 restart-ones-expanded-bignum
1745 ;;; (:declare-label-set retry-jumper-ones-expanded-bignum (retry-ones-expanded-bignum))
1746 ;; Calculate word-size from bytespec-size.
1747 (:compile-form
(:result-mode
:ecx
) size
)
1748 (:addl
,(* 31 movitz
:+movitz-fixnum-factor
+) :ecx
) ; Add 31
1749 (:shrl
5 :ecx
) ; Divide by 32
1750 (:andl
,(- movitz
:+movitz-fixnum-factor
+) :ecx
)
1751 (:leal
(:ecx
,movitz
:+movitz-fixnum-factor
+) ; Add 1 for header.
1754 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
1755 ;; Now inside atomically section.
1757 (:call-local-pf cons-non-pointer
)
1759 (:orl
,(movitz:tag
:bignum
0) :ecx
)
1760 (:movl
:ecx
(:eax
,movitz
:+other-type-offset
+))
1762 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)
1763 ,(* 1 movitz
:+movitz-fixnum-factor
+)) ; add 1 for header.
1765 (:call-local-pf cons-commit-non-pointer
)
1766 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
1767 (:leal
(:esp
16) :esp
)
1768 ;; Have fresh bignum in EAX, now fill it with ones.
1769 (:xorl
:ecx
:ecx
) ; counter
1771 (:movl
#xffffffff
(:eax
:ecx
(:offset movitz-bignum bigit0
)))
1773 (:cmpw
:cx
(:eax
(:offset movitz-bignum length
)))
1774 (:jne
'fill-ones-loop
)
1776 (:popl
:ecx
) ; The LSB bigit.
1777 (:sarl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1778 (:movl
:ecx
(:eax
(:offset movitz-bignum bigit0
)))
1780 ;; Compute MSB bigit mask in EDX
1781 (:compile-form
(:result-mode
:ecx
) size
)
1782 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1783 (:std
) ; <================= STD
1786 (:jz
'fixnum-mask-ok
)
1791 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1793 (:andl
:edx
; And EDX with the MSB bigit.
1794 (:ebx
:ecx
(:offset movitz-bignum bigit0 -
4)))
1797 (:cld
) ; =================> CLD
1802 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1803 (:movl
,movitz
:+movitz-fixnum-factor
+ :edx
) ; generate fixnum mask in EDX
1805 (:subl
,movitz
:+movitz-fixnum-factor
+ :edx
)
1815 ;; The result is likely to be a fixnum (or at least an u32), due to byte-size.
1818 `(with-inline-assembly (:returns
:eax
)
1819 (:compile-form
(:result-mode
:ebx
) integer
)
1820 (:compile-form
(:result-mode
:eax
) position
)
1821 (:movl
:eax
:ecx
) ; compute bigit-number in ecx
1825 (:cmpl
,(* #x4000 movitz
:+movitz-fixnum-factor
+)
1827 (:jae
'position-outside-integer
)
1828 (:cmpw
:cx
(:ebx
(:offset movitz-bignum length
)))
1829 (:jc
'(:sub-program
(position-outside-integer)
1830 (:movsxb
(:ebx
(:offset movitz-bignum sign
)) :ecx
)
1831 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :eax
)
1834 (:movl
(:ebx
:ecx
(:offset movitz-bignum bigit0 -
4))
1836 (:movl
0 :edx
) ; If position was in last bigit.. (don't touch EFLAGS)
1837 (:je
'no-top-bigit
) ; ..we must zero-extend rather than read top bigit.
1838 (:movl
(:ebx
:ecx
(:offset movitz-bignum bigit0
))
1839 :edx
) ; Read top bigit into EDX
1841 (:testl
#xff00
(:ebx
,movitz
:+other-type-offset
+))
1842 (:jnz
'(:sub-program
(negative-bignum)
1843 ;; We must negate the bigits..
1847 ;; EDX:EAX now holds the number that must be shifted and masked.
1848 (:compile-form
(:result-mode
:ecx
) position
)
1849 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1850 (:shrdl
:cl
:edx
:eax
) ; Shifted value into EAX
1851 (:compile-form
(:result-mode
:ecx
) size
)
1852 (:xorl
:edx
:edx
) ; Generate a mask in EDX
1853 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1861 (:movl
:eax
:ecx
) ; For boxing..
1865 ;; See if we can return same bignum..
1866 (:cmpl
,(dpb movitz
:+movitz-fixnum-factor
+
1867 (byte 16 16) (movitz:tag
:bignum
0))
1868 (:ebx
,movitz
:+other-type-offset
+))
1869 (:jne
'cant-return-same
)
1870 (:cmpl
:ecx
(:ebx
(:offset movitz-bignum bigit0
)))
1871 (:jne
'cant-return-same
)
1875 (:call-local-pf box-u32-ecx
)
1882 (with-inline-assembly (:returns
:eax
)
1883 (:compile-form
(:result-mode
:ebx
) integer
)
1884 (:compile-form
(:result-mode
:ecx
) position
)
1885 (:shrl
5 :ecx
) ; compute fixnum bigit-number in ecx
1886 (:cmpl
,(* #x4000 movitz
:+movitz-fixnum-factor
+)
1888 (:jnc
'position-outside-integer
)
1889 (:cmpw
:cx
(:ebx
(:offset movitz-bignum length
)))
1890 (:jbe
'(:sub-program
(position-outside-integer)
1891 (:movsxb
(:ebx
(:offset movitz-bignum sign
)) :ecx
)
1892 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :eax
)
1895 (:compile-two-forms
(:edx
:ecx
) position size
)
1896 (:movl
:ecx
:eax
) ; keep size/fixnum in EAX.
1898 (:into
) ; just to make sure
1899 (:shrl
5 :ecx
) ; compute msb bigit index/fixnum in ecx
1901 (:cmpw
:cx
(:ebx
(:offset movitz-bignum length
)))
1902 (:je
'(:sub-program
(equal-size-maybe-return-same)
1903 (:testl
:edx
:edx
) ; Can only return same if (zerop position).
1905 (:movl
:eax
:ecx
) ; size/fixnum
1906 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
1908 (:jz
'yes-return-same
)
1909 (:std
) ; <================
1910 ;; we know EDX=0, now generate mask in EDX
1913 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1915 (:cmpl
:edx
(:ebx
:ecx
(:offset movitz-bignum bigit0 -
4)))
1916 (:movl
0 :edx
) ; Safe value, and correct if we need to go to adjust-size.
1917 (:cld
) ; =================>
1918 (:jnc
'adjust-size
) ; nope, we have to generate a new bignum.
1920 (:movl
:ebx
:eax
) ; yep, we can return same bignum.
1923 ;; We now know that (+ size position) is beyond the size of the bignum.
1924 ;; So, if (zerop position), we can return the bignum as our result.
1926 (:jz
'(:sub-program
()
1927 (:movl
:ebx
:eax
) ; return the source bignum.
1930 ;; The bytespec is (partially) outside source-integer, so we make the
1931 ;; size smaller before proceeding. new-size = (- source-int-length position)
1932 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1933 :ecx
) ; length of source-integer
1934 (:shll
5 :ecx
) ; fixnum bit-position
1935 (:xorl
:eax
:eax
) ; In case the new size is zero.
1936 (:subl
:edx
:ecx
) ; subtract position
1937 (:js
'(:sub-program
(should-not-happen)
1938 ;; new size should never be negative.
1940 (:jz
'ldb-done
) ; New size was zero, so the result of ldb is zero.
1941 (:movl
:ecx
:eax
) ; New size into EAX.
1943 (:store-lexical
(:lexical-binding new-size
) :eax
:type fixnum
)
1945 ;; Set up atomically continuation.
1946 (:declare-label-set restart-ldb-jumper
(restart-ldb))
1947 (:locally
(:pushl
(:edi
(:edi-offset
:dynamic-env
))))
1948 (:pushl
'restart-ldb-jumper
)
1949 ;; ..this allows us to detect recursive atomicallies.
1950 (:locally
(:pushl
(:edi
(:edi-offset
:atomically-continuation
))))
1955 (:load-lexical
(:lexical-binding new-size
) :eax
)
1957 (:locally
(:movl
:esp
(:edi
(:edi-offset
:atomically-continuation
))))
1958 ;; Now inside atomically section.
1959 ;; (new) Size is in EAX.
1961 (:subl
,movitz
:+movitz-fixnum-factor
+ :eax
)
1962 (:andl
,(logxor #xffffffff
1963 (mask-field (byte (+ 5 movitz
:+movitz-fixnum-shift
+) 0) -
1))
1965 (:shrl
5 :eax
) ; Divide (size-1) by 32 to get number of bigits-1
1966 ;; Now add 1 for index->size, 1 for header, and 1 for tmp storage before shift.
1967 (:addl
,(* 3 movitz
:+movitz-fixnum-factor
+) :eax
)
1969 (:call-local-pf cons-non-pointer
)
1970 ;; (:store-lexical (:lexical-binding r) :eax :type t)
1972 (:subl
,(* 2 movitz
:+movitz-fixnum-factor
+) :ecx
) ; for tmp storage and header.
1974 (:orl
,(movitz:tag
:bignum
0) :ecx
)
1975 (:movl
:ecx
(:eax
,movitz
:+other-type-offset
+))
1976 (:compile-form
(:result-mode
:ebx
) integer
)
1979 ;; now: EAX = old integer, EBX = new result bignum
1981 ;; Edge case: When size(old)=size(new), the tail-tmp must be zero.
1982 ;; We check here, setting the tail-tmp to a mask for and-ing below.
1983 (:movzxw
(:ebx
(:offset movitz-bignum length
))
1984 :ecx
) ; length of source-integer
1985 ;; Initialize tail-tmp to #xffffffff, meaning copy from source-integer.
1986 (:movl
#xffffffff
(:ebx
:ecx
(:offset movitz-bignum bigit0
)))
1987 (:cmpw
:cx
(:eax
(:offset movitz-bignum length
)))
1988 (:jc
'(:sub-program
(result-too-big-shouldnt-happen)
1991 ;; Sizes was equal, so set tail-tmp to zero.
1992 (:movl
0 (:ebx
:ecx
(:offset movitz-bignum bigit0
)))
1994 ;; Now copy the relevant part of the integer
1996 (:compile-form
(:result-mode
:ecx
) position
)
1997 (:sarl
,(+ 5 movitz
:+movitz-fixnum-shift
+) :ecx
) ; compute bigit-number in ecx
1998 ;; We can use primitive pointers because we're both inside atomically and std.
1999 (:leal
(:eax
(:ecx
4) (:offset movitz-bignum bigit0
))
2000 :eax
) ; Use EAX as primitive pointer into source
2001 (:xorl
:ecx
:ecx
) ; counter
2005 (:movl
:edx
(:ebx
:ecx
(:offset movitz-bignum bigit0
)))
2007 (:cmpw
:cx
(:ebx
(:offset movitz-bignum length
)))
2008 (:jne
'copy-integer
)
2009 ;; Copy one more than the length, namely the tmp at the end.
2010 ;; Tail-tmp was initialized to a bit-mask above.
2012 (:andl
:edx
(:ebx
:ecx
(:offset movitz-bignum bigit0
)))
2013 ;; Copy done, now shift
2014 (:compile-form
(:result-mode
:ecx
) position
)
2015 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
2017 (:jz
'shift-done
) ; if (zerop (mod position 32)), no shift needed.
2018 (:xorl
:edx
:edx
) ; counter
2020 (:movl
(:ebx
:edx
(:offset movitz-bignum bigit0
4))
2021 :eax
) ; Next bigit into eax
2022 (:shrdl
:cl
:eax
; Now shift bigit, with msbs from eax.
2023 (:ebx
:edx
(:offset movitz-bignum bigit0
)))
2025 (:cmpw
:dx
(:ebx
(:offset movitz-bignum length
)))
2028 ;; Now we must mask MSB bigit.
2029 (:movzxw
(:ebx
(:offset movitz-bignum length
))
2031 (:load-lexical
(:lexical-binding size
) :ecx
)
2033 (:andl -
4 :ecx
) ; ECX = index of (conceptual) MSB
2037 (:load-lexical
(:lexical-binding size
) :ecx
)
2038 (:shrl
,movitz
:+movitz-fixnum-shift
+ :ecx
)
2041 (:movl
1 :eax
) ; Generate mask in EAX
2044 (:andl
:eax
(:ebx
:edx
(:offset movitz-bignum bigit0 -
4)))
2046 ;; (:movl :edi :edx) ; safe EDX
2047 (:movl
:edi
:eax
) ; safe EAX
2049 ;; Now we must zero-truncate the result bignum in EBX.
2050 (:movzxw
(:ebx
(:offset movitz-bignum length
))
2053 (:cmpl
0 (:ebx
:ecx
(:offset movitz-bignum bigit0 -
4)))
2054 (:jne
'zero-truncate-done
)
2056 (:jnz
'zero-truncate-loop
)
2057 ;; Zero bigits means the entire result collapsed to zero.
2059 (:jmp
'return-fixnum
) ; don't commit the bignum allocation.
2061 (:cmpl
4 :ecx
) ; If result size is 1, the result might have..
2062 (:jne
'complete-bignum-allocation
) ; ..collapsed to a fixnum.
2063 (:cmpl
,movitz
:+movitz-most-positive-fixnum
+
2064 (:ebx
(:offset movitz-bignum bigit0
)))
2065 (:ja
'complete-bignum-allocation
)
2066 (:movl
(:ebx
(:offset movitz-bignum bigit0
))
2068 (:leal
((:ecx
,movitz
:+movitz-fixnum-factor
+)) :eax
)
2069 (:jmp
'return-fixnum
)
2070 complete-bignum-allocation
2071 (:movw
:cx
(:ebx
(:offset movitz-bignum length
)))
2073 (:leal
(:ecx
,movitz
:+movitz-fixnum-factor
+)
2075 (:call-local-pf cons-commit-non-pointer
)
2077 (:locally
(:movl
0 (:edi
(:edi-offset atomically-continuation
))))
2078 (:leal
(:esp
16) :esp
)
2082 (defun ldb (bytespec integer
)
2083 (ldb%byte
(byte-size bytespec
) (byte-position bytespec
) integer
))
2085 (defun ldb-test (bytespec integer
)
2086 (case (byte-size bytespec
)
2088 (1 (logbitp (byte-position bytespec
) integer
))
2089 (t (/= 0 (ldb bytespec integer
)))))
2091 (defun logtest (integer-1 integer-2
)
2092 "=> generalized-boolean"
2093 (not (= 0 (logand integer-1 integer-2
))))
2095 (defun logcount (integer)
2098 (with-inline-assembly (:returns
:untagged-fixnum-ecx
:type
(integer 0 29))
2099 (:load-lexical
(:lexical-binding integer
) :eax
)
2105 (:jnz
'count-loop
)))
2107 (bignum-logcount integer
))))
2109 (defun dpb (newbyte bytespec integer
)
2110 (logior (if (= 0 newbyte
)
2112 (mask-field bytespec
(ash newbyte
(byte-position bytespec
))))
2115 (logandc2 integer
(mask-field bytespec -
1)))))
2117 (defun mask-field (bytespec integer
)
2118 (ash (ldb bytespec integer
) (byte-position bytespec
)))
2120 (defun deposit-field (newbyte bytespec integer
)
2121 (logior (mask-field bytespec newbyte
)
2122 (logandc2 integer
(mask-field bytespec -
1))))
2126 (defun plus-if (x y
)
2127 (if (integerp x
) (+ x y
) x
))
2129 (defun minus-if (x y
)
2130 (if (integerp x
) (- x y
) x
))
2132 (defun gcd (&rest integers
)
2136 ;; Code borrowed from CMUCL.
2140 (t (do ((k 0 (1+ k
))
2141 (u (abs u
) (truncate u
2))
2142 (v (abs v
) (truncate v
2)))
2143 ((or (oddp u
) (oddp v
))
2144 (do ((temp (if (oddp u
)
2155 (return (ash u k
))))))))))
2157 (declare (dynamic-extent integers
))
2158 (do ((gcd (car integers
)
2159 (gcd gcd
(car rest
)))
2160 (rest (cdr integers
) (cdr rest
)))
2161 ((null rest
) gcd
)))))
2163 (defun lcm (&rest numbers
)
2164 "Returns the least common multiple of one or more integers. LCM of no
2165 arguments is defined to be 1."
2170 (abs (* (truncate (max n m
) (gcd n m
)) (min n m
))))
2172 (declare (dynamic-extent numbers
))
2173 (reduce #'lcm numbers
))))
2175 (defun floor (n &optional
(divisor 1))
2176 "This is floor written in terms of truncate."
2179 (if (not (typep n
'ratio
))
2181 (multiple-value-bind (r q
)
2182 (floor (%ratio-numerator n
) (%ratio-denominator n
))
2183 (values r
(make-rational q
(%ratio-denominator n
))))))
2185 (multiple-value-bind (q r
)
2186 (truncate n divisor
)
2190 ((or (and (minusp r
) (plusp divisor
))
2191 (and (plusp r
) (minusp divisor
)))
2192 (values (1- q
) (+ r divisor
)))
2194 (t (n &optional
(divisor 1))
2195 (floor n divisor
))))
2197 (defun isqrt (natural)
2199 (check-type natural
(integer 0 *))
2203 (do ((next-r (truncate (+ r
(truncate natural r
)) 2)
2204 (truncate (+ r
(truncate natural r
)) 2)))
2205 ((typep (- next-r r
) '(integer 0 1))
2207 (if (<= (* r
+1 r
+1) natural
)
2212 (defun rootn (x root
)
2213 (check-type root
(integer 2 *))
2214 (let ((root-1 (1- root
))
2217 (let ((m (min (integer-length (numerator r
))
2218 (integer-length (denominator r
)))))
2220 (setf r
(/ (ash (numerator r
) (- 24 m
))
2221 (ash (denominator r
) (- 24 m
))))))
2222 #+ignore
(format t
"~&~D: ~X~%~D: ~F [~D ~D]~%" i r i r
2223 (integer-length (numerator r
))
2224 (integer-length (denominator r
)))
2225 (setf r
(/ (+ (* root-1 r
)
2226 (/ x
(expt r root-1
)))
2232 (defun expt (base-number power-number
)
2233 "Take base-number to the power-number."
2234 (etypecase power-number
2237 (r 1 (* r base-number
)))
2238 ((>= i power-number
) r
)
2239 (declare (index i
))))
2242 (r 1 (* r base-number
)))
2243 ((>= i power-number
) r
)))
2245 (/ (expt base-number
(- power-number
))))
2247 (expt (rootn base-number
(denominator power-number
))
2248 (numerator power-number
)))))
2251 (declare (ignore x
))
2254 (defun realpart (number)
2257 (defun imagpart (number)
2258 (declare (ignore number
))
2261 (defun rational (number)