1 ;;;; floating point support 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.
14 (macrolet ((ea-for-xf-desc (tn slot)
17 :disp (- (* ,slot n-word-bytes)
18 other-pointer-lowtag))))
19 (defun ea-for-df-desc (tn)
20 (ea-for-xf-desc tn double-float-value-slot))
22 (defun ea-for-csf-data-desc (tn)
23 (ea-for-xf-desc tn complex-single-float-data-slot))
24 (defun ea-for-csf-real-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-data-slot))
26 (defun ea-for-csf-imag-desc (tn)
27 (ea-for-xf-desc tn (+ complex-single-float-data-slot 1/2)))
29 (defun ea-for-cdf-data-desc (tn)
30 (ea-for-xf-desc tn complex-double-float-real-slot))
31 (defun ea-for-cdf-real-desc (tn)
32 (ea-for-xf-desc tn complex-double-float-real-slot))
33 (defun ea-for-cdf-imag-desc (tn)
34 (ea-for-xf-desc tn complex-double-float-imag-slot)))
36 (macrolet ((ea-for-xf-stack (tn kind)
37 (declare (ignore kind))
40 :disp (frame-byte-offset (tn-offset ,tn)))))
41 (defun ea-for-sf-stack (tn)
42 (ea-for-xf-stack tn :single))
43 (defun ea-for-df-stack (tn)
44 (ea-for-xf-stack tn :double)))
46 ;;; complex float stack EAs
47 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
50 :disp (frame-byte-offset
52 (cond ((= (tn-offset ,base) rsp-offset)
64 (defun ea-for-csf-data-stack (tn &optional (base rbp-tn))
65 (ea-for-cxf-stack tn :single :real base))
66 (defun ea-for-csf-real-stack (tn &optional (base rbp-tn))
67 (ea-for-cxf-stack tn :single :real base))
68 (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn))
69 (ea-for-cxf-stack tn :single :imag base))
71 (defun ea-for-cdf-data-stack (tn &optional (base rbp-tn))
72 (ea-for-cxf-stack tn :double :real base))
73 (defun ea-for-cdf-real-stack (tn &optional (base rbp-tn))
74 (ea-for-cxf-stack tn :double :real base))
75 (defun ea-for-cdf-imag-stack (tn &optional (base rbp-tn))
76 (ea-for-cxf-stack tn :double :imag base)))
80 ;;; X is source, Y is destination.
82 (define-move-fun (load-fp-zero 1) (vop x y)
83 ((fp-single-zero) (single-reg)
84 (fp-double-zero) (double-reg)
85 (fp-complex-single-zero) (complex-single-reg)
86 (fp-complex-double-zero) (complex-double-reg))
89 ((single-reg complex-single-reg) (inst xorps y y))
90 ((double-reg complex-double-reg) (inst xorpd y y))))
92 (define-move-fun (load-fp-immediate 1) (vop x y)
93 ((fp-single-immediate) (single-reg)
94 (fp-double-immediate) (double-reg)
95 (fp-complex-single-immediate) (complex-single-reg)
96 (fp-complex-double-immediate) (complex-double-reg))
97 (let ((x (register-inline-constant (tn-value x))))
99 (single-reg (inst movss y x))
100 (double-reg (inst movsd y x))
101 (complex-single-reg (inst movq y x))
102 (complex-double-reg (inst movapd y x)))))
104 (define-move-fun (load-single 2) (vop x y)
105 ((single-stack) (single-reg))
106 (inst movss y (ea-for-sf-stack x)))
108 (define-move-fun (store-single 2) (vop x y)
109 ((single-reg) (single-stack))
110 (inst movss (ea-for-sf-stack y) x))
112 (define-move-fun (load-double 2) (vop x y)
113 ((double-stack) (double-reg))
114 (inst movsd y (ea-for-df-stack x)))
116 (define-move-fun (store-double 2) (vop x y)
117 ((double-reg) (double-stack))
118 (inst movsd (ea-for-df-stack y) x))
120 (eval-when (:compile-toplevel :execute)
121 (setf *read-default-float-format* 'single-float))
123 ;;;; complex float move functions
125 ;;; X is source, Y is destination.
126 (define-move-fun (load-complex-single 2) (vop x y)
127 ((complex-single-stack) (complex-single-reg))
128 (inst movq y (ea-for-csf-data-stack x)))
130 (define-move-fun (store-complex-single 2) (vop x y)
131 ((complex-single-reg) (complex-single-stack))
132 (inst movq (ea-for-csf-data-stack y) x))
134 (define-move-fun (load-complex-double 2) (vop x y)
135 ((complex-double-stack) (complex-double-reg))
136 (inst movupd y (ea-for-cdf-data-stack x)))
138 (define-move-fun (store-complex-double 2) (vop x y)
139 ((complex-double-reg) (complex-double-stack))
140 (inst movupd (ea-for-cdf-data-stack y) x))
144 ;;; float register to register moves
145 (macrolet ((frob (vop sc)
150 :load-if (not (location= x y))))
151 (:results (y :scs (,sc)
152 :load-if (not (location= x y))))
156 (define-move-vop ,vop :move (,sc) (,sc)))))
157 (frob single-move single-reg)
158 (frob double-move double-reg)
159 (frob complex-single-move complex-single-reg)
160 (frob complex-double-move complex-double-reg))
163 ;;; Move from float to a descriptor reg. allocating a new float
164 ;;; object in the process.
165 (define-vop (move-from-single)
166 (:args (x :scs (single-reg) :to :save))
167 (:results (y :scs (descriptor-reg)))
168 (:note "float to pointer coercion")
172 (inst or y single-float-widetag)))
174 (define-move-vop move-from-single :move
175 (single-reg) (descriptor-reg))
177 (define-vop (move-from-double)
178 (:args (x :scs (double-reg) :to :save))
179 (:results (y :scs (descriptor-reg)))
181 (:note "float to pointer coercion")
183 (with-fixed-allocation (y
187 (inst movsd (ea-for-df-desc y) x))))
188 (define-move-vop move-from-double :move
189 (double-reg) (descriptor-reg))
191 ;;; Move from a descriptor to a float register.
192 (define-vop (move-to-single-reg)
193 (:args (x :scs (descriptor-reg) :target tmp
194 :load-if (not (sc-is x control-stack))))
195 (:temporary (:sc unsigned-reg :from :argument :to :result) tmp)
196 (:results (y :scs (single-reg)))
197 (:note "pointer to float coercion")
205 ;; When the single-float descriptor is in memory, the untagging
206 ;; is done in the target XMM register. This is faster than going
207 ;; through a general-purpose register and the code is smaller.
209 (inst shufps y y #4r3331)))))
210 (define-move-vop move-to-single-reg :move (descriptor-reg) (single-reg))
212 ;;; Move from a descriptor to a float stack.
213 (define-vop (move-to-single-stack)
214 (:args (x :scs (descriptor-reg) :target tmp))
215 (:temporary (:sc unsigned-reg :from :argument :to :result) tmp)
216 (:results (y :scs (single-stack)))
217 (:note "pointer to float coercion")
221 (let ((slot (make-ea :dword :base rbp-tn
222 :disp (frame-byte-offset (tn-offset y)))))
223 (inst mov slot (reg-in-size tmp :dword)))))
224 (define-move-vop move-to-single-stack :move (descriptor-reg) (single-stack))
226 (define-vop (move-to-double)
227 (:args (x :scs (descriptor-reg)))
228 (:results (y :scs (double-reg)))
229 (:note "pointer to float coercion")
231 (inst movsd y (ea-for-df-desc x))))
232 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
235 ;;; Move from complex float to a descriptor reg. allocating a new
236 ;;; complex float object in the process.
237 (define-vop (move-from-complex-single)
238 (:args (x :scs (complex-single-reg) :to :save))
239 (:results (y :scs (descriptor-reg)))
241 (:note "complex float to pointer coercion")
243 (with-fixed-allocation (y
244 complex-single-float-widetag
245 complex-single-float-size
247 (inst movq (ea-for-csf-data-desc y) x))))
248 (define-move-vop move-from-complex-single :move
249 (complex-single-reg) (descriptor-reg))
251 (define-vop (move-from-complex-double)
252 (:args (x :scs (complex-double-reg) :to :save))
253 (:results (y :scs (descriptor-reg)))
255 (:note "complex float to pointer coercion")
257 (with-fixed-allocation (y
258 complex-double-float-widetag
259 complex-double-float-size
261 (inst movapd (ea-for-cdf-data-desc y) x))))
262 (define-move-vop move-from-complex-double :move
263 (complex-double-reg) (descriptor-reg))
265 ;;; Move from a descriptor to a complex float register.
266 (macrolet ((frob (name sc format)
269 (:args (x :scs (descriptor-reg)))
270 (:results (y :scs (,sc)))
271 (:note "pointer to complex float coercion")
275 '(inst movq y (ea-for-csf-data-desc x)))
277 '(inst movapd y (ea-for-cdf-data-desc x))))))
278 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
279 (frob move-to-complex-single complex-single-reg :single)
280 (frob move-to-complex-double complex-double-reg :double))
282 ;;;; the move argument vops
284 ;;;; Note these are also used to stuff fp numbers onto the c-call
285 ;;;; stack so the order is different than the lisp-stack.
287 ;;; the general MOVE-ARG VOP
288 (macrolet ((frob (name sc stack-sc format)
291 (:args (x :scs (,sc) :target y)
293 :load-if (not (sc-is y ,sc))))
295 (:note "float argument move")
296 (:generator ,(case format (:single 2) (:double 3) )
301 (if (= (tn-offset fp) esp-offset)
302 (let* ((offset (* (tn-offset y) n-word-bytes))
303 (ea (make-ea :dword :base fp :disp offset)))
305 (:single '((inst movss ea x)))
306 (:double '((inst movsd ea x)))))
309 :disp (frame-byte-offset (tn-offset y)))))
311 (:single '((inst movss ea x)))
312 (:double '((inst movsd ea x))))))))))
313 (define-move-vop ,name :move-arg
314 (,sc descriptor-reg) (,sc)))))
315 (frob move-single-float-arg single-reg single-stack :single)
316 (frob move-double-float-arg double-reg double-stack :double))
318 ;;;; complex float MOVE-ARG VOP
319 (macrolet ((frob (name sc stack-sc format)
322 (:args (x :scs (,sc) :target y)
324 :load-if (not (sc-is y ,sc))))
326 (:note "complex float argument move")
327 (:generator ,(ecase format (:single 2) (:double 3))
334 '(inst movq (ea-for-csf-data-stack y fp) x))
336 '(inst movupd (ea-for-cdf-data-stack y fp) x)))))))
337 (define-move-vop ,name :move-arg
338 (,sc descriptor-reg) (,sc)))))
339 (frob move-complex-single-float-arg
340 complex-single-reg complex-single-stack :single)
341 (frob move-complex-double-float-arg
342 complex-double-reg complex-double-stack :double))
344 (define-move-vop move-arg :move-arg
345 (single-reg double-reg
346 complex-single-reg complex-double-reg)
352 (define-vop (float-op)
356 (:note "inline float arithmetic")
358 (:save-p :compute-only))
360 (macrolet ((frob (name comm-name sc constant-sc ptype)
362 (define-vop (,name float-op)
363 (:args (x :scs (,sc ,constant-sc)
365 :load-if (not (sc-is x ,constant-sc)))
366 (y :scs (,sc ,constant-sc)
367 :load-if (not (sc-is y ,constant-sc))))
368 (:results (r :scs (,sc)))
369 (:arg-types ,ptype ,ptype)
370 (:result-types ,ptype))
371 (define-vop (,comm-name float-op)
372 (:args (x :scs (,sc ,constant-sc)
374 :load-if (not (sc-is x ,constant-sc)))
375 (y :scs (,sc ,constant-sc)
377 :load-if (not (sc-is y ,constant-sc))))
378 (:results (r :scs (,sc)))
379 (:arg-types ,ptype ,ptype)
380 (:result-types ,ptype)))))
381 (frob single-float-op single-float-comm-op
382 single-reg fp-single-immediate single-float)
383 (frob double-float-op double-float-comm-op
384 double-reg fp-double-immediate double-float)
385 (frob complex-single-float-op complex-single-float-comm-op
386 complex-single-reg fp-complex-single-immediate
387 complex-single-float)
388 (frob complex-double-float-op complex-double-float-comm-op
389 complex-double-reg fp-complex-double-immediate
390 complex-double-float))
392 (macrolet ((generate (opinst commutative constant-sc load-inst)
393 `(flet ((get-constant (tn)
394 (register-inline-constant
395 ,@(and (eq constant-sc 'fp-single-immediate)
398 (declare (ignorable #'get-constant))
401 (when (sc-is y ,constant-sc)
402 (setf y (get-constant y)))
404 ((and ,commutative (location= y r))
405 (when (sc-is x ,constant-sc)
406 (setf x (get-constant x)))
408 ((not (location= r y))
409 (if (sc-is x ,constant-sc)
410 (inst ,load-inst r (get-constant x))
412 (when (sc-is y ,constant-sc)
413 (setf y (get-constant y)))
416 (if (sc-is x ,constant-sc)
417 (inst ,load-inst tmp (get-constant x))
421 (frob (op sinst sname scost dinst dname dcost commutative
422 &optional csinst csname cscost cdinst cdname cdcost)
424 (define-vop (,sname ,(if commutative
425 'single-float-comm-op
428 (:temporary (:sc single-reg) tmp)
430 (generate ,sinst ,commutative fp-single-immediate movss)))
431 (define-vop (,dname ,(if commutative
432 'double-float-comm-op
435 (:temporary (:sc double-reg) tmp)
437 (generate ,dinst ,commutative fp-double-immediate movsd)))
439 `(define-vop (,csname
441 'complex-single-float-comm-op
442 'complex-single-float-op))
444 (:temporary (:sc complex-single-reg) tmp)
446 (generate ,csinst ,commutative
447 fp-complex-single-immediate movq))))
449 `(define-vop (,cdname
451 'complex-double-float-comm-op
452 'complex-double-float-op))
454 (:temporary (:sc complex-double-reg) tmp)
456 (generate ,cdinst ,commutative
457 fp-complex-double-immediate movapd)))))))
458 (frob + addss +/single-float 2 addsd +/double-float 2 t
459 addps +/complex-single-float 3 addpd +/complex-double-float 3)
460 (frob - subss -/single-float 2 subsd -/double-float 2 nil
461 subps -/complex-single-float 3 subpd -/complex-double-float 3)
462 (frob * mulss */single-float 4 mulsd */double-float 5 t)
463 (frob / divss //single-float 12 divsd //double-float 19 nil))
465 (macrolet ((frob (op cost commutativep
466 duplicate-inst op-inst real-move-inst complex-move-inst
467 real-sc real-constant-sc real-type
468 complex-sc complex-constant-sc complex-type
469 real-complex-name complex-real-name)
470 (cond ((not duplicate-inst) ; simple case
471 `(flet ((load-into (r x)
474 (inst ,real-move-inst r
475 (register-inline-constant (tn-value x))))
476 (,complex-constant-sc
477 (inst ,complex-move-inst r
478 (register-inline-constant (tn-value x))))
480 ,(when real-complex-name
481 `(define-vop (,real-complex-name float-op)
483 (:args (x :scs (,real-sc ,real-constant-sc)
485 :load-if (not (sc-is x ,real-constant-sc)))
486 (y :scs (,complex-sc ,complex-constant-sc)
487 ,@(when commutativep '(:target r))
488 :load-if (not (sc-is y ,complex-constant-sc))))
489 (:arg-types ,real-type ,complex-type)
490 (:results (r :scs (,complex-sc)
491 ,@(unless commutativep '(:from (:argument 0)))))
492 (:result-types ,complex-type)
495 `(when (location= y r)
498 (when (sc-is y ,real-constant-sc ,complex-constant-sc)
499 (setf y (register-inline-constant
500 :aligned (tn-value y))))
501 (inst ,op-inst r y))))
503 ,(when complex-real-name
504 `(define-vop (,complex-real-name float-op)
506 (:args (x :scs (,complex-sc ,complex-constant-sc)
508 :load-if (not (sc-is x ,complex-constant-sc)))
509 (y :scs (,real-sc ,real-constant-sc)
510 ,@(when commutativep '(:target r))
511 :load-if (not (sc-is y ,real-constant-sc))))
512 (:arg-types ,complex-type ,real-type)
513 (:results (r :scs (,complex-sc)
514 ,@(unless commutativep '(:from (:argument 0)))))
515 (:result-types ,complex-type)
518 `(when (location= y r)
521 (when (sc-is y ,real-constant-sc ,complex-constant-sc)
522 (setf y (register-inline-constant
523 :aligned (tn-value y))))
524 (inst ,op-inst r y))))))
525 (commutativep ; must duplicate, but commutative
527 ,(when real-complex-name
528 `(define-vop (,real-complex-name float-op)
530 (:args (x :scs (,real-sc ,real-constant-sc)
532 :load-if (not (sc-is x ,real-constant-sc)))
533 (y :scs (,complex-sc ,complex-constant-sc)
536 :load-if (not (sc-is y ,complex-constant-sc))))
537 (:arg-types ,real-type ,complex-type)
538 (:temporary (:sc ,complex-sc :target r
542 (:results (r :scs (,complex-sc)))
543 (:result-types ,complex-type)
545 (if (sc-is x ,real-constant-sc)
546 (inst ,complex-move-inst dup
547 (register-inline-constant
548 (complex (tn-value x) (tn-value x))))
552 (when (location= dup r)
554 (if (sc-is y ,complex-constant-sc)
555 (inst ,complex-move-inst r
556 (register-inline-constant (tn-value y)))
558 (when (sc-is dup ,complex-constant-sc)
559 (setf dup (register-inline-constant
560 :aligned (tn-value dup))))
561 (inst ,op-inst r dup))))
563 ,(when complex-real-name
564 `(define-vop (,complex-real-name float-op)
566 (:args (x :scs (,complex-sc ,complex-constant-sc)
569 :load-if (not (sc-is x ,complex-constant-sc)))
570 (y :scs (,real-sc ,real-constant-sc)
572 :load-if (not (sc-is y ,real-constant-sc))))
573 (:arg-types ,complex-type ,real-type)
574 (:temporary (:sc ,complex-sc :target r
578 (:results (r :scs (,complex-sc)))
579 (:result-types ,complex-type)
581 (if (sc-is y ,real-constant-sc)
582 (inst ,complex-move-inst dup
583 (register-inline-constant
584 (complex (tn-value y) (tn-value y))))
587 (when (location= dup r)
589 (if (sc-is x ,complex-constant-sc)
590 (inst ,complex-move-inst r
591 (register-inline-constant (tn-value x)))
593 (when (sc-is dup ,complex-constant-sc)
594 (setf dup (register-inline-constant
595 :aligned (tn-value dup))))
596 (inst ,op-inst r dup))))))
597 (t ; duplicate, not commutative
599 ,(when real-complex-name
600 `(define-vop (,real-complex-name float-op)
602 (:args (x :scs (,real-sc ,real-constant-sc)
604 :load-if (not (sc-is x ,real-constant-sc)))
605 (y :scs (,complex-sc ,complex-constant-sc)
607 :load-if (not (sc-is y ,complex-constant-sc))))
608 (:arg-types ,real-type ,complex-type)
609 (:results (r :scs (,complex-sc) :from (:argument 0)))
610 (:result-types ,complex-type)
612 (if (sc-is x ,real-constant-sc)
613 (inst ,complex-move-inst dup
614 (register-inline-constant
615 (complex (tn-value x) (tn-value x))))
619 (when (sc-is y ,complex-constant-sc)
620 (setf y (register-inline-constant
621 :aligned (tn-value y))))
622 (inst ,op-inst r y))))
624 ,(when complex-real-name
625 `(define-vop (,complex-real-name float-op)
627 (:args (x :scs (,complex-sc)
630 (y :scs (,real-sc ,real-constant-sc)
632 :load-if (not (sc-is y ,complex-constant-sc))))
633 (:arg-types ,complex-type ,real-type)
634 (:temporary (:sc ,complex-sc :from (:argument 1))
636 (:results (r :scs (,complex-sc) :from :eval))
637 (:result-types ,complex-type)
639 (if (sc-is y ,real-constant-sc)
640 (setf dup (register-inline-constant
641 :aligned (complex (tn-value y)
646 (inst ,op-inst r dup))))))))
647 (def-real-complex-op (op commutativep duplicatep
648 single-inst single-real-complex-name single-complex-real-name single-cost
649 double-inst double-real-complex-name double-complex-real-name double-cost)
651 (frob ,op ,single-cost ,commutativep
655 (inst unpcklps dup dup)))
656 ,single-inst movss movq
657 single-reg fp-single-immediate single-float
658 complex-single-reg fp-complex-single-immediate complex-single-float
659 ,single-real-complex-name ,single-complex-real-name)
660 (frob ,op ,double-cost ,commutativep
664 (inst unpcklpd dup dup)))
665 ,double-inst movsd movapd
666 double-reg fp-double-immediate double-float
667 complex-double-reg fp-complex-double-immediate complex-double-float
668 ,double-real-complex-name ,double-complex-real-name))))
669 (def-real-complex-op + t nil
670 addps +/real-complex-single-float +/complex-real-single-float 3
671 addpd +/real-complex-double-float +/complex-real-double-float 4)
672 (def-real-complex-op - nil nil
673 subps -/real-complex-single-float -/complex-real-single-float 3
674 subpd -/real-complex-double-float -/complex-real-double-float 4)
675 (def-real-complex-op * t t
676 mulps */real-complex-single-float */complex-real-single-float 4
677 mulpd */real-complex-double-float */complex-real-double-float 5)
678 (def-real-complex-op / nil t
680 divpd nil //complex-real-double-float 19))
682 (define-vop (//complex-real-single-float float-op)
684 (:args (x :scs (complex-single-reg fp-complex-single-immediate fp-complex-single-zero)
687 :load-if (not (sc-is x fp-complex-single-immediate fp-complex-single-zero)))
688 (y :scs (single-reg fp-single-immediate fp-single-zero)
690 :load-if (not (sc-is y fp-single-immediate fp-single-zero))))
691 (:arg-types complex-single-float single-float)
692 (:temporary (:sc complex-single-reg :from (:argument 1)) dup)
693 (:results (r :scs (complex-single-reg)))
694 (:result-types complex-single-float)
696 (flet ((duplicate (x)
697 (let ((word (ldb (byte 64 0)
698 (logior (ash (single-float-bits (imagpart x)) 32)
700 (single-float-bits (realpart x)))))))
701 (register-inline-constant :oword (logior (ash word 64) word)))))
704 (setf dup (duplicate (complex (tn-value y) (tn-value y)))))
706 (inst xorps dup dup))
708 (inst shufps dup dup #b00000000)))
710 (fp-complex-single-immediate
711 (inst movaps r (duplicate (tn-value x))))
712 (fp-complex-single-zero
716 (inst unpcklpd r r)))
720 ;; Complex multiplication
721 ;; r := rx * ry - ix * iy
722 ;; i := rx * iy + ix * ry
724 ;; Transpose for SIMDness
729 ;;+ [ix ix] * [-iy ry]
732 (macrolet ((define-complex-* (name cost type sc tmp-p &body body)
733 `(define-vop (,name float-op)
735 (:args (x :scs (,sc) :target r)
736 (y :scs (,sc) :target copy-y))
737 (:arg-types ,type ,type)
738 (:temporary (:sc ,sc) imag)
739 (:temporary (:sc ,sc :from :eval) copy-y)
741 `((:temporary (:sc ,sc) xmm)))
742 (:results (r :scs (,sc) :from :eval))
743 (:result-types ,type)
745 (when (or (location= x copy-y)
749 (define-complex-* */complex-single-float 20
750 complex-single-float complex-single-reg t
755 (inst unpckhpd imag xmm)
756 (inst unpcklpd r xmm)
757 (move copy-y y) ; y == r only if y == x == r
762 (inst shufps y y #b11110001)
763 (inst xorps y (register-inline-constant :oword (ash 1 31)))
767 (define-complex-* */complex-double-float 25
768 complex-double-float complex-double-reg nil
774 (inst unpckhpd imag imag)
778 (inst shufpd y y #b01)
779 (inst xorpd y (register-inline-constant :oword (ash 1 63)))
782 (inst addpd r imag)))
785 (:args (x :scs (double-reg)))
786 (:results (y :scs (double-reg)))
789 (:arg-types double-float)
790 (:result-types double-float)
791 (:note "inline float arithmetic")
793 (:save-p :compute-only)
795 (unless (location= x y)
797 (note-this-location vop :internal-error)
800 (macrolet ((frob ((name translate sc type) &body body)
802 (:args (x :scs (,sc) :target y))
803 (:results (y :scs (,sc)))
804 (:translate ,translate)
807 (:result-types ,type)
808 (:note "inline float arithmetic")
810 (:save-p :compute-only)
812 (note-this-location vop :internal-error)
813 ;; we should be able to do this better. what we
814 ;; really would like to do is use the target as the
815 ;; temp whenever it's not also the source
818 (frob (%negate/double-float %negate double-reg double-float)
819 (inst xorpd y (register-inline-constant :oword (ash 1 63))))
820 (frob (%negate/complex-double-float %negate complex-double-reg complex-double-float)
821 (inst xorpd y (register-inline-constant
822 :oword (logior (ash 1 127) (ash 1 63)))))
823 (frob (conjugate/complex-double-float conjugate complex-double-reg complex-double-float)
824 (inst xorpd y (register-inline-constant :oword (ash 1 127))))
825 (frob (%negate/single-float %negate single-reg single-float)
826 (inst xorps y (register-inline-constant :oword (ash 1 31))))
827 (frob (%negate/complex-single-float %negate complex-single-reg complex-single-float)
828 (inst xorps y (register-inline-constant
829 :oword (logior (ash 1 31) (ash 1 63)))))
830 (frob (conjugate/complex-single-float conjugate complex-single-reg complex-single-float)
831 (inst xorpd y (register-inline-constant :oword (ash 1 63))))
832 (frob (abs/double-float abs double-reg double-float)
833 (inst andpd y (register-inline-constant :oword (ldb (byte 63 0) -1))))
834 (frob (abs/single-float abs single-reg single-float)
835 (inst andps y (register-inline-constant :oword (ldb (byte 31 0) -1)))))
840 (define-vop (float-compare)
843 (:save-p :compute-only)
844 (:note "inline float comparison"))
847 (macrolet ((define-float-eql (name cost sc constant-sc type)
848 `(define-vop (,name float-compare)
850 (:args (x :scs (,sc ,constant-sc)
852 :load-if (not (sc-is x ,constant-sc)))
853 (y :scs (,sc ,constant-sc)
855 :load-if (not (sc-is y ,constant-sc))))
856 (:arg-types ,type ,type)
857 (:temporary (:sc ,sc :from :eval) mask)
858 (:temporary (:sc any-reg) bits)
861 (when (or (location= y mask)
862 (not (xmm-register-p x)))
864 (aver (xmm-register-p x))
866 (when (sc-is y ,constant-sc)
867 (setf y (register-inline-constant :aligned (tn-value y))))
868 (inst pcmpeqd mask y)
869 (inst movmskps bits mask)
870 (inst cmp bits #b1111)))))
871 (define-float-eql eql/single-float 4
872 single-reg fp-single-immediate single-float)
873 (define-float-eql eql/double-float 4
874 double-reg fp-double-immediate double-float)
875 (define-float-eql eql/complex-single-float 5
876 complex-single-reg fp-complex-single-immediate complex-single-float)
877 (define-float-eql eql/complex-double-float 5
878 complex-double-reg fp-complex-double-immediate complex-double-float))
880 ;;; comiss and comisd can cope with one or other arg in memory: we
881 ;;; could (should, indeed) extend these to cope with descriptor args
884 (define-vop (single-float-compare float-compare)
885 (:args (x :scs (single-reg))
886 (y :scs (single-reg single-stack fp-single-immediate)
887 :load-if (not (sc-is y single-stack fp-single-immediate))))
888 (:arg-types single-float single-float))
889 (define-vop (double-float-compare float-compare)
890 (:args (x :scs (double-reg))
891 (y :scs (double-reg double-stack descriptor-reg fp-double-immediate)
892 :load-if (not (sc-is y double-stack descriptor-reg fp-double-immediate))))
893 (:arg-types double-float double-float))
895 (define-vop (=/single-float single-float-compare)
897 (:args (x :scs (single-reg single-stack fp-single-immediate)
899 :load-if (not (sc-is x single-stack fp-single-immediate)))
900 (y :scs (single-reg single-stack fp-single-immediate)
902 :load-if (not (sc-is y single-stack fp-single-immediate))))
903 (:temporary (:sc single-reg :from :eval) xmm)
905 (:conditional not :p :ne)
908 (when (or (location= y xmm)
909 (and (not (xmm-register-p x))
913 (single-reg (setf xmm x))
914 (single-stack (inst movss xmm (ea-for-sf-stack x)))
916 (inst movss xmm (register-inline-constant (tn-value x)))))
919 (setf y (ea-for-sf-stack y)))
921 (setf y (register-inline-constant (tn-value y))))
923 (note-this-location vop :internal-error)
925 ;; if PF&CF, there was a NaN involved => not equal
926 ;; otherwise, ZF => equal
929 (define-vop (=/double-float double-float-compare)
931 (:args (x :scs (double-reg double-stack fp-double-immediate descriptor-reg)
933 :load-if (not (sc-is x double-stack fp-double-immediate descriptor-reg)))
934 (y :scs (double-reg double-stack fp-double-immediate descriptor-reg)
936 :load-if (not (sc-is y double-stack fp-double-immediate descriptor-reg))))
937 (:temporary (:sc double-reg :from :eval) xmm)
939 (:conditional not :p :ne)
942 (when (or (location= y xmm)
943 (and (not (xmm-register-p x))
950 (inst movsd xmm (ea-for-df-stack x)))
952 (inst movsd xmm (register-inline-constant (tn-value x))))
954 (inst movsd xmm (ea-for-df-desc x))))
957 (setf y (ea-for-df-stack y)))
959 (setf y (register-inline-constant (tn-value y))))
961 (setf y (ea-for-df-desc y)))
963 (note-this-location vop :internal-error)
964 (inst comisd xmm y)))
966 (macrolet ((define-complex-float-= (complex-complex-name complex-real-name real-complex-name
967 real-sc real-constant-sc real-type
968 complex-sc complex-constant-sc complex-type
969 real-move-inst complex-move-inst
970 cmp-inst mask-inst mask)
972 (define-vop (,complex-complex-name float-compare)
974 (:args (x :scs (,complex-sc ,complex-constant-sc)
976 :load-if (not (sc-is x ,complex-constant-sc)))
977 (y :scs (,complex-sc ,complex-constant-sc)
979 :load-if (not (sc-is y ,complex-constant-sc))))
980 (:arg-types ,complex-type ,complex-type)
981 (:temporary (:sc ,complex-sc :from :eval) cmp)
982 (:temporary (:sc unsigned-reg) bits)
986 (when (location= y cmp)
990 (inst ,real-move-inst cmp (register-inline-constant
992 (,complex-constant-sc
993 (inst ,complex-move-inst cmp (register-inline-constant
997 (when (sc-is y ,real-constant-sc ,complex-constant-sc)
998 (setf y (register-inline-constant :aligned (tn-value y))))
999 (note-this-location vop :internal-error)
1000 (inst ,cmp-inst :eq cmp y)
1001 (inst ,mask-inst bits cmp)
1002 (inst cmp bits ,mask)))
1003 (define-vop (,complex-real-name ,complex-complex-name)
1004 (:args (x :scs (,complex-sc ,complex-constant-sc)
1006 :load-if (not (sc-is x ,complex-constant-sc)))
1007 (y :scs (,real-sc ,real-constant-sc)
1009 :load-if (not (sc-is y ,real-constant-sc))))
1010 (:arg-types ,complex-type ,real-type))
1011 (define-vop (,real-complex-name ,complex-complex-name)
1012 (:args (x :scs (,real-sc ,real-constant-sc)
1014 :load-if (not (sc-is x ,real-constant-sc)))
1015 (y :scs (,complex-sc ,complex-constant-sc)
1017 :load-if (not (sc-is y ,complex-constant-sc))))
1018 (:arg-types ,real-type ,complex-type)))))
1019 (define-complex-float-= =/complex-single-float =/complex-real-single-float =/real-complex-single-float
1020 single-reg fp-single-immediate single-float
1021 complex-single-reg fp-complex-single-immediate complex-single-float
1022 movss movq cmpps movmskps #b1111)
1023 (define-complex-float-= =/complex-double-float =/complex-real-double-float =/real-complex-double-float
1024 double-reg fp-double-immediate double-float
1025 complex-double-reg fp-complex-double-immediate complex-double-float
1026 movsd movapd cmppd movmskpd #b11))
1028 (macrolet ((define-</> (op single-name double-name &rest flags)
1030 (define-vop (,double-name double-float-compare)
1033 (:conditional ,@flags)
1037 (setf y (ea-for-df-stack y)))
1039 (setf y (ea-for-df-desc y)))
1040 (fp-double-immediate
1041 (setf y (register-inline-constant (tn-value y))))
1044 (define-vop (,single-name single-float-compare)
1047 (:conditional ,@flags)
1051 (setf y (ea-for-sf-stack y)))
1052 (fp-single-immediate
1053 (setf y (register-inline-constant (tn-value y))))
1055 (inst comiss x y))))))
1056 (define-</> < <single-float <double-float not :p :nc)
1057 (define-</> > >single-float >double-float not :p :na))
1062 (macrolet ((frob (name translate inst to-sc to-type)
1063 `(define-vop (,name)
1064 (:args (x :scs (signed-stack signed-reg)))
1065 (:results (y :scs (,to-sc)))
1066 (:arg-types signed-num)
1067 (:result-types ,to-type)
1068 (:policy :fast-safe)
1069 (:note "inline float coercion")
1070 (:translate ,translate)
1072 (:save-p :compute-only)
1075 (single-reg (inst xorps y y))
1076 (double-reg (inst xorpd y y)))
1077 (note-this-location vop :internal-error)
1078 (inst ,inst y x)))))
1079 (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
1080 (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
1082 (macrolet ((frob (name translate inst from-scs from-type ea-func to-sc to-type)
1083 `(define-vop (,name)
1084 (:args (x :scs ,from-scs :target y))
1085 (:results (y :scs (,to-sc)))
1086 (:arg-types ,from-type)
1087 (:result-types ,to-type)
1088 (:policy :fast-safe)
1089 (:note "inline float coercion")
1090 (:translate ,translate)
1092 (:save-p :compute-only)
1094 (unless (location= x y)
1096 (single-reg (inst xorps y y))
1097 (double-reg (inst xorpd y y))))
1098 (note-this-location vop :internal-error)
1099 (inst ,inst y (sc-case x
1100 (,(first from-scs) x)
1101 (,(second from-scs) (,ea-func x))))
1102 ,(when (and (eq from-type 'double-float) ; if the input is wider
1103 (eq to-type 'single-float)) ; than the output, clear
1104 `(when (location= x y) ; noise in the high part
1105 (inst shufps y y #4r3330)))))))
1106 (frob %single-float/double-float %single-float cvtsd2ss
1107 (double-reg double-stack) double-float ea-for-df-stack
1108 single-reg single-float)
1110 (frob %double-float/single-float %double-float cvtss2sd
1111 (single-reg single-stack) single-float ea-for-sf-stack
1112 double-reg double-float))
1114 (macrolet ((frob (trans inst from-scs from-type ea-func)
1115 `(define-vop (,(symbolicate trans "/" from-type))
1116 (:args (x :scs ,from-scs))
1117 (:results (y :scs (signed-reg)))
1118 (:arg-types ,from-type)
1119 (:result-types signed-num)
1121 (:policy :fast-safe)
1122 (:note "inline float truncate")
1124 (:save-p :compute-only)
1126 (inst ,inst y (sc-case x
1127 (,(first from-scs) x)
1128 (,(second from-scs) (,ea-func x))))))))
1129 (frob %unary-truncate/single-float cvttss2si
1130 (single-reg single-stack) single-float ea-for-sf-stack)
1131 (frob %unary-truncate/double-float cvttsd2si
1132 (double-reg double-stack) double-float ea-for-df-stack)
1134 (frob %unary-round cvtss2si
1135 (single-reg single-stack) single-float ea-for-sf-stack)
1136 (frob %unary-round cvtsd2si
1137 (double-reg double-stack) double-float ea-for-df-stack))
1139 (define-vop (make-single-float)
1140 (:args (bits :scs (signed-reg) :target res
1141 :load-if (not (or (and (sc-is bits signed-stack)
1142 (sc-is res single-reg))
1143 (and (sc-is bits signed-stack)
1144 (sc-is res single-stack)
1145 (location= bits res))))))
1146 (:results (res :scs (single-reg single-stack)))
1147 (:arg-types signed-num)
1148 (:result-types single-float)
1149 (:translate make-single-float)
1150 (:policy :fast-safe)
1157 (inst mov res bits))
1159 (aver (location= bits res)))))
1163 (inst movd res bits))
1165 (inst movd res bits)))))))
1167 (define-vop (make-single-float-c)
1168 (:results (res :scs (single-reg single-stack descriptor-reg)))
1169 (:arg-types (:constant (signed-byte 32)))
1170 (:result-types single-float)
1172 (:translate make-single-float)
1173 (:policy :fast-safe)
1178 (inst mov res bits))
1180 (inst movss res (register-inline-constant :dword bits)))
1182 (inst mov res (logior (ash bits 32)
1183 single-float-widetag))))))
1185 (define-vop (make-double-float)
1186 (:args (hi-bits :scs (signed-reg))
1187 (lo-bits :scs (unsigned-reg)))
1188 (:results (res :scs (double-reg)))
1189 (:temporary (:sc unsigned-reg) temp)
1190 (:arg-types signed-num unsigned-num)
1191 (:result-types double-float)
1192 (:translate make-double-float)
1193 (:policy :fast-safe)
1198 (inst or temp lo-bits)
1199 (inst movd res temp)))
1201 (define-vop (make-double-float-c)
1202 (:results (res :scs (double-reg)))
1203 (:arg-types (:constant (signed-byte 32)) (:constant (unsigned-byte 32)))
1204 (:result-types double-float)
1206 (:translate make-double-float)
1207 (:policy :fast-safe)
1210 (inst movsd res (register-inline-constant :qword (logior (ash hi 32) lo)))))
1212 (define-vop (single-float-bits)
1213 (:args (float :scs (single-reg descriptor-reg)
1214 :load-if (not (sc-is float single-stack))))
1215 (:results (bits :scs (signed-reg)))
1216 (:arg-types single-float)
1217 (:result-types signed-num)
1218 (:translate single-float-bits)
1219 (:policy :fast-safe)
1223 (inst movd bits float)
1224 (inst movsxd bits (reg-in-size bits :dword)))
1226 (inst movsxd bits (make-ea :dword ; c.f. ea-for-sf-stack
1228 :disp (frame-byte-offset (tn-offset float)))))
1231 (inst sar bits 32)))))
1233 (define-vop (double-float-high-bits)
1234 (:args (float :scs (double-reg descriptor-reg)
1235 :load-if (not (sc-is float double-stack))))
1236 (:results (hi-bits :scs (signed-reg)))
1237 (:temporary (:sc signed-stack :from :argument :to :result) temp)
1238 (:arg-types double-float)
1239 (:result-types signed-num)
1240 (:translate double-float-high-bits)
1241 (:policy :fast-safe)
1246 (inst movsd temp float)
1247 (move hi-bits temp))
1249 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1251 (loadw hi-bits float double-float-value-slot
1252 other-pointer-lowtag)))
1253 (inst sar hi-bits 32)))
1255 (define-vop (double-float-low-bits)
1256 (:args (float :scs (double-reg descriptor-reg)
1257 :load-if (not (sc-is float double-stack))))
1258 (:results (lo-bits :scs (unsigned-reg)))
1259 (:temporary (:sc signed-stack :from :argument :to :result) temp)
1260 (:arg-types double-float)
1261 (:result-types unsigned-num)
1262 (:translate double-float-low-bits)
1263 (:policy :fast-safe)
1268 (inst movsd temp float)
1269 (move lo-bits temp))
1271 (loadw lo-bits ebp-tn (frame-word-offset (tn-offset float))))
1273 (loadw lo-bits float double-float-value-slot
1274 other-pointer-lowtag)))
1275 (inst shl lo-bits 32)
1276 (inst shr lo-bits 32)))
1280 ;;;; complex float VOPs
1282 (define-vop (make-complex-single-float)
1283 (:translate complex)
1284 (:args (real :scs (single-reg fp-single-zero)
1286 :load-if (not (sc-is real fp-single-zero)))
1287 (imag :scs (single-reg fp-single-zero)
1288 :load-if (not (sc-is imag fp-single-zero))))
1289 (:arg-types single-float single-float)
1290 (:results (r :scs (complex-single-reg) :from (:argument 0)))
1291 (:result-types complex-single-float)
1292 (:note "inline complex single-float creation")
1293 (:policy :fast-safe)
1295 (cond ((sc-is real fp-single-zero)
1297 (unless (sc-is imag fp-single-zero)
1298 (inst unpcklps r imag)))
1299 ((location= real imag)
1301 (inst unpcklps r r))
1304 (unless (sc-is imag fp-single-zero)
1305 (inst unpcklps r imag))))))
1307 (define-vop (make-complex-double-float)
1308 (:translate complex)
1309 (:args (real :scs (double-reg fp-double-zero)
1311 :load-if (not (sc-is real fp-double-zero)))
1312 (imag :scs (double-reg fp-double-zero)
1313 :load-if (not (sc-is imag fp-double-zero))))
1314 (:arg-types double-float double-float)
1315 (:results (r :scs (complex-double-reg) :from (:argument 0)))
1316 (:result-types complex-double-float)
1317 (:note "inline complex double-float creation")
1318 (:policy :fast-safe)
1320 (cond ((sc-is real fp-double-zero)
1322 (unless (sc-is imag fp-double-zero)
1323 (inst unpcklpd r imag)))
1324 ((location= real imag)
1326 (inst unpcklpd r r))
1329 (unless (sc-is imag fp-double-zero)
1330 (inst unpcklpd r imag))))))
1332 (define-vop (complex-float-value)
1333 (:args (x :target r))
1334 (:temporary (:sc complex-double-reg) zero)
1336 (:variant-vars offset)
1337 (:policy :fast-safe)
1339 (cond ((sc-is x complex-double-reg)
1341 (inst xorpd zero zero)
1343 (0 (inst unpcklpd r zero))
1344 (1 (inst unpckhpd r zero))))
1345 ((sc-is x complex-single-reg)
1348 (0 (inst shufps r r #b11111100))
1349 (1 (inst shufps r r #b11111101))))
1350 ((sc-is r single-reg)
1351 (let ((ea (sc-case x
1352 (complex-single-stack
1354 (0 (ea-for-csf-real-stack x))
1355 (1 (ea-for-csf-imag-stack x))))
1358 (0 (ea-for-csf-real-desc x))
1359 (1 (ea-for-csf-imag-desc x)))))))
1361 ((sc-is r double-reg)
1362 (let ((ea (sc-case x
1363 (complex-double-stack
1365 (0 (ea-for-cdf-real-stack x))
1366 (1 (ea-for-cdf-imag-stack x))))
1369 (0 (ea-for-cdf-real-desc x))
1370 (1 (ea-for-cdf-imag-desc x)))))))
1372 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
1374 (define-vop (realpart/complex-single-float complex-float-value)
1375 (:translate realpart)
1376 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1378 (:arg-types complex-single-float)
1379 (:results (r :scs (single-reg)))
1380 (:result-types single-float)
1381 (:note "complex float realpart")
1384 (define-vop (realpart/complex-double-float complex-float-value)
1385 (:translate realpart)
1386 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1388 (:arg-types complex-double-float)
1389 (:results (r :scs (double-reg)))
1390 (:result-types double-float)
1391 (:note "complex float realpart")
1394 (define-vop (imagpart/complex-single-float complex-float-value)
1395 (:translate imagpart)
1396 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1398 (:arg-types complex-single-float)
1399 (:results (r :scs (single-reg)))
1400 (:result-types single-float)
1401 (:note "complex float imagpart")
1404 (define-vop (imagpart/complex-double-float complex-float-value)
1405 (:translate imagpart)
1406 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1408 (:arg-types complex-double-float)
1409 (:results (r :scs (double-reg)))
1410 (:result-types double-float)
1411 (:note "complex float imagpart")
1415 ;;; hack dummy VOPs to bias the representation selection of their
1416 ;;; arguments towards a FP register, which can help avoid consing at
1417 ;;; inappropriate locations
1418 (defknown double-float-reg-bias (double-float) (values))
1419 (define-vop (double-float-reg-bias)
1420 (:translate double-float-reg-bias)
1421 (:args (x :scs (double-reg double-stack) :load-if nil))
1422 (:arg-types double-float)
1423 (:policy :fast-safe)
1424 (:note "inline dummy FP register bias")
1427 (defknown single-float-reg-bias (single-float) (values))
1428 (define-vop (single-float-reg-bias)
1429 (:translate single-float-reg-bias)
1430 (:args (x :scs (single-reg single-stack) :load-if nil))
1431 (:arg-types single-float)
1432 (:policy :fast-safe)
1433 (:note "inline dummy FP register bias")
1437 (defknown swap-complex ((complex float)) (complex float)
1438 (foldable flushable movable always-translatable))
1439 (defoptimizer (swap-complex derive-type) ((x))
1440 (sb!c::lvar-type x))
1441 (defun swap-complex (x)
1442 (complex (imagpart x) (realpart x)))
1443 (define-vop (swap-complex-single-float)
1444 (:translate swap-complex)
1445 (:policy :fast-safe)
1446 (:args (x :scs (complex-single-reg) :target r))
1447 (:arg-types complex-single-float)
1448 (:results (r :scs (complex-single-reg)))
1449 (:result-types complex-single-float)
1452 (inst shufps r r #b11110001)))
1453 (define-vop (swap-complex-double-float)
1454 (:translate swap-complex)
1455 (:policy :fast-safe)
1456 (:args (x :scs (complex-double-reg) :target r))
1457 (:arg-types complex-double-float)
1458 (:results (r :scs (complex-double-reg)))
1459 (:result-types complex-double-float)
1462 (inst shufpd r r #b01)))