1 ;;;; simple cases for generic arithmetic
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 ;;;; addition, subtraction, and multiplication
16 (macrolet ((define-generic-arith-routine ((fun cost) &body body)
17 `(define-assembly-routine (,(symbolicate "GENERIC-" fun)
19 (:return-style :full-call)
23 ((:arg x (descriptor-reg any-reg) edx-offset)
24 (:arg y (descriptor-reg any-reg)
25 ;; this seems wrong esi-offset -- FIXME: What's it mean?
28 (:res res (descriptor-reg any-reg) edx-offset)
30 (:temp eax unsigned-reg eax-offset)
31 (:temp ebx unsigned-reg ebx-offset)
32 (:temp ecx unsigned-reg ecx-offset))
34 (declare (ignorable ebx))
36 (inst test x 3) ; fixnum?
37 (inst jmp :nz DO-STATIC-FUN) ; no - do generic
38 (inst test y 3) ; fixnum?
39 (inst jmp :z DO-BODY) ; yes - doit here
46 (make-ea :dword :base esp-tn :disp word-bytes))
47 (inst sub esp-tn (fixnumize 2))
48 (inst push eax) ; callers return addr
49 (inst mov ecx (fixnumize 2)) ; arg count
53 (static-function-offset
54 ',(symbolicate "TWO-ARG-" fun)))))
59 (define-generic-arith-routine (+ 10)
63 (inst rcr res 1) ; carry has correct sign
64 (inst sar res 1) ; remove type bits
68 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
69 (storew ecx res bignum-digits-offset other-pointer-type))
73 (define-generic-arith-routine (- 10)
74 ;; FIXME: This is screwed up.
75 ;;; I can't figure out the flags on subtract. Overflow never gets
76 ;;; set and carry always does. (- 0 most-negative-fixnum) can't be
77 ;;; easily detected so just let the upper level stuff do it.
78 (inst jmp DO-STATIC-FUN)
84 (inst sar res 1) ; remove type bits
88 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
89 (storew ecx res bignum-digits-offset other-pointer-type))
92 (define-generic-arith-routine (* 30)
93 (move eax x) ; must use eax for 64-bit result
94 (inst sar eax 2) ; remove *4 fixnum bias
95 (inst imul y) ; result in edx:eax
96 (inst jmp :no okay) ; still fixnum
98 ;; zzz jrd changed edx to ebx in here, as edx isn't listed as a temp, above
99 ;; pfw says that loses big -- edx is target for arg x and result res
100 ;; note that 'edx' is not defined -- using x
101 (inst shrd eax x 2) ; high bits from edx
102 (inst sar x 2) ; now shift edx too
104 (move ecx x) ; save high bits from cdq
105 (inst cdq) ; edx:eax <- sign-extend of eax
107 (inst jmp :e SINGLE-WORD-BIGNUM)
109 (with-fixed-allocation (res bignum-type (+ bignum-digits-offset 2))
110 (storew eax res bignum-digits-offset other-pointer-type)
111 (storew ecx res (1+ bignum-digits-offset) other-pointer-type))
116 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
117 (storew eax res bignum-digits-offset other-pointer-type))
126 (define-assembly-routine (generic-negate
128 (:return-style :full-call)
132 ((:arg x (descriptor-reg any-reg) edx-offset)
133 (:res res (descriptor-reg any-reg) edx-offset)
135 (:temp eax unsigned-reg eax-offset)
136 (:temp ecx unsigned-reg ecx-offset))
142 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
143 (inst sub esp-tn (fixnumize 2))
145 (inst mov ecx (fixnumize 1)) ; arg count
146 (inst jmp (make-ea :dword
147 :disp (+ nil-value (static-function-offset '%negate))))
151 (inst neg res) ; (- most-negative-fixnum) is BIGNUM
153 (inst shr res 2) ; sign bit is data - remove type bits
156 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
157 (storew ecx res bignum-digits-offset other-pointer-type))
163 (macrolet ((define-cond-assem-rtn (name translate static-fn test)
164 `(define-assembly-routine (,name
166 (:return-style :full-call)
168 (:translate ,translate)
170 ((:arg x (descriptor-reg any-reg) edx-offset)
171 (:arg y (descriptor-reg any-reg) edi-offset)
173 (:res res descriptor-reg edx-offset)
175 (:temp eax unsigned-reg eax-offset)
176 (:temp ecx unsigned-reg ecx-offset))
178 ;; KLUDGE: The "3" here is a mask for the bits which will be
179 ;; zero in a fixnum. It should have a symbolic name. (Actually,
180 ;; it might already have a symbolic name which the coder
181 ;; couldn't be bothered to use..) -- WHN 19990917
183 (inst jmp :nz TAIL-CALL-TO-STATIC-FN)
185 (inst jmp :z INLINE-FIXNUM-COMPARE)
187 TAIL-CALL-TO-STATIC-FN
190 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
191 (inst sub esp-tn (fixnumize 2)) ; FIXME: Push 2 words on stack,
194 (inst mov ecx (fixnumize 2)) ; FIXME: FIXNUMIZE and
195 ; SINGLE-FLOAT-BITS are parallel,
196 ; should be named parallelly.
197 (inst jmp (make-ea :dword
199 (static-function-offset
202 INLINE-FIXNUM-COMPARE
204 (inst jmp ,test RETURN-TRUE)
205 (inst mov res nil-value)
206 ;; FIXME: A note explaining this return convention, or a
207 ;; symbolic name for it, would be nice. (It looks as though we
208 ;; should be hand-crafting the same return sequence as would be
209 ;; produced by GENERATE-RETURN-SEQUENCE, but in that case it's
210 ;; not clear why we don't just jump to the end of this function
211 ;; to share the return sequence there.
217 (load-symbol res t))))
219 (define-cond-assem-rtn generic-< < two-arg-< :l)
220 (define-cond-assem-rtn generic-> > two-arg-> :g))
222 (define-assembly-routine (generic-eql
224 (:return-style :full-call)
228 ((:arg x (descriptor-reg any-reg) edx-offset)
229 (:arg y (descriptor-reg any-reg) edi-offset)
231 (:res res descriptor-reg edx-offset)
233 (:temp eax unsigned-reg eax-offset)
234 (:temp ecx unsigned-reg ecx-offset))
236 (inst jmp :e RETURN-T)
238 (inst jmp :z RETURN-NIL)
240 (inst jmp :nz DO-STATIC-FN)
243 (inst mov res nil-value)
251 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
252 (inst sub esp-tn (fixnumize 2))
254 (inst mov ecx (fixnumize 2))
255 (inst jmp (make-ea :dword
256 :disp (+ nil-value (static-function-offset 'eql))))
260 ;; FIXME: I don't understand how we return from here..
263 (define-assembly-routine (generic-=
265 (:return-style :full-call)
269 ((:arg x (descriptor-reg any-reg) edx-offset)
270 (:arg y (descriptor-reg any-reg) edi-offset)
272 (:res res descriptor-reg edx-offset)
274 (:temp eax unsigned-reg eax-offset)
275 (:temp ecx unsigned-reg ecx-offset)
277 (inst test x 3) ; descriptor?
278 (inst jmp :nz DO-STATIC-FN) ; yes, do it here
279 (inst test y 3) ; descriptor?
280 (inst jmp :nz DO-STATIC-FN)
282 (inst jmp :e RETURN-T) ; ok
284 (inst mov res nil-value)
292 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
293 (inst sub esp-tn (fixnumize 2))
295 (inst mov ecx (fixnumize 2))
296 (inst jmp (make-ea :dword
297 :disp (+ nil-value (static-function-offset 'two-arg-=))))
303 ;;; Support for the Mersenne Twister, MT19937, random number generator
304 ;;; due to Matsumoto and Nishimura.
306 ;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
307 ;;; 623-dimensionally equidistributed uniform pseudorandom number
308 ;;; generator.", ACM Transactions on Modeling and Computer Simulation,
312 ;;; 0-1: Constant matrix A. [0, #x9908b0df] (not used here)
313 ;;; 2: Index; init. to 1.
316 ;;; This assembly routine is called from the inline VOP and updates
317 ;;; the state vector with new random numbers. The state vector is
318 ;;; passed in the EAX register.
319 #+sb-assembling ; We don't want a vop for this one.
320 (define-assembly-routine
321 (random-mt19937-update)
322 ((:temp state unsigned-reg eax-offset)
323 (:temp k unsigned-reg ebx-offset)
324 (:temp y unsigned-reg ecx-offset)
325 (:temp tmp unsigned-reg edx-offset))
327 ;; Save the temporary registers.
332 ;; Generate a new set of results.
335 (inst mov y (make-ea :dword :base state :index k :scale 4
336 :disp (- (* (+ 3 sb!vm:vector-data-offset)
338 sb!vm:other-pointer-type)))
339 (inst mov tmp (make-ea :dword :base state :index k :scale 4
340 :disp (- (* (+ 1 3 sb!vm:vector-data-offset)
342 sb!vm:other-pointer-type)))
343 (inst and y #x80000000)
344 (inst and tmp #x7fffffff)
348 (inst xor y #x9908b0df)
350 (inst xor y (make-ea :dword :base state :index k :scale 4
351 :disp (- (* (+ 397 3 sb!vm:vector-data-offset)
353 sb!vm:other-pointer-type)))
354 (inst mov (make-ea :dword :base state :index k :scale 4
355 :disp (- (* (+ 3 sb!vm:vector-data-offset)
357 sb!vm:other-pointer-type))
360 (inst cmp k (- 624 397))
363 (inst mov y (make-ea :dword :base state :index k :scale 4
364 :disp (- (* (+ 3 sb!vm:vector-data-offset)
366 sb!vm:other-pointer-type)))
367 (inst mov tmp (make-ea :dword :base state :index k :scale 4
368 :disp (- (* (+ 1 3 sb!vm:vector-data-offset)
370 sb!vm:other-pointer-type)))
371 (inst and y #x80000000)
372 (inst and tmp #x7fffffff)
376 (inst xor y #x9908b0df)
378 (inst xor y (make-ea :dword :base state :index k :scale 4
379 :disp (- (* (+ (- 397 624) 3 sb!vm:vector-data-offset)
381 sb!vm:other-pointer-type)))
382 (inst mov (make-ea :dword :base state :index k :scale 4
383 :disp (- (* (+ 3 sb!vm:vector-data-offset)
385 sb!vm:other-pointer-type))
388 (inst cmp k (- 624 1))
391 (inst mov y (make-ea :dword :base state
392 :disp (- (* (+ (- 624 1) 3 sb!vm:vector-data-offset)
394 sb!vm:other-pointer-type)))
395 (inst mov tmp (make-ea :dword :base state
396 :disp (- (* (+ 0 3 sb!vm:vector-data-offset)
398 sb!vm:other-pointer-type)))
399 (inst and y #x80000000)
400 (inst and tmp #x7fffffff)
404 (inst xor y #x9908b0df)
406 (inst xor y (make-ea :dword :base state
407 :disp (- (* (+ (- 397 1) 3 sb!vm:vector-data-offset)
409 sb!vm:other-pointer-type)))
410 (inst mov (make-ea :dword :base state
411 :disp (- (* (+ (- 624 1) 3 sb!vm:vector-data-offset)
413 sb!vm:other-pointer-type))
416 ;; Restore the temporary registers and return.