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 32) 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 32) 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 32) 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 30)))
115 (:results (r :scs (any-reg)
116 :load-if (not (location= x r))))
117 (:result-types tagged-num)
118 (:note "inline fixnum arithmetic"))
120 (define-vop (fast-unsigned-binop-c fast-safe-arith-op)
121 (:args (x :target r :scs (unsigned-reg unsigned-stack)))
123 (:arg-types unsigned-num (:constant (unsigned-byte 32)))
124 (:results (r :scs (unsigned-reg)
125 :load-if (not (location= x r))))
126 (:result-types unsigned-num)
127 (:note "inline (unsigned-byte 32) arithmetic"))
129 (define-vop (fast-signed-binop-c fast-safe-arith-op)
130 (:args (x :target r :scs (signed-reg signed-stack)))
132 (:arg-types signed-num (:constant (signed-byte 32)))
133 (:results (r :scs (signed-reg)
134 :load-if (not (location= x r))))
135 (:result-types signed-num)
136 (:note "inline (signed-byte 32) arithmetic"))
138 (macrolet ((define-binop (translate untagged-penalty op)
140 (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM")
142 (:translate ,translate)
146 (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum)
148 (:translate ,translate)
151 (inst ,op r (fixnumize y))))
152 (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED")
154 (:translate ,translate)
155 (:generator ,(1+ untagged-penalty)
158 (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed)
160 (:translate ,translate)
161 (:generator ,untagged-penalty
164 (define-vop (,(symbolicate "FAST-"
166 "/UNSIGNED=>UNSIGNED")
168 (:translate ,translate)
169 (:generator ,(1+ untagged-penalty)
172 (define-vop (,(symbolicate 'fast-
174 '-c/unsigned=>unsigned)
175 fast-unsigned-binop-c)
176 (:translate ,translate)
177 (:generator ,untagged-penalty
179 ,(if (eq translate 'logand)
180 ;; for the -C/UNSIGNED=>UNSIGNED VOP, this case
181 ;; is optimized away as an identity somewhere
182 ;; along the lines. However, this VOP is used in
183 ;; -C/SIGNED=>UNSIGNED, below, when the
184 ;; higher-level lisp code can't optimize away the
185 ;; non-trivial identity.
186 `(unless (= y #.(1- (ash 1 n-word-bits)))
188 `(inst ,op r y)))))))
189 (define-binop - 4 sub)
190 (define-binop logand 2 and)
191 (define-binop logior 2 or)
192 (define-binop logxor 2 xor))
194 ;;; Special handling of add on the x86; can use lea to avoid a
195 ;;; register load, otherwise it uses add.
196 (define-vop (fast-+/fixnum=>fixnum fast-safe-arith-op)
198 (:args (x :scs (any-reg) :target r
199 :load-if (not (and (sc-is x control-stack)
201 (sc-is r control-stack)
203 (y :scs (any-reg control-stack)))
204 (:arg-types tagged-num tagged-num)
205 (:results (r :scs (any-reg) :from (:argument 0)
206 :load-if (not (and (sc-is x control-stack)
208 (sc-is r control-stack)
210 (:result-types tagged-num)
211 (:note "inline fixnum arithmetic")
213 (cond ((and (sc-is x any-reg) (sc-is y any-reg) (sc-is r any-reg)
214 (not (location= x r)))
215 (inst lea r (make-ea :dword :base x :index y :scale 1)))
220 (define-vop (fast-+-c/fixnum=>fixnum fast-safe-arith-op)
222 (:args (x :target r :scs (any-reg control-stack)))
224 (:arg-types tagged-num (:constant (signed-byte 30)))
225 (:results (r :scs (any-reg)
226 :load-if (not (location= x r))))
227 (:result-types tagged-num)
228 (:note "inline fixnum arithmetic")
230 (cond ((and (sc-is x any-reg) (sc-is r any-reg) (not (location= x r)))
231 (inst lea r (make-ea :dword :base x :disp (fixnumize y))))
234 (inst add r (fixnumize y))))))
236 (define-vop (fast-+/signed=>signed fast-safe-arith-op)
238 (:args (x :scs (signed-reg) :target r
239 :load-if (not (and (sc-is x signed-stack)
241 (sc-is r signed-stack)
243 (y :scs (signed-reg signed-stack)))
244 (:arg-types signed-num signed-num)
245 (:results (r :scs (signed-reg) :from (:argument 0)
246 :load-if (not (and (sc-is x signed-stack)
249 (:result-types signed-num)
250 (:note "inline (signed-byte 32) arithmetic")
252 (cond ((and (sc-is x signed-reg) (sc-is y signed-reg) (sc-is r signed-reg)
253 (not (location= x r)))
254 (inst lea r (make-ea :dword :base x :index y :scale 1)))
259 ;;;; Special logand cases: (logand signed unsigned) => unsigned
261 (define-vop (fast-logand/signed-unsigned=>unsigned
262 fast-logand/unsigned=>unsigned)
263 (:args (x :target r :scs (signed-reg)
264 :load-if (not (and (sc-is x signed-stack)
265 (sc-is y unsigned-reg)
266 (sc-is r unsigned-stack)
268 (y :scs (unsigned-reg unsigned-stack)))
269 (:arg-types signed-num unsigned-num))
271 (define-vop (fast-logand-c/signed-unsigned=>unsigned
272 fast-logand-c/unsigned=>unsigned)
273 (:args (x :target r :scs (signed-reg signed-stack)))
274 (:arg-types signed-num (:constant (unsigned-byte 32))))
276 (define-vop (fast-logand/unsigned-signed=>unsigned
277 fast-logand/unsigned=>unsigned)
278 (:args (x :target r :scs (unsigned-reg)
279 :load-if (not (and (sc-is x unsigned-stack)
281 (sc-is r unsigned-stack)
283 (y :scs (signed-reg signed-stack)))
284 (:arg-types unsigned-num signed-num))
287 (define-vop (fast-+-c/signed=>signed fast-safe-arith-op)
289 (:args (x :target r :scs (signed-reg signed-stack)))
291 (:arg-types signed-num (:constant (signed-byte 32)))
292 (:results (r :scs (signed-reg)
293 :load-if (not (location= x r))))
294 (:result-types signed-num)
295 (:note "inline (signed-byte 32) arithmetic")
297 (cond ((and (sc-is x signed-reg) (sc-is r signed-reg)
298 (not (location= x r)))
299 (inst lea r (make-ea :dword :base x :disp y)))
306 (define-vop (fast-+/unsigned=>unsigned fast-safe-arith-op)
308 (:args (x :scs (unsigned-reg) :target r
309 :load-if (not (and (sc-is x unsigned-stack)
310 (sc-is y unsigned-reg)
311 (sc-is r unsigned-stack)
313 (y :scs (unsigned-reg unsigned-stack)))
314 (:arg-types unsigned-num unsigned-num)
315 (:results (r :scs (unsigned-reg) :from (:argument 0)
316 :load-if (not (and (sc-is x unsigned-stack)
317 (sc-is y unsigned-reg)
318 (sc-is r unsigned-stack)
320 (:result-types unsigned-num)
321 (:note "inline (unsigned-byte 32) arithmetic")
323 (cond ((and (sc-is x unsigned-reg) (sc-is y unsigned-reg)
324 (sc-is r unsigned-reg) (not (location= x r)))
325 (inst lea r (make-ea :dword :base x :index y :scale 1)))
330 (define-vop (fast-+-c/unsigned=>unsigned fast-safe-arith-op)
332 (:args (x :target r :scs (unsigned-reg unsigned-stack)))
334 (:arg-types unsigned-num (:constant (unsigned-byte 32)))
335 (:results (r :scs (unsigned-reg)
336 :load-if (not (location= x r))))
337 (:result-types unsigned-num)
338 (:note "inline (unsigned-byte 32) arithmetic")
340 (cond ((and (sc-is x unsigned-reg) (sc-is r unsigned-reg)
341 (not (location= x r)))
342 (inst lea r (make-ea :dword :base x :disp y)))
349 ;;;; multiplication and division
351 (define-vop (fast-*/fixnum=>fixnum fast-safe-arith-op)
353 ;; We need different loading characteristics.
354 (:args (x :scs (any-reg) :target r)
355 (y :scs (any-reg control-stack)))
356 (:arg-types tagged-num tagged-num)
357 (:results (r :scs (any-reg) :from (:argument 0)))
358 (:result-types tagged-num)
359 (:note "inline fixnum arithmetic")
362 (inst sar r n-fixnum-tag-bits)
365 (define-vop (fast-*-c/fixnum=>fixnum fast-safe-arith-op)
367 ;; We need different loading characteristics.
368 (:args (x :scs (any-reg control-stack)))
370 (:arg-types tagged-num (:constant (signed-byte 30)))
371 (:results (r :scs (any-reg)))
372 (:result-types tagged-num)
373 (:note "inline fixnum arithmetic")
377 (define-vop (fast-*/signed=>signed fast-safe-arith-op)
379 ;; We need different loading characteristics.
380 (:args (x :scs (signed-reg) :target r)
381 (y :scs (signed-reg signed-stack)))
382 (:arg-types signed-num signed-num)
383 (:results (r :scs (signed-reg) :from (:argument 0)))
384 (:result-types signed-num)
385 (:note "inline (signed-byte 32) arithmetic")
390 (define-vop (fast-*-c/signed=>signed fast-safe-arith-op)
392 ;; We need different loading characteristics.
393 (:args (x :scs (signed-reg signed-stack)))
395 (:arg-types signed-num (:constant (signed-byte 32)))
396 (:results (r :scs (signed-reg)))
397 (:result-types signed-num)
398 (:note "inline (signed-byte 32) arithmetic")
402 (define-vop (fast-*/unsigned=>unsigned fast-safe-arith-op)
404 (:args (x :scs (unsigned-reg) :target eax)
405 (y :scs (unsigned-reg unsigned-stack)))
406 (:arg-types unsigned-num unsigned-num)
407 (:temporary (:sc unsigned-reg :offset eax-offset :target r
408 :from (:argument 0) :to :result) eax)
409 (:temporary (:sc unsigned-reg :offset edx-offset
410 :from :eval :to :result) edx)
412 (:results (r :scs (unsigned-reg)))
413 (:result-types unsigned-num)
414 (:note "inline (unsigned-byte 32) arithmetic")
416 (:save-p :compute-only)
423 (define-vop (fast-truncate/fixnum=>fixnum fast-safe-arith-op)
424 (:translate truncate)
425 (:args (x :scs (any-reg) :target eax)
426 (y :scs (any-reg control-stack)))
427 (:arg-types tagged-num tagged-num)
428 (:temporary (:sc signed-reg :offset eax-offset :target quo
429 :from (:argument 0) :to (:result 0)) eax)
430 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
431 :from (:argument 0) :to (:result 1)) edx)
432 (:results (quo :scs (any-reg))
433 (rem :scs (any-reg)))
434 (:result-types tagged-num tagged-num)
435 (:note "inline fixnum arithmetic")
437 (:save-p :compute-only)
439 (let ((zero (generate-error-code vop 'division-by-zero-error x y)))
440 (if (sc-is y any-reg)
441 (inst test y y) ; smaller instruction
447 (if (location= quo eax)
448 (inst shl eax n-fixnum-tag-bits)
449 (inst lea quo (make-ea :dword :index eax
450 :scale (ash 1 n-fixnum-tag-bits))))
453 (define-vop (fast-truncate-c/fixnum=>fixnum fast-safe-arith-op)
454 (:translate truncate)
455 (:args (x :scs (any-reg) :target eax))
457 (:arg-types tagged-num (:constant (signed-byte 30)))
458 (:temporary (:sc signed-reg :offset eax-offset :target quo
459 :from :argument :to (:result 0)) eax)
460 (:temporary (:sc any-reg :offset edx-offset :target rem
461 :from :eval :to (:result 1)) edx)
462 (:temporary (:sc any-reg :from :eval :to :result) y-arg)
463 (:results (quo :scs (any-reg))
464 (rem :scs (any-reg)))
465 (:result-types tagged-num tagged-num)
466 (:note "inline fixnum arithmetic")
468 (:save-p :compute-only)
472 (inst mov y-arg (fixnumize y))
473 (inst idiv eax y-arg)
474 (if (location= quo eax)
475 (inst shl eax n-fixnum-tag-bits)
476 (inst lea quo (make-ea :dword :index eax
477 :scale (ash 1 n-fixnum-tag-bits))))
480 (define-vop (fast-truncate/unsigned=>unsigned fast-safe-arith-op)
481 (:translate truncate)
482 (:args (x :scs (unsigned-reg) :target eax)
483 (y :scs (unsigned-reg signed-stack)))
484 (:arg-types unsigned-num unsigned-num)
485 (:temporary (:sc unsigned-reg :offset eax-offset :target quo
486 :from (:argument 0) :to (:result 0)) eax)
487 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
488 :from (:argument 0) :to (:result 1)) edx)
489 (:results (quo :scs (unsigned-reg))
490 (rem :scs (unsigned-reg)))
491 (:result-types unsigned-num unsigned-num)
492 (:note "inline (unsigned-byte 32) arithmetic")
494 (:save-p :compute-only)
496 (let ((zero (generate-error-code vop 'division-by-zero-error x y)))
497 (if (sc-is y unsigned-reg)
498 (inst test y y) ; smaller instruction
507 (define-vop (fast-truncate-c/unsigned=>unsigned fast-safe-arith-op)
508 (:translate truncate)
509 (:args (x :scs (unsigned-reg) :target eax))
511 (:arg-types unsigned-num (:constant (unsigned-byte 32)))
512 (:temporary (:sc unsigned-reg :offset eax-offset :target quo
513 :from :argument :to (:result 0)) eax)
514 (:temporary (:sc unsigned-reg :offset edx-offset :target rem
515 :from :eval :to (:result 1)) edx)
516 (:temporary (:sc unsigned-reg :from :eval :to :result) y-arg)
517 (:results (quo :scs (unsigned-reg))
518 (rem :scs (unsigned-reg)))
519 (:result-types unsigned-num unsigned-num)
520 (:note "inline (unsigned-byte 32) arithmetic")
522 (:save-p :compute-only)
531 (define-vop (fast-truncate/signed=>signed fast-safe-arith-op)
532 (:translate truncate)
533 (:args (x :scs (signed-reg) :target eax)
534 (y :scs (signed-reg signed-stack)))
535 (:arg-types signed-num signed-num)
536 (:temporary (:sc signed-reg :offset eax-offset :target quo
537 :from (:argument 0) :to (:result 0)) eax)
538 (:temporary (:sc signed-reg :offset edx-offset :target rem
539 :from (:argument 0) :to (:result 1)) edx)
540 (:results (quo :scs (signed-reg))
541 (rem :scs (signed-reg)))
542 (:result-types signed-num signed-num)
543 (:note "inline (signed-byte 32) arithmetic")
545 (:save-p :compute-only)
547 (let ((zero (generate-error-code vop 'division-by-zero-error x y)))
548 (if (sc-is y signed-reg)
549 (inst test y y) ; smaller instruction
558 (define-vop (fast-truncate-c/signed=>signed fast-safe-arith-op)
559 (:translate truncate)
560 (:args (x :scs (signed-reg) :target eax))
562 (:arg-types signed-num (:constant (signed-byte 32)))
563 (:temporary (:sc signed-reg :offset eax-offset :target quo
564 :from :argument :to (:result 0)) eax)
565 (:temporary (:sc signed-reg :offset edx-offset :target rem
566 :from :eval :to (:result 1)) edx)
567 (:temporary (:sc signed-reg :from :eval :to :result) y-arg)
568 (:results (quo :scs (signed-reg))
569 (rem :scs (signed-reg)))
570 (:result-types signed-num signed-num)
571 (:note "inline (signed-byte 32) arithmetic")
573 (:save-p :compute-only)
578 (inst idiv eax y-arg)
585 (define-vop (fast-ash-c/fixnum=>fixnum)
588 (:args (number :scs (any-reg) :target result
589 :load-if (not (and (sc-is number any-reg control-stack)
590 (sc-is result any-reg control-stack)
591 (location= number result)))))
593 (:arg-types tagged-num (:constant integer))
594 (:results (result :scs (any-reg)
595 :load-if (not (and (sc-is number control-stack)
596 (sc-is result control-stack)
597 (location= number result)))))
598 (:result-types tagged-num)
601 (:variant-vars modularp)
603 (cond ((and (= amount 1) (not (location= number result)))
604 (inst lea result (make-ea :dword :base number :index number)))
605 ((and (= amount 2) (not (location= number result)))
606 (inst lea result (make-ea :dword :index number :scale 4)))
607 ((and (= amount 3) (not (location= number result)))
608 (inst lea result (make-ea :dword :index number :scale 8)))
611 (cond ((< -32 amount 32)
612 ;; this code is used both in ASH and ASH-MODFX, so
615 (inst shl result amount)
617 (inst sar result (- amount))
618 (inst and result (lognot fixnum-tag-mask)))))
621 (aver (not "Impossible: fixnum ASH should not be called with
622 constant shift greater than word length")))
623 (if (sc-is result any-reg)
624 (inst xor result result)
625 (inst mov result 0)))
626 (t (inst sar result 31)
627 (inst and result (lognot fixnum-tag-mask))))))))
629 (define-vop (fast-ash-left/fixnum=>fixnum)
631 (:args (number :scs (any-reg) :target result
632 :load-if (not (and (sc-is number control-stack)
633 (sc-is result control-stack)
634 (location= number result))))
635 (amount :scs (unsigned-reg) :target ecx))
636 (:arg-types tagged-num positive-fixnum)
637 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
638 (:results (result :scs (any-reg) :from (:argument 0)
639 :load-if (not (and (sc-is number control-stack)
640 (sc-is result control-stack)
641 (location= number result)))))
642 (:result-types tagged-num)
648 ;; The result-type ensures us that this shift will not overflow.
649 (inst shl result :cl)))
651 (define-vop (fast-ash-c/signed=>signed)
654 (:args (number :scs (signed-reg) :target result
655 :load-if (not (and (sc-is number signed-stack)
656 (sc-is result signed-stack)
657 (location= number result)))))
659 (:arg-types signed-num (:constant integer))
660 (:results (result :scs (signed-reg)
661 :load-if (not (and (sc-is number signed-stack)
662 (sc-is result signed-stack)
663 (location= number result)))))
664 (:result-types signed-num)
667 (cond ((and (= amount 1) (not (location= number result)))
668 (inst lea result (make-ea :dword :base number :index number)))
669 ((and (= amount 2) (not (location= number result)))
670 (inst lea result (make-ea :dword :index number :scale 4)))
671 ((and (= amount 3) (not (location= number result)))
672 (inst lea result (make-ea :dword :index number :scale 8)))
675 (cond ((plusp amount) (inst shl result amount))
676 (t (inst sar result (min 31 (- amount)))))))))
678 (define-vop (fast-ash-c/unsigned=>unsigned)
681 (:args (number :scs (unsigned-reg) :target result
682 :load-if (not (and (sc-is number unsigned-stack)
683 (sc-is result unsigned-stack)
684 (location= number result)))))
686 (:arg-types unsigned-num (:constant integer))
687 (:results (result :scs (unsigned-reg)
688 :load-if (not (and (sc-is number unsigned-stack)
689 (sc-is result unsigned-stack)
690 (location= number result)))))
691 (:result-types unsigned-num)
694 (cond ((and (= amount 1) (not (location= number result)))
695 (inst lea result (make-ea :dword :base number :index number)))
696 ((and (= amount 2) (not (location= number result)))
697 (inst lea result (make-ea :dword :index number :scale 4)))
698 ((and (= amount 3) (not (location= number result)))
699 (inst lea result (make-ea :dword :index number :scale 8)))
702 (cond ((< -32 amount 32)
703 ;; this code is used both in ASH and ASH-MOD32, so
706 (inst shl result amount)
707 (inst shr result (- amount))))
708 (t (if (sc-is result unsigned-reg)
709 (inst xor result result)
710 (inst mov result 0))))))))
712 (define-vop (fast-ash-left/signed=>signed)
714 (:args (number :scs (signed-reg) :target result
715 :load-if (not (and (sc-is number signed-stack)
716 (sc-is result signed-stack)
717 (location= number result))))
718 (amount :scs (unsigned-reg) :target ecx))
719 (:arg-types signed-num positive-fixnum)
720 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
721 (:results (result :scs (signed-reg) :from (:argument 0)
722 :load-if (not (and (sc-is number signed-stack)
723 (sc-is result signed-stack)
724 (location= number result)))))
725 (:result-types signed-num)
731 (inst shl result :cl)))
733 (define-vop (fast-ash-left/unsigned=>unsigned)
735 (:args (number :scs (unsigned-reg) :target result
736 :load-if (not (and (sc-is number unsigned-stack)
737 (sc-is result unsigned-stack)
738 (location= number result))))
739 (amount :scs (unsigned-reg) :target ecx))
740 (:arg-types unsigned-num positive-fixnum)
741 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
742 (:results (result :scs (unsigned-reg) :from (:argument 0)
743 :load-if (not (and (sc-is number unsigned-stack)
744 (sc-is result unsigned-stack)
745 (location= number result)))))
746 (:result-types unsigned-num)
752 (inst shl result :cl)))
754 (define-vop (fast-ash/signed=>signed)
757 (:args (number :scs (signed-reg) :target result)
758 (amount :scs (signed-reg) :target ecx))
759 (:arg-types signed-num signed-num)
760 (:results (result :scs (signed-reg) :from (:argument 0)))
761 (:result-types signed-num)
762 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
768 (inst jmp :ns positive)
774 (inst sar result :cl)
778 ;; The result-type ensures us that this shift will not overflow.
779 (inst shl result :cl)
783 (define-vop (fast-ash/unsigned=>unsigned)
786 (:args (number :scs (unsigned-reg) :target result)
787 (amount :scs (signed-reg) :target ecx))
788 (:arg-types unsigned-num signed-num)
789 (:results (result :scs (unsigned-reg) :from (:argument 0)))
790 (:result-types unsigned-num)
791 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
797 (inst jmp :ns positive)
801 (inst xor result result)
804 (inst shr result :cl)
808 ;; The result-type ensures us that this shift will not overflow.
809 (inst shl result :cl)
814 (define-vop (fast-%ash/right/unsigned)
815 (:translate %ash/right)
817 (:args (number :scs (unsigned-reg) :target result)
818 (amount :scs (unsigned-reg) :target ecx))
819 (:arg-types unsigned-num unsigned-num)
820 (:results (result :scs (unsigned-reg) :from (:argument 0)))
821 (:result-types unsigned-num)
822 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
826 (inst shr result :cl)))
829 (define-vop (fast-%ash/right/signed)
830 (:translate %ash/right)
832 (:args (number :scs (signed-reg) :target result)
833 (amount :scs (unsigned-reg) :target ecx))
834 (:arg-types signed-num unsigned-num)
835 (:results (result :scs (signed-reg) :from (:argument 0)))
836 (:result-types signed-num)
837 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
841 (inst sar result :cl)))
844 (define-vop (fast-%ash/right/fixnum)
845 (:translate %ash/right)
847 (:args (number :scs (any-reg) :target result)
848 (amount :scs (unsigned-reg) :target ecx))
849 (:arg-types tagged-num unsigned-num)
850 (:results (result :scs (any-reg) :from (:argument 0)))
851 (:result-types tagged-num)
852 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
856 (inst sar result :cl)
857 (inst and result (lognot fixnum-tag-mask))))
861 (defknown %lea (integer integer (member 1 2 4 8) (signed-byte 32))
863 (foldable flushable movable))
865 (defoptimizer (%lea derive-type) ((base index scale disp))
866 (when (and (constant-lvar-p scale)
867 (constant-lvar-p disp))
868 (let ((scale (lvar-value scale))
869 (disp (lvar-value disp))
870 (base-type (lvar-type base))
871 (index-type (lvar-type index)))
872 (when (and (numeric-type-p base-type)
873 (numeric-type-p index-type))
874 (let ((base-lo (numeric-type-low base-type))
875 (base-hi (numeric-type-high base-type))
876 (index-lo (numeric-type-low index-type))
877 (index-hi (numeric-type-high index-type)))
878 (make-numeric-type :class 'integer
880 :low (when (and base-lo index-lo)
881 (+ base-lo (* index-lo scale) disp))
882 :high (when (and base-hi index-hi)
883 (+ base-hi (* index-hi scale) disp))))))))
885 (defun %lea (base index scale disp)
886 (+ base (* index scale) disp))
890 (define-vop (%lea/unsigned=>unsigned)
893 (:args (base :scs (unsigned-reg))
894 (index :scs (unsigned-reg)))
896 (:arg-types unsigned-num unsigned-num
897 (:constant (member 1 2 4 8))
898 (:constant (signed-byte 32)))
899 (:results (r :scs (unsigned-reg)))
900 (:result-types unsigned-num)
902 (inst lea r (make-ea :dword :base base :index index
903 :scale scale :disp disp))))
905 (define-vop (%lea/signed=>signed)
908 (:args (base :scs (signed-reg))
909 (index :scs (signed-reg)))
911 (:arg-types signed-num signed-num
912 (:constant (member 1 2 4 8))
913 (:constant (signed-byte 32)))
914 (:results (r :scs (signed-reg)))
915 (:result-types signed-num)
917 (inst lea r (make-ea :dword :base base :index index
918 :scale scale :disp disp))))
920 (define-vop (%lea/fixnum=>fixnum)
923 (:args (base :scs (any-reg))
924 (index :scs (any-reg)))
926 (:arg-types tagged-num tagged-num
927 (:constant (member 1 2 4 8))
928 (:constant (signed-byte 32)))
929 (:results (r :scs (any-reg)))
930 (:result-types tagged-num)
932 (inst lea r (make-ea :dword :base base :index index
933 :scale scale :disp disp))))
935 ;;; FIXME: before making knowledge of this too public, it needs to be
936 ;;; fixed so that it's actually _faster_ than the non-CMOV version; at
937 ;;; least on my Celeron-XXX laptop, this version is marginally slower
938 ;;; than the above version with branches. -- CSR, 2003-09-04
939 (define-vop (fast-cmov-ash/unsigned=>unsigned)
942 (:args (number :scs (unsigned-reg) :target result)
943 (amount :scs (signed-reg) :target ecx))
944 (:arg-types unsigned-num signed-num)
945 (:results (result :scs (unsigned-reg) :from (:argument 0)))
946 (:result-types unsigned-num)
947 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
948 (:temporary (:sc any-reg :from (:eval 0) :to (:eval 1)) zero)
950 (:guard (member :cmov *backend-subfeatures*))
955 (inst jmp :ns positive)
958 (inst shr result :cl)
960 (inst cmov :nbe result zero)
964 ;; The result-type ensures us that this shift will not overflow.
965 (inst shl result :cl)
969 (define-vop (signed-byte-32-len)
970 (:translate integer-length)
971 (:note "inline (signed-byte 32) integer-length")
973 (:args (arg :scs (signed-reg) :target res))
974 (:arg-types signed-num)
975 (:results (res :scs (unsigned-reg)))
976 (:result-types unsigned-num)
979 (if (sc-is res unsigned-reg)
993 (define-vop (unsigned-byte-32-len)
994 (:translate integer-length)
995 (:note "inline (unsigned-byte 32) integer-length")
997 (:args (arg :scs (unsigned-reg)))
998 (:arg-types unsigned-num)
999 (:results (res :scs (unsigned-reg)))
1000 (:result-types unsigned-num)
1010 (define-vop (unsigned-byte-32-count)
1011 (:translate logcount)
1012 (:note "inline (unsigned-byte 32) logcount")
1013 (:policy :fast-safe)
1014 (:args (arg :scs (unsigned-reg) :target result))
1015 (:arg-types unsigned-num)
1016 (:results (result :scs (unsigned-reg)))
1017 (:result-types positive-fixnum)
1018 (:temporary (:sc unsigned-reg) temp)
1020 ;; See the comments below for how the algorithm works. The tricks
1021 ;; used can be found for example in AMD's software optimization
1022 ;; guide or at "http://www.hackersdelight.org/HDcode/pop.cc" in the
1024 ;; Calculate 2-bit sums. Note that the value of a two-digit binary
1025 ;; number is the sum of the right digit and twice the left digit.
1026 ;; Thus we can calculate the sum of the two digits by shifting the
1027 ;; left digit to the right position and doing a two-bit subtraction.
1028 ;; This subtraction will never create a borrow and thus can be made
1029 ;; on all 16 2-digit numbers at once.
1033 (inst and result #x55555555)
1034 (inst sub temp result)
1035 ;; Calculate 4-bit sums by straightforward shift, mask and add.
1036 ;; Note that we shift the source operand of the MOV and not its
1037 ;; destination so that the SHR and the MOV can execute in the same
1039 (inst mov result temp)
1041 (inst and result #x33333333)
1042 (inst and temp #x33333333)
1043 (inst add result temp)
1044 ;; Calculate 8-bit sums. Since each sum is at most 8, which fits
1045 ;; into 4 bits, we can apply the mask after the addition, saving one
1047 (inst mov temp result)
1049 (inst add result temp)
1050 (inst and result #x0f0f0f0f)
1051 ;; Calculate the two 16-bit sums and the 32-bit sum. No masking is
1052 ;; necessary inbetween since the final sum is at most 32 which fits
1054 (inst mov temp result)
1056 (inst add result temp)
1057 (inst mov temp result)
1058 (inst shr result 16)
1059 (inst add result temp)
1060 (inst and result #xff)))
1062 ;;;; binary conditional VOPs
1064 (define-vop (fast-conditional)
1068 (:policy :fast-safe))
1070 (define-vop (fast-conditional/fixnum fast-conditional)
1071 (:args (x :scs (any-reg)
1072 :load-if (not (and (sc-is x control-stack)
1073 (sc-is y any-reg))))
1074 (y :scs (any-reg control-stack)))
1075 (:arg-types tagged-num tagged-num)
1076 (:note "inline fixnum comparison"))
1078 (define-vop (fast-conditional-c/fixnum fast-conditional/fixnum)
1079 (:args (x :scs (any-reg control-stack)))
1080 (:arg-types tagged-num (:constant (signed-byte 30)))
1083 (define-vop (fast-conditional/signed fast-conditional)
1084 (:args (x :scs (signed-reg)
1085 :load-if (not (and (sc-is x signed-stack)
1086 (sc-is y signed-reg))))
1087 (y :scs (signed-reg signed-stack)))
1088 (:arg-types signed-num signed-num)
1089 (:note "inline (signed-byte 32) comparison"))
1091 (define-vop (fast-conditional-c/signed fast-conditional/signed)
1092 (:args (x :scs (signed-reg signed-stack)))
1093 (:arg-types signed-num (:constant (signed-byte 32)))
1096 (define-vop (fast-conditional/unsigned fast-conditional)
1097 (:args (x :scs (unsigned-reg)
1098 :load-if (not (and (sc-is x unsigned-stack)
1099 (sc-is y unsigned-reg))))
1100 (y :scs (unsigned-reg unsigned-stack)))
1101 (:arg-types unsigned-num unsigned-num)
1102 (:note "inline (unsigned-byte 32) comparison"))
1104 (define-vop (fast-conditional-c/unsigned fast-conditional/unsigned)
1105 (:args (x :scs (unsigned-reg unsigned-stack)))
1106 (:arg-types unsigned-num (:constant (unsigned-byte 32)))
1109 (macrolet ((define-logtest-vops ()
1111 ,@(loop for suffix in '(/fixnum -c/fixnum
1113 /unsigned -c/unsigned)
1114 for cost in '(4 3 6 5 6 5)
1116 `(define-vop (,(symbolicate "FAST-LOGTEST" suffix)
1117 ,(symbolicate "FAST-CONDITIONAL" suffix))
1118 (:translate logtest)
1121 (emit-optimized-test-inst x
1122 ,(if (eq suffix '-c/fixnum)
1125 (define-logtest-vops))
1127 (defknown %logbitp (integer unsigned-byte) boolean
1128 (movable foldable flushable always-translatable))
1130 ;;; only for constant folding within the compiler
1131 (defun %logbitp (integer index)
1132 (logbitp index integer))
1134 ;;; too much work to do the non-constant case (maybe?)
1135 (define-vop (fast-logbitp-c/fixnum fast-conditional-c/fixnum)
1136 (:translate %logbitp)
1138 (:arg-types tagged-num (:constant (integer 0 29)))
1140 (inst bt x (+ y n-fixnum-tag-bits))))
1142 (define-vop (fast-logbitp/signed fast-conditional/signed)
1143 (:args (x :scs (signed-reg signed-stack))
1144 (y :scs (signed-reg)))
1145 (:translate %logbitp)
1150 (define-vop (fast-logbitp-c/signed fast-conditional-c/signed)
1151 (:translate %logbitp)
1153 (:arg-types signed-num (:constant (integer 0 31)))
1157 (define-vop (fast-logbitp/unsigned fast-conditional/unsigned)
1158 (:args (x :scs (unsigned-reg unsigned-stack))
1159 (y :scs (unsigned-reg)))
1160 (:translate %logbitp)
1165 (define-vop (fast-logbitp-c/unsigned fast-conditional-c/unsigned)
1166 (:translate %logbitp)
1168 (:arg-types unsigned-num (:constant (integer 0 31)))
1172 (macrolet ((define-conditional-vop (tran cond unsigned)
1175 (lambda (suffix cost signed)
1176 `(define-vop (;; FIXME: These could be done more
1177 ;; cleanly with SYMBOLICATE.
1178 ,(intern (format nil "~:@(FAST-IF-~A~A~)"
1181 (format nil "~:@(FAST-CONDITIONAL~A~)"
1184 (:conditional ,(if signed
1188 (cond ((and (sc-is x any-reg signed-reg unsigned-reg)
1193 ,(if (eq suffix '-c/fixnum)
1196 '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned)
1198 '(t t t t nil nil)))))
1200 (define-conditional-vop < :l :b)
1201 (define-conditional-vop > :g :a))
1203 (define-vop (fast-if-eql/signed fast-conditional/signed)
1208 (define-vop (fast-if-eql-c/signed fast-conditional-c/signed)
1211 (cond ((and (sc-is x signed-reg) (zerop y))
1212 (inst test x x)) ; smaller instruction
1216 (define-vop (fast-if-eql/unsigned fast-conditional/unsigned)
1221 (define-vop (fast-if-eql-c/unsigned fast-conditional-c/unsigned)
1224 (cond ((and (sc-is x unsigned-reg) (zerop y))
1225 (inst test x x)) ; smaller instruction
1229 ;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a
1232 ;;; These versions specify a fixnum restriction on their first arg. We have
1233 ;;; also generic-eql/fixnum VOPs which are the same, but have no restriction on
1234 ;;; the first arg and a higher cost. The reason for doing this is to prevent
1235 ;;; fixnum specific operations from being used on word integers, spuriously
1236 ;;; consing the argument.
1238 (define-vop (fast-eql/fixnum fast-conditional)
1239 (:args (x :scs (any-reg)
1240 :load-if (not (and (sc-is x control-stack)
1241 (sc-is y any-reg))))
1242 (y :scs (any-reg control-stack)))
1243 (:arg-types tagged-num tagged-num)
1244 (:note "inline fixnum comparison")
1248 (define-vop (generic-eql/fixnum fast-eql/fixnum)
1249 (:args (x :scs (any-reg descriptor-reg)
1250 :load-if (not (and (sc-is x control-stack)
1251 (sc-is y any-reg))))
1252 (y :scs (any-reg control-stack)))
1253 (:arg-types * tagged-num)
1256 (define-vop (fast-eql-c/fixnum fast-conditional/fixnum)
1257 (:args (x :scs (any-reg control-stack)))
1258 (:arg-types tagged-num (:constant (signed-byte 30)))
1262 (cond ((and (sc-is x any-reg) (zerop y))
1263 (inst test x x)) ; smaller instruction
1265 (inst cmp x (fixnumize y))))))
1266 (define-vop (generic-eql-c/fixnum fast-eql-c/fixnum)
1267 (:args (x :scs (any-reg descriptor-reg control-stack)))
1268 (:arg-types * (:constant (signed-byte 30)))
1271 ;;;; 32-bit logical operations
1273 ;;; Only the lower 5 bits of the shift amount are significant.
1274 (define-vop (shift-towards-someplace)
1275 (:policy :fast-safe)
1276 (:args (num :scs (unsigned-reg) :target r)
1277 (amount :scs (signed-reg) :target ecx))
1278 (:arg-types unsigned-num tagged-num)
1279 (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx)
1280 (:results (r :scs (unsigned-reg) :from (:argument 0)))
1281 (:result-types unsigned-num))
1283 (define-vop (shift-towards-start shift-towards-someplace)
1284 (:translate shift-towards-start)
1285 (:note "SHIFT-TOWARDS-START")
1291 (define-vop (shift-towards-end shift-towards-someplace)
1292 (:translate shift-towards-end)
1293 (:note "SHIFT-TOWARDS-END")
1299 ;;;; Modular functions
1300 (defmacro define-mod-binop ((name prototype) function)
1301 `(define-vop (,name ,prototype)
1302 (:args (x :target r :scs (unsigned-reg signed-reg)
1303 :load-if (not (and (or (sc-is x unsigned-stack)
1304 (sc-is x signed-stack))
1305 (or (sc-is y unsigned-reg)
1306 (sc-is y signed-reg))
1307 (or (sc-is r unsigned-stack)
1308 (sc-is r signed-stack))
1310 (y :scs (unsigned-reg signed-reg unsigned-stack signed-stack)))
1311 (:arg-types untagged-num untagged-num)
1312 (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0)
1313 :load-if (not (and (or (sc-is x unsigned-stack)
1314 (sc-is x signed-stack))
1315 (or (sc-is y unsigned-reg)
1316 (sc-is y unsigned-reg))
1317 (or (sc-is r unsigned-stack)
1318 (sc-is r unsigned-stack))
1320 (:result-types unsigned-num)
1321 (:translate ,function)))
1322 (defmacro define-mod-binop-c ((name prototype) function)
1323 `(define-vop (,name ,prototype)
1324 (:args (x :target r :scs (unsigned-reg signed-reg)
1325 :load-if (not (and (or (sc-is x unsigned-stack)
1326 (sc-is x signed-stack))
1327 (or (sc-is r unsigned-stack)
1328 (sc-is r signed-stack))
1331 (:arg-types untagged-num (:constant (or (unsigned-byte 32) (signed-byte 32))))
1332 (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0)
1333 :load-if (not (and (or (sc-is x unsigned-stack)
1334 (sc-is x signed-stack))
1335 (or (sc-is r unsigned-stack)
1336 (sc-is r unsigned-stack))
1338 (:result-types unsigned-num)
1339 (:translate ,function)))
1341 (macrolet ((def (name -c-p)
1342 (let ((fun32 (intern (format nil "~S-MOD32" name)))
1343 (vopu (intern (format nil "FAST-~S/UNSIGNED=>UNSIGNED" name)))
1344 (vopcu (intern (format nil "FAST-~S-C/UNSIGNED=>UNSIGNED" name)))
1345 (vopf (intern (format nil "FAST-~S/FIXNUM=>FIXNUM" name)))
1346 (vopcf (intern (format nil "FAST-~S-C/FIXNUM=>FIXNUM" name)))
1347 (vop32u (intern (format nil "FAST-~S-MOD32/WORD=>UNSIGNED" name)))
1348 (vop32f (intern (format nil "FAST-~S-MOD32/FIXNUM=>FIXNUM" name)))
1349 (vop32cu (intern (format nil "FAST-~S-MOD32-C/WORD=>UNSIGNED" name)))
1350 (vop32cf (intern (format nil "FAST-~S-MOD32-C/FIXNUM=>FIXNUM" name)))
1351 (funfx (intern (format nil "~S-MODFX" name)))
1352 (vopfxf (intern (format nil "FAST-~S-MODFX/FIXNUM=>FIXNUM" name)))
1353 (vopfxcf (intern (format nil "FAST-~S-MODFX-C/FIXNUM=>FIXNUM" name))))
1355 (define-modular-fun ,fun32 (x y) ,name :untagged nil 32)
1356 (define-modular-fun ,funfx (x y) ,name :tagged t
1357 #.(- n-word-bits n-fixnum-tag-bits))
1358 (define-mod-binop (,vop32u ,vopu) ,fun32)
1359 (define-vop (,vop32f ,vopf) (:translate ,fun32))
1360 (define-vop (,vopfxf ,vopf) (:translate ,funfx))
1362 `((define-mod-binop-c (,vop32cu ,vopcu) ,fun32)
1363 (define-vop (,vopfxcf ,vopcf) (:translate ,funfx))))))))
1366 ;; (no -C variant as x86 MUL instruction doesn't take an immediate)
1369 (define-modular-fun %negate-mod32 (x) %negate :untagged nil 32)
1370 (define-vop (%negate-mod32)
1371 (:translate %negate-mod32)
1372 (:policy :fast-safe)
1373 (:args (x :scs (unsigned-reg) :target r))
1374 (:arg-types unsigned-num)
1375 (:results (r :scs (unsigned-reg)))
1376 (:result-types unsigned-num)
1381 (define-modular-fun %negate-modfx (x) %negate :tagged t #.(- n-word-bits
1383 (define-vop (%negate-modfx fast-negate/fixnum)
1384 (:translate %negate-modfx))
1386 (define-vop (fast-ash-left-mod32-c/unsigned=>unsigned
1387 fast-ash-c/unsigned=>unsigned)
1388 (:translate ash-left-mod32))
1390 (define-vop (fast-ash-left-mod32/unsigned=>unsigned
1391 fast-ash-left/unsigned=>unsigned))
1392 (deftransform ash-left-mod32 ((integer count)
1393 ((unsigned-byte 32) (unsigned-byte 5)))
1394 (when (sb!c::constant-lvar-p count)
1395 (sb!c::give-up-ir1-transform))
1396 '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count))
1398 (define-vop (fast-ash-left-modfx-c/fixnum=>fixnum
1399 fast-ash-c/fixnum=>fixnum)
1401 (:translate ash-left-modfx))
1403 (define-vop (fast-ash-left-modfx/fixnum=>fixnum
1404 fast-ash-left/fixnum=>fixnum))
1405 (deftransform ash-left-modfx ((integer count)
1406 (fixnum (unsigned-byte 5)))
1407 (when (sb!c::constant-lvar-p count)
1408 (sb!c::give-up-ir1-transform))
1409 '(%primitive fast-ash-left-modfx/fixnum=>fixnum integer count))
1413 (defknown sb!vm::%lea-mod32 (integer integer (member 1 2 4 8) (signed-byte 32))
1415 (foldable flushable movable))
1416 (defknown sb!vm::%lea-modfx (integer integer (member 1 2 4 8) (signed-byte 32))
1418 (foldable flushable movable))
1420 (define-modular-fun-optimizer %lea ((base index scale disp) :untagged nil :width width)
1421 (when (and (<= width 32)
1422 (constant-lvar-p scale)
1423 (constant-lvar-p disp))
1424 (cut-to-width base :untagged width nil)
1425 (cut-to-width index :untagged width nil)
1426 'sb!vm::%lea-mod32))
1427 (define-modular-fun-optimizer %lea ((base index scale disp) :tagged t :width width)
1428 (when (and (<= width (- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits))
1429 (constant-lvar-p scale)
1430 (constant-lvar-p disp))
1431 (cut-to-width base :tagged width t)
1432 (cut-to-width index :tagged width t)
1433 'sb!vm::%lea-modfx))
1437 (defun sb!vm::%lea-mod32 (base index scale disp)
1438 (ldb (byte 32 0) (%lea base index scale disp)))
1439 (defun sb!vm::%lea-modfx (base index scale disp)
1440 (mask-signed-field (- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits)
1441 (%lea base index scale disp))))
1444 (defun sb!vm::%lea-mod32 (base index scale disp)
1445 (let ((base (logand base #xffffffff))
1446 (index (logand index #xffffffff)))
1447 ;; can't use modular version of %LEA, as we only have VOPs for
1448 ;; constant SCALE and DISP.
1449 (ldb (byte 32 0) (+ base (* index scale) disp))))
1450 (defun sb!vm::%lea-modfx (base index scale disp)
1451 (let* ((fixnum-width (- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits))
1452 (base (mask-signed-field fixnum-width base))
1453 (index (mask-signed-field fixnum-width index)))
1454 ;; can't use modular version of %LEA, as we only have VOPs for
1455 ;; constant SCALE and DISP.
1456 (mask-signed-field fixnum-width (+ base (* index scale) disp)))))
1458 (in-package "SB!VM")
1460 (define-vop (%lea-mod32/unsigned=>unsigned
1461 %lea/unsigned=>unsigned)
1462 (:translate %lea-mod32))
1463 (define-vop (%lea-modfx/fixnum=>fixnum
1464 %lea/fixnum=>fixnum)
1465 (:translate %lea-modfx))
1467 ;;; logical operations
1468 (define-modular-fun lognot-mod32 (x) lognot :untagged nil 32)
1469 (define-vop (lognot-mod32/word=>unsigned)
1470 (:translate lognot-mod32)
1471 (:args (x :scs (unsigned-reg signed-reg unsigned-stack signed-stack) :target r
1472 :load-if (not (and (or (sc-is x unsigned-stack)
1473 (sc-is x signed-stack))
1474 (or (sc-is r unsigned-stack)
1475 (sc-is r signed-stack))
1477 (:arg-types unsigned-num)
1478 (:results (r :scs (unsigned-reg)
1479 :load-if (not (and (or (sc-is x unsigned-stack)
1480 (sc-is x signed-stack))
1481 (or (sc-is r unsigned-stack)
1482 (sc-is r signed-stack))
1483 (sc-is r unsigned-stack)
1485 (:result-types unsigned-num)
1486 (:policy :fast-safe)
1491 (define-source-transform logeqv (&rest args)
1492 (if (oddp (length args))
1494 `(lognot (logxor ,@args))))
1495 (define-source-transform logandc1 (x y)
1496 `(logand (lognot ,x) ,y))
1497 (define-source-transform logandc2 (x y)
1498 `(logand ,x (lognot ,y)))
1499 (define-source-transform logorc1 (x y)
1500 `(logior (lognot ,x) ,y))
1501 (define-source-transform logorc2 (x y)
1502 `(logior ,x (lognot ,y)))
1503 (define-source-transform lognor (x y)
1504 `(lognot (logior ,x ,y)))
1505 (define-source-transform lognand (x y)
1506 `(lognot (logand ,x ,y)))
1510 (define-vop (bignum-length get-header-data)
1511 (:translate sb!bignum:%bignum-length)
1512 (:policy :fast-safe))
1514 (define-vop (bignum-set-length set-header-data)
1515 (:translate sb!bignum:%bignum-set-length)
1516 (:policy :fast-safe))
1518 (define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag
1519 (unsigned-reg) unsigned-num sb!bignum:%bignum-ref)
1520 (define-full-reffer+offset bignum-ref-with-offset *
1521 bignum-digits-offset other-pointer-lowtag
1522 (unsigned-reg) unsigned-num sb!bignum:%bignum-ref-with-offset)
1523 (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag
1524 (unsigned-reg) unsigned-num sb!bignum:%bignum-set)
1526 (define-vop (digit-0-or-plus)
1527 (:translate sb!bignum:%digit-0-or-plusp)
1528 (:policy :fast-safe)
1529 (:args (digit :scs (unsigned-reg)))
1530 (:arg-types unsigned-num)
1533 (inst test digit digit)))
1536 ;;; For add and sub with carry the sc of carry argument is any-reg so
1537 ;;; that it may be passed as a fixnum or word and thus may be 0, 1, or
1538 ;;; 4. This is easy to deal with and may save a fixnum-word
1540 (define-vop (add-w/carry)
1541 (:translate sb!bignum:%add-with-carry)
1542 (:policy :fast-safe)
1543 (:args (a :scs (unsigned-reg) :target result)
1544 (b :scs (unsigned-reg unsigned-stack) :to :eval)
1545 (c :scs (any-reg) :target temp))
1546 (:arg-types unsigned-num unsigned-num positive-fixnum)
1547 (:temporary (:sc any-reg :from (:argument 2) :to :eval) temp)
1548 (:results (result :scs (unsigned-reg) :from (:argument 0))
1549 (carry :scs (unsigned-reg)))
1550 (:result-types unsigned-num positive-fixnum)
1554 (inst neg temp) ; Set the carry flag to 0 if c=0 else to 1
1557 (inst adc carry carry)))
1559 ;;; Note: the borrow is 1 for no borrow and 0 for a borrow, the opposite
1560 ;;; of the x86 convention.
1561 (define-vop (sub-w/borrow)
1562 (:translate sb!bignum:%subtract-with-borrow)
1563 (:policy :fast-safe)
1564 (:args (a :scs (unsigned-reg) :to :eval :target result)
1565 (b :scs (unsigned-reg unsigned-stack) :to :result)
1566 (c :scs (any-reg control-stack)))
1567 (:arg-types unsigned-num unsigned-num positive-fixnum)
1568 (:results (result :scs (unsigned-reg) :from :eval)
1569 (borrow :scs (unsigned-reg)))
1570 (:result-types unsigned-num positive-fixnum)
1572 (inst cmp c 1) ; Set the carry flag to 1 if c=0 else to 0
1576 (inst sbb borrow 0)))
1579 (define-vop (bignum-mult-and-add-3-arg)
1580 (:translate sb!bignum:%multiply-and-add)
1581 (:policy :fast-safe)
1582 (:args (x :scs (unsigned-reg) :target eax)
1583 (y :scs (unsigned-reg unsigned-stack))
1584 (carry-in :scs (unsigned-reg unsigned-stack)))
1585 (:arg-types unsigned-num unsigned-num unsigned-num)
1586 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1587 :to (:result 1) :target lo) eax)
1588 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1589 :to (:result 0) :target hi) edx)
1590 (:results (hi :scs (unsigned-reg))
1591 (lo :scs (unsigned-reg)))
1592 (:result-types unsigned-num unsigned-num)
1596 (inst add eax carry-in)
1601 (define-vop (bignum-mult-and-add-4-arg)
1602 (:translate sb!bignum:%multiply-and-add)
1603 (:policy :fast-safe)
1604 (:args (x :scs (unsigned-reg) :target eax)
1605 (y :scs (unsigned-reg unsigned-stack))
1606 (prev :scs (unsigned-reg unsigned-stack))
1607 (carry-in :scs (unsigned-reg unsigned-stack)))
1608 (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num)
1609 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1610 :to (:result 1) :target lo) eax)
1611 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1612 :to (:result 0) :target hi) edx)
1613 (:results (hi :scs (unsigned-reg))
1614 (lo :scs (unsigned-reg)))
1615 (:result-types unsigned-num unsigned-num)
1621 (inst add eax carry-in)
1627 (define-vop (bignum-mult)
1628 (:translate sb!bignum:%multiply)
1629 (:policy :fast-safe)
1630 (:args (x :scs (unsigned-reg) :target eax)
1631 (y :scs (unsigned-reg unsigned-stack)))
1632 (:arg-types unsigned-num unsigned-num)
1633 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)
1634 :to (:result 1) :target lo) eax)
1635 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1636 :to (:result 0) :target hi) edx)
1637 (:results (hi :scs (unsigned-reg))
1638 (lo :scs (unsigned-reg)))
1639 (:result-types unsigned-num unsigned-num)
1646 #!+multiply-high-vops
1648 (:translate sb!kernel:%multiply-high)
1649 (:policy :fast-safe)
1650 (:args (x :scs (unsigned-reg) :target eax)
1651 (y :scs (unsigned-reg unsigned-stack)))
1652 (:arg-types unsigned-num unsigned-num)
1653 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0))
1655 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1)
1656 :to (:result 0) :target hi) edx)
1657 (:results (hi :scs (unsigned-reg)))
1658 (:result-types unsigned-num)
1664 #!+multiply-high-vops
1665 (define-vop (mulhi/fx)
1666 (:translate sb!kernel:%multiply-high)
1667 (:policy :fast-safe)
1668 (:args (x :scs (any-reg) :target eax)
1669 (y :scs (unsigned-reg unsigned-stack)))
1670 (:arg-types positive-fixnum unsigned-num)
1671 (:temporary (:sc any-reg :offset eax-offset :from (:argument 0)) eax)
1672 (:temporary (:sc any-reg :offset edx-offset :from (:argument 1)
1673 :to (:result 0) :target hi) edx)
1674 (:results (hi :scs (any-reg)))
1675 (:result-types positive-fixnum)
1680 (inst and hi (lognot fixnum-tag-mask))))
1682 (define-vop (bignum-lognot lognot-mod32/word=>unsigned)
1683 (:translate sb!bignum:%lognot))
1685 (define-vop (fixnum-to-digit)
1686 (:translate sb!bignum:%fixnum-to-digit)
1687 (:policy :fast-safe)
1688 (:args (fixnum :scs (any-reg control-stack) :target digit))
1689 (:arg-types tagged-num)
1690 (:results (digit :scs (unsigned-reg)
1691 :load-if (not (and (sc-is fixnum control-stack)
1692 (sc-is digit unsigned-stack)
1693 (location= fixnum digit)))))
1694 (:result-types unsigned-num)
1697 (inst sar digit n-fixnum-tag-bits)))
1699 (define-vop (bignum-floor)
1700 (:translate sb!bignum:%bigfloor)
1701 (:policy :fast-safe)
1702 (:args (div-high :scs (unsigned-reg) :target edx)
1703 (div-low :scs (unsigned-reg) :target eax)
1704 (divisor :scs (unsigned-reg unsigned-stack)))
1705 (:arg-types unsigned-num unsigned-num unsigned-num)
1706 (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 1)
1707 :to (:result 0) :target quo) eax)
1708 (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 0)
1709 :to (:result 1) :target rem) edx)
1710 (:results (quo :scs (unsigned-reg))
1711 (rem :scs (unsigned-reg)))
1712 (:result-types unsigned-num unsigned-num)
1716 (inst div eax divisor)
1720 (define-vop (signify-digit)
1721 (:translate sb!bignum:%fixnum-digit-with-correct-sign)
1722 (:policy :fast-safe)
1723 (:args (digit :scs (unsigned-reg unsigned-stack) :target res))
1724 (:arg-types unsigned-num)
1725 (:results (res :scs (any-reg signed-reg)
1726 :load-if (not (and (sc-is digit unsigned-stack)
1727 (sc-is res control-stack signed-stack)
1728 (location= digit res)))))
1729 (:result-types signed-num)
1732 (when (sc-is res any-reg control-stack)
1733 (inst shl res n-fixnum-tag-bits))))
1735 (define-vop (digit-ashr)
1736 (:translate sb!bignum:%ashr)
1737 (:policy :fast-safe)
1738 (:args (digit :scs (unsigned-reg unsigned-stack) :target result)
1739 (count :scs (unsigned-reg) :target ecx))
1740 (:arg-types unsigned-num positive-fixnum)
1741 (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx)
1742 (:results (result :scs (unsigned-reg) :from (:argument 0)
1743 :load-if (not (and (sc-is result unsigned-stack)
1744 (location= digit result)))))
1745 (:result-types unsigned-num)
1749 (inst sar result :cl)))
1751 (define-vop (digit-ashr/c)
1752 (:translate sb!bignum:%ashr)
1753 (:policy :fast-safe)
1754 (:args (digit :scs (unsigned-reg unsigned-stack) :target result))
1755 (:arg-types unsigned-num (:constant (integer 0 31)))
1757 (:results (result :scs (unsigned-reg) :from (:argument 0)
1758 :load-if (not (and (sc-is result unsigned-stack)
1759 (location= digit result)))))
1760 (:result-types unsigned-num)
1763 (inst sar result count)))
1765 (define-vop (digit-lshr digit-ashr)
1766 (:translate sb!bignum:%digit-logical-shift-right)
1770 (inst shr result :cl)))
1772 (define-vop (digit-ashl digit-ashr)
1773 (:translate sb!bignum:%ashl)
1777 (inst shl result :cl)))
1779 ;;;; static functions
1781 (define-static-fun two-arg-/ (x y) :translate /)
1783 (define-static-fun two-arg-gcd (x y) :translate gcd)
1784 (define-static-fun two-arg-lcm (x y) :translate lcm)
1786 (define-static-fun two-arg-and (x y) :translate logand)
1787 (define-static-fun two-arg-ior (x y) :translate logior)
1788 (define-static-fun two-arg-xor (x y) :translate logxor)
1791 ;;; Support for the Mersenne Twister, MT19937, random number generator
1792 ;;; due to Matsumoto and Nishimura.
1794 ;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
1795 ;;; 623-dimensionally equidistributed uniform pseudorandom number
1796 ;;; generator.", ACM Transactions on Modeling and Computer Simulation,
1797 ;;; 1997, to appear.
1800 ;;; 0-1: Constant matrix A. [0, #x9908b0df] (not used here)
1801 ;;; 2: Index; init. to 1.
1803 (defknown random-mt19937 ((simple-array (unsigned-byte 32) (*)))
1804 (unsigned-byte 32) ())
1805 (define-vop (random-mt19937)
1806 (:policy :fast-safe)
1807 (:translate random-mt19937)
1808 (:args (state :scs (descriptor-reg) :to :result))
1809 (:arg-types simple-array-unsigned-byte-32)
1810 (:temporary (:sc unsigned-reg :from (:eval 0) :to :result) k)
1811 (:temporary (:sc unsigned-reg :offset eax-offset
1812 :from (:eval 0) :to :result) tmp)
1813 (:results (y :scs (unsigned-reg) :from (:eval 0)))
1814 (:result-types unsigned-num)
1816 (loadw k state (+ 2 vector-data-offset) other-pointer-lowtag)
1818 (inst jmp :ne no-update)
1819 (inst mov tmp state) ; The state is passed in EAX.
1820 (inst call (make-fixup 'random-mt19937-update :assembly-routine))
1821 ;; Restore k, and set to 0.
1825 (inst mov y (make-ea-for-vector-data state :index k :offset 3))
1828 (inst xor y (make-ea-for-vector-data state :index k :offset 3))
1829 ;; y ^= (y << 7) & #x9d2c5680
1833 (storew k state (+ 2 vector-data-offset) other-pointer-lowtag)
1834 (inst and tmp #x9d2c5680)
1836 ;; y ^= (y << 15) & #xefc60000
1839 (inst and tmp #xefc60000)
1848 (defun mask-result (class width result)
1851 `(logand ,result ,(1- (ash 1 width))))
1853 `(mask-signed-field ,width ,result))))
1855 ;;; This is essentially a straight implementation of the algorithm in
1856 ;;; "Strength Reduction of Multiplications by Integer Constants",
1857 ;;; Youfeng Wu, ACM SIGPLAN Notices, Vol. 30, No.2, February 1995.
1858 (defun basic-decompose-multiplication (class width arg num n-bits condensed)
1859 (case (aref condensed 0)
1861 (let ((tmp (min 3 (aref condensed 1))))
1862 (decf (aref condensed 1) tmp)
1863 (mask-result class width
1865 ,(decompose-multiplication class width
1866 arg (ash (1- num) (- tmp)) (1- n-bits) (subseq condensed 1))
1869 (let ((r0 (aref condensed 0)))
1870 (incf (aref condensed 1) r0)
1871 (mask-result class width
1872 `(%lea ,(decompose-multiplication class width
1873 arg (- num (ash 1 r0)) (1- n-bits) (subseq condensed 1))
1876 (t (let ((r0 (aref condensed 0)))
1877 (setf (aref condensed 0) 0)
1878 (mask-result class width
1879 `(ash ,(decompose-multiplication class width
1880 arg (ash num (- r0)) n-bits condensed)
1883 (defun decompose-multiplication (class width arg num n-bits condensed)
1888 (mask-result class width `(ash ,arg ,(1- (integer-length num)))))
1889 ((let ((max 0) (end 0))
1890 (loop for i from 2 to (length condensed)
1891 for j = (reduce #'+ (subseq condensed 0 i))
1892 when (and (> (- (* 2 i) 3 j) max)
1893 (< (+ (ash 1 (1+ j))
1894 (ash (ldb (byte (- 32 (1+ j)) (1+ j)) num)
1897 do (setq max (- (* 2 i) 3 j)
1900 (let ((j (reduce #'+ (subseq condensed 0 end))))
1901 (let ((n2 (+ (ash 1 (1+ j))
1902 (ash (ldb (byte (- 32 (1+ j)) (1+ j)) num) (1+ j))))
1903 (n1 (1+ (ldb (byte (1+ j) 0) (lognot num)))))
1904 (mask-result class width
1905 `(- ,(optimize-multiply class width arg n2)
1906 ,(optimize-multiply class width arg n1))))))))
1907 ((dolist (i '(9 5 3))
1908 (when (integerp (/ num i))
1909 (when (< (logcount (/ num i)) (logcount num))
1911 (return `(let ((,x ,(optimize-multiply class width arg (/ num i))))
1912 ,(mask-result class width
1913 `(%lea ,x ,x (1- ,i) 0)))))))))
1914 (t (basic-decompose-multiplication class width arg num n-bits condensed))))
1916 (defun optimize-multiply (class width arg x)
1917 (let* ((n-bits (logcount x))
1918 (condensed (make-array n-bits)))
1919 (let ((count 0) (bit 0))
1921 (cond ((logbitp i x)
1922 (setf (aref condensed bit) count)
1926 (decompose-multiplication class width arg x n-bits condensed)))
1928 (defun *-transformer (class width y)
1930 ((= y (ash 1 (integer-length y)))
1931 ;; there's a generic transform for y = 2^k
1932 (give-up-ir1-transform))
1933 ((member y '(3 5 9))
1934 ;; we can do these multiplications directly using LEA
1935 `(%lea x x ,(1- y) 0))
1936 ((member :pentium4 *backend-subfeatures*)
1937 ;; the pentium4's multiply unit is reportedly very good
1938 (give-up-ir1-transform))
1939 ;; FIXME: should make this more fine-grained. If nothing else,
1940 ;; there should probably be a cutoff of about 9 instructions on
1941 ;; pentium-class machines.
1942 (t (optimize-multiply class width 'x y))))
1944 (deftransform * ((x y)
1945 ((unsigned-byte 32) (constant-arg (unsigned-byte 32)))
1947 "recode as leas, shifts and adds"
1948 (let ((y (lvar-value y)))
1949 (*-transformer :unsigned 32 y)))
1950 (deftransform sb!vm::*-mod32
1951 ((x y) ((unsigned-byte 32) (constant-arg (unsigned-byte 32)))
1953 "recode as leas, shifts and adds"
1954 (let ((y (lvar-value y)))
1955 (*-transformer :unsigned 32 y)))
1957 (deftransform * ((x y)
1958 (fixnum (constant-arg (unsigned-byte 32)))
1960 "recode as leas, shifts and adds"
1961 (let ((y (lvar-value y)))
1962 (*-transformer :signed (- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits) y)))
1963 (deftransform sb!vm::*-modfx
1964 ((x y) (fixnum (constant-arg (unsigned-byte 32)))
1966 "recode as leas, shifts and adds"
1967 (let ((y (lvar-value y)))
1968 (*-transformer :signed (- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits) y)))
1970 ;;; FIXME: we should also be able to write an optimizer or two to
1971 ;;; convert (+ (* x 2) 17), (- (* x 9) 5) to a %LEA.