1 ;;;; the VM definition of arithmetic VOPs for the x86
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.
16 (define-vop (fast-safe-arith-op)
21 (define-vop (fixnum-unop fast-safe-arith-op)
22 (:args (x :scs (any-reg) :target res))
23 (:results (res :scs (any-reg)))
24 (:note "inline fixnum arithmetic")
25 (:arg-types tagged-num)
26 (:result-types tagged-num))
28 (define-vop (signed-unop fast-safe-arith-op)
29 (:args (x :scs (signed-reg) :target res))
30 (:results (res :scs (signed-reg)))
31 (:note "inline (signed-byte 64) arithmetic")
32 (:arg-types signed-num)
33 (:result-types signed-num))
35 (define-vop (fast-negate/fixnum fixnum-unop)
41 (define-vop (fast-negate/signed signed-unop)
47 (define-vop (fast-lognot/fixnum fixnum-unop)
51 (inst xor res (fixnumize -1))))
53 (define-vop (fast-lognot/signed signed-unop)
59 ;;;; binary fixnum operations
61 ;;; Assume that any constant operand is the second arg...
63 (define-vop (fast-fixnum-binop fast-safe-arith-op)
64 (:args (x :target r :scs (any-reg)
65 :load-if (not (and (sc-is x control-stack)
67 (sc-is r control-stack)
69 (y :scs (any-reg control-stack)))
70 (:arg-types tagged-num tagged-num)
71 (:results (r :scs (any-reg) :from (:argument 0)
72 :load-if (not (and (sc-is x control-stack)
74 (sc-is r control-stack)
76 (:result-types tagged-num)
77 (:note "inline fixnum arithmetic"))
79 (define-vop (fast-unsigned-binop fast-safe-arith-op)
80 (:args (x :target r :scs (unsigned-reg)
81 :load-if (not (and (sc-is x unsigned-stack)
82 (sc-is y unsigned-reg)
83 (sc-is r unsigned-stack)
85 (y :scs (unsigned-reg unsigned-stack)))
86 (:arg-types unsigned-num unsigned-num)
87 (:results (r :scs (unsigned-reg) :from (:argument 0)
88 :load-if (not (and (sc-is x unsigned-stack)
89 (sc-is y unsigned-reg)
90 (sc-is r unsigned-stack)
92 (:result-types unsigned-num)
93 (:note "inline (unsigned-byte 64) arithmetic"))
95 (define-vop (fast-signed-binop fast-safe-arith-op)
96 (:args (x :target r :scs (signed-reg)
97 :load-if (not (and (sc-is x signed-stack)
99 (sc-is r signed-stack)
101 (y :scs (signed-reg signed-stack)))
102 (:arg-types signed-num signed-num)
103 (:results (r :scs (signed-reg) :from (:argument 0)
104 :load-if (not (and (sc-is x signed-stack)
106 (sc-is r signed-stack)
108 (:result-types signed-num)
109 (:note "inline (signed-byte 64) arithmetic"))
111 (define-vop (fast-fixnum-binop-c fast-safe-arith-op)
112 (:args (x :target r :scs (any-reg control-stack)))
114 (:arg-types tagged-num (:constant (signed-byte 29)))
115 (:results (r :scs (any-reg)
116 :load-if (not (location= x r))))
117 (:result-types tagged-num)
118 (:note "inline fixnum arithmetic"))
120 ;; 31 not 64 because it's hard work loading 64 bit constants, and since
121 ;; sign-extension of immediates causes problems with 32.
122 (define-vop (fast-unsigned-binop-c fast-safe-arith-op)
123 (:args (x :target r :scs (unsigned-reg unsigned-stack)))
125 (:arg-types unsigned-num (:constant (unsigned-byte 31)))
126 (:results (r :scs (unsigned-reg)
127 :load-if (not (location= x r))))
128 (:result-types unsigned-num)
129 (:note "inline (unsigned-byte 64) arithmetic"))
131 (define-vop (fast-signed-binop-c fast-safe-arith-op)
132 (:args (x :target r :scs (signed-reg signed-stack)))
134 (:arg-types signed-num (:constant (signed-byte 32)))
135 (:results (r :scs (signed-reg)
136 :load-if (not (location= x r))))
137 (:result-types signed-num)
138 (:note "inline (signed-byte 64) arithmetic"))
140 (macrolet ((define-binop (translate untagged-penalty op)
142 (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM")
144 (:translate ,translate)
148 (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum)
150 (:translate ,translate)
153 (inst ,op r (fixnumize y))))
154 (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED")
156 (:translate ,translate)
157 (:generator ,(1+ untagged-penalty)
160 (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed)
162 (:translate ,translate)
163 (:generator ,untagged-penalty
166 (define-vop (,(symbolicate "FAST-"
168 "/UNSIGNED=>UNSIGNED")
170 (:translate ,translate)
171 (:generator ,(1+ untagged-penalty)
174 (define-vop (,(symbolicate 'fast-
176 '-c/unsigned=>unsigned)
177 fast-unsigned-binop-c)
178 (:translate ,translate)
179 (:generator ,untagged-penalty
183 ;;(define-binop + 4 add)
184 (define-binop - 4 sub)
185 (define-binop logand 2 and)
186 (define-binop logior 2 or)
187 (define-binop logxor 2 xor))
189 ;;; Special handling of add on the x86; can use lea to avoid a
190 ;;; register load, otherwise it uses add.
191 (define-vop (fast-+/fixnum=>fixnum fast-safe-arith-op)
193 (:args (x :scs (any-reg) :target r
194 :load-if (not (and (sc-is x control-stack)
196 (sc-is r control-stack)
198 (y :scs (any-reg control-stack)))
199 (:arg-types tagged-num tagged-num)
200 (:results (r :scs (any-reg) :from (:argument 0)
201 :load-if (not (and (sc-is x control-stack)
203 (sc-is r control-stack)
205 (:result-types tagged-num)
206 (:note "inline fixnum arithmetic")
208 (cond ((and (sc-is x any-reg) (sc-is y any-reg) (sc-is r any-reg)
209 (not (location= x r)))
210 (inst lea r (make-ea :qword :base x :index y :scale 1)))
215 (define-vop (fast-+-c/fixnum=>fixnum fast-safe-arith-op)
217 (:args (x :target r :scs (any-reg control-stack)))
219 (:arg-types tagged-num (:constant (signed-byte 29)))
220 (:results (r :scs (any-reg)
221 :load-if (not (location= x r))))
222 (:result-types tagged-num)
223 (:note "inline fixnum arithmetic")
225 (cond ((and (sc-is x any-reg) (sc-is r any-reg) (not (location= x r)))
226 (inst lea r (make-ea :qword :base x :disp (fixnumize y))))
229 (inst add r (fixnumize y))))))
231 (define-vop (fast-+/signed=>signed fast-safe-arith-op)
233 (:args (x :scs (signed-reg) :target r
234 :load-if (not (and (sc-is x signed-stack)
236 (sc-is r signed-stack)
238 (y :scs (signed-reg signed-stack)))
239 (:arg-types signed-num signed-num)
240 (:results (r :scs (signed-reg) :from (:argument 0)
241 :load-if (not (and (sc-is x signed-stack)
244 (:result-types signed-num)
245 (:note "inline (signed-byte 64) arithmetic")
247 (cond ((and (sc-is x signed-reg) (sc-is y signed-reg) (sc-is r signed-reg)
248 (not (location= x r)))
249 (inst lea r (make-ea :qword :base x :index y :scale 1)))
255 ;;;; Special logand cases: (logand signed unsigned) => unsigned
257 (define-vop (fast-logand/signed-unsigned=>unsigned
258 fast-logand/unsigned=>unsigned)
259 (:args (x :target r :scs (signed-reg)
260 :load-if (not (and (sc-is x signed-stack)
261 (sc-is y unsigned-reg)
262 (sc-is r unsigned-stack)
264 (y :scs (unsigned-reg unsigned-stack)))
265 (:arg-types signed-num unsigned-num))
267 (define-vop (fast-logand-c/signed-unsigned=>unsigned
268 fast-logand-c/unsigned=>unsigned)
269 (:args (x :target r :scs (signed-reg signed-stack)))
270 (:arg-types signed-num (:constant (unsigned-byte 31))))
272 (define-vop (fast-logand/unsigned-signed=>unsigned
273 fast-logand/unsigned=>unsigned)
274 (:args (x :target r :scs (unsigned-reg)
275 :load-if (not (and (sc-is x unsigned-stack)
277 (sc-is r unsigned-stack)
279 (y :scs (signed-reg signed-stack)))
280 (:arg-types unsigned-num signed-num))
283 (define-vop (fast-+-c/signed=>signed fast-safe-arith-op)
285 (:args (x :target r :scs (signed-reg signed-stack)))
287 (:arg-types signed-num (:constant (signed-byte 32)))
288 (:results (r :scs (signed-reg)
289 :load-if (not (location= x r))))
290 (:result-types signed-num)
291 (:note "inline (signed-byte 64) arithmetic")
293 (cond ((and (sc-is x signed-reg) (sc-is r signed-reg)
294 (not (location= x r)))
295 (inst lea r (make-ea :qword :base x :disp y)))
302 (define-vop (fast-+/unsigned=>unsigned fast-safe-arith-op)
304 (:args (x :scs (unsigned-reg) :target r
305 :load-if (not (and (sc-is x unsigned-stack)
306 (sc-is y unsigned-reg)
307 (sc-is r unsigned-stack)
309 (y :scs (unsigned-reg unsigned-stack)))
310 (:arg-types unsigned-num unsigned-num)
311 (:results (r :scs (unsigned-reg) :from (:argument 0)
312 :load-if (not (and (sc-is x unsigned-stack)
313 (sc-is y unsigned-reg)
314 (sc-is r unsigned-stack)
316 (:result-types unsigned-num)
317 (:note "inline (unsigned-byte 64) arithmetic")
319 (cond ((and (sc-is x unsigned-reg) (sc-is y unsigned-reg)
320 (sc-is r unsigned-reg) (not (location= x r)))
321 (inst lea r (make-ea :qword :base x :index y :scale 1)))
326 (define-vop (fast-+-c/unsigned=>unsigned fast-safe-arith-op)
328 (:args (x :target r :scs (unsigned-reg unsigned-stack)))
330 (:arg-types unsigned-num (:constant (unsigned-byte 31)))
331 (:results (r :scs (unsigned-reg)
332 :load-if (not (location= x r))))
333 (:result-types unsigned-num)
334 (:note "inline (unsigned-byte 64) arithmetic")
336 (cond ((and (sc-is x unsigned-reg) (sc-is r unsigned-reg)
337 (not (location= x r)))
338 (inst lea r (make-ea :qword :base x :disp y)))
345 ;;;; multiplication and division
347 (define-vop (fast-*/fixnum=>fixnum fast-safe-arith-op)
349 ;; We need different loading characteristics.
350 (:args (x :scs (any-reg) :target r)
351 (y :scs (any-reg control-stack)))
352 (:arg-types tagged-num tagged-num)
353 (:results (r :scs (any-reg) :from (:argument 0)))
354 (:result-types tagged-num)
355 (:note "inline fixnum arithmetic")
361 (define-vop (fast-*-c/fixnum=>fixnum fast-safe-arith-op)
363 ;; We need different loading characteristics.
364 (:args (x :scs (any-reg control-stack)))
366 (:arg-types tagged-num (:constant (signed-byte 29)))
367 (:results (r :scs (any-reg)))
368 (:result-types tagged-num)
369 (:note "inline fixnum arithmetic")
373 (define-vop (fast-*/signed=>signed fast-safe-arith-op)
375 ;; We need different loading characteristics.
376 (:args (x :scs (signed-reg) :target r)
377 (y :scs (signed-reg signed-stack)))
378 (:arg-types signed-num signed-num)
379 (:results (r :scs (signed-reg) :from (:argument 0)))
380 (:result-types signed-num)
381 (:note "inline (signed-byte 64) arithmetic")
386 (define-vop (fast-*-c/signed=>signed fast-safe-arith-op)
388 ;; We need different loading characteristics.
389 (:args (x :scs (signed-reg signed-stack)))
391 (:arg-types signed-num (:constant (signed-byte 32)))
392 (:results (r :scs (signed-reg)))
393 (:result-types signed-num)
394 (:note "inline (signed-byte 64) arithmetic")
398 (define-vop (fast-*/unsigned=>unsigned fast-safe-arith-op)
400 (:args (x :scs (unsigned-reg) :target eax)
401 (y :scs (unsigned-reg unsigned-stack)))
402 (:arg-types unsigned-num unsigned-num)
403 (:temporary (:sc unsigned-reg :offset eax-offset :target result
404 :from (:argument 0) :to :result) eax)
405 (:temporary (:sc unsigned-reg :offset edx-offset
406 :from :eval :to :result) edx)
408 (:results (result :scs (unsigned-reg)))
409 (:result-types unsigned-num)
410 (:note "inline (unsigned-byte 64) arithmetic")
412 (:save-p :compute-only)
419 (define-vop (fast-truncate/fixnum=>fixnum fast-safe-arith-op)
420 (:translate truncate)
421 (:args (x :scs (any-reg) :target eax)
422 (y :scs (any-reg control-stack)))
423 (:arg-types tagged-num tagged-num)
424 (:temporary (:sc signed-reg :offset eax-offset :target quo
425 :from (:argument 0) :to (:result 0)) eax)
426 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
427 :from (:argument 0) :to (:result 1)) edx)
428 (:results (quo :scs (any-reg))
429 (rem :scs (any-reg)))
430 (:result-types tagged-num tagged-num)
431 (:note "inline fixnum arithmetic")
433 (:save-p :compute-only)
435 (let ((zero (generate-error-code vop division-by-zero-error x y)))
436 (if (sc-is y any-reg)
437 (inst test y y) ; smaller instruction
443 (if (location= quo eax)
445 (inst lea quo (make-ea :qword :index eax :scale 8)))
448 (define-vop (fast-truncate-c/fixnum=>fixnum fast-safe-arith-op)
449 (:translate truncate)
450 (:args (x :scs (any-reg) :target eax))
452 (:arg-types tagged-num (:constant (signed-byte 29)))
453 (:temporary (:sc signed-reg :offset eax-offset :target quo
454 :from :argument :to (:result 0)) eax)
455 (:temporary (:sc any-reg :offset edx-offset :target rem
456 :from :eval :to (:result 1)) edx)
457 (:temporary (:sc any-reg :from :eval :to :result) y-arg)
458 (:results (quo :scs (any-reg))
459 (rem :scs (any-reg)))
460 (:result-types tagged-num tagged-num)
461 (:note "inline fixnum arithmetic")
463 (:save-p :compute-only)
467 (inst mov y-arg (fixnumize y))
468 (inst idiv eax y-arg)
469 (if (location= quo eax)
471 (inst lea quo (make-ea :qword :index eax :scale 8)))
474 (define-vop (fast-truncate/unsigned=>unsigned fast-safe-arith-op)
475 (:translate truncate)
476 (:args (x :scs (unsigned-reg) :target eax)
477 (y :scs (unsigned-reg signed-stack)))
478 (:arg-types unsigned-num unsigned-num)
479 (:temporary (:sc unsigned-reg :offset eax-offset :target quo
480 :from (:argument 0) :to (:result 0)) eax)
481 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
482 :from (:argument 0) :to (:result 1)) edx)
483 (:results (quo :scs (unsigned-reg))
484 (rem :scs (unsigned-reg)))
485 (:result-types unsigned-num unsigned-num)
486 (:note "inline (unsigned-byte 64) arithmetic")
488 (:save-p :compute-only)
490 (let ((zero (generate-error-code vop division-by-zero-error x y)))
491 (if (sc-is y unsigned-reg)
492 (inst test y y) ; smaller instruction
501 (define-vop (fast-truncate-c/unsigned=>unsigned fast-safe-arith-op)
502 (:translate truncate)
503 (:args (x :scs (unsigned-reg) :target eax))
505 (:arg-types unsigned-num (:constant (unsigned-byte 31)))
506 (:temporary (:sc unsigned-reg :offset eax-offset :target quo
507 :from :argument :to (:result 0)) eax)
508 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
509 :from :eval :to (:result 1)) edx)
510 (:temporary (:sc unsigned-reg :from :eval :to :result) y-arg)
511 (:results (quo :scs (unsigned-reg))
512 (rem :scs (unsigned-reg)))
513 (:result-types unsigned-num unsigned-num)
514 (:note "inline (unsigned-byte 64) arithmetic")
516 (:save-p :compute-only)
525 (define-vop (fast-truncate/signed=>signed fast-safe-arith-op)
526 (:translate truncate)
527 (:args (x :scs (signed-reg) :target eax)
528 (y :scs (signed-reg signed-stack)))
529 (:arg-types signed-num signed-num)
530 (:temporary (:sc signed-reg :offset eax-offset :target quo
531 :from (:argument 0) :to (:result 0)) eax)
532 (:temporary (:sc signed-reg :offset edx-offset :target rem
533 :from (:argument 0) :to (:result 1)) edx)
534 (:results (quo :scs (signed-reg))
535 (rem :scs (signed-reg)))
536 (:result-types signed-num signed-num)
537 (:note "inline (signed-byte 64) arithmetic")
539 (:save-p :compute-only)
541 (let ((zero (generate-error-code vop division-by-zero-error x y)))
542 (if (sc-is y signed-reg)
543 (inst test y y) ; smaller instruction
552 (define-vop (fast-truncate-c/signed=>signed fast-safe-arith-op)
553 (:translate truncate)
554 (:args (x :scs (signed-reg) :target eax))
556 (:arg-types signed-num (:constant (signed-byte 32)))
557 (:temporary (:sc signed-reg :offset eax-offset :target quo
558 :from :argument :to (:result 0)) eax)
559 (:temporary (:sc signed-reg :offset edx-offset :target rem
560 :from :eval :to (:result 1)) edx)
561 (:temporary (:sc signed-reg :from :eval :to :result) y-arg)
562 (:results (quo :scs (signed-reg))
563 (rem :scs (signed-reg)))
564 (:result-types signed-num signed-num)
565 (:note "inline (signed-byte 64) arithmetic")
567 (:save-p :compute-only)
572 (inst idiv eax y-arg)
579 (define-vop (fast-ash-c/fixnum=>fixnum)
582 (:args (number :scs (any-reg) :target result
583 :load-if (not (and (sc-is number any-reg control-stack)
584 (sc-is result any-reg control-stack)
585 (location= number result)))))
587 (:arg-types tagged-num (:constant integer))
588 (:results (result :scs (any-reg)
589 :load-if (not (and (sc-is number control-stack)
590 (sc-is result control-stack)
591 (location= number result)))))
592 (:result-types tagged-num)
595 (cond ((and (= amount 1) (not (location= number result)))
596 (inst lea result (make-ea :qword :base number :index number)))
597 ((and (= amount 2) (not (location= number result)))
598 (inst lea result (make-ea :qword :index number :scale 4)))
599 ((and (= amount 3) (not (location= number result)))
600 (inst lea result (make-ea :qword :index number :scale 8)))
603 (cond ((plusp amount)
604 ;; We don't have to worry about overflow because of the
605 ;; result type restriction.
606 (inst shl result amount))
608 ;; Since the shift instructions take the shift amount
609 ;; modulo 64 we must special case amounts of 64 and more.
610 ;; Because fixnums have only 61 bits, the result is 0 or
611 ;; -1 for all amounts of 60 or more, so use this as the
613 (inst sar result (min (- n-word-bits n-fixnum-tag-bits 1)
615 (inst and result (lognot fixnum-tag-mask))))))))
617 (define-vop (fast-ash-left/fixnum=>fixnum)
619 (:args (number :scs (any-reg) :target result
620 :load-if (not (and (sc-is number control-stack)
621 (sc-is result control-stack)
622 (location= number result))))
623 (amount :scs (unsigned-reg) :target ecx))
624 (:arg-types tagged-num positive-fixnum)
625 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
626 (:results (result :scs (any-reg) :from (:argument 0)
627 :load-if (not (and (sc-is number control-stack)
628 (sc-is result control-stack)
629 (location= number result)))))
630 (:result-types tagged-num)
636 ;; The result-type ensures us that this shift will not overflow.
637 (inst shl result :cl)))
639 (define-vop (fast-ash-c/signed=>signed)
642 (:args (number :scs (signed-reg) :target result
643 :load-if (not (and (sc-is number signed-stack)
644 (sc-is result signed-stack)
645 (location= number result)))))
647 (:arg-types signed-num (:constant integer))
648 (:results (result :scs (signed-reg)
649 :load-if (not (and (sc-is number signed-stack)
650 (sc-is result signed-stack)
651 (location= number result)))))
652 (:result-types signed-num)
655 (cond ((and (= amount 1) (not (location= number result)))
656 (inst lea result (make-ea :qword :base number :index number)))
657 ((and (= amount 2) (not (location= number result)))
658 (inst lea result (make-ea :qword :index number :scale 4)))
659 ((and (= amount 3) (not (location= number result)))
660 (inst lea result (make-ea :qword :index number :scale 8)))
663 (cond ((plusp amount) (inst shl result amount))
664 (t (inst sar result (min 63 (- amount)))))))))
666 (define-vop (fast-ash-c/unsigned=>unsigned)
669 (:args (number :scs (unsigned-reg) :target result
670 :load-if (not (and (sc-is number unsigned-stack)
671 (sc-is result unsigned-stack)
672 (location= number result)))))
674 (:arg-types unsigned-num (:constant integer))
675 (:results (result :scs (unsigned-reg)
676 :load-if (not (and (sc-is number unsigned-stack)
677 (sc-is result unsigned-stack)
678 (location= number result)))))
679 (:result-types unsigned-num)
682 (cond ((and (= amount 1) (not (location= number result)))
683 (inst lea result (make-ea :qword :base number :index number)))
684 ((and (= amount 2) (not (location= number result)))
685 (inst lea result (make-ea :qword :index number :scale 4)))
686 ((and (= amount 3) (not (location= number result)))
687 (inst lea result (make-ea :qword :index number :scale 8)))
690 (cond ((< -64 amount 64) ;; XXXX
691 ;; this code is used both in ASH and ASH-MOD32, so
694 (inst shl result amount)
695 (inst shr result (- amount))))
696 (t (if (sc-is result unsigned-reg)
698 (inst mov result 0))))))))
700 (define-vop (fast-ash-left/signed=>signed)
702 (:args (number :scs (signed-reg) :target result
703 :load-if (not (and (sc-is number signed-stack)
704 (sc-is result signed-stack)
705 (location= number result))))
706 (amount :scs (unsigned-reg) :target ecx))
707 (:arg-types signed-num positive-fixnum)
708 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
709 (:results (result :scs (signed-reg) :from (:argument 0)
710 :load-if (not (and (sc-is number signed-stack)
711 (sc-is result signed-stack)
712 (location= number result)))))
713 (:result-types signed-num)
719 (inst shl result :cl)))
721 (define-vop (fast-ash-left/unsigned=>unsigned)
723 (:args (number :scs (unsigned-reg) :target result
724 :load-if (not (and (sc-is number unsigned-stack)
725 (sc-is result unsigned-stack)
726 (location= number result))))
727 (amount :scs (unsigned-reg) :target ecx))
728 (:arg-types unsigned-num positive-fixnum)
729 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
730 (:results (result :scs (unsigned-reg) :from (:argument 0)
731 :load-if (not (and (sc-is number unsigned-stack)
732 (sc-is result unsigned-stack)
733 (location= number result)))))
734 (:result-types unsigned-num)
740 (inst shl result :cl)))
742 (define-vop (fast-ash/signed=>signed)
745 (:args (number :scs (signed-reg) :target result)
746 (amount :scs (signed-reg) :target ecx))
747 (:arg-types signed-num signed-num)
748 (:results (result :scs (signed-reg) :from (:argument 0)))
749 (:result-types signed-num)
750 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
756 (inst jmp :ns POSITIVE)
762 (inst sar result :cl)
766 ;; The result-type ensures us that this shift will not overflow.
767 (inst shl result :cl)
771 (define-vop (fast-ash/unsigned=>unsigned)
774 (:args (number :scs (unsigned-reg) :target result)
775 (amount :scs (signed-reg) :target ecx))
776 (:arg-types unsigned-num signed-num)
777 (:results (result :scs (unsigned-reg) :from (:argument 0)))
778 (:result-types unsigned-num)
779 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
785 (inst jmp :ns POSITIVE)
792 (inst shr result :cl)
796 ;; The result-type ensures us that this shift will not overflow.
797 (inst shl result :cl)
803 (defknown %lea (integer integer (member 1 2 4 8 16) (signed-byte 64))
805 (foldable flushable movable))
807 (defoptimizer (%lea derive-type) ((base index scale disp))
808 (when (and (constant-lvar-p scale)
809 (constant-lvar-p disp))
810 (let ((scale (lvar-value scale))
811 (disp (lvar-value disp))
812 (base-type (lvar-type base))
813 (index-type (lvar-type index)))
814 (when (and (numeric-type-p base-type)
815 (numeric-type-p index-type))
816 (let ((base-lo (numeric-type-low base-type))
817 (base-hi (numeric-type-high base-type))
818 (index-lo (numeric-type-low index-type))
819 (index-hi (numeric-type-high index-type)))
820 (make-numeric-type :class 'integer
822 :low (when (and base-lo index-lo)
823 (+ base-lo (* index-lo scale) disp))
824 :high (when (and base-hi index-hi)
825 (+ base-hi (* index-hi scale) disp))))))))
827 (defun %lea (base index scale disp)
828 (+ base (* index scale) disp))
832 (define-vop (%lea/unsigned=>unsigned)
835 (:args (base :scs (unsigned-reg))
836 (index :scs (unsigned-reg)))
838 (:arg-types unsigned-num unsigned-num
839 (:constant (member 1 2 4 8))
840 (:constant (signed-byte 64)))
841 (:results (r :scs (unsigned-reg)))
842 (:result-types unsigned-num)
844 (inst lea r (make-ea :qword :base base :index index
845 :scale scale :disp disp))))
847 (define-vop (%lea/signed=>signed)
850 (:args (base :scs (signed-reg))
851 (index :scs (signed-reg)))
853 (:arg-types signed-num signed-num
854 (:constant (member 1 2 4 8))
855 (:constant (signed-byte 64)))
856 (:results (r :scs (signed-reg)))
857 (:result-types signed-num)
859 (inst lea r (make-ea :qword :base base :index index
860 :scale scale :disp disp))))
862 (define-vop (%lea/fixnum=>fixnum)
865 (:args (base :scs (any-reg))
866 (index :scs (any-reg)))
868 (:arg-types tagged-num tagged-num
869 (:constant (member 1 2 4 8))
870 (:constant (signed-byte 64)))
871 (:results (r :scs (any-reg)))
872 (:result-types tagged-num)
874 (inst lea r (make-ea :qword :base base :index index
875 :scale scale :disp disp))))
877 ;;; FIXME: before making knowledge of this too public, it needs to be
878 ;;; fixed so that it's actually _faster_ than the non-CMOV version; at
879 ;;; least on my Celeron-XXX laptop, this version is marginally slower
880 ;;; than the above version with branches. -- CSR, 2003-09-04
881 (define-vop (fast-cmov-ash/unsigned=>unsigned)
884 (:args (number :scs (unsigned-reg) :target result)
885 (amount :scs (signed-reg) :target ecx))
886 (:arg-types unsigned-num signed-num)
887 (:results (result :scs (unsigned-reg) :from (:argument 0)))
888 (:result-types unsigned-num)
889 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
890 (:temporary (:sc any-reg :from (:eval 0) :to (:eval 1)) zero)
892 (:guard (member :cmov *backend-subfeatures*))
897 (inst jmp :ns POSITIVE)
900 (inst shr result :cl)
902 (inst cmov :nbe result zero)
906 ;; The result-type ensures us that this shift will not overflow.
907 (inst shl result :cl)
911 (define-vop (signed-byte-64-len)
912 (:translate integer-length)
913 (:note "inline (signed-byte 64) integer-length")
915 (:args (arg :scs (signed-reg) :target res))
916 (:arg-types signed-num)
917 (:results (res :scs (unsigned-reg)))
918 (:result-types unsigned-num)
933 (define-vop (unsigned-byte-64-len)
934 (:translate integer-length)
935 (:note "inline (unsigned-byte 64) integer-length")
937 (:args (arg :scs (unsigned-reg)))
938 (:arg-types unsigned-num)
939 (:results (res :scs (unsigned-reg)))
940 (:result-types unsigned-num)
950 (define-vop (unsigned-byte-64-count)
951 (:translate logcount)
952 (:note "inline (unsigned-byte 64) logcount")
954 (:args (arg :scs (unsigned-reg) :target result))
955 (:arg-types unsigned-num)
956 (:results (result :scs (unsigned-reg)))
957 (:result-types positive-fixnum)
958 (:temporary (:sc unsigned-reg) temp)
959 (:temporary (:sc unsigned-reg) mask)
961 ;; See the comments below for how the algorithm works. The tricks
962 ;; used can be found for example in AMD's software optimization
963 ;; guide or at "http://www.hackersdelight.org/HDcode/pop.cc" in the
964 ;; function "pop1", for 32-bit words. The extension to 64 bits is
966 ;; Calculate 2-bit sums. Note that the value of a two-digit binary
967 ;; number is the sum of the right digit and twice the left digit.
968 ;; Thus we can calculate the sum of the two digits by shifting the
969 ;; left digit to the right position and doing a two-bit subtraction.
970 ;; This subtraction will never create a borrow and thus can be made
971 ;; on all 32 2-digit numbers at once.
975 (inst mov mask #x5555555555555555)
976 (inst and result mask)
977 (inst sub temp result)
978 ;; Calculate 4-bit sums by straightforward shift, mask and add.
979 ;; Note that we shift the source operand of the MOV and not its
980 ;; destination so that the SHR and the MOV can execute in the same
982 (inst mov result temp)
984 (inst mov mask #x3333333333333333)
985 (inst and result mask)
987 (inst add result temp)
988 ;; Calculate 8-bit sums. Since each sum is at most 8, which fits
989 ;; into 4 bits, we can apply the mask after the addition, saving one
991 (inst mov temp result)
993 (inst add result temp)
994 (inst mov mask #x0f0f0f0f0f0f0f0f)
995 (inst and result mask)
996 ;; Add all 8 bytes at once by multiplying with #256r11111111.
997 ;; We need to calculate only the lower 8 bytes of the product.
998 ;; Of these the most significant byte contains the final result.
999 ;; Note that there can be no overflow from one byte to the next
1000 ;; as the sum is at most 64 which needs only 7 bits.
1001 (inst mov mask #x0101010101010101)
1002 (inst imul result mask)
1003 (inst shr result 56)))
1005 ;;;; binary conditional VOPs
1007 (define-vop (fast-conditional)
1009 (:info target not-p)
1012 (:policy :fast-safe))
1014 ;;; constant variants are declared for 32 bits not 64 bits, because
1015 ;;; loading a 64 bit constant is silly
1017 (define-vop (fast-conditional/fixnum fast-conditional)
1018 (:args (x :scs (any-reg)
1019 :load-if (not (and (sc-is x control-stack)
1020 (sc-is y any-reg))))
1021 (y :scs (any-reg control-stack)))
1022 (:arg-types tagged-num tagged-num)
1023 (:note "inline fixnum comparison"))
1025 (define-vop (fast-conditional-c/fixnum fast-conditional/fixnum)
1026 (:args (x :scs (any-reg control-stack)))
1027 (:arg-types tagged-num (:constant (signed-byte 29)))
1028 (:info target not-p y))
1030 (define-vop (fast-conditional/signed fast-conditional)
1031 (:args (x :scs (signed-reg)
1032 :load-if (not (and (sc-is x signed-stack)
1033 (sc-is y signed-reg))))
1034 (y :scs (signed-reg signed-stack)))
1035 (:arg-types signed-num signed-num)
1036 (:note "inline (signed-byte 64) comparison"))
1038 (define-vop (fast-conditional-c/signed fast-conditional/signed)
1039 (:args (x :scs (signed-reg signed-stack)))
1040 (:arg-types signed-num (:constant (signed-byte 31)))
1041 (:info target not-p y))
1043 (define-vop (fast-conditional/unsigned fast-conditional)
1044 (:args (x :scs (unsigned-reg)
1045 :load-if (not (and (sc-is x unsigned-stack)
1046 (sc-is y unsigned-reg))))
1047 (y :scs (unsigned-reg unsigned-stack)))
1048 (:arg-types unsigned-num unsigned-num)
1049 (:note "inline (unsigned-byte 64) comparison"))
1051 (define-vop (fast-conditional-c/unsigned fast-conditional/unsigned)
1052 (:args (x :scs (unsigned-reg unsigned-stack)))
1053 (:arg-types unsigned-num (:constant (unsigned-byte 31)))
1054 (:info target not-p y))
1056 (macrolet ((define-conditional-vop (tran cond unsigned not-cond not-unsigned)
1059 (lambda (suffix cost signed)
1060 `(define-vop (;; FIXME: These could be done more
1061 ;; cleanly with SYMBOLICATE.
1062 ,(intern (format nil "~:@(FAST-IF-~A~A~)"
1065 (format nil "~:@(FAST-CONDITIONAL~A~)"
1070 ,(if (eq suffix '-c/fixnum)
1081 '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned)
1082 ; '(/fixnum /signed /unsigned)
1084 '(t t t t nil nil)))))
1086 (define-conditional-vop < :l :b :ge :ae)
1087 (define-conditional-vop > :g :a :le :be))
1089 (define-vop (fast-if-eql/signed fast-conditional/signed)
1093 (inst jmp (if not-p :ne :e) target)))
1095 (define-vop (fast-if-eql-c/signed fast-conditional-c/signed)
1098 (cond ((and (sc-is x signed-reg) (zerop y))
1099 (inst test x x)) ; smaller instruction
1102 (inst jmp (if not-p :ne :e) target)))
1104 (define-vop (fast-if-eql/unsigned fast-conditional/unsigned)
1108 (inst jmp (if not-p :ne :e) target)))
1110 (define-vop (fast-if-eql-c/unsigned fast-conditional-c/unsigned)
1113 (cond ((and (sc-is x unsigned-reg) (zerop y))
1114 (inst test x x)) ; smaller instruction
1117 (inst jmp (if not-p :ne :e) target)))
1119 ;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a
1122 ;;; These versions specify a fixnum restriction on their first arg. We have
1123 ;;; also generic-eql/fixnum VOPs which are the same, but have no restriction on
1124 ;;; the first arg and a higher cost. The reason for doing this is to prevent
1125 ;;; fixnum specific operations from being used on word integers, spuriously
1126 ;;; consing the argument.
1128 (define-vop (fast-eql/fixnum fast-conditional)
1129 (:args (x :scs (any-reg)
1130 :load-if (not (and (sc-is x control-stack)
1131 (sc-is y any-reg))))
1132 (y :scs (any-reg control-stack)))
1133 (:arg-types tagged-num tagged-num)
1134 (:note "inline fixnum comparison")
1138 (inst jmp (if not-p :ne :e) target)))
1139 (define-vop (generic-eql/fixnum fast-eql/fixnum)
1140 (:args (x :scs (any-reg descriptor-reg)
1141 :load-if (not (and (sc-is x control-stack)
1142 (sc-is y any-reg))))
1143 (y :scs (any-reg control-stack)))
1144 (:arg-types * tagged-num)
1148 (define-vop (fast-eql-c/fixnum fast-conditional/fixnum)
1149 (:args (x :scs (any-reg control-stack)))
1150 (:arg-types tagged-num (:constant (signed-byte 29)))
1151 (:info target not-p y)
1154 (cond ((and (sc-is x any-reg) (zerop y))
1155 (inst test x x)) ; smaller instruction
1157 (inst cmp x (fixnumize y))))
1158 (inst jmp (if not-p :ne :e) target)))
1160 (define-vop (generic-eql-c/fixnum fast-eql-c/fixnum)
1161 (:args (x :scs (any-reg descriptor-reg control-stack)))
1162 (:arg-types * (:constant (signed-byte 29)))
1165 ;;;; 32-bit logical operations
1167 (define-vop (merge-bits)
1168 (:translate merge-bits)
1169 (:args (shift :scs (signed-reg unsigned-reg) :target ecx)
1170 (prev :scs (unsigned-reg) :target result)
1171 (next :scs (unsigned-reg)))
1172 (:arg-types tagged-num unsigned-num unsigned-num)
1173 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 0)) ecx)
1174 (:results (result :scs (unsigned-reg) :from (:argument 1)))
1175 (:result-types unsigned-num)
1176 (:policy :fast-safe)
1180 (inst shrd result next :cl)))
1182 ;;; Only the lower 6 bits of the shift amount are significant.
1183 (define-vop (shift-towards-someplace)
1184 (:policy :fast-safe)
1185 (:args (num :scs (unsigned-reg) :target r)
1186 (amount :scs (signed-reg) :target ecx))
1187 (:arg-types unsigned-num tagged-num)
1188 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
1189 (:results (r :scs (unsigned-reg) :from (:argument 0)))
1190 (:result-types unsigned-num))
1192 (define-vop (shift-towards-start shift-towards-someplace)
1193 (:translate shift-towards-start)
1194 (:note "SHIFT-TOWARDS-START")
1200 (define-vop (shift-towards-end shift-towards-someplace)
1201 (:translate shift-towards-end)
1202 (:note "SHIFT-TOWARDS-END")
1208 ;;;; Modular functions
1210 (macrolet ((def (name -c-p)
1211 (let ((fun64 (intern (format nil "~S-MOD64" name)))
1212 (vopu (intern (format nil "FAST-~S/UNSIGNED=>UNSIGNED" name)))
1213 (vopcu (intern (format nil "FAST-~S-C/UNSIGNED=>UNSIGNED" name)))
1214 (vopf (intern (format nil "FAST-~S/FIXNUM=>FIXNUM" name)))
1215 (vopcf (intern (format nil "FAST-~S-C/FIXNUM=>FIXNUM" name)))
1216 (vop64u (intern (format nil "FAST-~S-MOD64/UNSIGNED=>UNSIGNED" name)))
1217 (vop64f (intern (format nil "FAST-~S-MOD64/FIXNUM=>FIXNUM" name)))
1218 (vop64cu (intern (format nil "FAST-~S-MOD64-C/UNSIGNED=>UNSIGNED" name)))
1219 (vop64cf (intern (format nil "FAST-~S-MOD64-C/FIXNUM=>FIXNUM" name)))
1220 (sfun61 (intern (format nil "~S-SMOD61" name)))
1221 (svop61f (intern (format nil "FAST-~S-SMOD61/FIXNUM=>FIXNUM" name)))
1222 (svop61cf (intern (format nil "FAST-~S-SMOD61-C/FIXNUM=>FIXNUM" name))))
1224 (define-modular-fun ,fun64 (x y) ,name :unsigned 64)
1225 (define-modular-fun ,sfun61 (x y) ,name :signed 61)
1226 (define-vop (,vop64u ,vopu) (:translate ,fun64))
1227 (define-vop (,vop64f ,vopf) (:translate ,fun64))
1228 (define-vop (,svop61f ,vopf) (:translate ,sfun61))
1230 `((define-vop (,vop64cu ,vopcu) (:translate ,fun64))
1231 (define-vop (,svop61cf ,vopcf) (:translate ,sfun61))))))))
1234 ;; (no -C variant as x86 MUL instruction doesn't take an immediate)
1237 (define-vop (fast-ash-left-mod64-c/unsigned=>unsigned
1238 fast-ash-c/unsigned=>unsigned)
1239 (:translate ash-left-mod64))
1240 (define-vop (fast-ash-left-mod64/unsigned=>unsigned
1241 fast-ash-left/unsigned=>unsigned))
1242 (deftransform ash-left-mod64 ((integer count)
1243 ((unsigned-byte 64) (unsigned-byte 6)))
1244 (when (sb!c::constant-lvar-p count)
1245 (sb!c::give-up-ir1-transform))
1246 '(%primitive fast-ash-left-mod64/unsigned=>unsigned integer count))
1248 (define-vop (fast-ash-left-smod61-c/fixnum=>fixnum
1249 fast-ash-c/fixnum=>fixnum)
1250 (:translate ash-left-smod61))
1251 (define-vop (fast-ash-left-smod61/fixnum=>fixnum
1252 fast-ash-left/fixnum=>fixnum))
1253 (deftransform ash-left-smod61 ((integer count)
1254 ((signed-byte 61) (unsigned-byte 6)))
1255 (when (sb!c::constant-lvar-p count)
1256 (sb!c::give-up-ir1-transform))
1257 '(%primitive fast-ash-left-smod61/fixnum=>fixnum integer count))
1261 (defknown sb!vm::%lea-mod64 (integer integer (member 1 2 4 8) (signed-byte 64))
1263 (foldable flushable movable))
1264 (defknown sb!vm::%lea-smod61 (integer integer (member 1 2 4 8) (signed-byte 64))
1266 (foldable flushable movable))
1268 (define-modular-fun-optimizer %lea ((base index scale disp) :unsigned :width width)
1269 (when (and (<= width 64)
1270 (constant-lvar-p scale)
1271 (constant-lvar-p disp))
1272 (cut-to-width base :unsigned width)
1273 (cut-to-width index :unsigned width)
1274 'sb!vm::%lea-mod64))
1275 (define-modular-fun-optimizer %lea ((base index scale disp) :signed :width width)
1276 (when (and (<= width 61)
1277 (constant-lvar-p scale)
1278 (constant-lvar-p disp))
1279 (cut-to-width base :signed width)
1280 (cut-to-width index :signed width)
1281 'sb!vm::%lea-smod61))
1285 (defun sb!vm::%lea-mod64 (base index scale disp)
1286 (ldb (byte 64 0) (%lea base index scale disp)))
1287 (defun sb!vm::%lea-smod61 (base index scale disp)
1288 (mask-signed-field 61 (%lea base index scale disp))))
1291 (defun sb!vm::%lea-mod64 (base index scale disp)
1292 (let ((base (logand base #xffffffffffffffff))
1293 (index (logand index #xffffffffffffffff)))
1294 ;; can't use modular version of %LEA, as we only have VOPs for
1295 ;; constant SCALE and DISP.
1296 (ldb (byte 64 0) (+ base (* index scale) disp))))
1297 (defun sb!vm::%lea-smod61 (base index scale disp)
1298 (let ((base (mask-signed-field 61 base))
1299 (index (mask-signed-field 61 index)))
1300 ;; can't use modular version of %LEA, as we only have VOPs for
1301 ;; constant SCALE and DISP.
1302 (mask-signed-field 61 (+ base (* index scale) disp)))))
1304 (in-package "SB!VM")
1306 (define-vop (%lea-mod64/unsigned=>unsigned
1307 %lea/unsigned=>unsigned)
1308 (:translate %lea-mod64))
1309 (define-vop (%lea-smod61/fixnum=>fixnum
1310 %lea/fixnum=>fixnum)
1311 (:translate %lea-smod61))
1313 ;;; logical operations
1314 (define-modular-fun lognot-mod64 (x) lognot :unsigned 64)
1315 (define-vop (lognot-mod64/unsigned=>unsigned)
1316 (:translate lognot-mod64)
1317 (:args (x :scs (unsigned-reg unsigned-stack) :target r
1318 :load-if (not (and (sc-is x unsigned-stack)
1319 (sc-is r unsigned-stack)
1321 (:arg-types unsigned-num)
1322 (:results (r :scs (unsigned-reg)
1323 :load-if (not (and (sc-is x unsigned-stack)
1324 (sc-is r unsigned-stack)
1326 (:result-types unsigned-num)
1327 (:policy :fast-safe)
1332 (define-modular-fun logxor-mod64 (x y) logxor :unsigned 64)
1333 (define-vop (fast-logxor-mod64/unsigned=>unsigned
1334 fast-logxor/unsigned=>unsigned)
1335 (:translate logxor-mod64))
1336 (define-vop (fast-logxor-mod64-c/unsigned=>unsigned
1337 fast-logxor-c/unsigned=>unsigned)
1338 (:translate logxor-mod64))
1339 (define-vop (fast-logxor-mod64/fixnum=>fixnum
1340 fast-logxor/fixnum=>fixnum)
1341 (:translate logxor-mod64))
1342 (define-vop (fast-logxor-mod64-c/fixnum=>fixnum
1343 fast-logxor-c/fixnum=>fixnum)
1344 (:translate logxor-mod64))
1346 (define-source-transform logeqv (&rest args)
1347 (if (oddp (length args))
1349 `(lognot (logxor ,@args))))
1350 (define-source-transform logandc1 (x y)
1351 `(logand (lognot ,x) ,y))
1352 (define-source-transform logandc2 (x y)
1353 `(logand ,x (lognot ,y)))
1354 (define-source-transform logorc1 (x y)
1355 `(logior (lognot ,x) ,y))
1356 (define-source-transform logorc2 (x y)
1357 `(logior ,x (lognot ,y)))
1358 (define-source-transform lognor (x y)
1359 `(lognot (logior ,x ,y)))
1360 (define-source-transform lognand (x y)
1361 `(lognot (logand ,x ,y)))
1365 (define-vop (bignum-length get-header-data)
1366 (:translate sb!bignum:%bignum-length)
1367 (:policy :fast-safe))
1369 (define-vop (bignum-set-length set-header-data)
1370 (:translate sb!bignum:%bignum-set-length)
1371 (:policy :fast-safe))
1373 (define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag
1374 (unsigned-reg) unsigned-num sb!bignum:%bignum-ref)
1376 (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag
1377 (unsigned-reg) unsigned-num sb!bignum:%bignum-set)
1379 (define-vop (digit-0-or-plus)
1380 (:translate sb!bignum:%digit-0-or-plusp)
1381 (:policy :fast-safe)
1382 (:args (digit :scs (unsigned-reg)))
1383 (:arg-types unsigned-num)
1385 (:info target not-p)
1387 (inst or digit digit)
1388 (inst jmp (if not-p :s :ns) target)))
1391 ;;; For add and sub with carry the sc of carry argument is any-reg so
1392 ;;; that it may be passed as a fixnum or word and thus may be 0, 1, or
1393 ;;; 8. This is easy to deal with and may save a fixnum-word
1395 (define-vop (add-w/carry)
1396 (:translate sb!bignum:%add-with-carry)
1397 (:policy :fast-safe)
1398 (:args (a :scs (unsigned-reg) :target result)
1399 (b :scs (unsigned-reg unsigned-stack) :to :eval)
1400 (c :scs (any-reg) :target temp))
1401 (:arg-types unsigned-num unsigned-num positive-fixnum)
1402 (:temporary (:sc any-reg :from (:argument 2) :to :eval) temp)
1403 (:results (result :scs (unsigned-reg) :from (:argument 0))
1404 (carry :scs (unsigned-reg)))
1405 (:result-types unsigned-num positive-fixnum)
1409 (inst neg temp) ; Set the carry flag to 0 if c=0 else to 1
1412 (inst adc carry carry)))
1414 ;;; Note: the borrow is 1 for no borrow and 0 for a borrow, the opposite
1415 ;;; of the x86-64 convention.
1416 (define-vop (sub-w/borrow)
1417 (:translate sb!bignum:%subtract-with-borrow)
1418 (:policy :fast-safe)
1419 (:args (a :scs (unsigned-reg) :to :eval :target result)
1420 (b :scs (unsigned-reg unsigned-stack) :to :result)
1421 (c :scs (any-reg control-stack)))
1422 (:arg-types unsigned-num unsigned-num positive-fixnum)
1423 (:results (result :scs (unsigned-reg) :from :eval)
1424 (borrow :scs (unsigned-reg)))
1425 (:result-types unsigned-num positive-fixnum)
1427 (inst cmp c 1) ; Set the carry flag to 1 if c=0 else to 0
1431 (inst sbb borrow 0)))
1434 (define-vop (bignum-mult-and-add-3-arg)
1435 (:translate sb!bignum:%multiply-and-add)
1436 (:policy :fast-safe)
1437 (:args (x :scs (unsigned-reg) :target eax)
1438 (y :scs (unsigned-reg unsigned-stack))
1439 (carry-in :scs (unsigned-reg unsigned-stack)))
1440 (:arg-types unsigned-num unsigned-num unsigned-num)
1441 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1442 :to (:result 1) :target lo) eax)
1443 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1444 :to (:result 0) :target hi) edx)
1445 (:results (hi :scs (unsigned-reg))
1446 (lo :scs (unsigned-reg)))
1447 (:result-types unsigned-num unsigned-num)
1451 (inst add eax carry-in)
1456 (define-vop (bignum-mult-and-add-4-arg)
1457 (:translate sb!bignum:%multiply-and-add)
1458 (:policy :fast-safe)
1459 (:args (x :scs (unsigned-reg) :target eax)
1460 (y :scs (unsigned-reg unsigned-stack))
1461 (prev :scs (unsigned-reg unsigned-stack))
1462 (carry-in :scs (unsigned-reg unsigned-stack)))
1463 (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num)
1464 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1465 :to (:result 1) :target lo) eax)
1466 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1467 :to (:result 0) :target hi) edx)
1468 (:results (hi :scs (unsigned-reg))
1469 (lo :scs (unsigned-reg)))
1470 (:result-types unsigned-num unsigned-num)
1476 (inst add eax carry-in)
1482 (define-vop (bignum-mult)
1483 (:translate sb!bignum:%multiply)
1484 (:policy :fast-safe)
1485 (:args (x :scs (unsigned-reg) :target eax)
1486 (y :scs (unsigned-reg unsigned-stack)))
1487 (:arg-types unsigned-num unsigned-num)
1488 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1489 :to (:result 1) :target lo) eax)
1490 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1491 :to (:result 0) :target hi) edx)
1492 (:results (hi :scs (unsigned-reg))
1493 (lo :scs (unsigned-reg)))
1494 (:result-types unsigned-num unsigned-num)
1501 (define-vop (bignum-lognot lognot-mod64/unsigned=>unsigned)
1502 (:translate sb!bignum:%lognot))
1504 (define-vop (fixnum-to-digit)
1505 (:translate sb!bignum:%fixnum-to-digit)
1506 (:policy :fast-safe)
1507 (:args (fixnum :scs (any-reg control-stack) :target digit))
1508 (:arg-types tagged-num)
1509 (:results (digit :scs (unsigned-reg)
1510 :load-if (not (and (sc-is fixnum control-stack)
1511 (sc-is digit unsigned-stack)
1512 (location= fixnum digit)))))
1513 (:result-types unsigned-num)
1516 (inst sar digit 3)))
1518 (define-vop (bignum-floor)
1519 (:translate sb!bignum:%floor)
1520 (:policy :fast-safe)
1521 (:args (div-high :scs (unsigned-reg) :target edx)
1522 (div-low :scs (unsigned-reg) :target eax)
1523 (divisor :scs (unsigned-reg unsigned-stack)))
1524 (:arg-types unsigned-num unsigned-num unsigned-num)
1525 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 1)
1526 :to (:result 0) :target quo) eax)
1527 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 0)
1528 :to (:result 1) :target rem) edx)
1529 (:results (quo :scs (unsigned-reg))
1530 (rem :scs (unsigned-reg)))
1531 (:result-types unsigned-num unsigned-num)
1535 (inst div eax divisor)
1539 (define-vop (signify-digit)
1540 (:translate sb!bignum:%fixnum-digit-with-correct-sign)
1541 (:policy :fast-safe)
1542 (:args (digit :scs (unsigned-reg unsigned-stack) :target res))
1543 (:arg-types unsigned-num)
1544 (:results (res :scs (any-reg signed-reg)
1545 :load-if (not (and (sc-is digit unsigned-stack)
1546 (sc-is res control-stack signed-stack)
1547 (location= digit res)))))
1548 (:result-types signed-num)
1551 (when (sc-is res any-reg control-stack)
1554 (define-vop (digit-ashr)
1555 (:translate sb!bignum:%ashr)
1556 (:policy :fast-safe)
1557 (:args (digit :scs (unsigned-reg unsigned-stack) :target result)
1558 (count :scs (unsigned-reg) :target ecx))
1559 (:arg-types unsigned-num positive-fixnum)
1560 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
1561 (:results (result :scs (unsigned-reg) :from (:argument 0)
1562 :load-if (not (and (sc-is result unsigned-stack)
1563 (location= digit result)))))
1564 (:result-types unsigned-num)
1568 (inst sar result :cl)))
1570 (define-vop (digit-ashr/c)
1571 (:translate sb!bignum:%ashr)
1572 (:policy :fast-safe)
1573 (:args (digit :scs (unsigned-reg unsigned-stack) :target result))
1574 (:arg-types unsigned-num (:constant (integer 0 63)))
1576 (:results (result :scs (unsigned-reg) :from (:argument 0)
1577 :load-if (not (and (sc-is result unsigned-stack)
1578 (location= digit result)))))
1579 (:result-types unsigned-num)
1582 (inst sar result count)))
1584 (define-vop (digit-lshr digit-ashr)
1585 (:translate sb!bignum:%digit-logical-shift-right)
1589 (inst shr result :cl)))
1591 (define-vop (digit-ashl digit-ashr)
1592 (:translate sb!bignum:%ashl)
1596 (inst shl result :cl)))
1598 ;;;; static functions
1600 (define-static-fun two-arg-/ (x y) :translate /)
1602 (define-static-fun two-arg-gcd (x y) :translate gcd)
1603 (define-static-fun two-arg-lcm (x y) :translate lcm)
1605 (define-static-fun two-arg-and (x y) :translate logand)
1606 (define-static-fun two-arg-ior (x y) :translate logior)
1607 (define-static-fun two-arg-xor (x y) :translate logxor)
1612 (defun *-transformer (y)
1614 ((= y (ash 1 (integer-length y)))
1615 ;; there's a generic transform for y = 2^k
1616 (give-up-ir1-transform))
1617 ((member y '(3 5 9))
1618 ;; we can do these multiplications directly using LEA
1619 `(%lea x x ,(1- y) 0))
1621 ;; A normal 64-bit multiplication takes 4 cycles on Athlon 64/Opteron.
1622 ;; Optimizing multiplications (other than the above cases) to
1623 ;; shifts/adds/leas gives a maximum improvement of 1 cycle, but requires
1624 ;; quite a lot of hairy code.
1625 (give-up-ir1-transform))))
1627 (deftransform * ((x y)
1628 ((unsigned-byte 64) (constant-arg (unsigned-byte 64)))
1630 "recode as leas, shifts and adds"
1631 (let ((y (lvar-value y)))
1633 (deftransform sb!vm::*-mod64
1634 ((x y) ((unsigned-byte 64) (constant-arg (unsigned-byte 64)))
1636 "recode as leas, shifts and adds"
1637 (let ((y (lvar-value y)))
1640 (deftransform * ((x y)
1641 ((signed-byte 61) (constant-arg (unsigned-byte 64)))
1643 "recode as leas, shifts and adds"
1644 (let ((y (lvar-value y)))
1646 (deftransform sb!vm::*-smod61
1647 ((x y) ((signed-byte 61) (constant-arg (unsigned-byte 64)))
1649 "recode as leas, shifts and adds"
1650 (let ((y (lvar-value y)))