Moved ATA driver into its own package
[movitz-core.git] / losp / muerte / integers.lisp
blob122df57de88745c615e05bfe7dd1e948e9f6ffe5
1 ;;;;------------------------------------------------------------------
2 ;;;;
3 ;;;; Copyright (C) 2000-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway
5 ;;;;
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.
11 ;;;;
12 ;;;; $Id: integers.lisp,v 1.124 2008/02/04 10:08:18 ffjeld Exp $
13 ;;;;
14 ;;;;------------------------------------------------------------------
16 (require :muerte/basic-macros)
17 (require :muerte/typep)
18 (require :muerte/arithmetic-macros)
19 (provide :muerte/integers)
21 (in-package muerte)
23 (defconstant most-positive-fixnum #.movitz::+movitz-most-positive-fixnum+)
24 (defconstant most-negative-fixnum #.movitz::+movitz-most-negative-fixnum+)
26 ;;; Comparison
28 (define-primitive-function fast-compare-two-reals (n1 n2)
29 "Compare two numbers (i.e. set EFLAGS accordingly)."
30 (macrolet
31 ((do-it ()
32 `(with-inline-assembly (:returns :nothing) ; unspecified
33 (:testb ,movitz::+movitz-fixnum-zmask+ :al)
34 (:jnz 'n1-not-fixnum)
35 (:testb ,movitz::+movitz-fixnum-zmask+ :bl)
36 (:jnz 'n2-not-fixnum-but-n1-is)
37 (:cmpl :ebx :eax) ; both were fixnum
38 (:ret)
39 n1-not-fixnum ; but we don't know about n2
40 (:testb ,movitz::+movitz-fixnum-zmask+ :bl)
41 (:jnz 'neither-is-fixnum)
42 ;; n2 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))))
46 neither-is-fixnum
47 ;; Check that both numbers are bignums, and compare them.
48 (:leal (:eax ,(- (movitz:tag :other))) :ecx)
49 (:testb 7 :cl)
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)
59 (:ret)))
61 (:leal (:ebx ,(- (movitz:tag :other))) :ecx)
62 (:testb 7 :cl)
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!
71 (:ret)))
72 (:testl #xff00 :ecx)
73 (:jnz 'compare-negatives)
74 ;; Both n1 and n2 are positive bignums.
76 (:shrl 16 :ecx)
77 (:movzxw (:eax (:offset movitz-bignum length)) :edx)
78 ;; (:cmpw :cx (:eax (:offset movitz-bignum length)))
79 (:cmpl :ecx :edx)
80 (:jne '(:sub-program (positive-different-sizes)
81 (:ret)))
83 ;; Both n1 and n2 are positive bignums of the same size, namely ECX.
84 ;; (:movl :ecx :edx) ; counter
85 positive-compare-loop
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)
91 positive-compare-lsb
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))
105 upper-16-decisive
106 (:ret)
108 compare-negatives
109 ;; Moth n1 and n2 are negative bignums.
111 (:shrl 16 :ecx)
112 (:cmpw (:eax (:offset movitz-bignum length)) :cx)
113 (:jne '(:sub-program (negative-different-sizes)
114 (:ret)))
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)
124 (:ret)
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
141 (:ret))))
142 (do-it)))
144 (defun complicated-eql (x y)
145 (macrolet
146 ((do-it ()
147 `(with-inline-assembly (:returns :multiple-values) ; well..
148 (:compile-two-forms (:eax :ebx) x y)
149 (:cmpl :eax :ebx) ; EQ?
150 (:je 'done)
151 (:leal (:eax ,(- (movitz:tag :other))) :ecx)
152 (:testb 7 :cl)
153 (:jne 'done)
154 (:leal (:ebx ,(- (movitz:tag :other))) :ecx)
155 (:testb 7 :cl)
156 (:jne 'done)
157 (:movl (:eax ,movitz:+other-type-offset+) :ecx)
158 (:cmpb ,(movitz:tag :bignum) :cl)
159 (:jne 'not-bignum)
160 (:cmpl :ecx (:ebx ,movitz:+other-type-offset+))
161 (:jne 'done)
162 ;; Ok.. we have two bignums of identical sign and size.
163 (:shrl 16 :ecx)
164 (:leal (:ecx 4) :edx) ; counter
165 compare-loop
166 (:subl ,movitz:+movitz-fixnum-factor+ :edx)
167 (:jz 'done)
168 (:movl (:eax :edx (:offset movitz-bignum bigit0 -4)) :ecx)
169 (:cmpl :ecx (:ebx :edx (:offset movitz-bignum bigit0 -4)))
170 (:je 'compare-loop)
171 (:jmp 'done)
172 not-bignum
173 (:cmpb ,(movitz:tag :ratio) :cl)
174 (:jne 'not-ratio)
175 (:cmpl :ecx (:ebx ,movitz:+other-type-offset+))
176 (:jne 'done)
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)))
180 (:jne 'done)
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)))
185 (:jmp 'done)
186 not-ratio
188 done
189 (:movl :edi :eax)
190 (:clc)
192 (do-it)))
194 (define-primitive-function fast-compare-fixnum-real (n1 n2)
195 "Compare (known) fixnum <n1> with real <n2>."
196 (macrolet
197 ((do-it ()
198 `(with-inline-assembly (:returns :nothing) ; unspecified
199 (:testb ,movitz::+movitz-fixnum-zmask+ :bl)
200 (:jnz 'n2-not-fixnum)
201 (:cmpl :ebx :eax)
202 (:ret)
203 n2-not-fixnum
204 (:leal (:ebx ,(- (movitz:tag :other))) :ecx)
205 (:testb 7 :cl)
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)
214 (:ret)
215 not-plusbignum
216 (:cmpw ,(movitz:tag :bignum #xff) :cx)
217 (:jne 'go-complicated)
218 ;; compare ebx with something bigger
219 (:cmpl #x-10000000 :edi)
220 (:ret))))
221 (do-it)))
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)
227 (:jnz 'not-fixnum)
228 (:cmpl :ebx :eax)
229 (:ret)
230 not-fixnum
231 (:leal (:eax #.(cl:- (movitz:tag :other))) :ecx)
232 (:testb 7 :cl)
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)
241 (:ret)
242 not-plusbignum
243 (:cmpw #.(movitz:tag :bignum #xff) :cx)
244 (:jne 'go-complicated)
245 ;; compare ebx with something bigger
246 (:cmpl #x10000000 :edi)
247 (:ret)))
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.
256 (:movl :edi :eax))))
262 ;;; Unsigned
264 (defun below (x max)
265 "Is x between 0 and max?"
266 (compiler-macro-call below x max))
269 ;;; Equality
271 (define-compiler-macro =%2op (n1 n2 &environment env)
272 (cond
273 #+ignore
274 ((movitz:movitz-constantp n1 env)
275 (let ((n1 (movitz:movitz-eval n1 env)))
276 (etypecase n1
277 ((eql 0)
278 `(do-result-mode-case ()
279 (:booleans
280 (with-inline-assembly (:returns :boolean-zf=1 :side-effects nil)
281 (:compile-form (:result-mode :eax) ,n2)
282 (:testl :eax :eax)))
283 (t (with-inline-assembly (:returns :boolean-cf=1 :side-effects nil)
284 (:compile-form (:result-mode :eax) ,n2)
285 (:cmpl 1 :eax)))))
286 ((signed-byte 30)
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)))
290 (integer
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))))))
294 #+ignore
295 ((movitz:movitz-constantp n2 env)
296 `(=%2op ,n2 ,n1))
297 (t `(eql ,n1 ,n2))))
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)
305 (return nil))))
307 (define-compiler-macro /=%2op (n1 n2)
308 `(not (= ,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)))
315 ((null p) t)
316 (do ((v numbers (cdr v)))
317 ((eq p v))
318 (when (= (car p) (car v))
319 (return-from /= nil)))))
322 ;;;;
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+)))
336 (defun fixnump (x)
337 (typep x 'fixnum))
339 (defun evenp (x)
340 (compiler-macro-call evenp x))
342 (defun oddp (x)
343 (compiler-macro-call oddp x))
346 ;;;
348 (defun %negatef (x p0 p1)
349 "Negate x. If x is not eq to p0 or p1, negate x destructively."
350 (etypecase x
351 (fixnum (- x))
352 (bignum
353 (if (or (eq x p0) (eq x p1))
354 (- x)
355 (with-inline-assembly (:returns :eax)
356 (:compile-form (:result-mode :eax) x)
357 (:xorl #xff00 (:eax #.movitz:+other-type-offset+)))))))
359 ;;; Addition
361 (defun + (&rest terms)
362 (declare (without-check-stack-limit))
363 (numargs-case
364 (1 (x) x)
365 (2 (x y)
366 (macrolet
367 ((do-it ()
368 `(number-double-dispatch (x y)
369 ((fixnum fixnum)
370 (with-inline-assembly (:returns :eax)
371 (:compile-form (:result-mode :eax) x)
372 (:compile-form (:result-mode :ebx) y)
373 (:addl :ebx :eax)
374 (:jo '(:sub-program (fix-fix-overflow)
375 (:movl :eax :ecx)
376 (:jns 'fix-fix-negative)
377 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
378 (:call-local-pf box-u32-ecx)
379 (:jmp 'fix-fix-ok)
380 fix-fix-negative
381 (:jz 'fix-double-negative)
382 (:negl :ecx)
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+))
388 (:jmp 'fix-fix-ok)
389 fix-double-negative
390 (:compile-form (:result-mode :eax)
391 ,(* 2 movitz:+movitz-most-negative-fixnum+))
392 (:jmp 'fix-fix-ok)))
393 fix-fix-ok))
394 ((positive-bignum positive-fixnum)
395 (+ y x))
396 ((positive-fixnum positive-bignum)
397 (bignum-add-fixnum y x))
398 ((positive-bignum negative-fixnum)
399 (+ y x))
400 ((negative-fixnum positive-bignum)
401 (with-inline-assembly (:returns :eax :labels (restart-addition
402 retry-jumper
403 not-size1
404 copy-bignum-loop
405 add-bignum-loop
406 add-bignum-done
407 no-expansion
408 pfix-pbig-done))
409 (:compile-two-forms (:eax :ebx) y x)
410 (:movzxw (:eax (:offset movitz-bignum length)) :ecx)
411 (:cmpl 4 :ecx)
412 (:jne 'not-size1)
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)
419 not-size1
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))))
425 (:pushl :ebp)
427 restart-addition
428 (:movl (:esp) :ebp)
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+)
441 :edx)
442 copy-bignum-loop
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
451 (:negl :ecx)
452 (:subl :ecx (:eax (:offset movitz-bignum bigit0)))
453 (:jnc 'add-bignum-done)
454 add-bignum-loop
455 (:addl 4 :ebx)
456 (:subl 1 (:eax :ebx (:offset movitz-bignum bigit0)))
457 (:jc 'add-bignum-loop)
458 add-bignum-done
459 (:movzxw (:eax (:offset movitz-bignum length))
460 :ecx)
461 (:leal ((:ecx 1) ,movitz:+movitz-fixnum-factor+)
462 :ecx) ; result bignum word-size
463 (:cmpl 0 (:eax :ecx (:offset movitz-bignum bigit0 -8)))
464 (:jne 'no-expansion)
465 (:subl #x40000 (:eax ,movitz:+other-type-offset+))
466 (:subl ,movitz:+movitz-fixnum-factor+ :ecx)
467 no-expansion
468 (:call-local-pf cons-commit-non-pointer)
469 (:locally (:movl 0 (:edi (:edi-offset atomically-continuation))))
470 (:leal (:esp 16) :esp)
472 pfix-pbig-done))
473 ((positive-bignum positive-bignum)
474 (if (< (%bignum-bigits y) (%bignum-bigits x))
475 (+ y x)
476 ;; Assume x is smallest.
477 (with-inline-assembly (:returns :eax :labels (restart-addition
478 retry-jumper
479 not-size1
480 copy-bignum-loop
481 add-bignum-loop
482 add-bignum-done
483 no-expansion
484 pfix-pbig-done
485 zero-padding-loop))
486 (:compile-two-forms (:eax :ebx) y x)
487 (:testl :ebx :ebx)
488 (:jz 'pfix-pbig-done)
489 (:movzxw (:eax (:offset movitz-bignum length)) :ecx)
490 (:cmpl ,movitz:+movitz-fixnum-factor+ :ecx)
491 (:jne 'not-size1)
492 (:movl (:ebx (:offset movitz-bignum bigit0)) :ecx)
493 (:addl (:eax (:offset movitz-bignum bigit0)) :ecx)
494 (:jc 'not-size1)
495 (:call-local-pf box-u32-ecx)
496 (:jmp 'pfix-pbig-done)
498 not-size1
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))))
505 (:pushl :ebp)
506 restart-addition
508 (:movl (:esp) :ebp)
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+)
522 :edx)
523 (:movl 0 (:eax :edx ,movitz:+other-type-offset+)) ; MSB
524 copy-bignum-loop
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
533 add-bignum-loop
534 (:cmpw :dx (:ebx (:offset movitz-bignum length)))
535 (:jbe '(:sub-program (zero-padding-loop)
536 (:addl :ecx (:eax :edx (:offset movitz-bignum
537 bigit0)))
538 (:sbbl :ecx :ecx)
539 (:negl :ecx) ; ECX = Add's Carry.
540 (:addl 4 :edx)
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))
545 :ecx)
546 (:jc '(:sub-program (term1-carry)
547 ;; The digit + carry carried over, ECX = 0
548 (:addl 1 :ecx)
549 (:addl 4 :edx)
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)))
554 (:sbbl :ecx :ecx)
555 (:negl :ecx) ; ECX = Add's Carry.
556 (:addl 4 :edx)
557 (:cmpw :dx (:eax (:offset movitz-bignum length)))
558 (:jae 'add-bignum-loop)
559 add-bignum-done
560 (:movzxw (:eax (:offset movitz-bignum length))
561 :ecx)
562 (:leal ((:ecx 1) ,movitz:+movitz-fixnum-factor+)
563 :ecx)
564 (:cmpl 0 (:eax :ecx (:offset movitz-bignum bigit0 -4)))
565 (:je 'no-expansion)
566 (:addl #x40000 (:eax ,movitz:+other-type-offset+))
567 (:addl ,movitz:+movitz-fixnum-factor+ :ecx)
568 no-expansion
569 (:call-local-pf cons-commit-non-pointer)
570 (:locally (:movl 0 (:edi (:edi-offset atomically-continuation))))
571 (:leal (:esp 16) :esp)
572 pfix-pbig-done)
574 (((integer * -1) (integer 0 *))
575 (- y (- x)))
576 (((integer 0 *) (integer * -1))
577 (- x (- y)))
578 (((integer * -1) (integer * -1))
579 (%negatef (+ (- x) (- y)) x y))
580 ((rational rational)
581 (/ (+ (* (numerator x) (denominator y))
582 (* (numerator y) (denominator x)))
583 (* (denominator x) (denominator y))))
585 (do-it)))
586 (t (&rest terms)
587 (declare (dynamic-extent terms))
588 (if (null terms)
590 (reduce #'+ terms)))))
592 (defun 1+ (number)
593 (+ 1 number))
595 (defun 1- (number)
596 (+ -1 number))
598 ;;; Subtraction
600 (defun - (minuend &rest subtrahends)
601 (declare (dynamic-extent subtrahends))
602 (numargs-case
603 (1 (x)
604 (etypecase x
605 (fixnum
606 (macrolet
607 ((do-it ()
608 `(with-inline-assembly (:returns :eax)
609 (:compile-form (:result-mode :eax) x)
610 (:negl :eax)
611 (:jo '(:sub-program (fix-overflow)
612 (:compile-form (:result-mode :eax)
613 ,(1+ movitz:+movitz-most-positive-fixnum+))
614 (:jmp 'fix-ok)))
615 fix-ok)))
616 (do-it)))
617 (bignum
618 (%bignum-negate (copy-bignum x)))
619 (ratio
620 (make-ratio (- (ratio-numerator x)) (ratio-denominator x)))))
621 (2 (minuend subtrahend)
622 (macrolet
623 ((do-it ()
624 `(number-double-dispatch (minuend subtrahend)
625 ((number (eql 0))
626 minuend)
627 (((eql 0) t)
628 (- subtrahend))
629 ((fixnum fixnum)
630 (with-inline-assembly (:returns :eax :labels (done negative-result))
631 (:compile-two-forms (:eax :ebx) minuend subtrahend)
632 (:subl :ebx :eax)
633 (:jno 'done)
634 (:jnc 'negative-result)
635 (:movl :eax :ecx)
636 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
637 (:orl ,(- movitz:+movitz-most-negative-fixnum+) :ecx)
638 (:call-local-pf box-u32-ecx)
639 (:jmp 'done)
640 negative-result
641 (:movl :eax :ecx)
642 (:negl :ecx)
643 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
644 (:call-local-pf box-u32-ecx)
645 (:xorl #xff00 (:eax (:offset movitz-bignum type)))
646 done))
647 ((positive-bignum fixnum)
648 (+ (- subtrahend) minuend))
649 ((fixnum positive-bignum)
650 (%negatef (+ subtrahend (- minuend))
651 subtrahend minuend))
652 ;;; ((positive-fixnum positive-bignum)
653 ;;; (bignum-canonicalize
654 ;;; (%bignum-negate
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)
661 (cond
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
672 sub-loop
673 (:addl (:ebx :edx (:offset movitz-bignum bigit0))
674 :ecx)
675 (:jc '(:sub-program (carry-overflow)
676 ;; Just propagate carry
677 (:addl 1 :ecx)
678 (:addl 4 :edx)
679 (:cmpw :dx (:ebx (:offset movitz-bignum length)))
680 (:jne 'sub-loop)
681 (:jmp 'bignum-sub-done)))
682 (:subl :ecx (:eax :edx (:offset movitz-bignum bigit0)))
683 (:sbbl :ecx :ecx)
684 (:negl :ecx)
685 (:addl 4 :edx)
686 (:cmpw :dx (:ebx (:offset movitz-bignum length)))
687 (:jne 'sub-loop)
688 (:subl :ecx (:eax :edx (:offset movitz-bignum bigit0)))
689 (:jnc 'bignum-sub-done)
690 propagate-carry
691 (:addl 4 :edx)
692 (:subl 1 (:eax :edx (:offset movitz-bignum bigit0)))
693 (:jc 'propagate-carry)
694 bignum-sub-done
695 )))))
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)))
702 ((rational rational)
703 (/ (- (* (numerator minuend) (denominator subtrahend))
704 (* (numerator subtrahend) (denominator minuend)))
705 (* (denominator minuend) (denominator subtrahend))))
707 (do-it)))
708 (t (minuend &rest subtrahends)
709 (declare (dynamic-extent subtrahends))
710 (if subtrahends
711 (reduce #'- subtrahends :initial-value minuend)
712 (- minuend)))))
716 (defun zerop (number)
717 (= 0 number))
719 (defun plusp (number)
720 (> number 0))
722 (defun minusp (number)
723 (< number 0))
725 (defun abs (x)
726 (compiler-macro-call abs x))
728 (defun signum (x)
729 (cond
730 ((> x 0) 1)
731 ((< x 0) -1)
732 (t 0)))
736 (defun max (number1 &rest numbers)
737 (numargs-case
738 (2 (x y)
739 (compiler-macro-call max x y))
740 (t (number1 &rest numbers)
741 (declare (dynamic-extent numbers))
742 (let ((max number1))
743 (dolist (x numbers max)
744 (when (> x max)
745 (setq max x)))))))
747 (defun min (number1 &rest numbers)
748 (numargs-case
749 (2 (x y)
750 (compiler-macro-call min x y))
751 (t (number1 &rest numbers)
752 (declare (dynamic-extent numbers))
753 (let ((min number1))
754 (dolist (x numbers min)
755 (when (< x min)
756 (setq min x)))))))
758 ;; shift
760 (defun ash (integer count)
761 (cond
762 ((= 0 count)
763 integer)
764 ((= 0 integer) 0)
765 ((typep count '(integer 0 *))
766 (let ((result-length (+ (integer-length (if (minusp integer) (1- integer) integer))
767 count)))
768 (cond
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)
773 (:shll :cl :eax)))
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)
778 integer)
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)))
785 (cond
786 ((minusp (+ pos 16)) 0)
787 ((<= 0 pos)
788 (ldb (byte 16 pos) integer))
789 (t (ash (ldb (byte (+ pos 16) 0) integer)
790 (- pos)))))))
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)
802 (- integer))
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)))
814 (etypecase integer
815 (fixnum
816 (with-inline-assembly (:returns :eax :type fixnum)
817 (:compile-two-forms (:eax :ecx) integer count)
818 (:shrl #.movitz:+movitz-fixnum-shift+ :ecx)
819 (:std)
820 (:sarl :cl :eax)
821 (:andl -4 :eax)
822 (:cld)))
823 (positive-bignum
824 (let ((result-length (- (integer-length integer) count)))
825 (cond
826 ((<= result-length 1)
827 result-length) ; 1 or 0.
828 (t (multiple-value-bind (long short)
829 (truncate count 16)
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)))
833 (declare (index i))
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)
838 0)))))
839 (bignum-canonicalize
840 (macrolet
841 ((do-it ()
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)
847 (:std)
848 shift-short-loop
849 (:addl 4 :edx)
850 (:cmpw :dx (:ebx (:offset movitz-bignum length)))
851 (:jbe 'end-shift-short-loop)
852 (:movl (:ebx :edx (:offset movitz-bignum bigit0))
853 :eax)
854 (:shrdl :cl :eax
855 (:ebx :edx (:offset movitz-bignum bigit0 -4)))
856 (:jmp 'shift-short-loop)
857 end-shift-short-loop
858 (:movl :edx :eax) ; Safe EAX
859 (:shrl :cl (:ebx :edx (:offset movitz-bignum bigit0 -4)))
860 (:cld))))
861 (do-it))))))))))))))
863 ;;;;
865 (defun integer-length (integer)
866 "=> number-of-bits"
867 (etypecase integer
868 (fixnum
869 (macrolet
870 ((do-it ()
871 `(with-inline-assembly (:returns :eax)
872 (:xorl :eax :eax)
873 (:compile-form (:result-mode :ecx) integer)
874 (:testl :ecx :ecx)
875 (:jns 'not-negative)
876 (:notl :ecx)
877 not-negative
878 (:bsrl :ecx :ecx)
879 (:jz 'zero)
880 (:leal ((:ecx ,movitz:+movitz-fixnum-factor+)
881 ,(* -1 movitz:+movitz-fixnum-factor+))
882 :eax)
883 zero)))
884 (do-it)))
885 (positive-bignum
886 (macrolet
887 ((do-it ()
888 `(with-inline-assembly (:returns :eax)
889 (:compile-form (:result-mode :ebx) integer)
890 (:movzxw (:ebx (:offset movitz-bignum length))
891 :edx)
892 (:xorl :eax :eax)
893 bigit-scan-loop
894 (:subl 4 :edx)
895 (:jc 'done)
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))
901 :ecx)
902 (:leal ((:eax 4)) :eax) ; Factor 4
903 (:leal ((:ecx 4) :eax 4) :eax)
904 done)))
905 (do-it)))
906 (negative-bignum
907 (let ((abs-length (bignum-integer-length integer)))
908 (if (= 1 (bignum-logcount integer))
909 (1- abs-length)
910 abs-length)))))
912 ;;; Multiplication
914 (defun * (&rest factors)
915 (numargs-case
916 (1 (x) x)
917 (2 (x y)
918 (macrolet
919 ((do-it ()
920 `(number-double-dispatch (x y)
921 ((fixnum fixnum)
922 (let (d0 d1)
923 (with-inline-assembly (:returns :eax)
924 (:compile-two-forms (:eax :ecx) x y)
925 (:sarl ,movitz::+movitz-fixnum-shift+ :ecx)
926 (:std)
927 (:imull :ecx :eax :edx)
928 (:jno 'fixnum-result) ; most likely/optimized path.
929 (:cmpl ,movitz::+movitz-fixnum-factor+ :edx)
930 (:jc 'u32-result)
931 (:cmpl #xfffffffc :edx)
932 (:ja 'u32-negative-result)
933 (:jne 'two-bigits)
934 (:testl :eax :eax)
935 (:jnz 'u32-negative-result)
936 ;; The result requires 2 bigits..
937 two-bigits
938 (:shll ,movitz::+movitz-fixnum-shift+ :edx) ; guaranteed won't overflow.
939 (:cld)
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+
950 :ecx)
951 (:shrdl ,movitz:+movitz-fixnum-shift+ :ecx
952 (:eax (:offset movitz-bignum bigit0)))
953 (:sarl ,movitz:+movitz-fixnum-shift+
954 :ecx)
955 (:movl :ecx (:eax (:offset movitz-bignum bigit0 4)))
956 (:jns 'fixnum-done)
957 ;; if result was negative, we must negate bignum
958 (:notl (:eax (:offset movitz-bignum bigit0 4)))
959 (:negl (:eax (:offset movitz-bignum bigit0)))
960 (:cmc)
961 (:adcl 0 (:eax (:offset movitz-bignum bigit0 4)))
962 (:xorl #xff00 (:eax ,movitz:+other-type-offset+))
963 (:jmp 'fixnum-done)
965 u32-result
966 (:movl :eax :ecx)
967 (:shrdl ,movitz::+movitz-fixnum-shift+ :edx :ecx)
968 (:movl :edi :edx)
969 (:cld)
970 (:call-local-pf box-u32-ecx)
971 (:jmp 'fixnum-done)
973 u32-negative-result
974 (:movl :eax :ecx)
975 (:shrdl ,movitz::+movitz-fixnum-shift+ :edx :ecx)
976 (:movl :edi :edx)
977 (:cld)
978 (:negl :ecx)
979 (:call-local-pf box-u32-ecx)
980 (:xorl #xff00 (:eax ,movitz:+other-type-offset+))
981 (:jmp 'fixnum-done)
983 fixnum-result
984 (:movl :edi :edx)
985 (:cld)
986 fixnum-done)))
987 (((eql 0) t) 0)
988 (((eql 1) t) y)
989 (((eql -1) t) (- y))
990 ((t fixnum) (* y x))
991 ((fixnum bignum)
992 (let (r)
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))))
1000 (:pushl :ebp)
1001 restart-multiplication
1003 (:movl (:esp) :ebp)
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)
1013 (:shrl 5 :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
1029 multiply-loop
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))
1034 :eax)
1036 (:mull :ecx :eax :edx)
1037 (:compile-form (:result-mode :ebx) r)
1038 (:addl :eax (:ebx :esi (:offset movitz-bignum bigit0)))
1039 (:adcl 0 :edx)
1040 (:addl 4 :esi)
1041 (:cmpw :si (:ebx (:offset movitz-bignum length)))
1042 (:ja 'multiply-loop)
1043 (:testl :edx :edx)
1044 (:jz 'no-carry-expansion)
1045 (:movl :edx (:ebx :esi (:offset movitz-bignum bigit0)))
1046 (:addl 4 :esi)
1047 (:movw :si (:ebx (:offset movitz-bignum length)))
1048 no-carry-expansion
1049 (:leal (:esi ,movitz:+movitz-fixnum-factor+)
1050 :ecx) ; Put bignum length into ECX
1051 (:movl (:ebp -4) :esi)
1052 (:movl :ebx :eax)
1053 (:movl :edi :edx)
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)
1059 (:testl :ebx :ebx)
1060 (:jns 'positive-result)
1061 ;; Negate the resulting bignum
1062 (:xorl #xff00 (:eax ,movitz:+other-type-offset+))
1063 positive-result
1065 ((positive-bignum positive-bignum)
1066 (if (< x y)
1067 (* y x)
1068 ;; X is the biggest factor.
1069 #-movitz-reference-code
1070 (do ((tmp (%make-bignum (ceiling (+ (integer-length x)
1071 (integer-length y))
1072 32)))
1073 (r (bignum-set-zerof (%make-bignum (ceiling (+ (integer-length x)
1074 (integer-length y))
1075 32))))
1076 (length (integer-length y))
1077 (i 0 (+ i 29)))
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))
1082 i)))
1083 #+movitz-reference-code
1084 (do ((r 0)
1085 (length (integer-length y))
1086 (i 0 (+ i 29)))
1087 ((>= i length) r)
1088 (incf r (ash (* x (ldb (byte 29 i) y)) i)))))
1089 ((ratio ratio)
1090 (make-rational (* (ratio-numerator x) (ratio-numerator y))
1091 (* (ratio-denominator x) (ratio-denominator y))))
1092 ((ratio t)
1093 (make-rational (* y (ratio-numerator x))
1094 (ratio-denominator x)))
1095 ((t ratio)
1096 (make-rational (* x (ratio-numerator y))
1097 (ratio-denominator y)))
1098 ((t (integer * -1))
1099 (%negatef (* x (- y)) x y))
1100 (((integer * -1) t)
1101 (%negatef (* (- x) y) x y))
1102 (((integer * -1) (integer * -1))
1103 (* (- x) (- y))))))
1104 (do-it)))
1105 (t (&rest factors)
1106 (declare (dynamic-extent factors))
1107 (if (null factors)
1109 (reduce '* factors)))))
1111 ;;; Division
1113 (defun truncate (number &optional (divisor 1))
1114 (numargs-case
1115 (1 (number)
1116 (if (not (typep number 'ratio))
1117 (values number 0)
1118 (multiple-value-bind (q r)
1119 (truncate (%ratio-numerator number)
1120 (%ratio-denominator number))
1121 (values q (make-rational r (%ratio-denominator number))))))
1122 (t (number divisor)
1123 (number-double-dispatch (number divisor)
1124 ((t (eql 1))
1125 (if (not (typep number 'ratio))
1126 (values number 0)
1127 (multiple-value-bind (q r)
1128 (truncate (%ratio-numerator number)
1129 (%ratio-denominator number))
1130 (values q (make-rational r (%ratio-denominator number))))))
1131 ((fixnum fixnum)
1132 (with-inline-assembly (:returns :multiple-values)
1133 (:compile-form (:result-mode :eax) number)
1134 (:compile-form (:result-mode :ebx) divisor)
1135 (:std)
1136 (:cdq :eax :edx)
1137 (:idivl :ebx :eax :edx)
1138 (:shll #.movitz::+movitz-fixnum-shift+ :eax)
1139 (:cld)
1140 (:movl :edx :ebx)
1141 (:xorl :ecx :ecx)
1142 (:movb 2 :cl) ; return values: qutient, remainder.
1143 (:stc)))
1144 ((positive-fixnum positive-bignum)
1145 (values 0 number))
1146 ((positive-bignum positive-fixnum)
1147 (macrolet
1148 ((do-it ()
1149 `(let (r n)
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)))
1154 (:jne 'not-size1)
1155 (:compile-form (:result-mode :ecx) divisor)
1156 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
1157 (:std)
1158 (:movl (:ebx (:offset movitz-bignum bigit0)) :eax)
1159 (:xorl :edx :edx)
1160 (:divl :ecx :eax :edx)
1161 (:movl :eax :ecx)
1162 (:shll ,movitz:+movitz-fixnum-shift+ :edx)
1163 (:movl :edi :eax)
1164 (:cld)
1165 (:pushl :edx)
1166 (:call-local-pf box-u32-ecx)
1167 (:popl :ebx)
1168 (:jmp 'done)
1170 not-size1
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))))
1177 (:pushl :ebp)
1178 restart-truncation
1180 (:movl (:esp) :ebp)
1181 (:xorl :eax :eax)
1182 (:compile-form (:result-mode :ebx) number)
1183 (:movw (:ebx (:offset movitz-bignum length)) :ax)
1184 (:addl 4 :eax)
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+))
1195 (:shrl 16 :ecx)
1196 (:testb 3 :cl)
1197 (:jnz '(:sub-program () (:int 63)))
1198 (:movl :ecx :esi)
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)
1204 (:std)
1206 divide-loop
1207 (:load-lexical (:lexical-binding number) :ebx)
1208 (:movl (:ebx :esi (:offset movitz-bignum bigit0 -4))
1209 :eax)
1210 (:divl :ecx :eax :edx)
1211 (:load-lexical (:lexical-binding r) :ebx)
1212 (:movl :eax (:ebx :esi (:offset movitz-bignum bigit0 -4)))
1213 (:subl 4 :esi)
1214 (:jnz 'divide-loop)
1215 (:movl :edi :eax) ; safe value
1216 (:leal ((:edx ,movitz:+movitz-fixnum-factor+)) :edx)
1217 (:cld)
1218 (:movl (:ebp -4) :esi)
1219 (:movl :ebx :eax)
1220 (:movl :edx :ebx)
1222 (:movzxw (:eax (:offset movitz-bignum length))
1223 :ecx)
1224 (:leal ((:ecx 1) ,movitz:+movitz-fixnum-factor+)
1225 :ecx)
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))
1237 :ecx)
1238 (:leal ((:ecx ,movitz:+movitz-fixnum-factor+)) :eax)
1239 (:jmp 'fixnum-result) ; don't commit the bignum
1240 no-more-shrinkage
1241 (:call-local-pf cons-commit-non-pointer)
1242 fixnum-result
1243 ;; Exit atomically block.
1244 (:locally (:movl 0 (:edi (:edi-offset atomically-continuation))))
1245 (:leal (:esp 16) :esp)
1246 done
1247 (:movl 2 :ecx)
1248 (:stc)))))
1249 (do-it)))
1250 ((positive-bignum positive-bignum)
1251 (cond
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)
1260 (incf guess-pos)
1261 (setf msb (ash msb -1)))
1262 (incf msb)
1263 (do ((tmp (copy-bignum number))
1264 (tmp2 (copy-bignum number))
1265 (q (bignum-set-zerof (%make-bignum (ceiling (1+ (- (integer-length number)
1266 divisor-length))
1267 32))))
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)
1275 msb)
1276 guess-pos)))
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))
1286 i))))))))
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)
1291 (incf guess-pos)
1292 (setf msb (ash msb -1)))
1293 (incf msb)
1294 (do ((shift (- guess-pos))
1295 (q 0)
1296 (r number))
1297 ((< r divisor)
1298 (values q r))
1299 (let ((guess (ash (truncate r msb) shift)))
1300 (if (= 0 guess)
1301 (setf q (1+ q)
1302 r (- r divisor))
1303 (setf q (+ q guess)
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)
1314 r)))
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))))))
1327 ))))
1329 (defun / (number &rest denominators)
1330 (numargs-case
1331 (1 (x)
1332 (if (not (typep x 'ratio))
1333 (make-rational 1 x)
1334 (make-rational (%ratio-denominator x)
1335 (%ratio-numerator x))))
1336 (2 (x y)
1337 (multiple-value-bind (q r)
1338 (truncate x y)
1339 (cond
1340 ((= 0 r)
1342 (t (make-rational (* (numerator x) (denominator y))
1343 (* (denominator x) (numerator y)))))))
1344 (t (number &rest denominators)
1345 (declare (dynamic-extent denominators))
1346 (cond
1347 ((null denominators)
1348 (make-rational 1 number))
1349 ((null (cdr denominators))
1350 (multiple-value-bind (q r)
1351 (truncate number (first denominators))
1352 (if (= 0 r)
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))
1364 (#b00 (cond
1365 ((= divisor rem2)
1366 (if (evenp quotient)
1367 (values quotient remainder)
1368 (values (1+ quotient) (- remainder divisor))))
1369 ((< rem2 divisor)
1370 (values quotient remainder))
1371 (t (values (1+ quotient) (- remainder divisor)))))
1372 (#b11 (cond
1373 ((= divisor rem2)
1374 (if (evenp quotient)
1375 (values quotient remainder)
1376 (values (1+ quotient) (- remainder divisor))))
1377 ((> rem2 divisor)
1378 (values quotient remainder))
1379 (t (values (1+ quotient) (- remainder divisor)))))
1380 (#b10 (cond
1381 ((= (- divisor) rem2)
1382 (if (evenp quotient)
1383 (values quotient remainder)
1384 (values (1- quotient) (- remainder))))
1385 ((< rem2 divisor)
1386 (values quotient remainder))
1387 (t (values (1+ quotient) (- remainder divisor)))))
1388 (#b01 (cond
1389 ((= (- divisor) rem2)
1390 (if (evenp quotient)
1391 (values quotient remainder)
1392 (values (1- quotient) (- remainder))))
1393 ((> rem2 divisor)
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)
1413 (plusp number)
1414 (minusp number)))
1415 (+ rem divisor)
1416 rem)))
1418 ;;; bytes
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)
1426 (ash bytespec -20))
1428 (defun byte-position (bytespec)
1429 (ldb (byte 20 0) bytespec))
1431 (defun logbitp (index integer)
1432 (check-type index positive-fixnum)
1433 (macrolet
1434 ((do-it ()
1435 `(etypecase integer
1436 (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)
1441 (:btl :ecx :ebx)))
1442 (positive-bignum
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))))))))
1447 (do-it)))
1449 (define-compiler-macro logbitp (&whole form &environment env index integer)
1450 (if (not (movitz:movitz-constantp index env))
1451 form
1452 (let ((index (movitz:movitz-eval index env)))
1453 (check-type index (integer 0 *))
1454 (typecase index
1455 ((integer 0 31)
1456 `(with-inline-assembly (:returns :boolean-cf=1)
1457 (:compile-form (:result-mode :untagged-fixnum-ecx) ,integer)
1458 (:btl ,index :ecx)))
1459 (t form)))))
1462 (defun logand (&rest integers)
1463 (numargs-case
1464 (1 (x) x)
1465 (2 (x y)
1466 (macrolet
1467 ((do-it ()
1468 `(number-double-dispatch (x y)
1469 ((fixnum fixnum)
1470 (with-inline-assembly (:returns :eax)
1471 (:compile-two-forms (:eax :ebx) x y)
1472 (:andl :ebx :eax)))
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)
1479 (:andl :ecx :eax)))
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)
1486 (:andl :ecx :eax)))
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))
1499 (logand y 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))
1504 :ecx)
1505 (:leal ((:ecx 1) -4) :edx)
1506 pb-pb-and-loop
1507 (:movl (:ebx :edx (:offset movitz-bignum bigit0))
1508 :ecx)
1509 (:andl :ecx
1510 (:eax :edx (:offset movitz-bignum bigit0)))
1511 (:subl 4 :edx)
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)
1518 (:notl :ecx)
1519 (:andl :ecx :eax)))
1520 ((negative-bignum positive-bignum)
1521 (cond
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)
1527 (:xorl :edx :edx)
1528 (:movl #xffffffff :ecx)
1529 loop
1530 (:addl (:ebx :edx (:offset movitz-bignum bigit0))
1531 :ecx)
1532 (:notl :ecx)
1533 (:andl :ecx (:eax :edx (:offset movitz-bignum bigit0)))
1534 (:notl :ecx)
1535 (:cmpl -1 :ecx)
1536 (:je 'carry)
1537 (:xorl :ecx :ecx)
1538 carry
1539 (:addl 4 :edx)
1540 (:cmpw :dx (:eax (:offset movitz-bignum length)))
1541 (:ja 'loop))))
1542 (t (error "Logand not implemented."))))
1544 (do-it)))
1545 (t (&rest integers)
1546 (declare (dynamic-extent integers))
1547 (if (null integers)
1549 (reduce #'logand integers)))))
1551 (defun logandc1 (integer1 integer2)
1552 (macrolet
1553 ((do-it ()
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)
1561 (:notl :ecx)
1562 (:andl :ecx :eax)))
1563 (((eql 0) t) integer2)
1564 (((eql -1) t) 0)
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)
1570 (:notl :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))
1577 :ecx)
1578 (:leal ((:ecx 1) -4) :edx)
1579 pb-pb-andc1-loop
1580 (:movl (:ebx :edx (:offset movitz-bignum bigit0))
1581 :ecx)
1582 (:notl :ecx)
1583 (:andl :ecx (:eax :edx (:offset movitz-bignum bigit0)))
1584 (:subl 4 :edx)
1585 (:jnc 'pb-pb-andc1-loop)))))))
1586 (do-it)))
1589 (defun logandc2 (integer1 integer2)
1590 (logandc1 integer2 integer1))
1592 (defun logior (&rest integers)
1593 (numargs-case
1594 (1 (x) x)
1595 (2 (x y)
1596 (number-double-dispatch (x y)
1597 ((fixnum fixnum)
1598 (with-inline-assembly (:returns :eax)
1599 (:compile-two-forms (:eax :ebx) x y)
1600 (:orl :ebx :eax)))
1601 ((positive-fixnum positive-bignum)
1602 (macrolet
1603 ((do-it ()
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)))))))
1609 (do-it)))
1610 ((positive-bignum positive-fixnum)
1611 (macrolet
1612 ((do-it ()
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)))))))
1618 (do-it)))
1619 ((positive-bignum positive-bignum)
1620 (if (< (%bignum-bigits x) (%bignum-bigits y))
1621 (logior y x)
1622 (let ((r (copy-bignum x)))
1623 (macrolet
1624 ((do-it ()
1625 `(with-inline-assembly (:returns :eax)
1626 (:compile-two-forms (:eax :ebx) r y)
1627 (:movzxw (:ebx (:offset movitz-bignum length))
1628 :ecx)
1629 (:leal ((:ecx 1) ,(* -1 movitz:+movitz-fixnum-factor+))
1630 :edx) ; EDX is loop counter
1631 or-loop
1632 (:movl (:ebx :edx (:offset movitz-bignum bigit0))
1633 :ecx)
1634 (:orl :ecx
1635 (:eax :edx (:offset movitz-bignum bigit0)))
1636 (:subl 4 :edx)
1637 (:jnc 'or-loop))))
1638 (do-it)))))))
1639 (t (&rest integers)
1640 (declare (dynamic-extent integers))
1641 (if (null integers)
1643 (reduce #'logior integers)))))
1645 (defun logxor (&rest integers)
1646 (numargs-case
1647 (1 (x) x)
1648 (2 (x y)
1649 (number-double-dispatch (x y)
1650 ((fixnum fixnum)
1651 (with-inline-assembly (:returns :eax)
1652 (:compile-two-forms (:eax :ebx) x y)
1653 (:xorl :ebx :eax)))
1654 (((eql 0) t) y)
1655 ((t (eql 0)) x)
1656 ((positive-fixnum positive-bignum)
1657 (macrolet
1658 ((do-it ()
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))))))
1663 (do-it)))
1664 ((positive-bignum positive-fixnum)
1665 (macrolet
1666 ((do-it ()
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))))))
1671 (do-it)))
1672 ((positive-bignum positive-bignum)
1673 (if (< (%bignum-bigits x) (%bignum-bigits y))
1674 (logxor y x)
1675 (let ((r (copy-bignum x)))
1676 (macrolet
1677 ((do-it ()
1678 `(bignum-canonicalize
1679 (with-inline-assembly (:returns :eax)
1680 (:compile-two-forms (:eax :ebx) r y)
1681 (:movzxw (:ebx (:offset movitz-bignum length))
1682 :ecx)
1683 (:leal ((:ecx 1),(* -1 movitz:+movitz-fixnum-factor+))
1684 :edx) ; EDX is loop counter
1685 xor-loop
1686 (:movl (:ebx :edx (:offset movitz-bignum bigit0))
1687 :ecx)
1688 (:xorl :ecx (:eax :edx (:offset movitz-bignum bigit0)))
1689 (:subl 4 :edx)
1690 (:jnc 'xor-loop)
1691 ))))
1692 (do-it)))))))
1693 (t (&rest integers)
1694 (declare (dynamic-extent integers))
1695 (if (null integers)
1697 (reduce #'logxor integers)))))
1699 (defun lognot (integer)
1700 (- -1 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)
1706 (etypecase integer
1707 (fixnum
1708 (macrolet
1709 ((do-it ()
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+)
1713 :ecx)
1714 (:ja '(:sub-program (outside-fixnum)
1715 (:addl #x80000000 :eax) ; sign into carry
1716 (:sbbl :ecx :ecx)
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
1724 mask-fixnum
1725 (:compile-form (:result-mode :ecx) size)
1726 (:cmpl ,(* (1- movitz:+movitz-fixnum-bits+) movitz:+movitz-fixnum-factor+)
1727 :ecx)
1728 (:jna 'fixnum-result)
1729 (:testl :eax :eax)
1730 (:jns 'fixnum-done)
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))))
1741 (:pushl :ebp)
1742 restart-ones-expanded-bignum
1744 (:movl (:esp) :ebp)
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.
1752 :eax)
1754 (:locally (:movl :esp (:edi (:edi-offset :atomically-continuation))))
1755 ;; Now inside atomically section.
1757 (:call-local-pf cons-non-pointer)
1758 (:shll 16 :ecx)
1759 (:orl ,(movitz:tag :bignum 0) :ecx)
1760 (:movl :ecx (:eax ,movitz:+other-type-offset+))
1761 (:shrl 16 :ecx)
1762 (:leal ((:ecx ,movitz:+movitz-fixnum-factor+)
1763 ,(* 1 movitz:+movitz-fixnum-factor+)) ; add 1 for header.
1764 :ecx)
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
1770 fill-ones-loop
1771 (:movl #xffffffff (:eax :ecx (:offset movitz-bignum bigit0)))
1772 (:addl 4 :ecx)
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)))
1779 (:movl :eax :ebx)
1780 ;; Compute MSB bigit mask in EDX
1781 (:compile-form (:result-mode :ecx) size)
1782 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
1783 (:std) ; <================= STD
1784 (:xorl :edx :edx)
1785 (:andl 31 :ecx)
1786 (:jz 'fixnum-mask-ok)
1787 (:addl 1 :edx)
1788 (:shll :cl :edx)
1789 fixnum-mask-ok
1790 (:subl 1 :edx)
1791 (:movzxw (:ebx (:offset movitz-bignum length))
1792 :ecx)
1793 (:andl :edx ; And EDX with the MSB bigit.
1794 (:ebx :ecx (:offset movitz-bignum bigit0 -4)))
1795 (:movl :edi :edx)
1796 (:movl :edi :eax)
1797 (:cld) ; =================> CLD
1798 (:movl :ebx :eax)
1799 (:jmp 'fixnum-done)
1801 fixnum-result
1802 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
1803 (:movl ,movitz:+movitz-fixnum-factor+ :edx) ; generate fixnum mask in EDX
1804 (:shll :cl :edx)
1805 (:subl ,movitz:+movitz-fixnum-factor+ :edx)
1806 (:andl :edx :eax)
1807 (:jmp 'fixnum-done)
1808 fixnum-done
1810 (do-it)))
1811 (positive-bignum
1812 (cond
1813 ((= size 0) 0)
1814 ((<= size 32)
1815 ;; The result is likely to be a fixnum (or at least an u32), due to byte-size.
1816 (macrolet
1817 ((do-it ()
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
1822 (:sarl 5 :ecx)
1823 (:andl -4 :ecx)
1824 (:addl 4 :ecx)
1825 (:cmpl ,(* #x4000 movitz:+movitz-fixnum-factor+)
1826 :ecx)
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)
1832 (:jmp 'done-u32)))
1833 (:std)
1834 (:movl (:ebx :ecx (:offset movitz-bignum bigit0 -4))
1835 :eax)
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
1840 no-top-bigit
1841 (:testl #xff00 (:ebx ,movitz:+other-type-offset+))
1842 (:jnz '(:sub-program (negative-bignum)
1843 ;; We must negate the bigits..
1844 (:break)
1846 edx-eax-ok
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)
1854 (:testl 31 :ecx)
1855 (:jz 'mask-ok-u32)
1856 (:addl 1 :edx)
1857 (:shll :cl :edx)
1858 mask-ok-u32
1859 (:subl 1 :edx)
1860 (:andl :edx :eax)
1861 (:movl :eax :ecx) ; For boxing..
1862 (:movl :edi :eax)
1863 (:movl :edi :edx)
1864 (:cld)
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)
1872 (:movl :ebx :eax)
1873 (:jmp 'done-u32)
1874 cant-return-same
1875 (:call-local-pf box-u32-ecx)
1876 done-u32
1878 (do-it)))
1879 (t (macrolet
1880 ((do-it ()
1881 `(let (new-size)
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+)
1887 :ecx)
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)
1893 (:jmp 'done-u32)))
1895 (:compile-two-forms (:edx :ecx) position size)
1896 (:movl :ecx :eax) ; keep size/fixnum in EAX.
1897 (:addl :edx :ecx)
1898 (:into) ; just to make sure
1899 (:shrl 5 :ecx) ; compute msb bigit index/fixnum in ecx
1900 (:addl 4 :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).
1904 (:jnz 'adjust-size)
1905 (:movl :eax :ecx) ; size/fixnum
1906 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
1907 (:andl 31 :ecx)
1908 (:jz 'yes-return-same)
1909 (:std) ; <================
1910 ;; we know EDX=0, now generate mask in EDX
1911 (:addl 1 :edx)
1912 (:shll :cl :edx)
1913 (:movzxw (:ebx (:offset movitz-bignum length))
1914 :ecx)
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.
1919 yes-return-same
1920 (:movl :ebx :eax) ; yep, we can return same bignum.
1921 (:jmp 'ldb-done)))
1922 (:jnc 'size-ok)
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.
1925 (:testl :edx :edx)
1926 (:jz '(:sub-program ()
1927 (:movl :ebx :eax) ; return the source bignum.
1928 (:jmp 'ldb-done)))
1929 adjust-size
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.
1939 (:break)))
1940 (:jz 'ldb-done) ; New size was zero, so the result of ldb is zero.
1941 (:movl :ecx :eax) ; New size into EAX.
1942 size-ok
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))))
1951 (:pushl :ebp)
1952 restart-ldb
1954 (:movl (:esp) :ebp)
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))
1964 :eax)
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)
1968 (:pushl :eax)
1969 (:call-local-pf cons-non-pointer)
1970 ;; (:store-lexical (:lexical-binding r) :eax :type t)
1971 (:popl :ecx)
1972 (:subl ,(* 2 movitz:+movitz-fixnum-factor+) :ecx) ; for tmp storage and header.
1973 (:shll 16 :ecx)
1974 (:orl ,(movitz:tag :bignum 0) :ecx)
1975 (:movl :ecx (:eax ,movitz:+other-type-offset+))
1976 (:compile-form (:result-mode :ebx) integer)
1978 (:xchgl :eax :ebx)
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)
1989 (:int 4)))
1990 (:jne 'tail-tmp-ok)
1991 ;; Sizes was equal, so set tail-tmp to zero.
1992 (:movl 0 (:ebx :ecx (:offset movitz-bignum bigit0)))
1993 tail-tmp-ok
1994 ;; Now copy the relevant part of the integer
1995 (:std)
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
2002 copy-integer
2003 (:movl (:eax) :edx)
2004 (:addl 4 :eax)
2005 (:movl :edx (:ebx :ecx (:offset movitz-bignum bigit0)))
2006 (:addl 4 :ecx)
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.
2011 (:movl (:eax) :edx)
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)
2016 (:andl 31 :ecx)
2017 (:jz 'shift-done) ; if (zerop (mod position 32)), no shift needed.
2018 (:xorl :edx :edx) ; counter
2019 shift-loop
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)))
2024 (:addl 4 :edx)
2025 (:cmpw :dx (:ebx (:offset movitz-bignum length)))
2026 (:jne 'shift-loop)
2027 shift-done
2028 ;; Now we must mask MSB bigit.
2029 (:movzxw (:ebx (:offset movitz-bignum length))
2030 :edx)
2031 (:load-lexical (:lexical-binding size) :ecx)
2032 (:shrl 5 :ecx)
2033 (:andl -4 :ecx) ; ECX = index of (conceptual) MSB
2034 (:cmpl :ecx :edx)
2035 (:jbe 'mask-done)
2037 (:load-lexical (:lexical-binding size) :ecx)
2038 (:shrl ,movitz:+movitz-fixnum-shift+ :ecx)
2039 (:andl 31 :ecx)
2040 (:jz 'mask-done)
2041 (:movl 1 :eax) ; Generate mask in EAX
2042 (:shll :cl :eax)
2043 (:subl 1 :eax)
2044 (:andl :eax (:ebx :edx (:offset movitz-bignum bigit0 -4)))
2045 mask-done
2046 ;; (:movl :edi :edx) ; safe EDX
2047 (:movl :edi :eax) ; safe EAX
2048 (:cld)
2049 ;; Now we must zero-truncate the result bignum in EBX.
2050 (:movzxw (:ebx (:offset movitz-bignum length))
2051 :ecx)
2052 zero-truncate-loop
2053 (:cmpl 0 (:ebx :ecx (:offset movitz-bignum bigit0 -4)))
2054 (:jne 'zero-truncate-done)
2055 (:subl 4 :ecx)
2056 (:jnz 'zero-truncate-loop)
2057 ;; Zero bigits means the entire result collapsed to zero.
2058 (:xorl :eax :eax)
2059 (:jmp 'return-fixnum) ; don't commit the bignum allocation.
2060 zero-truncate-done
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))
2067 :ecx)
2068 (:leal ((:ecx ,movitz:+movitz-fixnum-factor+)) :eax)
2069 (:jmp 'return-fixnum)
2070 complete-bignum-allocation
2071 (:movw :cx (:ebx (:offset movitz-bignum length)))
2072 (:movl :ebx :eax)
2073 (:leal (:ecx ,movitz:+movitz-fixnum-factor+)
2074 :ecx)
2075 (:call-local-pf cons-commit-non-pointer)
2076 return-fixnum
2077 (:locally (:movl 0 (:edi (:edi-offset atomically-continuation))))
2078 (:leal (:esp 16) :esp)
2079 ldb-done))))
2080 (do-it)))))))
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)
2087 (0 nil)
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)
2096 (etypecase integer
2097 (positive-fixnum
2098 (with-inline-assembly (:returns :untagged-fixnum-ecx :type (integer 0 29))
2099 (:load-lexical (:lexical-binding integer) :eax)
2100 (:xorl :ecx :ecx)
2101 count-loop
2102 (:shll 1 :eax)
2103 (:adcl 0 :ecx)
2104 (:testl :eax :eax)
2105 (:jnz 'count-loop)))
2106 (positive-bignum
2107 (bignum-logcount integer))))
2109 (defun dpb (newbyte bytespec integer)
2110 (logior (if (= 0 newbyte)
2112 (mask-field bytespec (ash newbyte (byte-position bytespec))))
2113 (if (= 0 integer)
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)
2133 (numargs-case
2134 (1 (u) u)
2135 (2 (u v)
2136 ;; Code borrowed from CMUCL.
2137 (cond
2138 ((= 0 u) v)
2139 ((= 0 v) u)
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)
2145 (- v)
2146 (truncate u 2))
2147 (truncate temp 2)))
2148 (nil)
2149 (when (oddp temp)
2150 (if (plusp temp)
2151 (setq u temp)
2152 (setq v (- temp)))
2153 (setq temp (- u v))
2154 (when (zerop temp)
2155 (return (ash u k))))))))))
2156 (t (&rest integers)
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."
2166 (numargs-case
2167 (1 (n)
2168 (abs n))
2169 (2 (n m)
2170 (abs (* (truncate (max n m) (gcd n m)) (min n m))))
2171 (t (&rest numbers)
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."
2177 (numargs-case
2178 (1 (n)
2179 (if (not (typep n 'ratio))
2180 (values n 0)
2181 (multiple-value-bind (r q)
2182 (floor (%ratio-numerator n) (%ratio-denominator n))
2183 (values r (make-rational q (%ratio-denominator n))))))
2184 (2 (n divisor)
2185 (multiple-value-bind (q r)
2186 (truncate n divisor)
2187 (cond
2188 ((= 0 r)
2189 (values q r))
2190 ((or (and (minusp r) (plusp divisor))
2191 (and (plusp r) (minusp divisor)))
2192 (values (1- q) (+ r divisor)))
2193 (t (values q r)))))
2194 (t (n &optional (divisor 1))
2195 (floor n divisor))))
2197 (defun isqrt (natural)
2198 "=> natural-root"
2199 (check-type natural (integer 0 *))
2200 (if (= 0 natural)
2202 (let ((r 1))
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))
2206 (let ((r+1 (1+ r)))
2207 (if (<= (* r+1 r+1) natural)
2209 r)))
2210 (setf r next-r)))))
2212 (defun rootn (x root)
2213 (check-type root (integer 2 *))
2214 (let ((root-1 (1- root))
2215 (r (/ x root)))
2216 (dotimes (i 10 r)
2217 (let ((m (min (integer-length (numerator r))
2218 (integer-length (denominator r)))))
2219 (when (>= m 32)
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)))
2227 root)))))
2229 (defun sqrt (x)
2230 (rootn x 2))
2232 (defun expt (base-number power-number)
2233 "Take base-number to the power-number."
2234 (etypecase power-number
2235 (positive-fixnum
2236 (do ((i 0 (1+ i))
2237 (r 1 (* r base-number)))
2238 ((>= i power-number) r)
2239 (declare (index i))))
2240 (positive-bignum
2241 (do ((i 0 (1+ i))
2242 (r 1 (* r base-number)))
2243 ((>= i power-number) r)))
2244 ((number * -1)
2245 (/ (expt base-number (- power-number))))
2246 (ratio
2247 (expt (rootn base-number (denominator power-number))
2248 (numerator power-number)))))
2250 (defun floatp (x)
2251 (declare (ignore x))
2252 nil)
2254 (defun realpart (number)
2255 number)
2257 (defun imagpart (number)
2258 (declare (ignore number))
2261 (defun rational (number)
2262 number)
2264 (defun realp (x)
2265 (typep x 'real))