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