1 ;;;; Stuff to handle 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 and subtraction.
16 (define-assembly-routine (generic-+
18 (:return-style :full-call)
22 ((:arg x (descriptor-reg any-reg) a0-offset)
23 (:arg y (descriptor-reg any-reg) a1-offset)
25 (:res res (descriptor-reg any-reg) a0-offset)
27 (:temp temp non-descriptor-reg nl0-offset)
28 (:temp temp2 non-descriptor-reg nl1-offset)
29 (:temp lra descriptor-reg lra-offset)
30 (:temp nargs any-reg nargs-offset)
31 (:temp ocfp any-reg ocfp-offset))
32 (inst andcc zero-tn x fixnum-tag-mask)
33 (inst b :ne DO-STATIC-FUN)
34 (inst andcc zero-tn y fixnum-tag-mask)
35 (inst b :ne DO-STATIC-FUN)
41 (inst sra temp x n-fixnum-tag-bits)
42 (inst sra temp2 y n-fixnum-tag-bits)
44 (with-fixed-allocation (res temp bignum-widetag (1+ bignum-digits-offset))
45 (storew temp2 res bignum-digits-offset other-pointer-lowtag))
46 (lisp-return lra :offset 2)
49 (inst ld code-tn null-tn (static-fun-offset 'two-arg-+))
50 (inst li nargs (fixnumize 2))
51 (inst move ocfp cfp-tn)
53 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
54 (inst move cfp-tn csp-tn)
60 (define-assembly-routine (generic--
62 (:return-style :full-call)
66 ((:arg x (descriptor-reg any-reg) a0-offset)
67 (:arg y (descriptor-reg any-reg) a1-offset)
69 (:res res (descriptor-reg any-reg) a0-offset)
71 (:temp temp non-descriptor-reg nl0-offset)
72 (:temp temp2 non-descriptor-reg nl1-offset)
73 (:temp lra descriptor-reg lra-offset)
74 (:temp nargs any-reg nargs-offset)
75 (:temp ocfp any-reg ocfp-offset))
76 (inst andcc zero-tn x fixnum-tag-mask)
77 (inst b :ne DO-STATIC-FUN)
78 (inst andcc zero-tn y fixnum-tag-mask)
79 (inst b :ne DO-STATIC-FUN)
85 (inst sra temp x n-fixnum-tag-bits)
86 (inst sra temp2 y n-fixnum-tag-bits)
87 (inst sub temp2 temp temp2)
88 (with-fixed-allocation (res temp bignum-widetag (1+ bignum-digits-offset))
89 (storew temp2 res bignum-digits-offset other-pointer-lowtag))
90 (lisp-return lra :offset 2)
93 (inst ld code-tn null-tn (static-fun-offset 'two-arg--))
94 (inst li nargs (fixnumize 2))
95 (inst move ocfp cfp-tn)
97 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
98 (inst move cfp-tn csp-tn)
108 (define-assembly-routine (generic-*
110 (:return-style :full-call)
114 ((:arg x (descriptor-reg any-reg) a0-offset)
115 (:arg y (descriptor-reg any-reg) a1-offset)
117 (:res res (descriptor-reg any-reg) a0-offset)
119 (:temp temp non-descriptor-reg nl0-offset)
120 (:temp lo non-descriptor-reg nl1-offset)
121 (:temp hi non-descriptor-reg nl2-offset)
122 (:temp lra descriptor-reg lra-offset)
123 (:temp nargs any-reg nargs-offset)
124 (:temp ocfp any-reg ocfp-offset))
125 ;; If either arg is not a fixnum, call the static function.
126 (inst andcc zero-tn x fixnum-tag-mask)
127 (inst b :ne DO-STATIC-FUN)
128 (inst andcc zero-tn y fixnum-tag-mask)
129 (inst b :ne DO-STATIC-FUN)
132 ;; Remove the tag from one arg so that the result will have the correct
134 (inst sra temp x n-fixnum-tag-bits)
135 ;; Compute the produce temp * y and return the double-word product
138 ((member :sparc-64 *backend-subfeatures*)
139 ;; Sign extend y to a full 64-bits. temp was already
140 ;; sign-extended by the sra instruction above.
142 (inst mulx hi temp y)
145 ((or (member :sparc-v8 *backend-subfeatures*)
146 (member :sparc-v9 *backend-subfeatures*))
147 (inst smul lo temp y)
150 (let ((MULTIPLIER-POSITIVE (gen-label)))
152 (inst andcc hi zero-tn)
157 (inst mulscc hi zero-tn)
159 (inst b :ge MULTIPLIER-POSITIVE)
162 (emit-label MULTIPLIER-POSITIVE)
164 ;; Check to see if the result will fit in a fixnum. (I.e. the high word
165 ;; is just 32 copies of the sign bit of the low word).
166 (inst sra temp lo 31)
168 (inst b :eq LOW-FITS-IN-FIXNUM)
169 ;; Shift the double word hi:lo down two bits to get rid of the fixnum tag.
170 (inst sll temp hi 30)
171 (inst srl lo n-fixnum-tag-bits)
173 (inst sra hi n-fixnum-tag-bits)
174 ;; Always allocate 2 words for the bignum result, even if we only
175 ;; need one. The copying GC will take care of the extra word if it
177 (with-fixed-allocation
178 (res temp bignum-widetag (+ 2 bignum-digits-offset))
179 (let ((one-word (gen-label)))
180 ;; We start out assuming that we need one word. Is that correct?
181 (inst sra temp lo 31)
183 (inst b :eq one-word)
184 (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag))
185 ;; Need 2 words. Set the header appropriately, and save the
186 ;; high and low parts.
187 (inst li temp (logior (ash 2 n-widetag-bits) bignum-widetag))
188 (storew hi res (1+ bignum-digits-offset) other-pointer-lowtag)
189 (emit-label one-word)
190 (storew temp res 0 other-pointer-lowtag)
191 (storew lo res bignum-digits-offset other-pointer-lowtag)))
193 (lisp-return lra :offset 2)
196 (inst ld code-tn null-tn (static-fun-offset 'two-arg-*))
197 (inst li nargs (fixnumize 2))
198 (inst move ocfp cfp-tn)
200 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
201 (inst move cfp-tn csp-tn)
207 ((frob (name note cost type sc)
208 `(define-assembly-routine (,name
213 (:arg-types ,type ,type)
214 (:result-types ,type))
215 ((:arg x ,sc nl0-offset)
216 (:arg y ,sc nl1-offset)
217 (:res res ,sc nl0-offset)
218 (:temp temp ,sc nl2-offset))
219 ,@(when (eq type 'tagged-num)
222 ((member :sparc-64 *backend-subfeatures*)
223 ;; Sign extend, then multiply
227 ((or (member :sparc-v8 *backend-subfeatures*)
228 (member :sparc-v9 *backend-subfeatures*))
232 (inst andcc temp zero-tn)
236 (inst mulscc temp y))
237 (inst mulscc temp zero-tn)
239 (frob unsigned-* "unsigned *" 40 unsigned-num unsigned-reg)
240 (frob signed-* "signed *" 41 signed-num signed-reg)
241 (frob fixnum-* "fixnum *" 30 tagged-num any-reg))
248 (defun emit-divide-loop (divisor rem quo tagged)
256 (let ((label-1 (gen-label))
257 (label-2 (gen-label)))
258 (inst cmp divisor rem)
259 (inst b :geu label-1)
264 (inst cmp divisor rem)
266 (inst b :gtu label-2)
268 (inst add quo (if tagged (fixnumize 1) 1))
269 (inst sub rem divisor)
270 (emit-label label-2))))))
271 (do-loop (if tagged 30 32))))
273 (define-assembly-routine (positive-fixnum-truncate
274 (:note "unsigned fixnum truncate")
276 (:translate truncate)
278 (:arg-types positive-fixnum positive-fixnum)
279 (:result-types positive-fixnum positive-fixnum))
280 ((:arg dividend any-reg nl0-offset)
281 (:arg divisor any-reg nl1-offset)
283 (:res quo any-reg nl2-offset)
284 (:res rem any-reg nl0-offset))
286 (let ((error (generate-error-code nil division-by-zero-error
292 (emit-divide-loop divisor rem quo t))
295 (define-assembly-routine (fixnum-truncate
296 (:note "fixnum truncate")
299 (:translate truncate)
300 (:arg-types tagged-num tagged-num)
301 (:result-types tagged-num tagged-num))
302 ((:arg dividend any-reg nl0-offset)
303 (:arg divisor any-reg nl1-offset)
305 (:res quo any-reg nl2-offset)
306 (:res rem any-reg nl0-offset)
308 (:temp quo-sign any-reg nl5-offset)
309 (:temp rem-sign any-reg nargs-offset))
311 (let ((error (generate-error-code nil division-by-zero-error
316 (inst xor quo-sign dividend divisor)
317 (inst move rem-sign dividend)
318 (let ((label (gen-label)))
323 (let ((label (gen-label)))
329 (emit-divide-loop divisor rem quo t)
330 (let ((label (gen-label)))
331 ;; If the quo-sign is negative, we need to negate quo.
336 (let ((label (gen-label)))
337 ;; If the rem-sign is negative, we need to negate rem.
344 (define-assembly-routine (signed-truncate
345 (:note "(signed-byte 32) truncate")
348 (:translate truncate)
349 (:arg-types signed-num signed-num)
350 (:result-types signed-num signed-num))
352 ((:arg dividend signed-reg nl0-offset)
353 (:arg divisor signed-reg nl1-offset)
355 (:res quo signed-reg nl2-offset)
356 (:res rem signed-reg nl0-offset)
358 (:temp quo-sign signed-reg nl5-offset)
359 (:temp rem-sign signed-reg nargs-offset))
361 (let ((error (generate-error-code nil division-by-zero-error
366 (inst xor quo-sign dividend divisor)
367 (inst move rem-sign dividend)
368 (let ((label (gen-label)))
373 (let ((label (gen-label)))
379 (emit-divide-loop divisor rem quo nil)
380 (let ((label (gen-label)))
381 ;; If the quo-sign is negative, we need to negate quo.
386 (let ((label (gen-label)))
387 ;; If the rem-sign is negative, we need to negate rem.
397 ((define-cond-assem-rtn (name translate static-fn cmp)
398 `(define-assembly-routine (,name
400 (:return-style :full-call)
402 (:translate ,translate)
404 ((:arg x (descriptor-reg any-reg) a0-offset)
405 (:arg y (descriptor-reg any-reg) a1-offset)
407 (:res res descriptor-reg a0-offset)
409 (:temp nargs any-reg nargs-offset)
410 (:temp ocfp any-reg ocfp-offset))
411 (inst andcc zero-tn x fixnum-tag-mask)
412 (inst b :ne DO-STATIC-FN)
413 (inst andcc zero-tn y fixnum-tag-mask)
414 (inst b :eq DO-COMPARE)
418 (inst ld code-tn null-tn (static-fun-offset ',static-fn))
419 (inst li nargs (fixnumize 2))
420 (inst move ocfp cfp-tn)
422 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
423 (inst move cfp-tn csp-tn)
428 (inst move res null-tn)
431 (define-cond-assem-rtn generic-< < two-arg-< :lt)
432 (define-cond-assem-rtn generic-<= <= two-arg-<= :le)
433 (define-cond-assem-rtn generic-> > two-arg-> :gt)
434 (define-cond-assem-rtn generic->= >= two-arg->= :ge))
437 (define-assembly-routine (generic-eql
439 (:return-style :full-call)
443 ((:arg x (descriptor-reg any-reg) a0-offset)
444 (:arg y (descriptor-reg any-reg) a1-offset)
446 (:res res descriptor-reg a0-offset)
448 (:temp lra descriptor-reg lra-offset)
449 (:temp nargs any-reg nargs-offset)
450 (:temp ocfp any-reg ocfp-offset))
452 (inst b :eq RETURN-T)
453 (inst andcc zero-tn x fixnum-tag-mask)
454 (inst b :eq RETURN-NIL)
455 (inst andcc zero-tn y fixnum-tag-mask)
456 (inst b :ne DO-STATIC-FN)
460 (inst move res null-tn)
461 (lisp-return lra :offset 2)
464 (inst ld code-tn null-tn (static-fun-offset 'eql))
465 (inst li nargs (fixnumize 2))
466 (inst move ocfp cfp-tn)
468 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
469 (inst move cfp-tn csp-tn)
474 (define-assembly-routine (generic-=
476 (:return-style :full-call)
480 ((:arg x (descriptor-reg any-reg) a0-offset)
481 (:arg y (descriptor-reg any-reg) a1-offset)
483 (:res res descriptor-reg a0-offset)
485 (:temp lra descriptor-reg lra-offset)
486 (:temp nargs any-reg nargs-offset)
487 (:temp ocfp any-reg ocfp-offset))
488 (inst andcc zero-tn x fixnum-tag-mask)
489 (inst b :ne DO-STATIC-FN)
490 (inst andcc zero-tn y fixnum-tag-mask)
491 (inst b :ne DO-STATIC-FN)
493 (inst b :eq RETURN-T)
496 (inst move res null-tn)
497 (lisp-return lra :offset 2)
500 (inst ld code-tn null-tn (static-fun-offset 'two-arg-=))
501 (inst li nargs (fixnumize 2))
502 (inst move ocfp cfp-tn)
504 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
505 (inst move cfp-tn csp-tn)
510 (define-assembly-routine (generic-/=
512 (:return-style :full-call)
516 ((:arg x (descriptor-reg any-reg) a0-offset)
517 (:arg y (descriptor-reg any-reg) a1-offset)
519 (:res res descriptor-reg a0-offset)
521 (:temp lra descriptor-reg lra-offset)
522 (:temp nargs any-reg nargs-offset)
523 (:temp ocfp any-reg ocfp-offset))
525 (inst b :eq RETURN-NIL)
526 (inst andcc zero-tn x fixnum-tag-mask)
527 (inst b :ne DO-STATIC-FN)
528 (inst andcc zero-tn y fixnum-tag-mask)
529 (inst b :ne DO-STATIC-FN)
533 (lisp-return lra :offset 2)
536 (inst ld code-tn null-tn (static-fun-offset 'two-arg-/=))
537 (inst li nargs (fixnumize 2))
538 (inst move ocfp cfp-tn)
540 (- (* simple-fun-code-offset n-word-bytes) fun-pointer-lowtag))
541 (inst move cfp-tn csp-tn)
544 (inst move res null-tn))