Remove more disassembler bogosity
[sbcl.git] / src / assembly / x86 / arith.lisp
blob2a22eae8b3509f29c1e20acb06f67a1bea375676
1 ;;;; simple cases for generic arithmetic
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
12 (in-package "SB!VM")
14 ;;;; addition, subtraction, and multiplication
16 (macrolet ((define-generic-arith-routine ((fun cost) &body body)
17 `(define-assembly-routine (,(symbolicate "GENERIC-" fun)
18 (:cost ,cost)
19 (:return-style :full-call)
20 (:translate ,fun)
21 (:policy :safe)
22 (:save-p t))
23 ((:arg x (descriptor-reg any-reg) edx-offset)
24 (:arg y (descriptor-reg any-reg) edi-offset)
26 (:res res (descriptor-reg any-reg) edx-offset)
28 (:temp eax unsigned-reg eax-offset)
29 (:temp ecx unsigned-reg ecx-offset))
31 (inst mov ecx x)
32 (inst or ecx y)
33 (inst test ecx fixnum-tag-mask) ; both fixnums?
34 (inst jmp :nz DO-STATIC-FUN) ; no - do generic
36 ,@body
37 (inst clc) ; single-value return
38 (inst ret)
40 DO-STATIC-FUN
41 ;; Same as: (inst enter (fixnumize 1))
42 (inst push ebp-tn)
43 (inst mov ebp-tn esp-tn)
44 (inst sub esp-tn (fixnumize 1))
45 (inst push (make-ea :dword :base ebp-tn
46 :disp (frame-byte-offset return-pc-save-offset)))
47 (inst mov ecx (fixnumize 2)) ; arg count
48 (inst jmp
49 (make-ea :dword
50 :disp (+ nil-value
51 (static-fun-offset
52 ',(symbolicate "TWO-ARG-" fun))))))))
54 (define-generic-arith-routine (+ 10)
55 (move res x)
56 (inst add res y)
57 (inst jmp :no OKAY)
58 (inst rcr res 1) ; carry has correct sign
59 (inst sar res 1) ; remove type bits
61 (move ecx res)
63 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
64 (storew ecx res bignum-digits-offset other-pointer-lowtag))
66 OKAY)
68 (define-generic-arith-routine (- 10)
69 (move res x)
70 (inst sub res y)
71 (inst jmp :no OKAY)
72 (inst cmc) ; carry has correct sign now
73 (inst rcr res 1)
74 (inst sar res 1) ; remove type bits
76 (move ecx res)
78 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
79 (storew ecx res bignum-digits-offset other-pointer-lowtag))
80 OKAY)
82 (define-generic-arith-routine (* 30)
83 (move eax x) ; must use eax for 64-bit result
84 (inst sar eax n-fixnum-tag-bits) ; remove *4 fixnum bias
85 (inst imul y) ; result in edx:eax
86 (inst jmp :no OKAY) ; still fixnum
88 ;; zzz jrd changed edx to ebx in here, as edx isn't listed as a temp, above
89 ;; pfw says that loses big -- edx is target for arg x and result res
90 ;; note that 'edx' is not defined -- using x
91 (inst shrd eax x n-fixnum-tag-bits) ; high bits from edx
92 (inst sar x n-fixnum-tag-bits) ; now shift edx too
94 (move ecx x) ; save high bits from cdq
95 (inst cdq) ; edx:eax <- sign-extend of eax
96 (inst cmp x ecx)
97 (inst jmp :e SINGLE-WORD-BIGNUM)
99 (with-fixed-allocation (res bignum-widetag (+ bignum-digits-offset 2))
100 (storew eax res bignum-digits-offset other-pointer-lowtag)
101 (storew ecx res (1+ bignum-digits-offset) other-pointer-lowtag))
102 (inst jmp DONE)
104 SINGLE-WORD-BIGNUM
106 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
107 (storew eax res bignum-digits-offset other-pointer-lowtag))
108 (inst jmp DONE)
110 OKAY
111 (move res eax)
112 DONE))
114 ;;;; negation
116 (define-assembly-routine (generic-negate
117 (:cost 10)
118 (:return-style :full-call)
119 (:policy :safe)
120 (:translate %negate)
121 (:save-p t))
122 ((:arg x (descriptor-reg any-reg) edx-offset)
123 (:res res (descriptor-reg any-reg) edx-offset)
124 (:temp ecx unsigned-reg ecx-offset))
125 (inst test x fixnum-tag-mask)
126 (inst jmp :z FIXNUM)
128 (inst push ebp-tn)
129 (inst mov ebp-tn esp-tn)
130 (inst sub esp-tn (fixnumize 1))
131 (inst push (make-ea :dword :base ebp-tn
132 :disp (frame-byte-offset return-pc-save-offset)))
133 (inst mov ecx (fixnumize 1)) ; arg count
134 (inst jmp (make-ea :dword
135 :disp (+ nil-value (static-fun-offset '%negate))))
137 FIXNUM
138 (move res x)
139 (inst neg res) ; (- most-negative-fixnum) is BIGNUM
140 (inst jmp :no OKAY)
141 (inst shr res n-fixnum-tag-bits) ; sign bit is data - remove type bits
142 (move ecx res)
144 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
145 (storew ecx res bignum-digits-offset other-pointer-lowtag))
147 OKAY)
149 ;;;; comparison
151 (macrolet ((define-cond-assem-rtn (name translate static-fn test)
152 `(define-assembly-routine (,name
153 (:translate ,translate)
154 (:policy :safe)
155 (:save-p t)
156 (:conditional ,test)
157 (:cost 10))
158 ((:arg x (descriptor-reg any-reg) edx-offset)
159 (:arg y (descriptor-reg any-reg) edi-offset)
161 (:temp ecx unsigned-reg ecx-offset))
163 (inst mov ecx x)
164 (inst or ecx y)
165 (inst test ecx fixnum-tag-mask)
166 (inst jmp :nz DO-STATIC-FUN) ; are both fixnums?
168 (inst cmp x y)
169 (inst ret)
171 DO-STATIC-FUN
172 (inst push ebp-tn)
173 (inst mov ebp-tn esp-tn)
174 (inst sub esp-tn (fixnumize 3))
175 (inst mov (make-ea :dword :base esp-tn
176 :disp (frame-byte-offset
177 (+ sp->fp-offset
179 ocfp-save-offset)))
180 ebp-tn)
181 (inst lea ebp-tn (make-ea :dword :base esp-tn
182 :disp (frame-byte-offset
183 (+ sp->fp-offset
185 ocfp-save-offset))))
186 (inst mov ecx (fixnumize 2))
187 (inst call (make-ea :dword
188 :disp (+ nil-value
189 (static-fun-offset ',static-fn))))
190 ;; HACK: We depend on NIL having the lowest address of all
191 ;; static symbols (including T)
192 ,@(ecase test
193 (:l `((inst mov y (1+ nil-value))
194 (inst cmp y x)))
195 (:g `((inst cmp x (1+ nil-value)))))
196 (inst pop ebp-tn))))
197 (define-cond-assem-rtn generic-< < two-arg-< :l)
198 (define-cond-assem-rtn generic-> > two-arg-> :g))
200 (define-assembly-routine (generic-eql
201 (:translate eql)
202 (:policy :safe)
203 (:save-p t)
204 (:conditional :e)
205 (:cost 10))
206 ((:arg x (descriptor-reg any-reg) edx-offset)
207 (:arg y (descriptor-reg any-reg) edi-offset)
209 (:temp ecx unsigned-reg ecx-offset))
210 (inst mov ecx x)
211 (inst and ecx y)
212 (inst and ecx lowtag-mask)
213 (inst cmp ecx other-pointer-lowtag)
214 (inst jmp :e DO-STATIC-FUN)
216 ;; At least one fixnum
217 (inst cmp x y)
219 (inst ret)
221 DO-STATIC-FUN
222 ;; Might as well fast path that...
223 (inst cmp x y)
224 (inst jmp :e RET)
226 (inst push ebp-tn)
227 (inst mov ebp-tn esp-tn)
228 (inst sub esp-tn (fixnumize 3))
229 (inst mov (make-ea :dword :base esp-tn
230 :disp (frame-byte-offset
231 (+ sp->fp-offset
233 ocfp-save-offset)))
234 ebp-tn)
235 (inst lea ebp-tn (make-ea :dword :base esp-tn
236 :disp (frame-byte-offset
237 (+ sp->fp-offset
239 ocfp-save-offset))))
240 (inst mov ecx (fixnumize 2))
241 (inst call (make-ea :dword
242 :disp (+ nil-value (static-fun-offset 'eql))))
243 (load-symbol y t)
244 (inst cmp x y)
245 (inst pop ebp-tn))
247 (define-assembly-routine (generic-=
248 (:translate =)
249 (:policy :safe)
250 (:save-p t)
251 (:conditional :e)
252 (:cost 10))
253 ((:arg x (descriptor-reg any-reg) edx-offset)
254 (:arg y (descriptor-reg any-reg) edi-offset)
256 (:temp ecx unsigned-reg ecx-offset))
257 (inst mov ecx x)
258 (inst or ecx y)
259 (inst test ecx fixnum-tag-mask)
260 (inst jmp :nz DO-STATIC-FUN)
262 ;; Both fixnums
263 (inst cmp x y)
264 (inst ret)
266 DO-STATIC-FUN
267 (inst push ebp-tn)
268 (inst mov ebp-tn esp-tn)
269 (inst sub esp-tn (fixnumize 3))
270 (inst mov (make-ea :dword :base esp-tn
271 :disp (frame-byte-offset
272 (+ sp->fp-offset
274 ocfp-save-offset)))
275 ebp-tn)
276 (inst lea ebp-tn (make-ea :dword :base esp-tn
277 :disp (frame-byte-offset
278 (+ sp->fp-offset
280 ocfp-save-offset))))
281 (inst mov ecx (fixnumize 2))
282 (inst call (make-ea :dword
283 :disp (+ nil-value (static-fun-offset 'two-arg-=))))
284 (load-symbol y t)
285 (inst cmp x y)
286 (inst pop ebp-tn))
289 ;;; Support for the Mersenne Twister, MT19937, random number generator
290 ;;; due to Matsumoto and Nishimura.
292 ;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
293 ;;; 623-dimensionally equidistributed uniform pseudorandom number
294 ;;; generator.", ACM Transactions on Modeling and Computer Simulation,
295 ;;; 1997, to appear.
297 ;;; State:
298 ;;; 0-1: Constant matrix A. [0, #x9908b0df] (not used here)
299 ;;; 2: Index; init. to 1.
300 ;;; 3-626: State.
302 ;;; This assembly routine is called from the inline VOP and updates
303 ;;; the state vector with new random numbers. The state vector is
304 ;;; passed in the EAX register.
305 #+sb-assembling ; We don't want a vop for this one.
306 (define-assembly-routine
307 (random-mt19937-update)
308 ((:temp state unsigned-reg eax-offset)
309 (:temp k unsigned-reg ebx-offset)
310 (:temp y unsigned-reg ecx-offset)
311 (:temp tmp unsigned-reg edx-offset))
313 ;; Save the temporary registers.
314 (inst push k)
315 (inst push y)
316 (inst push tmp)
318 ;; Generate a new set of results.
319 (inst xor k k)
320 LOOP1
321 (inst mov y (make-ea-for-vector-data state :index k :offset 3))
322 (inst mov tmp (make-ea-for-vector-data state :index k :offset (+ 1 3)))
323 (inst and y #x80000000)
324 (inst and tmp #x7fffffff)
325 (inst or y tmp)
326 (inst shr y 1)
327 (inst jmp :nc skip1)
328 (inst xor y #x9908b0df)
329 SKIP1
330 (inst xor y (make-ea-for-vector-data state :index k :offset (+ 397 3)))
331 (inst mov (make-ea-for-vector-data state :index k :offset 3) y)
332 (inst inc k)
333 (inst cmp k (- 624 397))
334 (inst jmp :b loop1)
335 LOOP2
336 (inst mov y (make-ea-for-vector-data state :index k :offset 3))
337 (inst mov tmp (make-ea-for-vector-data state :index k :offset (+ 1 3)))
338 (inst and y #x80000000)
339 (inst and tmp #x7fffffff)
340 (inst or y tmp)
341 (inst shr y 1)
342 (inst jmp :nc skip2)
343 (inst xor y #x9908b0df)
344 SKIP2
345 (inst xor y (make-ea-for-vector-data state :index k :offset (+ (- 397 624) 3)))
346 (inst mov (make-ea-for-vector-data state :index k :offset 3) y)
347 (inst inc k)
348 (inst cmp k (- 624 1))
349 (inst jmp :b loop2)
351 (inst mov y (make-ea-for-vector-data state :offset (+ (- 624 1) 3)))
352 (inst mov tmp (make-ea-for-vector-data state :offset (+ 0 3)))
353 (inst and y #x80000000)
354 (inst and tmp #x7fffffff)
355 (inst or y tmp)
356 (inst shr y 1)
357 (inst jmp :nc skip3)
358 (inst xor y #x9908b0df)
359 SKIP3
360 (inst xor y (make-ea-for-vector-data state :offset (+ (- 397 1) 3)))
361 (inst mov (make-ea-for-vector-data state :offset (+ (- 624 1) 3)) y)
363 ;; Restore the temporary registers and return.
364 (inst pop tmp)
365 (inst pop y)
366 (inst pop k))