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.
17 ;;;; addition, subtraction, and multiplication
19 (macrolet ((define-generic-arith-routine ((fun cost) &body body)
20 `(define-assembly-routine (,(symbolicate "GENERIC-" fun)
22 (:return-style :full-call)
26 ((:arg x (descriptor-reg any-reg) edx-offset)
27 (:arg y (descriptor-reg any-reg)
28 ;; this seems wrong esi-offset -- FIXME: What's it mean?
31 (:res res (descriptor-reg any-reg) edx-offset)
33 (:temp eax unsigned-reg eax-offset)
34 (:temp ebx unsigned-reg ebx-offset)
35 (:temp ecx unsigned-reg ecx-offset))
37 (declare (ignorable ebx))
39 (inst test x 3) ; fixnum?
40 (inst jmp :nz DO-STATIC-FUN) ; no - do generic
41 (inst test y 3) ; fixnum?
42 (inst jmp :z DO-BODY) ; yes - doit here
49 (make-ea :dword :base esp-tn :disp word-bytes))
50 (inst sub esp-tn (fixnumize 2))
51 (inst push eax) ; callers return addr
52 (inst mov ecx (fixnumize 2)) ; arg count
56 (static-function-offset
57 ',(symbolicate "TWO-ARG-" fun)))))
62 (define-generic-arith-routine (+ 10)
66 (inst rcr res 1) ; carry has correct sign
67 (inst sar res 1) ; remove type bits
71 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
72 (storew ecx res bignum-digits-offset other-pointer-type))
76 (define-generic-arith-routine (- 10)
77 ;; FIXME: This is screwed up.
78 ;;; I can't figure out the flags on subtract. Overflow never gets
79 ;;; set and carry always does. (- 0 most-negative-fixnum) can't be
80 ;;; easily detected so just let the upper level stuff do it.
81 (inst jmp DO-STATIC-FUN)
87 (inst sar res 1) ; remove type bits
91 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
92 (storew ecx res bignum-digits-offset other-pointer-type))
95 (define-generic-arith-routine (* 30)
96 (move eax x) ; must use eax for 64-bit result
97 (inst sar eax 2) ; remove *4 fixnum bias
98 (inst imul y) ; result in edx:eax
99 (inst jmp :no okay) ; still fixnum
101 ;; zzz jrd changed edx to ebx in here, as edx isn't listed as a temp, above
102 ;; pfw says that loses big -- edx is target for arg x and result res
103 ;; note that 'edx' is not defined -- using x
104 (inst shrd eax x 2) ; high bits from edx
105 (inst sar x 2) ; now shift edx too
107 (move ecx x) ; save high bits from cdq
108 (inst cdq) ; edx:eax <- sign-extend of eax
110 (inst jmp :e SINGLE-WORD-BIGNUM)
112 (with-fixed-allocation (res bignum-type (+ bignum-digits-offset 2))
113 (storew eax res bignum-digits-offset other-pointer-type)
114 (storew ecx res (1+ bignum-digits-offset) other-pointer-type))
119 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
120 (storew eax res bignum-digits-offset other-pointer-type))
129 (define-assembly-routine (generic-negate
131 (:return-style :full-call)
135 ((:arg x (descriptor-reg any-reg) edx-offset)
136 (:res res (descriptor-reg any-reg) edx-offset)
138 (:temp eax unsigned-reg eax-offset)
139 (:temp ecx unsigned-reg ecx-offset))
145 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
146 (inst sub esp-tn (fixnumize 2))
148 (inst mov ecx (fixnumize 1)) ; arg count
149 (inst jmp (make-ea :dword
150 :disp (+ *nil-value* (static-function-offset '%negate))))
154 (inst neg res) ; (- most-negative-fixnum) is BIGNUM
156 (inst shr res 2) ; sign bit is data - remove type bits
159 (with-fixed-allocation (res bignum-type (1+ bignum-digits-offset))
160 (storew ecx res bignum-digits-offset other-pointer-type))
166 (macrolet ((define-cond-assem-rtn (name translate static-fn test)
167 `(define-assembly-routine (,name
169 (:return-style :full-call)
171 (:translate ,translate)
173 ((:arg x (descriptor-reg any-reg) edx-offset)
174 (:arg y (descriptor-reg any-reg) edi-offset)
176 (:res res descriptor-reg edx-offset)
178 (:temp eax unsigned-reg eax-offset)
179 (:temp ecx unsigned-reg ecx-offset))
181 ;; KLUDGE: The "3" here is a mask for the bits which will be
182 ;; zero in a fixnum. It should have a symbolic name. (Actually,
183 ;; it might already have a symbolic name which the coder
184 ;; couldn't be bothered to use..) -- WHN 19990917
186 (inst jmp :nz TAIL-CALL-TO-STATIC-FN)
188 (inst jmp :z INLINE-FIXNUM-COMPARE)
190 TAIL-CALL-TO-STATIC-FN
193 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
194 (inst sub esp-tn (fixnumize 2)) ; FIXME: Push 2 words on stack,
197 (inst mov ecx (fixnumize 2)) ; FIXME: FIXNUMIZE and
198 ; SINGLE-FLOAT-BITS are parallel,
199 ; should be named parallelly.
200 (inst jmp (make-ea :dword
202 (static-function-offset
205 INLINE-FIXNUM-COMPARE
207 (inst jmp ,test RETURN-TRUE)
208 (inst mov res *nil-value*)
209 ;; FIXME: A note explaining this return convention, or a
210 ;; symbolic name for it, would be nice. (It looks as though we
211 ;; should be hand-crafting the same return sequence as would be
212 ;; produced by GENERATE-RETURN-SEQUENCE, but in that case it's
213 ;; not clear why we don't just jump to the end of this function
214 ;; to share the return sequence there.
220 (load-symbol res t))))
222 (define-cond-assem-rtn generic-< < two-arg-< :l)
223 (define-cond-assem-rtn generic-> > two-arg-> :g))
225 (define-assembly-routine (generic-eql
227 (:return-style :full-call)
231 ((:arg x (descriptor-reg any-reg) edx-offset)
232 (:arg y (descriptor-reg any-reg) edi-offset)
234 (:res res descriptor-reg edx-offset)
236 (:temp eax unsigned-reg eax-offset)
237 (:temp ecx unsigned-reg ecx-offset))
239 (inst jmp :e RETURN-T)
241 (inst jmp :z RETURN-NIL)
243 (inst jmp :nz DO-STATIC-FN)
246 (inst mov res *nil-value*)
254 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
255 (inst sub esp-tn (fixnumize 2))
257 (inst mov ecx (fixnumize 2))
258 (inst jmp (make-ea :dword
259 :disp (+ *nil-value* (static-function-offset 'eql))))
263 ;; FIXME: I don't understand how we return from here..
266 (define-assembly-routine (generic-=
268 (:return-style :full-call)
272 ((:arg x (descriptor-reg any-reg) edx-offset)
273 (:arg y (descriptor-reg any-reg) edi-offset)
275 (:res res descriptor-reg edx-offset)
277 (:temp eax unsigned-reg eax-offset)
278 (:temp ecx unsigned-reg ecx-offset)
280 (inst test x 3) ; descriptor?
281 (inst jmp :nz DO-STATIC-FN) ; yes do it here
282 (inst test y 3) ; descriptor?
283 (inst jmp :nz DO-STATIC-FN)
285 (inst jmp :e RETURN-T) ; ok
287 (inst mov res *nil-value*)
295 (inst lea ebp-tn (make-ea :dword :base esp-tn :disp word-bytes))
296 (inst sub esp-tn (fixnumize 2))
298 (inst mov ecx (fixnumize 2))
299 (inst jmp (make-ea :dword
300 :disp (+ *nil-value* (static-function-offset 'two-arg-=))))
306 ;;; Support for the Mersenne Twister, MT19937, random number generator
307 ;;; due to Matsumoto and Nishimura.
309 ;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
310 ;;; 623-dimensionally equidistributed uniform pseudorandom number
311 ;;; generator.", ACM Transactions on Modeling and Computer Simulation,
315 ;;; 0-1: Constant matrix A. [0, #x9908b0df] (not used here)
316 ;;; 2: Index; init. to 1.
319 ;;; This assembly routine is called from the inline VOP and updates
320 ;;; the state vector with new random numbers. The state vector is
321 ;;; passed in the EAX register.
322 #+sb-assembling ; We don't want a vop for this one.
323 (define-assembly-routine
324 (random-mt19937-update)
325 ((:temp state unsigned-reg eax-offset)
326 (:temp k unsigned-reg ebx-offset)
327 (:temp y unsigned-reg ecx-offset)
328 (:temp tmp unsigned-reg edx-offset))
330 ;; Save the temporary registers.
335 ;; Generate a new set of results.
338 (inst mov y (make-ea :dword :base state :index k :scale 4
339 :disp (- (* (+ 3 sb!vm:vector-data-offset)
341 sb!vm:other-pointer-type)))
342 (inst mov tmp (make-ea :dword :base state :index k :scale 4
343 :disp (- (* (+ 1 3 sb!vm:vector-data-offset)
345 sb!vm:other-pointer-type)))
346 (inst and y #x80000000)
347 (inst and tmp #x7fffffff)
351 (inst xor y #x9908b0df)
353 (inst xor y (make-ea :dword :base state :index k :scale 4
354 :disp (- (* (+ 397 3 sb!vm:vector-data-offset)
356 sb!vm:other-pointer-type)))
357 (inst mov (make-ea :dword :base state :index k :scale 4
358 :disp (- (* (+ 3 sb!vm:vector-data-offset)
360 sb!vm:other-pointer-type))
363 (inst cmp k (- 624 397))
366 (inst mov y (make-ea :dword :base state :index k :scale 4
367 :disp (- (* (+ 3 sb!vm:vector-data-offset)
369 sb!vm:other-pointer-type)))
370 (inst mov tmp (make-ea :dword :base state :index k :scale 4
371 :disp (- (* (+ 1 3 sb!vm:vector-data-offset)
373 sb!vm:other-pointer-type)))
374 (inst and y #x80000000)
375 (inst and tmp #x7fffffff)
379 (inst xor y #x9908b0df)
381 (inst xor y (make-ea :dword :base state :index k :scale 4
382 :disp (- (* (+ (- 397 624) 3 sb!vm:vector-data-offset)
384 sb!vm:other-pointer-type)))
385 (inst mov (make-ea :dword :base state :index k :scale 4
386 :disp (- (* (+ 3 sb!vm:vector-data-offset)
388 sb!vm:other-pointer-type))
391 (inst cmp k (- 624 1))
394 (inst mov y (make-ea :dword :base state
395 :disp (- (* (+ (- 624 1) 3 sb!vm:vector-data-offset)
397 sb!vm:other-pointer-type)))
398 (inst mov tmp (make-ea :dword :base state
399 :disp (- (* (+ 0 3 sb!vm:vector-data-offset)
401 sb!vm:other-pointer-type)))
402 (inst and y #x80000000)
403 (inst and tmp #x7fffffff)
407 (inst xor y #x9908b0df)
409 (inst xor y (make-ea :dword :base state
410 :disp (- (* (+ (- 397 1) 3 sb!vm:vector-data-offset)
412 sb!vm:other-pointer-type)))
413 (inst mov (make-ea :dword :base state
414 :disp (- (* (+ (- 624 1) 3 sb!vm:vector-data-offset)
416 sb!vm:other-pointer-type))
419 ;; Restore the temporary registers and return.