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 n-word-bytes
))
47 (inst sub esp-tn
(fixnumize 2))
48 (inst push eax
) ; callers return addr
49 (inst mov ecx
(fixnumize 2)) ; arg count
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-widetag
(1+ bignum-digits-offset
))
69 (storew ecx res bignum-digits-offset other-pointer-lowtag
))
73 (define-generic-arith-routine (- 10)
77 (inst cmc
) ; carry has correct sign now
79 (inst sar res
1) ; remove type bits
83 (with-fixed-allocation (res bignum-widetag
(1+ bignum-digits-offset
))
84 (storew ecx res bignum-digits-offset other-pointer-lowtag
))
87 (define-generic-arith-routine (* 30)
88 (move eax x
) ; must use eax for 64-bit result
89 (inst sar eax
2) ; remove *4 fixnum bias
90 (inst imul y
) ; result in edx:eax
91 (inst jmp
:no okay
) ; still fixnum
93 ;; zzz jrd changed edx to ebx in here, as edx isn't listed as a temp, above
94 ;; pfw says that loses big -- edx is target for arg x and result res
95 ;; note that 'edx' is not defined -- using x
96 (inst shrd eax x
2) ; high bits from edx
97 (inst sar x
2) ; now shift edx too
99 (move ecx x
) ; save high bits from cdq
100 (inst cdq
) ; edx:eax <- sign-extend of eax
102 (inst jmp
:e SINGLE-WORD-BIGNUM
)
104 (with-fixed-allocation (res bignum-widetag
(+ bignum-digits-offset
2))
105 (storew eax res bignum-digits-offset other-pointer-lowtag
)
106 (storew ecx res
(1+ bignum-digits-offset
) other-pointer-lowtag
))
111 (with-fixed-allocation (res bignum-widetag
(1+ bignum-digits-offset
))
112 (storew eax res bignum-digits-offset other-pointer-lowtag
))
121 (define-assembly-routine (generic-negate
123 (:return-style
:full-call
)
127 ((:arg x
(descriptor-reg any-reg
) edx-offset
)
128 (:res res
(descriptor-reg any-reg
) edx-offset
)
130 (:temp eax unsigned-reg eax-offset
)
131 (:temp ecx unsigned-reg ecx-offset
))
137 (inst lea ebp-tn
(make-ea :dword
:base esp-tn
:disp n-word-bytes
))
138 (inst sub esp-tn
(fixnumize 2))
140 (inst mov ecx
(fixnumize 1)) ; arg count
141 (inst jmp
(make-ea :dword
142 :disp
(+ nil-value
(static-fun-offset '%negate
))))
146 (inst neg res
) ; (- most-negative-fixnum) is BIGNUM
148 (inst shr res
2) ; sign bit is data - remove type bits
151 (with-fixed-allocation (res bignum-widetag
(1+ bignum-digits-offset
))
152 (storew ecx res bignum-digits-offset other-pointer-lowtag
))
158 (macrolet ((define-cond-assem-rtn (name translate static-fn test
)
159 `(define-assembly-routine (,name
161 (:return-style
:full-call
)
163 (:translate
,translate
)
165 ((:arg x
(descriptor-reg any-reg
) edx-offset
)
166 (:arg y
(descriptor-reg any-reg
) edi-offset
)
168 (:res res descriptor-reg edx-offset
)
170 (:temp eax unsigned-reg eax-offset
)
171 (:temp ecx unsigned-reg ecx-offset
))
173 ;; KLUDGE: The "3" here is a mask for the bits which will be
174 ;; zero in a fixnum. It should have a symbolic name. (Actually,
175 ;; it might already have a symbolic name which the coder
176 ;; couldn't be bothered to use..) -- WHN 19990917
178 (inst jmp
:nz TAIL-CALL-TO-STATIC-FN
)
180 (inst jmp
:z INLINE-FIXNUM-COMPARE
)
182 TAIL-CALL-TO-STATIC-FN
185 (inst lea ebp-tn
(make-ea :dword
188 (inst sub esp-tn
(fixnumize 2)) ; FIXME: Push 2 words on stack,
191 (inst mov ecx
(fixnumize 2)) ; FIXME: FIXNUMIZE and
192 ; SINGLE-FLOAT-BITS are parallel,
193 ; should be named parallelly.
194 (inst jmp
(make-ea :dword
196 (static-fun-offset ',static-fn
))))
198 INLINE-FIXNUM-COMPARE
200 (inst mov res nil-value
)
201 (inst jmp
,test RETURN-FALSE
)
208 (define-cond-assem-rtn generic-
< < two-arg-
< :ge
)
209 (define-cond-assem-rtn generic-
> > two-arg-
> :le
))
211 (define-assembly-routine (generic-eql
213 (:return-style
:full-call
)
217 ((:arg x
(descriptor-reg any-reg
) edx-offset
)
218 (:arg y
(descriptor-reg any-reg
) edi-offset
)
220 (:res res descriptor-reg edx-offset
)
222 (:temp eax unsigned-reg eax-offset
)
223 (:temp ecx unsigned-reg ecx-offset
))
225 (inst jmp
:e RETURN-T
)
227 (inst jmp
:z RETURN-NIL
)
229 (inst jmp
:nz DO-STATIC-FN
)
232 (inst mov res nil-value
)
238 (inst lea ebp-tn
(make-ea :dword
:base esp-tn
:disp n-word-bytes
))
239 (inst sub esp-tn
(fixnumize 2))
241 (inst mov ecx
(fixnumize 2))
242 (inst jmp
(make-ea :dword
243 :disp
(+ nil-value
(static-fun-offset 'eql
))))
250 (define-assembly-routine (generic-=
252 (:return-style
:full-call
)
256 ((:arg x
(descriptor-reg any-reg
) edx-offset
)
257 (:arg y
(descriptor-reg any-reg
) edi-offset
)
259 (:res res descriptor-reg edx-offset
)
261 (:temp eax unsigned-reg eax-offset
)
262 (:temp ecx unsigned-reg ecx-offset
)
264 (inst test x
3) ; descriptor?
265 (inst jmp
:nz DO-STATIC-FN
) ; yes, do it here
266 (inst test y
3) ; descriptor?
267 (inst jmp
:nz DO-STATIC-FN
)
269 (inst jmp
:e RETURN-T
) ; ok
271 (inst mov res nil-value
)
277 (inst lea ebp-tn
(make-ea :dword
:base esp-tn
:disp n-word-bytes
))
278 (inst sub esp-tn
(fixnumize 2))
280 (inst mov ecx
(fixnumize 2))
281 (inst jmp
(make-ea :dword
282 :disp
(+ nil-value
(static-fun-offset 'two-arg-
=))))
290 ;;; Support for the Mersenne Twister, MT19937, random number generator
291 ;;; due to Matsumoto and Nishimura.
293 ;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
294 ;;; 623-dimensionally equidistributed uniform pseudorandom number
295 ;;; generator.", ACM Transactions on Modeling and Computer Simulation,
299 ;;; 0-1: Constant matrix A. [0, #x9908b0df] (not used here)
300 ;;; 2: Index; init. to 1.
303 ;;; This assembly routine is called from the inline VOP and updates
304 ;;; the state vector with new random numbers. The state vector is
305 ;;; passed in the EAX register.
306 #+sb-assembling
; We don't want a vop for this one.
307 (define-assembly-routine
308 (random-mt19937-update)
309 ((:temp state unsigned-reg eax-offset
)
310 (:temp k unsigned-reg ebx-offset
)
311 (:temp y unsigned-reg ecx-offset
)
312 (:temp tmp unsigned-reg edx-offset
))
314 ;; Save the temporary registers.
319 ;; Generate a new set of results.
322 (inst mov y
(make-ea :dword
:base state
:index k
:scale
4
323 :disp
(- (* (+ 3 vector-data-offset
)
325 other-pointer-lowtag
)))
326 (inst mov tmp
(make-ea :dword
:base state
:index k
:scale
4
327 :disp
(- (* (+ 1 3 vector-data-offset
)
329 other-pointer-lowtag
)))
330 (inst and y
#x80000000
)
331 (inst and tmp
#x7fffffff
)
335 (inst xor y
#x9908b0df
)
337 (inst xor y
(make-ea :dword
:base state
:index k
:scale
4
338 :disp
(- (* (+ 397 3 vector-data-offset
)
340 other-pointer-lowtag
)))
341 (inst mov
(make-ea :dword
:base state
:index k
:scale
4
342 :disp
(- (* (+ 3 vector-data-offset
)
344 other-pointer-lowtag
))
347 (inst cmp k
(- 624 397))
350 (inst mov y
(make-ea :dword
:base state
:index k
:scale
4
351 :disp
(- (* (+ 3 vector-data-offset
)
353 other-pointer-lowtag
)))
354 (inst mov tmp
(make-ea :dword
:base state
:index k
:scale
4
355 :disp
(- (* (+ 1 3 vector-data-offset
)
357 other-pointer-lowtag
)))
358 (inst and y
#x80000000
)
359 (inst and tmp
#x7fffffff
)
363 (inst xor y
#x9908b0df
)
365 (inst xor y
(make-ea :dword
:base state
:index k
:scale
4
366 :disp
(- (* (+ (- 397 624) 3 vector-data-offset
)
368 other-pointer-lowtag
)))
369 (inst mov
(make-ea :dword
:base state
:index k
:scale
4
370 :disp
(- (* (+ 3 vector-data-offset
)
372 other-pointer-lowtag
))
375 (inst cmp k
(- 624 1))
378 (inst mov y
(make-ea :dword
:base state
379 :disp
(- (* (+ (- 624 1) 3 vector-data-offset
)
381 other-pointer-lowtag
)))
382 (inst mov tmp
(make-ea :dword
:base state
383 :disp
(- (* (+ 0 3 vector-data-offset
)
385 other-pointer-lowtag
)))
386 (inst and y
#x80000000
)
387 (inst and tmp
#x7fffffff
)
391 (inst xor y
#x9908b0df
)
393 (inst xor y
(make-ea :dword
:base state
394 :disp
(- (* (+ (- 397 1) 3 vector-data-offset
)
396 other-pointer-lowtag
)))
397 (inst mov
(make-ea :dword
:base state
398 :disp
(- (* (+ (- 624 1) 3 vector-data-offset
)
400 other-pointer-lowtag
))
403 ;; Restore the temporary registers and return.