Micro-optimize DOUBLE-FLOAT-LOW-BITS on x68-64.
[sbcl.git] / src / compiler / x86-64 / float.lisp
1 ;;;; floating point support for the x86
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!VM")
13 \f
14 (macrolet ((ea-for-xf-desc (tn slot)
15              `(make-ea
16                :qword :base ,tn
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))
21   ;; complex floats
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)))
28
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)))
35
36 (macrolet ((ea-for-xf-stack (tn kind)
37              (declare (ignore kind))
38              `(make-ea
39                :qword :base rbp-tn
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)))
45
46 ;;; complex float stack EAs
47 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
48              `(make-ea
49                :qword :base ,base
50                :disp (frame-byte-offset
51                       (+ (tn-offset ,tn)
52                        (cond ((= (tn-offset ,base) rsp-offset)
53                               sp->fp-offset)
54                              (t 0))
55                        (ecase ,kind
56                          (:single
57                             (ecase ,slot
58                               (:real 0)
59                               (:imag -1/2)))
60                          (:double
61                             (ecase ,slot
62                               (:real 1)
63                               (:imag 0)))))))))
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))
70
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)))
77 \f
78 ;;;; move functions
79
80 ;;; X is source, Y is destination.
81
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))
87   (identity x)
88   (sc-case y
89     ((single-reg complex-single-reg) (inst xorps y y))
90     ((double-reg complex-double-reg) (inst xorpd y y))))
91
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))))
98     (sc-case y
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)))))
103
104 (define-move-fun (load-single 2) (vop x y)
105   ((single-stack) (single-reg))
106   (inst movss y (ea-for-sf-stack x)))
107
108 (define-move-fun (store-single 2) (vop x y)
109   ((single-reg) (single-stack))
110   (inst movss (ea-for-sf-stack y) x))
111
112 (define-move-fun (load-double 2) (vop x y)
113   ((double-stack) (double-reg))
114   (inst movsd y (ea-for-df-stack x)))
115
116 (define-move-fun (store-double 2) (vop x y)
117   ((double-reg) (double-stack))
118   (inst movsd  (ea-for-df-stack y) x))
119
120 (eval-when (:compile-toplevel :execute)
121   (setf *read-default-float-format* 'single-float))
122 \f
123 ;;;; complex float move functions
124
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)))
129
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))
133
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)))
137
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))
141 \f
142 ;;;; move VOPs
143
144 ;;; float register to register moves
145 (macrolet ((frob (vop sc)
146              `(progn
147                 (define-vop (,vop)
148                   (:args (x :scs (,sc)
149                             :target y
150                             :load-if (not (location= x y))))
151                   (:results (y :scs (,sc)
152                                :load-if (not (location= x y))))
153                   (:note "float move")
154                   (:generator 0
155                     (move y x)))
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))
161
162 \f
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")
169   (:generator 4
170     (inst movd y x)
171     (inst shl y 32)
172     (inst or y single-float-widetag)))
173
174 (define-move-vop move-from-single :move
175   (single-reg) (descriptor-reg))
176
177 (define-vop (move-from-double)
178   (:args (x :scs (double-reg) :to :save))
179   (:results (y :scs (descriptor-reg)))
180   (:node-var node)
181   (:note "float to pointer coercion")
182   (:generator 13
183      (with-fixed-allocation (y
184                              double-float-widetag
185                              double-float-size
186                              node)
187        (inst movsd (ea-for-df-desc y) x))))
188 (define-move-vop move-from-double :move
189   (double-reg) (descriptor-reg))
190
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")
198    (:generator 2
199      (sc-case x
200        (descriptor-reg
201         (move tmp x)
202         (inst shr tmp 32)
203         (inst movd y tmp))
204        (control-stack
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.
208         (inst movq y x)
209         (inst shufps y y #4r3331)))))
210 (define-move-vop move-to-single-reg :move (descriptor-reg) (single-reg))
211
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")
218   (:generator 2
219     (move tmp x)
220     (inst shr tmp 32)
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))
225
226 (define-vop (move-to-double)
227   (:args (x :scs (descriptor-reg)))
228   (:results (y :scs (double-reg)))
229   (:note "pointer to float coercion")
230   (:generator 2
231     (inst movsd y (ea-for-df-desc x))))
232 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
233
234 \f
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)))
240   (:node-var node)
241   (:note "complex float to pointer coercion")
242   (:generator 13
243      (with-fixed-allocation (y
244                              complex-single-float-widetag
245                              complex-single-float-size
246                              node)
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))
250
251 (define-vop (move-from-complex-double)
252   (:args (x :scs (complex-double-reg) :to :save))
253   (:results (y :scs (descriptor-reg)))
254   (:node-var node)
255   (:note "complex float to pointer coercion")
256   (:generator 13
257      (with-fixed-allocation (y
258                              complex-double-float-widetag
259                              complex-double-float-size
260                              node)
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))
264
265 ;;; Move from a descriptor to a complex float register.
266 (macrolet ((frob (name sc format)
267              `(progn
268                 (define-vop (,name)
269                   (:args (x :scs (descriptor-reg)))
270                   (:results (y :scs (,sc)))
271                   (:note "pointer to complex float coercion")
272                   (:generator 2
273                     ,(ecase format
274                       (:single
275                          '(inst movq y (ea-for-csf-data-desc x)))
276                       (:double
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))
281 \f
282 ;;;; the move argument vops
283 ;;;;
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.
286
287 ;;; the general MOVE-ARG VOP
288 (macrolet ((frob (name sc stack-sc format)
289              `(progn
290                 (define-vop (,name)
291                   (:args (x :scs (,sc) :target y)
292                          (fp :scs (any-reg)
293                              :load-if (not (sc-is y ,sc))))
294                   (:results (y))
295                   (:note "float argument move")
296                   (:generator ,(case format (:single 2) (:double 3) )
297                     (sc-case y
298                       (,sc
299                        (move y x))
300                       (,stack-sc
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)))
304                              ,@(ecase format
305                                       (:single '((inst movss ea x)))
306                                       (:double '((inst movsd ea x)))))
307                            (let ((ea (make-ea
308                                       :dword :base fp
309                                       :disp (frame-byte-offset (tn-offset y)))))
310                              ,@(ecase format
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))
317
318 ;;;; complex float MOVE-ARG VOP
319 (macrolet ((frob (name sc stack-sc format)
320              `(progn
321                 (define-vop (,name)
322                   (:args (x :scs (,sc) :target y)
323                          (fp :scs (any-reg)
324                              :load-if (not (sc-is y ,sc))))
325                   (:results (y))
326                   (:note "complex float argument move")
327                   (:generator ,(ecase format (:single 2) (:double 3))
328                     (sc-case y
329                       (,sc
330                        (move y x))
331                       (,stack-sc
332                        ,(ecase format
333                           (:single
334                              '(inst movq (ea-for-csf-data-stack y fp) x))
335                           (:double
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))
343
344 (define-move-vop move-arg :move-arg
345   (single-reg double-reg
346    complex-single-reg complex-double-reg)
347   (descriptor-reg))
348
349 \f
350 ;;;; arithmetic VOPs
351
352 (define-vop (float-op)
353   (:args (x) (y))
354   (:results (r))
355   (:policy :fast-safe)
356   (:note "inline float arithmetic")
357   (:vop-var vop)
358   (:save-p :compute-only))
359
360 (macrolet ((frob (name comm-name sc constant-sc ptype)
361              `(progn
362                 (define-vop (,name float-op)
363                   (:args (x :scs (,sc ,constant-sc)
364                             :target r
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)
373                             :target r
374                             :load-if (not (sc-is x ,constant-sc)))
375                          (y :scs (,sc ,constant-sc)
376                             :target r
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))
391
392 (macrolet ((generate (opinst commutative constant-sc load-inst)
393              `(flet ((get-constant (tn &optional maybe-aligned)
394                        (declare (ignorable maybe-aligned))
395                        (let ((value (tn-value tn)))
396                          ,(if (eq constant-sc 'fp-complex-single-immediate)
397                               `(if maybe-aligned
398                                    (register-inline-constant
399                                     :aligned value)
400                                    (register-inline-constant value))
401                               `(register-inline-constant value)))))
402                 (declare (ignorable #'get-constant))
403                 (cond
404                   ((location= x r)
405                    (when (sc-is y ,constant-sc)
406                      (setf y (get-constant y t)))
407                    (inst ,opinst x y))
408                   ((and ,commutative (location= y r))
409                    (when (sc-is x ,constant-sc)
410                      (setf x (get-constant x t)))
411                    (inst ,opinst y x))
412                   ((not (location= r y))
413                    (if (sc-is x ,constant-sc)
414                        (inst ,load-inst r (get-constant x))
415                        (move r x))
416                    (when (sc-is y ,constant-sc)
417                      (setf y (get-constant y t)))
418                    (inst ,opinst r y))
419                   (t
420                    (if (sc-is x ,constant-sc)
421                        (inst ,load-inst tmp (get-constant x))
422                        (move tmp x))
423                    (inst ,opinst tmp y)
424                    (move r tmp)))))
425            (frob (op sinst sname scost dinst dname dcost commutative
426                      &optional csinst csname cscost cdinst cdname cdcost)
427              `(progn
428                 (define-vop (,sname ,(if commutative
429                                          'single-float-comm-op
430                                          'single-float-op))
431                   (:translate ,op)
432                   (:temporary (:sc single-reg) tmp)
433                   (:generator ,scost
434                     (generate ,sinst ,commutative fp-single-immediate movss)))
435                 (define-vop (,dname ,(if commutative
436                                          'double-float-comm-op
437                                          'double-float-op))
438                   (:translate ,op)
439                   (:temporary (:sc double-reg) tmp)
440                   (:generator ,dcost
441                     (generate ,dinst ,commutative fp-double-immediate movsd)))
442                 ,(when csinst
443                    `(define-vop (,csname
444                                  ,(if commutative
445                                       'complex-single-float-comm-op
446                                       'complex-single-float-op))
447                       (:translate ,op)
448                       (:temporary (:sc complex-single-reg) tmp)
449                       (:generator ,cscost
450                         (generate ,csinst ,commutative
451                                   fp-complex-single-immediate movq))))
452                 ,(when cdinst
453                    `(define-vop (,cdname
454                                  ,(if commutative
455                                       'complex-double-float-comm-op
456                                       'complex-double-float-op))
457                       (:translate ,op)
458                       (:temporary (:sc complex-double-reg) tmp)
459                       (:generator ,cdcost
460                         (generate ,cdinst ,commutative
461                                   fp-complex-double-immediate movapd)))))))
462   (frob + addss +/single-float 2 addsd +/double-float 2 t
463         addps +/complex-single-float 3 addpd +/complex-double-float 3)
464   (frob - subss -/single-float 2 subsd -/double-float 2 nil
465         subps -/complex-single-float 3 subpd -/complex-double-float 3)
466   (frob * mulss */single-float 4 mulsd */double-float 5 t)
467   (frob / divss //single-float 12 divsd //double-float 19 nil))
468
469 (macrolet ((frob (op cost commutativep
470                      duplicate-inst op-inst real-move-inst complex-move-inst
471                      real-sc real-constant-sc real-type
472                      complex-sc complex-constant-sc complex-type
473                      real-complex-name complex-real-name)
474              (cond ((not duplicate-inst) ; simple case
475                     `(flet ((load-into (r x)
476                               (sc-case x
477                                 (,real-constant-sc
478                                  (inst ,real-move-inst r
479                                        (register-inline-constant (tn-value x))))
480                                 (,complex-constant-sc
481                                  (inst ,complex-move-inst r
482                                        (register-inline-constant (tn-value x))))
483                                 (t (move r x)))))
484                        ,(when real-complex-name
485                           `(define-vop (,real-complex-name float-op)
486                              (:translate ,op)
487                              (:args (x :scs (,real-sc ,real-constant-sc)
488                                        :target r
489                                        :load-if (not (sc-is x ,real-constant-sc)))
490                                     (y :scs (,complex-sc ,complex-constant-sc)
491                                        ,@(when commutativep '(:target r))
492                                        :load-if (not (sc-is y ,complex-constant-sc))))
493                              (:arg-types ,real-type ,complex-type)
494                              (:results (r :scs (,complex-sc)
495                                           ,@(unless commutativep '(:from (:argument 0)))))
496                              (:result-types ,complex-type)
497                              (:generator ,cost
498                                ,(when commutativep
499                                   `(when (location= y r)
500                                      (rotatef x y)))
501                                (load-into r x)
502                                (when (sc-is y ,real-constant-sc ,complex-constant-sc)
503                                  (setf y (register-inline-constant
504                                           :aligned (tn-value y))))
505                                (inst ,op-inst r y))))
506
507                        ,(when complex-real-name
508                           `(define-vop (,complex-real-name float-op)
509                              (:translate ,op)
510                              (:args (x :scs (,complex-sc ,complex-constant-sc)
511                                        :target r
512                                        :load-if (not (sc-is x ,complex-constant-sc)))
513                                     (y :scs (,real-sc ,real-constant-sc)
514                                        ,@(when commutativep '(:target r))
515                                        :load-if (not (sc-is y ,real-constant-sc))))
516                              (:arg-types ,complex-type ,real-type)
517                              (:results (r :scs (,complex-sc)
518                                           ,@(unless commutativep '(:from (:argument 0)))))
519                              (:result-types ,complex-type)
520                              (:generator ,cost
521                                ,(when commutativep
522                                   `(when (location= y r)
523                                      (rotatef x y)))
524                                (load-into r x)
525                                (when (sc-is y ,real-constant-sc ,complex-constant-sc)
526                                  (setf y (register-inline-constant
527                                           :aligned (tn-value y))))
528                                (inst ,op-inst r y))))))
529                    (commutativep ; must duplicate, but commutative
530                     `(progn
531                        ,(when real-complex-name
532                           `(define-vop (,real-complex-name float-op)
533                              (:translate ,op)
534                              (:args (x :scs (,real-sc ,real-constant-sc)
535                                        :target dup
536                                        :load-if (not (sc-is x ,real-constant-sc)))
537                                     (y :scs (,complex-sc ,complex-constant-sc)
538                                        :target r
539                                        :to  :result
540                                        :load-if (not (sc-is y ,complex-constant-sc))))
541                              (:arg-types ,real-type ,complex-type)
542                              (:temporary (:sc ,complex-sc :target r
543                                           :from (:argument 0)
544                                           :to   :result)
545                                          dup)
546                              (:results (r :scs (,complex-sc)))
547                              (:result-types ,complex-type)
548                              (:generator ,cost
549                                (if (sc-is x ,real-constant-sc)
550                                    (inst ,complex-move-inst dup
551                                          (register-inline-constant
552                                           (complex (tn-value x) (tn-value x))))
553                                    (let ((real x))
554                                      ,duplicate-inst))
555                                 ;; safe: dup /= y
556                                 (when (location= dup r)
557                                   (rotatef dup y))
558                                 (if (sc-is y ,complex-constant-sc)
559                                     (inst ,complex-move-inst r
560                                           (register-inline-constant (tn-value y)))
561                                     (move r y))
562                                 (when (sc-is dup ,complex-constant-sc)
563                                   (setf dup (register-inline-constant
564                                              :aligned (tn-value dup))))
565                                 (inst ,op-inst r dup))))
566
567                        ,(when complex-real-name
568                           `(define-vop (,complex-real-name float-op)
569                              (:translate ,op)
570                              (:args (x :scs (,complex-sc ,complex-constant-sc)
571                                        :target r
572                                        :to  :result
573                                        :load-if (not (sc-is x ,complex-constant-sc)))
574                                     (y :scs (,real-sc ,real-constant-sc)
575                                        :target dup
576                                        :load-if (not (sc-is y ,real-constant-sc))))
577                              (:arg-types ,complex-type ,real-type)
578                              (:temporary (:sc ,complex-sc :target r
579                                           :from (:argument 1)
580                                           :to :result)
581                                          dup)
582                              (:results (r :scs (,complex-sc)))
583                              (:result-types ,complex-type)
584                              (:generator ,cost
585                                (if (sc-is y ,real-constant-sc)
586                                    (inst ,complex-move-inst dup
587                                          (register-inline-constant
588                                           (complex (tn-value y) (tn-value y))))
589                                    (let ((real y))
590                                      ,duplicate-inst))
591                                 (when (location= dup r)
592                                   (rotatef x dup))
593                                 (if (sc-is x ,complex-constant-sc)
594                                     (inst ,complex-move-inst r
595                                           (register-inline-constant (tn-value x)))
596                                     (move r x))
597                                 (when (sc-is dup ,complex-constant-sc)
598                                   (setf dup (register-inline-constant
599                                              :aligned (tn-value dup))))
600                                 (inst ,op-inst r dup))))))
601                    (t ; duplicate, not commutative
602                     `(progn
603                        ,(when real-complex-name
604                           `(define-vop (,real-complex-name float-op)
605                              (:translate ,op)
606                              (:args (x :scs (,real-sc ,real-constant-sc)
607                                        :target r
608                                        :load-if (not (sc-is x ,real-constant-sc)))
609                                     (y :scs (,complex-sc ,complex-constant-sc)
610                                        :to :result
611                                        :load-if (not (sc-is y ,complex-constant-sc))))
612                              (:arg-types ,real-type ,complex-type)
613                              (:results (r :scs (,complex-sc) :from (:argument 0)))
614                              (:result-types ,complex-type)
615                              (:generator ,cost
616                                (if (sc-is x ,real-constant-sc)
617                                    (inst ,complex-move-inst dup
618                                          (register-inline-constant
619                                           (complex (tn-value x) (tn-value x))))
620                                    (let ((real x)
621                                          (dup  r))
622                                      ,duplicate-inst))
623                                (when (sc-is y ,complex-constant-sc)
624                                  (setf y (register-inline-constant
625                                           :aligned (tn-value y))))
626                                (inst ,op-inst r y))))
627
628                        ,(when complex-real-name
629                           `(define-vop (,complex-real-name float-op)
630                              (:translate ,op)
631                              (:args (x :scs (,complex-sc)
632                                        :target r
633                                        :to :eval)
634                                     (y :scs (,real-sc ,real-constant-sc)
635                                        :target dup
636                                        :load-if (not (sc-is y ,complex-constant-sc))))
637                              (:arg-types ,complex-type ,real-type)
638                              (:temporary (:sc ,complex-sc :from (:argument 1))
639                                          dup)
640                              (:results (r :scs (,complex-sc) :from :eval))
641                              (:result-types ,complex-type)
642                              (:generator ,cost
643                                (if (sc-is y ,real-constant-sc)
644                                    (setf dup (register-inline-constant
645                                               :aligned (complex (tn-value y)
646                                                                 (tn-value y))))
647                                    (let ((real y))
648                                      ,duplicate-inst))
649                                (move r x)
650                                (inst ,op-inst r dup))))))))
651            (def-real-complex-op (op commutativep duplicatep
652                                     single-inst single-real-complex-name single-complex-real-name single-cost
653                                     double-inst double-real-complex-name double-complex-real-name double-cost)
654                `(progn
655                   (frob ,op ,single-cost ,commutativep
656                         ,(and duplicatep
657                               `(progn
658                                  (move dup real)
659                                  (inst unpcklps dup dup)))
660                         ,single-inst movss movq
661                         single-reg fp-single-immediate single-float
662                         complex-single-reg fp-complex-single-immediate complex-single-float
663                         ,single-real-complex-name ,single-complex-real-name)
664                   (frob ,op ,double-cost ,commutativep
665                         ,(and duplicatep
666                               `(progn
667                                  (move dup real)
668                                  (inst unpcklpd dup dup)))
669                         ,double-inst movsd movapd
670                         double-reg fp-double-immediate double-float
671                         complex-double-reg fp-complex-double-immediate complex-double-float
672                         ,double-real-complex-name ,double-complex-real-name))))
673   (def-real-complex-op + t nil
674     addps +/real-complex-single-float +/complex-real-single-float 3
675     addpd +/real-complex-double-float +/complex-real-double-float 4)
676   (def-real-complex-op - nil nil
677     subps -/real-complex-single-float -/complex-real-single-float 3
678     subpd -/real-complex-double-float -/complex-real-double-float 4)
679   (def-real-complex-op * t t
680     mulps */real-complex-single-float */complex-real-single-float 4
681     mulpd */real-complex-double-float */complex-real-double-float 5)
682   (def-real-complex-op / nil t
683     nil nil nil nil
684     divpd nil //complex-real-double-float 19))
685
686 (define-vop (//complex-real-single-float float-op)
687   (:translate /)
688   (:args (x :scs (complex-single-reg fp-complex-single-immediate fp-complex-single-zero)
689             :to (:result 0)
690             :target r
691             :load-if (not (sc-is x fp-complex-single-immediate fp-complex-single-zero)))
692          (y :scs (single-reg fp-single-immediate fp-single-zero)
693             :target dup
694             :load-if (not (sc-is y fp-single-immediate fp-single-zero))))
695   (:arg-types complex-single-float single-float)
696   (:temporary (:sc complex-single-reg :from (:argument 1)) dup)
697   (:results (r :scs (complex-single-reg)))
698   (:result-types complex-single-float)
699   (:generator 12
700     (flet ((duplicate (x)
701              (let ((word (ldb (byte 64 0)
702                               (logior (ash (single-float-bits (imagpart x)) 32)
703                                       (ldb (byte 32 0)
704                                            (single-float-bits (realpart x)))))))
705                (register-inline-constant :oword (logior (ash word 64) word)))))
706       (sc-case y
707         (fp-single-immediate
708          (setf dup (duplicate (complex (tn-value y) (tn-value y)))))
709         (fp-single-zero
710          (inst xorps dup dup))
711         (t (move dup y)
712            (inst shufps dup dup #b00000000)))
713       (sc-case x
714         (fp-complex-single-immediate
715          (inst movaps r (duplicate (tn-value x))))
716         (fp-complex-single-zero
717          (inst xorps r r))
718         (t
719          (move r x)
720          (inst unpcklpd r r)))
721       (inst divps r dup)
722       (inst movq r r))))
723
724 ;; Complex multiplication
725 ;; r := rx * ry - ix * iy
726 ;; i := rx * iy + ix * ry
727 ;;
728 ;; Transpose for SIMDness
729 ;;  rx*ry    rx*iy
730 ;; -ix*iy   +ix*ry
731 ;;
732 ;;  [rx rx] * [ry iy]
733 ;;+ [ix ix] * [-iy ry]
734 ;;       [r i]
735
736 (macrolet ((define-complex-* (name cost type sc tmp-p &body body)
737                `(define-vop (,name float-op)
738                   (:translate *)
739                   (:args (x :scs (,sc) :target r)
740                          (y :scs (,sc) :target copy-y))
741                   (:arg-types ,type ,type)
742                   (:temporary (:sc ,sc) imag)
743                   (:temporary (:sc ,sc :from :eval) copy-y)
744                   ,@(when tmp-p
745                       `((:temporary (:sc ,sc) xmm)))
746                   (:results (r :scs (,sc) :from :eval))
747                   (:result-types ,type)
748                   (:generator ,cost
749                     (when (or (location= x copy-y)
750                               (location= y r))
751                       (rotatef x y))
752                     ,@body))))
753   (define-complex-* */complex-single-float 20
754     complex-single-float complex-single-reg t
755     (inst xorps xmm xmm)
756     (move r x)
757     (inst unpcklps r r)
758     (move imag r)
759     (inst unpckhpd imag xmm)
760     (inst unpcklpd r    xmm)
761     (move copy-y y)  ; y == r only if y == x == r
762     (setf y copy-y)
763
764     (inst mulps r y)
765
766     (inst shufps y y #b11110001)
767     (inst xorps y (register-inline-constant :oword (ash 1 31)))
768
769     (inst mulps imag y)
770     (inst addps r imag))
771   (define-complex-* */complex-double-float 25
772     complex-double-float complex-double-reg nil
773     (move imag x)
774     (move r x)
775     (move copy-y y)
776     (setf y copy-y)
777     (inst unpcklpd r r)
778     (inst unpckhpd imag imag)
779
780     (inst mulpd r y)
781
782     (inst shufpd y y #b01)
783     (inst xorpd y (register-inline-constant :oword (ash 1 63)))
784
785     (inst mulpd imag y)
786     (inst addpd r imag)))
787
788 (define-vop (fsqrt)
789   (:args (x :scs (double-reg)))
790   (:results (y :scs (double-reg)))
791   (:translate %sqrt)
792   (:policy :fast-safe)
793   (:arg-types double-float)
794   (:result-types double-float)
795   (:note "inline float arithmetic")
796   (:vop-var vop)
797   (:save-p :compute-only)
798   (:generator 1
799      (unless (location= x y)
800        (inst xorpd y y))
801      (note-this-location vop :internal-error)
802      (inst sqrtsd y x)))
803 \f
804 (macrolet ((frob ((name translate sc type) &body body)
805              `(define-vop (,name)
806                   (:args (x :scs (,sc) :target y))
807                 (:results (y :scs (,sc)))
808                 (:translate ,translate)
809                 (:policy :fast-safe)
810                 (:arg-types ,type)
811                 (:result-types ,type)
812                 (:note "inline float arithmetic")
813                 (:vop-var vop)
814                 (:save-p :compute-only)
815                 (:generator 1
816                   (note-this-location vop :internal-error)
817                   (move y x)
818                   ,@body))))
819   (frob (%negate/double-float %negate double-reg double-float)
820         (inst xorpd y (register-inline-constant :oword (ash 1 63))))
821   (frob (%negate/complex-double-float %negate complex-double-reg complex-double-float)
822         (inst xorpd y (register-inline-constant
823                        :oword (logior (ash 1 127) (ash 1 63)))))
824   (frob (conjugate/complex-double-float conjugate complex-double-reg complex-double-float)
825         (inst xorpd y (register-inline-constant :oword (ash 1 127))))
826   (frob (%negate/single-float %negate single-reg single-float)
827         (inst xorps y (register-inline-constant :oword (ash 1 31))))
828   (frob (%negate/complex-single-float %negate complex-single-reg complex-single-float)
829         (inst xorps y (register-inline-constant
830                        :oword (logior (ash 1 31) (ash 1 63)))))
831   (frob (conjugate/complex-single-float conjugate complex-single-reg complex-single-float)
832         (inst xorpd y (register-inline-constant :oword (ash 1 63))))
833   (frob (abs/double-float abs  double-reg double-float)
834         (inst andpd y (register-inline-constant :oword (ldb (byte 63 0) -1))))
835   (frob (abs/single-float abs  single-reg single-float)
836         (inst andps y (register-inline-constant :oword (ldb (byte 31 0) -1)))))
837
838 \f
839 ;;;; comparison
840
841 (define-vop (float-compare)
842   (:policy :fast-safe)
843   (:vop-var vop)
844   (:save-p :compute-only)
845   (:note "inline float comparison"))
846
847 ;;; EQL
848 (macrolet ((define-float-eql (name cost sc constant-sc type)
849                `(define-vop (,name float-compare)
850                   (:translate eql)
851                   (:args (x :scs (,sc ,constant-sc)
852                             :target mask
853                             :load-if (not (sc-is x ,constant-sc)))
854                          (y :scs (,sc ,constant-sc)
855                             :target mask
856                             :load-if (not (sc-is y ,constant-sc))))
857                   (:arg-types ,type ,type)
858                   (:temporary (:sc ,sc :from :eval) mask)
859                   (:temporary (:sc dword-reg) bits)
860                   (:conditional :e)
861                   (:generator ,cost
862                     (when (or (location= y mask)
863                               (not (xmm-register-p x)))
864                       (rotatef x y))
865                     (aver (xmm-register-p x))
866                     (move mask x)
867                     (when (sc-is y ,constant-sc)
868                       (setf y (register-inline-constant :aligned (tn-value y))))
869                     (inst pcmpeqd mask y)
870                     (inst movmskps bits mask)
871                     (inst cmp (if (location= bits eax-tn) al-tn bits)
872                           #b1111)))))
873   (define-float-eql eql/single-float 4
874     single-reg fp-single-immediate single-float)
875   (define-float-eql eql/double-float 4
876     double-reg fp-double-immediate double-float)
877   (define-float-eql eql/complex-single-float 5
878     complex-single-reg fp-complex-single-immediate complex-single-float)
879   (define-float-eql eql/complex-double-float 5
880     complex-double-reg fp-complex-double-immediate complex-double-float))
881
882 ;;; comiss and comisd can cope with one or other arg in memory: we
883 ;;; could (should, indeed) extend these to cope with descriptor args
884 ;;; and stack args
885
886 (define-vop (single-float-compare float-compare)
887   (:args (x :scs (single-reg))
888          (y :scs (single-reg single-stack fp-single-immediate)
889             :load-if (not (sc-is y single-stack fp-single-immediate))))
890   (:arg-types single-float single-float))
891 (define-vop (double-float-compare float-compare)
892   (:args (x :scs (double-reg))
893          (y :scs (double-reg double-stack descriptor-reg fp-double-immediate)
894             :load-if (not (sc-is y double-stack descriptor-reg fp-double-immediate))))
895   (:arg-types double-float double-float))
896
897 (define-vop (=/single-float single-float-compare)
898   (:translate =)
899   (:args (x :scs (single-reg single-stack fp-single-immediate)
900             :target xmm
901             :load-if (not (sc-is x single-stack fp-single-immediate)))
902          (y :scs (single-reg single-stack fp-single-immediate)
903             :target xmm
904             :load-if (not (sc-is y single-stack fp-single-immediate))))
905   (:temporary (:sc single-reg :from :eval) xmm)
906   (:info)
907   (:conditional not :p :ne)
908   (:vop-var vop)
909   (:generator 3
910     (when (or (location= y xmm)
911               (and (not (xmm-register-p x))
912                    (xmm-register-p y)))
913       (rotatef x y))
914     (sc-case x
915       (single-reg (setf xmm x))
916       (single-stack (inst movss xmm (ea-for-sf-stack x)))
917       (fp-single-immediate
918        (inst movss xmm (register-inline-constant (tn-value x)))))
919     (sc-case y
920       (single-stack
921        (setf y (ea-for-sf-stack y)))
922       (fp-single-immediate
923        (setf y (register-inline-constant (tn-value y))))
924       (t))
925     (note-this-location vop :internal-error)
926     (inst comiss xmm y)
927     ;; if PF&CF, there was a NaN involved => not equal
928     ;; otherwise, ZF => equal
929     ))
930
931 (define-vop (=/double-float double-float-compare)
932   (:translate =)
933   (:args (x :scs (double-reg double-stack fp-double-immediate descriptor-reg)
934             :target xmm
935             :load-if (not (sc-is x double-stack fp-double-immediate descriptor-reg)))
936          (y :scs (double-reg double-stack fp-double-immediate descriptor-reg)
937             :target xmm
938             :load-if (not (sc-is y double-stack fp-double-immediate descriptor-reg))))
939   (:temporary (:sc double-reg :from :eval) xmm)
940   (:info)
941   (:conditional not :p :ne)
942   (:vop-var vop)
943   (:generator 3
944     (when (or (location= y xmm)
945               (and (not (xmm-register-p x))
946                    (xmm-register-p y)))
947       (rotatef x y))
948     (sc-case x
949       (double-reg
950        (setf xmm x))
951       (double-stack
952        (inst movsd xmm (ea-for-df-stack x)))
953       (fp-double-immediate
954        (inst movsd xmm (register-inline-constant (tn-value x))))
955       (descriptor-reg
956        (inst movsd xmm (ea-for-df-desc x))))
957     (sc-case y
958       (double-stack
959        (setf y (ea-for-df-stack y)))
960       (fp-double-immediate
961        (setf y (register-inline-constant (tn-value y))))
962       (descriptor-reg
963        (setf y (ea-for-df-desc y)))
964       (t))
965     (note-this-location vop :internal-error)
966     (inst comisd xmm y)))
967
968 (macrolet ((define-complex-float-= (complex-complex-name complex-real-name real-complex-name
969                                     real-sc real-constant-sc real-type
970                                     complex-sc complex-constant-sc complex-type
971                                     real-move-inst complex-move-inst
972                                     cmp-inst mask-inst mask)
973                `(progn
974                   (define-vop (,complex-complex-name float-compare)
975                     (:translate =)
976                     (:args (x :scs (,complex-sc ,complex-constant-sc)
977                               :target cmp
978                               :load-if (not (sc-is x ,complex-constant-sc)))
979                            (y :scs (,complex-sc ,complex-constant-sc)
980                               :target cmp
981                               :load-if (not (sc-is y ,complex-constant-sc))))
982                     (:arg-types ,complex-type ,complex-type)
983                     (:temporary (:sc ,complex-sc :from :eval) cmp)
984                     (:temporary (:sc dword-reg) bits)
985                     (:info)
986                     (:conditional :e)
987                     (:generator 3
988                       (when (location= y cmp)
989                         (rotatef x y))
990                       (sc-case x
991                         (,real-constant-sc
992                          (inst ,real-move-inst cmp (register-inline-constant
993                                                     (tn-value x))))
994                         (,complex-constant-sc
995                          (inst ,complex-move-inst cmp (register-inline-constant
996                                                        (tn-value x))))
997                         (t
998                          (move cmp x)))
999                       (when (sc-is y ,real-constant-sc ,complex-constant-sc)
1000                         (setf y (register-inline-constant :aligned (tn-value y))))
1001                       (note-this-location vop :internal-error)
1002                       (inst ,cmp-inst :eq cmp y)
1003                       (inst ,mask-inst bits cmp)
1004                       (inst cmp (if (location= bits eax-tn) al-tn bits)
1005                             ,mask)))
1006                   (define-vop (,complex-real-name ,complex-complex-name)
1007                     (:args (x :scs (,complex-sc ,complex-constant-sc)
1008                               :target cmp
1009                               :load-if (not (sc-is x ,complex-constant-sc)))
1010                            (y :scs (,real-sc ,real-constant-sc)
1011                               :target cmp
1012                               :load-if (not (sc-is y ,real-constant-sc))))
1013                     (:arg-types ,complex-type ,real-type))
1014                   (define-vop (,real-complex-name ,complex-complex-name)
1015                     (:args (x :scs (,real-sc ,real-constant-sc)
1016                               :target cmp
1017                               :load-if (not (sc-is x ,real-constant-sc)))
1018                            (y :scs (,complex-sc ,complex-constant-sc)
1019                               :target cmp
1020                               :load-if (not (sc-is y ,complex-constant-sc))))
1021                     (:arg-types ,real-type ,complex-type)))))
1022   (define-complex-float-= =/complex-single-float =/complex-real-single-float =/real-complex-single-float
1023     single-reg fp-single-immediate single-float
1024     complex-single-reg fp-complex-single-immediate complex-single-float
1025     movss movq cmpps movmskps #b1111)
1026   (define-complex-float-= =/complex-double-float =/complex-real-double-float =/real-complex-double-float
1027     double-reg fp-double-immediate double-float
1028     complex-double-reg fp-complex-double-immediate complex-double-float
1029     movsd movapd cmppd movmskpd #b11))
1030
1031 (macrolet ((define-</> (op single-name double-name &rest flags)
1032                `(progn
1033                   (define-vop (,double-name double-float-compare)
1034                     (:translate ,op)
1035                     (:info)
1036                     (:conditional ,@flags)
1037                     (:generator 3
1038                       (sc-case y
1039                         (double-stack
1040                          (setf y (ea-for-df-stack y)))
1041                         (descriptor-reg
1042                          (setf y (ea-for-df-desc y)))
1043                         (fp-double-immediate
1044                          (setf y (register-inline-constant (tn-value y))))
1045                         (t))
1046                       (inst comisd x y)))
1047                   (define-vop (,single-name single-float-compare)
1048                     (:translate ,op)
1049                     (:info)
1050                     (:conditional ,@flags)
1051                     (:generator 3
1052                       (sc-case y
1053                         (single-stack
1054                          (setf y (ea-for-sf-stack y)))
1055                         (fp-single-immediate
1056                          (setf y (register-inline-constant (tn-value y))))
1057                         (t))
1058                       (inst comiss x y))))))
1059   (define-</> < <single-float <double-float not :p :nc)
1060   (define-</> > >single-float >double-float not :p :na))
1061
1062 \f
1063 ;;;; conversion
1064
1065 (macrolet ((frob (name translate inst to-sc to-type)
1066              `(define-vop (,name)
1067                 (:args (x :scs (signed-stack signed-reg)))
1068                 (:results (y :scs (,to-sc)))
1069                 (:arg-types signed-num)
1070                 (:result-types ,to-type)
1071                 (:policy :fast-safe)
1072                 (:note "inline float coercion")
1073                 (:translate ,translate)
1074                 (:vop-var vop)
1075                 (:save-p :compute-only)
1076                 (:generator 5
1077                   (sc-case y
1078                     (single-reg (inst xorps y y))
1079                     (double-reg (inst xorpd y y)))
1080                   (note-this-location vop :internal-error)
1081                   (inst ,inst y x)))))
1082   (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
1083   (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
1084
1085 (macrolet ((frob (name translate inst from-scs from-type ea-func to-sc to-type)
1086              `(define-vop (,name)
1087                (:args (x :scs ,from-scs :target y))
1088                (:results (y :scs (,to-sc)))
1089                (:arg-types ,from-type)
1090                (:result-types ,to-type)
1091                (:policy :fast-safe)
1092                (:note "inline float coercion")
1093                (:translate ,translate)
1094                (:vop-var vop)
1095                (:save-p :compute-only)
1096                (:generator 2
1097                 (unless (location= x y)
1098                   (sc-case y
1099                     (single-reg (inst xorps y y))
1100                     (double-reg (inst xorpd y y))))
1101                 (note-this-location vop :internal-error)
1102                 (inst ,inst y (sc-case x
1103                                 (,(first from-scs) x)
1104                                 (,(second from-scs) (,ea-func x))))
1105                 ,(when (and (eq from-type 'double-float) ; if the input is wider
1106                             (eq to-type 'single-float))  ; than the output, clear
1107                    `(when (location= x y)                ; noise in the high part
1108                       (inst shufps y y #4r3330)))))))
1109   (frob %single-float/double-float %single-float cvtsd2ss
1110         (double-reg double-stack) double-float ea-for-df-stack
1111         single-reg single-float)
1112
1113   (frob %double-float/single-float %double-float cvtss2sd
1114         (single-reg single-stack) single-float ea-for-sf-stack
1115         double-reg double-float))
1116
1117 (macrolet ((frob (trans inst from-scs from-type ea-func)
1118              `(define-vop (,(symbolicate trans "/" from-type))
1119                (:args (x :scs ,from-scs))
1120                (:results (y :scs (signed-reg)))
1121                (:arg-types ,from-type)
1122                (:result-types signed-num)
1123                (:translate ,trans)
1124                (:policy :fast-safe)
1125                (:note "inline float truncate")
1126                (:vop-var vop)
1127                (:save-p :compute-only)
1128                (:generator 5
1129                  (inst ,inst y (sc-case x
1130                                  (,(first from-scs) x)
1131                                  (,(second from-scs) (,ea-func x))))))))
1132   (frob %unary-truncate/single-float cvttss2si
1133         (single-reg single-stack) single-float ea-for-sf-stack)
1134   (frob %unary-truncate/double-float cvttsd2si
1135         (double-reg double-stack) double-float ea-for-df-stack)
1136
1137   (frob %unary-round cvtss2si
1138         (single-reg single-stack) single-float ea-for-sf-stack)
1139   (frob %unary-round cvtsd2si
1140         (double-reg double-stack) double-float ea-for-df-stack))
1141
1142 (define-vop (make-single-float)
1143   (:args (bits :scs (signed-reg) :target res
1144                :load-if (not (or (and (sc-is bits signed-stack)
1145                                       (sc-is res single-reg))
1146                                  (and (sc-is bits signed-stack)
1147                                       (sc-is res single-stack)
1148                                       (location= bits res))))))
1149   (:results (res :scs (single-reg single-stack)))
1150   (:arg-types signed-num)
1151   (:result-types single-float)
1152   (:translate make-single-float)
1153   (:policy :fast-safe)
1154   (:vop-var vop)
1155   (:generator 4
1156     (sc-case res
1157        (single-stack
1158         (sc-case bits
1159           (signed-reg
1160            (inst mov res bits))
1161           (signed-stack
1162            (aver (location= bits res)))))
1163        (single-reg
1164         (sc-case bits
1165           (signed-reg
1166            (inst movd res bits))
1167           (signed-stack
1168            (inst movd res bits)))))))
1169
1170 (define-vop (make-single-float-c)
1171   (:results (res :scs (single-reg single-stack descriptor-reg)))
1172   (:arg-types (:constant (signed-byte 32)))
1173   (:result-types single-float)
1174   (:info bits)
1175   (:translate make-single-float)
1176   (:policy :fast-safe)
1177   (:vop-var vop)
1178   (:generator 1
1179     (sc-case res
1180        (single-stack
1181         (inst mov res bits))
1182        (single-reg
1183         (inst movss res (register-inline-constant :dword bits)))
1184        (descriptor-reg
1185         (inst mov res (logior (ash bits 32)
1186                               single-float-widetag))))))
1187
1188 (define-vop (make-double-float)
1189   (:args (hi-bits :scs (signed-reg))
1190          (lo-bits :scs (unsigned-reg)))
1191   (:results (res :scs (double-reg)))
1192   (:temporary (:sc unsigned-reg) temp)
1193   (:arg-types signed-num unsigned-num)
1194   (:result-types double-float)
1195   (:translate make-double-float)
1196   (:policy :fast-safe)
1197   (:vop-var vop)
1198   (:generator 2
1199     (move temp hi-bits)
1200     (inst shl temp 32)
1201     (inst or temp lo-bits)
1202     (inst movd res temp)))
1203
1204 (define-vop (make-double-float-c)
1205   (:results (res :scs (double-reg)))
1206   (:arg-types (:constant (signed-byte 32)) (:constant (unsigned-byte 32)))
1207   (:result-types double-float)
1208   (:info hi lo)
1209   (:translate make-double-float)
1210   (:policy :fast-safe)
1211   (:vop-var vop)
1212   (:generator 1
1213     (inst movsd res (register-inline-constant :qword (logior (ash hi 32) lo)))))
1214
1215 (define-vop (single-float-bits)
1216   (:args (float :scs (single-reg descriptor-reg)
1217                 :load-if (not (sc-is float single-stack))))
1218   (:results (bits :scs (signed-reg)))
1219   (:arg-types single-float)
1220   (:result-types signed-num)
1221   (:translate single-float-bits)
1222   (:policy :fast-safe)
1223   (:generator 4
1224      (sc-case float
1225        (single-reg
1226         (inst movd bits float)
1227         (inst movsxd bits (reg-in-size bits :dword)))
1228        (single-stack
1229         (inst movsxd bits (make-ea :dword ; c.f. ea-for-sf-stack
1230                                    :base rbp-tn
1231                                    :disp (frame-byte-offset (tn-offset float)))))
1232        (descriptor-reg
1233         (move bits float)
1234         (inst sar bits 32)))))
1235
1236 (define-vop (double-float-high-bits)
1237   (:args (float :scs (double-reg descriptor-reg)
1238                 :load-if (not (sc-is float double-stack))))
1239   (:results (hi-bits :scs (signed-reg)))
1240   (:temporary (:sc signed-stack :from :argument :to :result) temp)
1241   (:arg-types double-float)
1242   (:result-types signed-num)
1243   (:translate double-float-high-bits)
1244   (:policy :fast-safe)
1245   (:vop-var vop)
1246   (:generator 5
1247      (sc-case float
1248        (double-reg
1249         (inst movsd temp float)
1250         (move hi-bits temp))
1251        (double-stack
1252         (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1253        (descriptor-reg
1254         (loadw hi-bits float double-float-value-slot
1255                other-pointer-lowtag)))
1256      (inst sar hi-bits 32)))
1257
1258 (define-vop (double-float-low-bits)
1259   (:args (float :scs (double-reg descriptor-reg)
1260                 :load-if (not (sc-is float double-stack))))
1261   (:results (lo-bits :scs (unsigned-reg)))
1262   (:temporary (:sc signed-stack :from :argument :to :result) temp)
1263   (:arg-types double-float)
1264   (:result-types unsigned-num)
1265   (:translate double-float-low-bits)
1266   (:policy :fast-safe)
1267   (:vop-var vop)
1268   (:generator 5
1269      (let ((dword-lo-bits (reg-in-size lo-bits :dword)))
1270        (sc-case float
1271         (double-reg
1272          (inst movsd temp float)
1273          (inst mov dword-lo-bits
1274                (make-ea :dword :base rbp-tn
1275                         :disp (frame-byte-offset (tn-offset temp)))))
1276         (double-stack
1277          (inst mov dword-lo-bits
1278                (make-ea :dword :base rbp-tn
1279                         :disp (frame-byte-offset (tn-offset float)))))
1280         (descriptor-reg
1281          (inst mov dword-lo-bits
1282                (make-ea-for-object-slot-half float double-float-value-slot
1283                                              other-pointer-lowtag)))))))
1284
1285 \f
1286
1287 ;;;; complex float VOPs
1288
1289 (define-vop (make-complex-single-float)
1290   (:translate complex)
1291   (:args (real :scs (single-reg fp-single-zero)
1292                :target r
1293                :load-if (not (sc-is real fp-single-zero)))
1294          (imag :scs (single-reg fp-single-zero)
1295                :load-if (not (sc-is imag fp-single-zero))))
1296   (:arg-types single-float single-float)
1297   (:results (r :scs (complex-single-reg) :from (:argument 0)))
1298   (:result-types complex-single-float)
1299   (:note "inline complex single-float creation")
1300   (:policy :fast-safe)
1301   (:generator 5
1302     (cond ((sc-is real fp-single-zero)
1303            (inst xorps r r)
1304            (unless (sc-is imag fp-single-zero)
1305              (inst unpcklps r imag)))
1306           ((location= real imag)
1307            (move r real)
1308            (inst unpcklps r r))
1309           (t
1310            (move r real)
1311            (unless (sc-is imag fp-single-zero)
1312              (inst unpcklps r imag))))))
1313
1314 (define-vop (make-complex-double-float)
1315   (:translate complex)
1316   (:args (real :scs (double-reg fp-double-zero)
1317                :target r
1318                :load-if (not (sc-is real fp-double-zero)))
1319          (imag :scs (double-reg fp-double-zero)
1320                :load-if (not (sc-is imag fp-double-zero))))
1321   (:arg-types double-float double-float)
1322   (:results (r :scs (complex-double-reg) :from (:argument 0)))
1323   (:result-types complex-double-float)
1324   (:note "inline complex double-float creation")
1325   (:policy :fast-safe)
1326   (:generator 5
1327     (cond ((sc-is real fp-double-zero)
1328            (inst xorpd r r)
1329            (unless (sc-is imag fp-double-zero)
1330              (inst unpcklpd r imag)))
1331           ((location= real imag)
1332            (move r real)
1333            (inst unpcklpd r r))
1334           (t
1335            (move r real)
1336            (unless (sc-is imag fp-double-zero)
1337              (inst unpcklpd r imag))))))
1338
1339 (define-vop (complex-float-value)
1340   (:args (x :target r))
1341   (:temporary (:sc complex-double-reg) zero)
1342   (:results (r))
1343   (:variant-vars offset)
1344   (:policy :fast-safe)
1345   (:generator 3
1346     (cond ((sc-is x complex-double-reg)
1347            (move r x)
1348            (inst xorpd zero zero)
1349            (ecase offset
1350              (0 (inst unpcklpd r zero))
1351              (1 (inst unpckhpd r zero))))
1352           ((sc-is x complex-single-reg)
1353            (move r x)
1354            (ecase offset
1355              (0 (inst shufps r r #b11111100))
1356              (1 (inst shufps r r #b11111101))))
1357           ((sc-is r single-reg)
1358            (let ((ea (sc-case x
1359                        (complex-single-stack
1360                         (ecase offset
1361                           (0 (ea-for-csf-real-stack x))
1362                           (1 (ea-for-csf-imag-stack x))))
1363                        (descriptor-reg
1364                         (ecase offset
1365                           (0 (ea-for-csf-real-desc x))
1366                           (1 (ea-for-csf-imag-desc x)))))))
1367              (inst movss r ea)))
1368           ((sc-is r double-reg)
1369            (let ((ea (sc-case x
1370                        (complex-double-stack
1371                         (ecase offset
1372                           (0 (ea-for-cdf-real-stack x))
1373                           (1 (ea-for-cdf-imag-stack x))))
1374                        (descriptor-reg
1375                         (ecase offset
1376                           (0 (ea-for-cdf-real-desc x))
1377                           (1 (ea-for-cdf-imag-desc x)))))))
1378              (inst movsd r ea)))
1379           (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
1380
1381 (define-vop (realpart/complex-single-float complex-float-value)
1382   (:translate realpart)
1383   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1384             :target r))
1385   (:arg-types complex-single-float)
1386   (:results (r :scs (single-reg)))
1387   (:result-types single-float)
1388   (:note "complex float realpart")
1389   (:variant 0))
1390
1391 (define-vop (realpart/complex-double-float complex-float-value)
1392   (:translate realpart)
1393   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1394             :target r))
1395   (:arg-types complex-double-float)
1396   (:results (r :scs (double-reg)))
1397   (:result-types double-float)
1398   (:note "complex float realpart")
1399   (:variant 0))
1400
1401 (define-vop (imagpart/complex-single-float complex-float-value)
1402   (:translate imagpart)
1403   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1404             :target r))
1405   (:arg-types complex-single-float)
1406   (:results (r :scs (single-reg)))
1407   (:result-types single-float)
1408   (:note "complex float imagpart")
1409   (:variant 1))
1410
1411 (define-vop (imagpart/complex-double-float complex-float-value)
1412   (:translate imagpart)
1413   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1414             :target r))
1415   (:arg-types complex-double-float)
1416   (:results (r :scs (double-reg)))
1417   (:result-types double-float)
1418   (:note "complex float imagpart")
1419   (:variant 1))
1420
1421 \f
1422 ;;; hack dummy VOPs to bias the representation selection of their
1423 ;;; arguments towards a FP register, which can help avoid consing at
1424 ;;; inappropriate locations
1425 (defknown double-float-reg-bias (double-float) (values))
1426 (define-vop (double-float-reg-bias)
1427   (:translate double-float-reg-bias)
1428   (:args (x :scs (double-reg double-stack) :load-if nil))
1429   (:arg-types double-float)
1430   (:policy :fast-safe)
1431   (:note "inline dummy FP register bias")
1432   (:ignore x)
1433   (:generator 0))
1434 (defknown single-float-reg-bias (single-float) (values))
1435 (define-vop (single-float-reg-bias)
1436   (:translate single-float-reg-bias)
1437   (:args (x :scs (single-reg single-stack) :load-if nil))
1438   (:arg-types single-float)
1439   (:policy :fast-safe)
1440   (:note "inline dummy FP register bias")
1441   (:ignore x)
1442   (:generator 0))
1443
1444 (defknown swap-complex ((complex float)) (complex float)
1445     (foldable flushable movable always-translatable))
1446 (defoptimizer (swap-complex derive-type) ((x))
1447   (sb!c::lvar-type x))
1448 (defun swap-complex (x)
1449   (complex (imagpart x) (realpart x)))
1450 (define-vop (swap-complex-single-float)
1451   (:translate swap-complex)
1452   (:policy :fast-safe)
1453   (:args (x :scs (complex-single-reg) :target r))
1454   (:arg-types complex-single-float)
1455   (:results (r :scs (complex-single-reg)))
1456   (:result-types complex-single-float)
1457   (:generator 2
1458      (move r x)
1459      (inst shufps r r #b11110001)))
1460 (define-vop (swap-complex-double-float)
1461   (:translate swap-complex)
1462   (:policy :fast-safe)
1463   (:args (x :scs (complex-double-reg) :target r))
1464   (:arg-types complex-double-float)
1465   (:results (r :scs (complex-double-reg)))
1466   (:result-types complex-double-float)
1467   (:generator 2
1468      (move r x)
1469      (inst shufpd r r #b01)))