1.0.41.26: ppc: Calling-convention fixes for static-fun VOPs.
[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                              ((= (tn-offset ,base) rbp-offset)
55                               0)
56                              (t (error "Unexpected offset.")))
57                        (ecase ,kind
58                          (:single
59                             (ecase ,slot
60                               (:real 0)
61                               (:imag -1/2)))
62                          (:double
63                             (ecase ,slot
64                               (:real 1)
65                               (:imag 0)))))))))
66   (defun ea-for-csf-data-stack (tn &optional (base rbp-tn))
67     (ea-for-cxf-stack tn :single :real base))
68   (defun ea-for-csf-real-stack (tn &optional (base rbp-tn))
69     (ea-for-cxf-stack tn :single :real base))
70   (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn))
71     (ea-for-cxf-stack tn :single :imag base))
72
73   (defun ea-for-cdf-data-stack (tn &optional (base rbp-tn))
74     (ea-for-cxf-stack tn :double :real base))
75   (defun ea-for-cdf-real-stack (tn &optional (base rbp-tn))
76     (ea-for-cxf-stack tn :double :real base))
77   (defun ea-for-cdf-imag-stack (tn &optional (base rbp-tn))
78     (ea-for-cxf-stack tn :double :imag base)))
79 \f
80 ;;;; move functions
81
82 ;;; X is source, Y is destination.
83
84 (define-move-fun (load-fp-zero 1) (vop x y)
85   ((fp-single-zero) (single-reg)
86    (fp-double-zero) (double-reg)
87    (fp-complex-single-zero) (complex-single-reg)
88    (fp-complex-double-zero) (complex-double-reg))
89   (identity x)
90   (sc-case y
91     ((single-reg complex-single-reg) (inst xorps y y))
92     ((double-reg complex-double-reg) (inst xorpd y y))))
93
94 (define-move-fun (load-fp-immediate 1) (vop x y)
95   ((fp-single-immediate) (single-reg)
96    (fp-double-immediate) (double-reg)
97    (fp-complex-single-immediate) (complex-single-reg)
98    (fp-complex-double-immediate) (complex-double-reg))
99   (let ((x (register-inline-constant (tn-value x))))
100     (sc-case y
101       (single-reg (inst movss y x))
102       (double-reg (inst movsd y x))
103       (complex-single-reg (inst movq y x))
104       (complex-double-reg (inst movapd y x)))))
105
106 (define-move-fun (load-single 2) (vop x y)
107   ((single-stack) (single-reg))
108   (inst movss y (ea-for-sf-stack x)))
109
110 (define-move-fun (store-single 2) (vop x y)
111   ((single-reg) (single-stack))
112   (inst movss (ea-for-sf-stack y) x))
113
114 (define-move-fun (load-double 2) (vop x y)
115   ((double-stack) (double-reg))
116   (inst movsd y (ea-for-df-stack x)))
117
118 (define-move-fun (store-double 2) (vop x y)
119   ((double-reg) (double-stack))
120   (inst movsd  (ea-for-df-stack y) x))
121
122 (eval-when (:compile-toplevel :execute)
123   (setf *read-default-float-format* 'single-float))
124 \f
125 ;;;; complex float move functions
126
127 ;;; X is source, Y is destination.
128 (define-move-fun (load-complex-single 2) (vop x y)
129   ((complex-single-stack) (complex-single-reg))
130   (inst movq y (ea-for-csf-data-stack x)))
131
132 (define-move-fun (store-complex-single 2) (vop x y)
133   ((complex-single-reg) (complex-single-stack))
134   (inst movq (ea-for-csf-data-stack y) x))
135
136 (define-move-fun (load-complex-double 2) (vop x y)
137   ((complex-double-stack) (complex-double-reg))
138   (inst movupd y (ea-for-cdf-data-stack x)))
139
140 (define-move-fun (store-complex-double 2) (vop x y)
141   ((complex-double-reg) (complex-double-stack))
142   (inst movupd (ea-for-cdf-data-stack y) x))
143 \f
144 ;;;; move VOPs
145
146 ;;; float register to register moves
147 (macrolet ((frob (vop sc)
148              `(progn
149                 (define-vop (,vop)
150                   (:args (x :scs (,sc)
151                             :target y
152                             :load-if (not (location= x y))))
153                   (:results (y :scs (,sc)
154                                :load-if (not (location= x y))))
155                   (:note "float move")
156                   (:generator 0
157                     (move y x)))
158                 (define-move-vop ,vop :move (,sc) (,sc)))))
159   (frob single-move single-reg)
160   (frob double-move double-reg)
161   (frob complex-single-move complex-single-reg)
162   (frob complex-double-move complex-double-reg))
163
164 \f
165 ;;; Move from float to a descriptor reg. allocating a new float
166 ;;; object in the process.
167 (define-vop (move-from-single)
168   (:args (x :scs (single-reg) :to :save))
169   (:results (y :scs (descriptor-reg)))
170   (:note "float to pointer coercion")
171   (:generator 4
172     (inst movd y x)
173     (inst shl y 32)
174     (inst or y single-float-widetag)))
175
176 (define-move-vop move-from-single :move
177   (single-reg) (descriptor-reg))
178
179 (define-vop (move-from-double)
180   (:args (x :scs (double-reg) :to :save))
181   (:results (y :scs (descriptor-reg)))
182   (:node-var node)
183   (:note "float to pointer coercion")
184   (:generator 13
185      (with-fixed-allocation (y
186                              double-float-widetag
187                              double-float-size
188                              node)
189        (inst movsd (ea-for-df-desc y) x))))
190 (define-move-vop move-from-double :move
191   (double-reg) (descriptor-reg))
192
193 ;;; Move from a descriptor to a float register.
194 (define-vop (move-to-single-reg)
195    (:args (x :scs (descriptor-reg) :target tmp
196              :load-if (not (sc-is x control-stack))))
197    (:temporary (:sc unsigned-reg :from :argument :to :result) tmp)
198    (:results (y :scs (single-reg)))
199    (:note "pointer to float coercion")
200    (:generator 2
201      (sc-case x
202        (descriptor-reg
203         (move tmp x)
204         (inst shr tmp 32)
205         (inst movd y tmp))
206        (control-stack
207         ;; When the single-float descriptor is in memory, the untagging
208         ;; is done in the target XMM register. This is faster than going
209         ;; through a general-purpose register and the code is smaller.
210         (inst movq y x)
211         (inst shufps y y #4r3331)))))
212 (define-move-vop move-to-single-reg :move (descriptor-reg) (single-reg))
213
214 ;;; Move from a descriptor to a float stack.
215 (define-vop (move-to-single-stack)
216   (:args (x :scs (descriptor-reg) :target tmp))
217   (:temporary (:sc unsigned-reg :from :argument :to :result) tmp)
218   (:results (y :scs (single-stack)))
219   (:note "pointer to float coercion")
220   (:generator 2
221     (move tmp x)
222     (inst shr tmp 32)
223     (let ((slot (make-ea :dword :base rbp-tn
224                          :disp (frame-byte-offset (tn-offset y)))))
225       (inst mov slot (reg-in-size tmp :dword)))))
226 (define-move-vop move-to-single-stack :move (descriptor-reg) (single-stack))
227
228 (define-vop (move-to-double)
229   (:args (x :scs (descriptor-reg)))
230   (:results (y :scs (double-reg)))
231   (:note "pointer to float coercion")
232   (:generator 2
233     (inst movsd y (ea-for-df-desc x))))
234 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
235
236 \f
237 ;;; Move from complex float to a descriptor reg. allocating a new
238 ;;; complex float object in the process.
239 (define-vop (move-from-complex-single)
240   (:args (x :scs (complex-single-reg) :to :save))
241   (:results (y :scs (descriptor-reg)))
242   (:node-var node)
243   (:note "complex float to pointer coercion")
244   (:generator 13
245      (with-fixed-allocation (y
246                              complex-single-float-widetag
247                              complex-single-float-size
248                              node)
249        (inst movq (ea-for-csf-data-desc y) x))))
250 (define-move-vop move-from-complex-single :move
251   (complex-single-reg) (descriptor-reg))
252
253 (define-vop (move-from-complex-double)
254   (:args (x :scs (complex-double-reg) :to :save))
255   (:results (y :scs (descriptor-reg)))
256   (:node-var node)
257   (:note "complex float to pointer coercion")
258   (:generator 13
259      (with-fixed-allocation (y
260                              complex-double-float-widetag
261                              complex-double-float-size
262                              node)
263        (inst movapd (ea-for-cdf-data-desc y) x))))
264 (define-move-vop move-from-complex-double :move
265   (complex-double-reg) (descriptor-reg))
266
267 ;;; Move from a descriptor to a complex float register.
268 (macrolet ((frob (name sc format)
269              `(progn
270                 (define-vop (,name)
271                   (:args (x :scs (descriptor-reg)))
272                   (:results (y :scs (,sc)))
273                   (:note "pointer to complex float coercion")
274                   (:generator 2
275                     ,(ecase format
276                       (:single
277                          '(inst movq y (ea-for-csf-data-desc x)))
278                       (:double
279                          '(inst movapd y (ea-for-cdf-data-desc x))))))
280                 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
281   (frob move-to-complex-single complex-single-reg :single)
282   (frob move-to-complex-double complex-double-reg :double))
283 \f
284 ;;;; the move argument vops
285 ;;;;
286 ;;;; Note these are also used to stuff fp numbers onto the c-call
287 ;;;; stack so the order is different than the lisp-stack.
288
289 ;;; the general MOVE-ARG VOP
290 (macrolet ((frob (name sc stack-sc format)
291              `(progn
292                 (define-vop (,name)
293                   (:args (x :scs (,sc) :target y)
294                          (fp :scs (any-reg)
295                              :load-if (not (sc-is y ,sc))))
296                   (:results (y))
297                   (:note "float argument move")
298                   (:generator ,(case format (:single 2) (:double 3) )
299                     (sc-case y
300                       (,sc
301                        (move y x))
302                       (,stack-sc
303                        (if (= (tn-offset fp) esp-offset)
304                            (let* ((offset (* (tn-offset y) n-word-bytes))
305                                   (ea (make-ea :dword :base fp :disp offset)))
306                              ,@(ecase format
307                                       (:single '((inst movss ea x)))
308                                       (:double '((inst movsd ea x)))))
309                            (let ((ea (make-ea
310                                       :dword :base fp
311                                       :disp (frame-byte-offset (tn-offset y)))))
312                              ,@(ecase format
313                                  (:single '((inst movss ea x)))
314                                  (:double '((inst movsd ea x))))))))))
315                 (define-move-vop ,name :move-arg
316                   (,sc descriptor-reg) (,sc)))))
317   (frob move-single-float-arg single-reg single-stack :single)
318   (frob move-double-float-arg double-reg double-stack :double))
319
320 ;;;; complex float MOVE-ARG VOP
321 (macrolet ((frob (name sc stack-sc format)
322              `(progn
323                 (define-vop (,name)
324                   (:args (x :scs (,sc) :target y)
325                          (fp :scs (any-reg)
326                              :load-if (not (sc-is y ,sc))))
327                   (:results (y))
328                   (:note "complex float argument move")
329                   (:generator ,(ecase format (:single 2) (:double 3))
330                     (sc-case y
331                       (,sc
332                        (move y x))
333                       (,stack-sc
334                        ,(ecase format
335                           (:single
336                              '(inst movq (ea-for-csf-data-stack y fp) x))
337                           (:double
338                              '(inst movupd (ea-for-cdf-data-stack y fp) x)))))))
339                 (define-move-vop ,name :move-arg
340                   (,sc descriptor-reg) (,sc)))))
341   (frob move-complex-single-float-arg
342         complex-single-reg complex-single-stack :single)
343   (frob move-complex-double-float-arg
344         complex-double-reg complex-double-stack :double))
345
346 (define-move-vop move-arg :move-arg
347   (single-reg double-reg
348    complex-single-reg complex-double-reg)
349   (descriptor-reg))
350
351 \f
352 ;;;; arithmetic VOPs
353
354 (define-vop (float-op)
355   (:args (x) (y))
356   (:results (r))
357   (:policy :fast-safe)
358   (:note "inline float arithmetic")
359   (:vop-var vop)
360   (:save-p :compute-only))
361
362 (macrolet ((frob (name comm-name sc constant-sc ptype)
363              `(progn
364                 (define-vop (,name float-op)
365                   (:args (x :scs (,sc ,constant-sc)
366                             :target r
367                             :load-if (not (sc-is x ,constant-sc)))
368                          (y :scs (,sc ,constant-sc)
369                             :load-if (not (sc-is y ,constant-sc))))
370                   (:results (r :scs (,sc)))
371                   (:arg-types ,ptype ,ptype)
372                   (:result-types ,ptype))
373                 (define-vop (,comm-name float-op)
374                   (:args (x :scs (,sc ,constant-sc)
375                             :target r
376                             :load-if (not (sc-is x ,constant-sc)))
377                          (y :scs (,sc ,constant-sc)
378                             :target r
379                             :load-if (not (sc-is y ,constant-sc))))
380                   (:results (r :scs (,sc)))
381                   (:arg-types ,ptype ,ptype)
382                   (:result-types ,ptype)))))
383   (frob single-float-op single-float-comm-op
384         single-reg fp-single-immediate single-float)
385   (frob double-float-op double-float-comm-op
386         double-reg fp-double-immediate double-float)
387   (frob complex-single-float-op complex-single-float-comm-op
388         complex-single-reg fp-complex-single-immediate
389         complex-single-float)
390   (frob complex-double-float-op complex-double-float-comm-op
391         complex-double-reg fp-complex-double-immediate
392         complex-double-float))
393
394 (macrolet ((generate (opinst commutative constant-sc load-inst)
395              `(flet ((get-constant (tn)
396                        (register-inline-constant
397                         ,@(and (eq constant-sc 'fp-single-immediate)
398                                '(:aligned))
399                         (tn-value tn))))
400                 (declare (ignorable #'get-constant))
401                 (cond
402                   ((location= x r)
403                    (when (sc-is y ,constant-sc)
404                      (setf y (get-constant y)))
405                    (inst ,opinst x y))
406                   ((and ,commutative (location= y r))
407                    (when (sc-is x ,constant-sc)
408                      (setf x (get-constant x)))
409                    (inst ,opinst y x))
410                   ((not (location= r y))
411                    (if (sc-is x ,constant-sc)
412                        (inst ,load-inst r (get-constant x))
413                        (move r x))
414                    (when (sc-is y ,constant-sc)
415                      (setf y (get-constant y)))
416                    (inst ,opinst r y))
417                   (t
418                    (if (sc-is x ,constant-sc)
419                        (inst ,load-inst tmp (get-constant x))
420                        (move tmp x))
421                    (inst ,opinst tmp y)
422                    (move r tmp)))))
423            (frob (op sinst sname scost dinst dname dcost commutative
424                      &optional csinst csname cscost cdinst cdname cdcost)
425              `(progn
426                 (define-vop (,sname ,(if commutative
427                                          'single-float-comm-op
428                                          'single-float-op))
429                   (:translate ,op)
430                   (:temporary (:sc single-reg) tmp)
431                   (:generator ,scost
432                     (generate ,sinst ,commutative fp-single-immediate movss)))
433                 (define-vop (,dname ,(if commutative
434                                          'double-float-comm-op
435                                          'double-float-op))
436                   (:translate ,op)
437                   (:temporary (:sc double-reg) tmp)
438                   (:generator ,dcost
439                     (generate ,dinst ,commutative fp-double-immediate movsd)))
440                 ,(when csinst
441                    `(define-vop (,csname
442                                  ,(if commutative
443                                       'complex-single-float-comm-op
444                                       'complex-single-float-op))
445                       (:translate ,op)
446                       (:temporary (:sc complex-single-reg) tmp)
447                       (:generator ,cscost
448                         (generate ,csinst ,commutative
449                                   fp-complex-single-immediate movq))))
450                 ,(when cdinst
451                    `(define-vop (,cdname
452                                  ,(if commutative
453                                       'complex-double-float-comm-op
454                                       'complex-double-float-op))
455                       (:translate ,op)
456                       (:temporary (:sc complex-double-reg) tmp)
457                       (:generator ,cdcost
458                         (generate ,cdinst ,commutative
459                                   fp-complex-double-immediate movapd)))))))
460   (frob + addss +/single-float 2 addsd +/double-float 2 t
461         addps +/complex-single-float 3 addpd +/complex-double-float 3)
462   (frob - subss -/single-float 2 subsd -/double-float 2 nil
463         subps -/complex-single-float 3 subpd -/complex-double-float 3)
464   (frob * mulss */single-float 4 mulsd */double-float 5 t)
465   (frob / divss //single-float 12 divsd //double-float 19 nil))
466
467 (macrolet ((frob (op cost commutativep
468                      duplicate-inst op-inst real-move-inst complex-move-inst
469                      real-sc real-constant-sc real-type
470                      complex-sc complex-constant-sc complex-type
471                      real-complex-name complex-real-name)
472              (cond ((not duplicate-inst) ; simple case
473                     `(flet ((load-into (r x)
474                               (sc-case x
475                                 (,real-constant-sc
476                                  (inst ,real-move-inst r
477                                        (register-inline-constant (tn-value x))))
478                                 (,complex-constant-sc
479                                  (inst ,complex-move-inst r
480                                        (register-inline-constant (tn-value x))))
481                                 (t (move r x)))))
482                        ,(when real-complex-name
483                           `(define-vop (,real-complex-name float-op)
484                              (:translate ,op)
485                              (:args (x :scs (,real-sc ,real-constant-sc)
486                                        :target r
487                                        :load-if (not (sc-is x ,real-constant-sc)))
488                                     (y :scs (,complex-sc ,complex-constant-sc)
489                                        ,@(when commutativep '(:target r))
490                                        :load-if (not (sc-is y ,complex-constant-sc))))
491                              (:arg-types ,real-type ,complex-type)
492                              (:results (r :scs (,complex-sc)
493                                           ,@(unless commutativep '(:from (:argument 0)))))
494                              (:result-types ,complex-type)
495                              (:generator ,cost
496                                ,(when commutativep
497                                   `(when (location= y r)
498                                      (rotatef x y)))
499                                (load-into r x)
500                                (when (sc-is y ,real-constant-sc ,complex-constant-sc)
501                                  (setf y (register-inline-constant
502                                           :aligned (tn-value y))))
503                                (inst ,op-inst r y))))
504
505                        ,(when complex-real-name
506                           `(define-vop (,complex-real-name float-op)
507                              (:translate ,op)
508                              (:args (x :scs (,complex-sc ,complex-constant-sc)
509                                        :target r
510                                        :load-if (not (sc-is x ,complex-constant-sc)))
511                                     (y :scs (,real-sc ,real-constant-sc)
512                                        ,@(when commutativep '(:target r))
513                                        :load-if (not (sc-is y ,real-constant-sc))))
514                              (:arg-types ,complex-type ,real-type)
515                              (:results (r :scs (,complex-sc)
516                                           ,@(unless commutativep '(:from (:argument 0)))))
517                              (:result-types ,complex-type)
518                              (:generator ,cost
519                                ,(when commutativep
520                                   `(when (location= y r)
521                                      (rotatef x y)))
522                                (load-into r x)
523                                (when (sc-is y ,real-constant-sc ,complex-constant-sc)
524                                  (setf y (register-inline-constant
525                                           :aligned (tn-value y))))
526                                (inst ,op-inst r y))))))
527                    (commutativep ; must duplicate, but commutative
528                     `(progn
529                        ,(when real-complex-name
530                           `(define-vop (,real-complex-name float-op)
531                              (:translate ,op)
532                              (:args (x :scs (,real-sc ,real-constant-sc)
533                                        :target dup
534                                        :load-if (not (sc-is x ,real-constant-sc)))
535                                     (y :scs (,complex-sc ,complex-constant-sc)
536                                        :target r
537                                        :to  :result
538                                        :load-if (not (sc-is y ,complex-constant-sc))))
539                              (:arg-types ,real-type ,complex-type)
540                              (:temporary (:sc ,complex-sc :target r
541                                           :from (:argument 0)
542                                           :to   :result)
543                                          dup)
544                              (:results (r :scs (,complex-sc)))
545                              (:result-types ,complex-type)
546                              (:generator ,cost
547                                (if (sc-is x ,real-constant-sc)
548                                    (inst ,complex-move-inst dup
549                                          (register-inline-constant
550                                           (complex (tn-value x) (tn-value x))))
551                                    (let ((real x))
552                                      ,duplicate-inst))
553                                 ;; safe: dup /= y
554                                 (when (location= dup r)
555                                   (rotatef dup y))
556                                 (if (sc-is y ,complex-constant-sc)
557                                     (inst ,complex-move-inst r
558                                           (register-inline-constant (tn-value y)))
559                                     (move r y))
560                                 (when (sc-is dup ,complex-constant-sc)
561                                   (setf dup (register-inline-constant
562                                              :aligned (tn-value dup))))
563                                 (inst ,op-inst r dup))))
564
565                        ,(when complex-real-name
566                           `(define-vop (,complex-real-name float-op)
567                              (:translate ,op)
568                              (:args (x :scs (,complex-sc ,complex-constant-sc)
569                                        :target r
570                                        :to  :result
571                                        :load-if (not (sc-is x ,complex-constant-sc)))
572                                     (y :scs (,real-sc ,real-constant-sc)
573                                        :target dup
574                                        :load-if (not (sc-is y ,real-constant-sc))))
575                              (:arg-types ,complex-type ,real-type)
576                              (:temporary (:sc ,complex-sc :target r
577                                           :from (:argument 1)
578                                           :to :result)
579                                          dup)
580                              (:results (r :scs (,complex-sc)))
581                              (:result-types ,complex-type)
582                              (:generator ,cost
583                                (if (sc-is y ,real-constant-sc)
584                                    (inst ,complex-move-inst dup
585                                          (register-inline-constant
586                                           (complex (tn-value y) (tn-value y))))
587                                    (let ((real y))
588                                      ,duplicate-inst))
589                                 (when (location= dup r)
590                                   (rotatef x dup))
591                                 (if (sc-is x ,complex-constant-sc)
592                                     (inst ,complex-move-inst r
593                                           (register-inline-constant (tn-value x)))
594                                     (move r x))
595                                 (when (sc-is dup ,complex-constant-sc)
596                                   (setf dup (register-inline-constant
597                                              :aligned (tn-value dup))))
598                                 (inst ,op-inst r dup))))))
599                    (t ; duplicate, not commutative
600                     `(progn
601                        ,(when real-complex-name
602                           `(define-vop (,real-complex-name float-op)
603                              (:translate ,op)
604                              (:args (x :scs (,real-sc ,real-constant-sc)
605                                        :target r
606                                        :load-if (not (sc-is x ,real-constant-sc)))
607                                     (y :scs (,complex-sc ,complex-constant-sc)
608                                        :to :result
609                                        :load-if (not (sc-is y ,complex-constant-sc))))
610                              (:arg-types ,real-type ,complex-type)
611                              (:results (r :scs (,complex-sc) :from (:argument 0)))
612                              (:result-types ,complex-type)
613                              (:generator ,cost
614                                (if (sc-is x ,real-constant-sc)
615                                    (inst ,complex-move-inst dup
616                                          (register-inline-constant
617                                           (complex (tn-value x) (tn-value x))))
618                                    (let ((real x)
619                                          (dup  r))
620                                      ,duplicate-inst))
621                                (when (sc-is y ,complex-constant-sc)
622                                  (setf y (register-inline-constant
623                                           :aligned (tn-value y))))
624                                (inst ,op-inst r y))))
625
626                        ,(when complex-real-name
627                           `(define-vop (,complex-real-name float-op)
628                              (:translate ,op)
629                              (:args (x :scs (,complex-sc)
630                                        :target r
631                                        :to :eval)
632                                     (y :scs (,real-sc ,real-constant-sc)
633                                        :target dup
634                                        :load-if (not (sc-is y ,complex-constant-sc))))
635                              (:arg-types ,complex-type ,real-type)
636                              (:temporary (:sc ,complex-sc :from (:argument 1))
637                                          dup)
638                              (:results (r :scs (,complex-sc) :from :eval))
639                              (:result-types ,complex-type)
640                              (:generator ,cost
641                                (if (sc-is y ,real-constant-sc)
642                                    (setf dup (register-inline-constant
643                                               :aligned (complex (tn-value y)
644                                                                 (tn-value y))))
645                                    (let ((real y))
646                                      ,duplicate-inst))
647                                (move r x)
648                                (inst ,op-inst r dup))))))))
649            (def-real-complex-op (op commutativep duplicatep
650                                     single-inst single-real-complex-name single-complex-real-name single-cost
651                                     double-inst double-real-complex-name double-complex-real-name double-cost)
652                `(progn
653                   (frob ,op ,single-cost ,commutativep
654                         ,(and duplicatep
655                               `(progn
656                                  (move dup real)
657                                  (inst unpcklps dup dup)))
658                         ,single-inst movss movq
659                         single-reg fp-single-immediate single-float
660                         complex-single-reg fp-complex-single-immediate complex-single-float
661                         ,single-real-complex-name ,single-complex-real-name)
662                   (frob ,op ,double-cost ,commutativep
663                         ,(and duplicatep
664                               `(progn
665                                  (move dup real)
666                                  (inst unpcklpd dup dup)))
667                         ,double-inst movsd movapd
668                         double-reg fp-double-immediate double-float
669                         complex-double-reg fp-complex-double-immediate complex-double-float
670                         ,double-real-complex-name ,double-complex-real-name))))
671   (def-real-complex-op + t nil
672     addps +/real-complex-single-float +/complex-real-single-float 3
673     addpd +/real-complex-double-float +/complex-real-double-float 4)
674   (def-real-complex-op - nil nil
675     subps -/real-complex-single-float -/complex-real-single-float 3
676     subpd -/real-complex-double-float -/complex-real-double-float 4)
677   (def-real-complex-op * t t
678     mulps */real-complex-single-float */complex-real-single-float 4
679     mulpd */real-complex-double-float */complex-real-double-float 5)
680   (def-real-complex-op / nil t
681     nil nil nil nil
682     divpd nil //complex-real-double-float 19))
683
684 (define-vop (//complex-real-single-float float-op)
685   (:translate /)
686   (:args (x :scs (complex-single-reg fp-complex-single-immediate fp-complex-single-zero)
687             :to (:result 0)
688             :target r
689             :load-if (not (sc-is x fp-complex-single-immediate fp-complex-single-zero)))
690          (y :scs (single-reg fp-single-immediate fp-single-zero)
691             :target dup
692             :load-if (not (sc-is y fp-single-immediate fp-single-zero))))
693   (:arg-types complex-single-float single-float)
694   (:temporary (:sc complex-single-reg :from (:argument 1)) dup)
695   (:results (r :scs (complex-single-reg)))
696   (:result-types complex-single-float)
697   (:generator 12
698     (flet ((duplicate (x)
699              (let ((word (ldb (byte 64 0)
700                               (logior (ash (single-float-bits (imagpart x)) 32)
701                                       (ldb (byte 32 0)
702                                            (single-float-bits (realpart x)))))))
703                (register-inline-constant :oword (logior (ash word 64) word)))))
704       (sc-case y
705         (fp-single-immediate
706          (setf dup (duplicate (complex (tn-value y) (tn-value y)))))
707         (fp-single-zero
708          (inst xorps dup dup))
709         (t (move dup y)
710            (inst shufps dup dup #b00000000)))
711       (sc-case x
712         (fp-complex-single-immediate
713          (inst movaps r (duplicate (tn-value x))))
714         (fp-complex-single-zero
715          (inst xorps r r))
716         (t
717          (move r x)
718          (inst unpcklpd r r)))
719       (inst divps r dup)
720       (inst movq r r))))
721
722 ;; Complex multiplication
723 ;; r := rx * ry - ix * iy
724 ;; i := rx * iy + ix * ry
725 ;;
726 ;; Transpose for SIMDness
727 ;;  rx*ry    rx*iy
728 ;; -ix*iy   +ix*ry
729 ;;
730 ;;  [rx rx] * [ry iy]
731 ;;+ [ix ix] * [-iy ry]
732 ;;       [r i]
733
734 (macrolet ((define-complex-* (name cost type sc tmp-p &body body)
735                `(define-vop (,name float-op)
736                   (:translate *)
737                   (:args (x :scs (,sc) :target r)
738                          (y :scs (,sc) :target copy-y))
739                   (:arg-types ,type ,type)
740                   (:temporary (:sc ,sc) imag)
741                   (:temporary (:sc ,sc :from :eval) copy-y)
742                   ,@(when tmp-p
743                       `((:temporary (:sc ,sc) xmm)))
744                   (:results (r :scs (,sc) :from :eval))
745                   (:result-types ,type)
746                   (:generator ,cost
747                     (when (or (location= x copy-y)
748                               (location= y r))
749                       (rotatef x y))
750                     ,@body))))
751   (define-complex-* */complex-single-float 20
752     complex-single-float complex-single-reg t
753     (inst xorps xmm xmm)
754     (move r x)
755     (inst unpcklps r r)
756     (move imag r)
757     (inst unpckhpd imag xmm)
758     (inst unpcklpd r    xmm)
759     (move copy-y y)  ; y == r only if y == x == r
760     (setf y copy-y)
761
762     (inst mulps r y)
763
764     (inst shufps y y #b11110001)
765     (inst xorps y (register-inline-constant :oword (ash 1 31)))
766
767     (inst mulps imag y)
768     (inst addps r imag))
769   (define-complex-* */complex-double-float 25
770     complex-double-float complex-double-reg nil
771     (move imag x)
772     (move r x)
773     (move copy-y y)
774     (setf y copy-y)
775     (inst unpcklpd r r)
776     (inst unpckhpd imag imag)
777
778     (inst mulpd r y)
779
780     (inst shufpd y y #b01)
781     (inst xorpd y (register-inline-constant :oword (ash 1 63)))
782
783     (inst mulpd imag y)
784     (inst addpd r imag)))
785
786 (define-vop (fsqrt)
787   (:args (x :scs (double-reg)))
788   (:results (y :scs (double-reg)))
789   (:translate %sqrt)
790   (:policy :fast-safe)
791   (:arg-types double-float)
792   (:result-types double-float)
793   (:note "inline float arithmetic")
794   (:vop-var vop)
795   (:save-p :compute-only)
796   (:generator 1
797      (unless (location= x y)
798        (inst xorpd y y))
799      (note-this-location vop :internal-error)
800      (inst sqrtsd y x)))
801 \f
802 (macrolet ((frob ((name translate sc type) &body body)
803              `(define-vop (,name)
804                   (:args (x :scs (,sc) :target y))
805                 (:results (y :scs (,sc)))
806                 (:translate ,translate)
807                 (:policy :fast-safe)
808                 (:arg-types ,type)
809                 (:result-types ,type)
810                 (:note "inline float arithmetic")
811                 (:vop-var vop)
812                 (:save-p :compute-only)
813                 (:generator 1
814                             (note-this-location vop :internal-error)
815                             ;; we should be able to do this better.  what we
816                             ;; really would like to do is use the target as the
817                             ;; temp whenever it's not also the source
818                             (move y x)
819                             ,@body))))
820   (frob (%negate/double-float %negate double-reg double-float)
821         (inst xorpd y (register-inline-constant :oword (ash 1 63))))
822   (frob (%negate/complex-double-float %negate complex-double-reg complex-double-float)
823         (inst xorpd y (register-inline-constant
824                        :oword (logior (ash 1 127) (ash 1 63)))))
825   (frob (conjugate/complex-double-float conjugate complex-double-reg complex-double-float)
826         (inst xorpd y (register-inline-constant :oword (ash 1 127))))
827   (frob (%negate/single-float %negate single-reg single-float)
828         (inst xorps y (register-inline-constant :oword (ash 1 31))))
829   (frob (%negate/complex-single-float %negate complex-single-reg complex-single-float)
830         (inst xorps y (register-inline-constant
831                        :oword (logior (ash 1 31) (ash 1 63)))))
832   (frob (conjugate/complex-single-float conjugate complex-single-reg complex-single-float)
833         (inst xorpd y (register-inline-constant :oword (ash 1 63))))
834   (frob (abs/double-float abs  double-reg double-float)
835         (inst andpd y (register-inline-constant :oword (ldb (byte 63 0) -1))))
836   (frob (abs/single-float abs  single-reg single-float)
837         (inst andps y (register-inline-constant :oword (ldb (byte 31 0) -1)))))
838
839 \f
840 ;;;; comparison
841
842 (define-vop (float-compare)
843   (:policy :fast-safe)
844   (:vop-var vop)
845   (:save-p :compute-only)
846   (:note "inline float comparison"))
847
848 ;;; EQL
849 (macrolet ((define-float-eql (name cost sc constant-sc type)
850                `(define-vop (,name float-compare)
851                   (:translate eql)
852                   (:args (x :scs (,sc ,constant-sc)
853                             :target mask
854                             :load-if (not (sc-is x ,constant-sc)))
855                          (y :scs (,sc ,constant-sc)
856                             :target mask
857                             :load-if (not (sc-is y ,constant-sc))))
858                   (:arg-types ,type ,type)
859                   (:temporary (:sc ,sc :from :eval) mask)
860                   (:temporary (:sc any-reg) bits)
861                   (:conditional :e)
862                   (:generator ,cost
863                     (when (or (location= y mask)
864                               (not (xmm-register-p x)))
865                       (rotatef x y))
866                     (aver (xmm-register-p x))
867                     (move mask x)
868                     (when (sc-is y ,constant-sc)
869                       (setf y (register-inline-constant :aligned (tn-value y))))
870                     (inst pcmpeqd mask y)
871                     (inst movmskps bits mask)
872                     (inst cmp bits #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 unsigned-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 bits ,mask)))
1005                   (define-vop (,complex-real-name ,complex-complex-name)
1006                     (:args (x :scs (,complex-sc ,complex-constant-sc)
1007                               :target cmp
1008                               :load-if (not (sc-is x ,complex-constant-sc)))
1009                            (y :scs (,real-sc ,real-constant-sc)
1010                               :target cmp
1011                               :load-if (not (sc-is y ,real-constant-sc))))
1012                     (:arg-types ,complex-type ,real-type))
1013                   (define-vop (,real-complex-name ,complex-complex-name)
1014                     (:args (x :scs (,real-sc ,real-constant-sc)
1015                               :target cmp
1016                               :load-if (not (sc-is x ,real-constant-sc)))
1017                            (y :scs (,complex-sc ,complex-constant-sc)
1018                               :target cmp
1019                               :load-if (not (sc-is y ,complex-constant-sc))))
1020                     (:arg-types ,real-type ,complex-type)))))
1021   (define-complex-float-= =/complex-single-float =/complex-real-single-float =/real-complex-single-float
1022     single-reg fp-single-immediate single-float
1023     complex-single-reg fp-complex-single-immediate complex-single-float
1024     movss movq cmpps movmskps #b1111)
1025   (define-complex-float-= =/complex-double-float =/complex-real-double-float =/real-complex-double-float
1026     double-reg fp-double-immediate double-float
1027     complex-double-reg fp-complex-double-immediate complex-double-float
1028     movsd movapd cmppd movmskpd #b11))
1029
1030 (macrolet ((define-</> (op single-name double-name &rest flags)
1031                `(progn
1032                   (define-vop (,double-name double-float-compare)
1033                     (:translate ,op)
1034                     (:info)
1035                     (:conditional ,@flags)
1036                     (:generator 3
1037                       (sc-case y
1038                         (double-stack
1039                          (setf y (ea-for-df-stack y)))
1040                         (descriptor-reg
1041                          (setf y (ea-for-df-desc y)))
1042                         (fp-double-immediate
1043                          (setf y (register-inline-constant (tn-value y))))
1044                         (t))
1045                       (inst comisd x y)))
1046                   (define-vop (,single-name single-float-compare)
1047                     (:translate ,op)
1048                     (:info)
1049                     (:conditional ,@flags)
1050                     (:generator 3
1051                       (sc-case y
1052                         (single-stack
1053                          (setf y (ea-for-sf-stack y)))
1054                         (fp-single-immediate
1055                          (setf y (register-inline-constant (tn-value y))))
1056                         (t))
1057                       (inst comiss x y))))))
1058   (define-</> < <single-float <double-float not :p :nc)
1059   (define-</> > >single-float >double-float not :p :na))
1060
1061 \f
1062 ;;;; conversion
1063
1064 (macrolet ((frob (name translate inst to-sc to-type)
1065              `(define-vop (,name)
1066                 (:args (x :scs (signed-stack signed-reg)))
1067                 (:results (y :scs (,to-sc)))
1068                 (:arg-types signed-num)
1069                 (:result-types ,to-type)
1070                 (:policy :fast-safe)
1071                 (:note "inline float coercion")
1072                 (:translate ,translate)
1073                 (:vop-var vop)
1074                 (:save-p :compute-only)
1075                 (:generator 5
1076                   (sc-case y
1077                     (single-reg (inst xorps y y))
1078                     (double-reg (inst xorpd y y)))
1079                   (note-this-location vop :internal-error)
1080                   (inst ,inst y x)))))
1081   (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
1082   (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
1083
1084 (macrolet ((frob (name translate inst from-scs from-type ea-func to-sc to-type)
1085              `(define-vop (,name)
1086                (:args (x :scs ,from-scs :target y))
1087                (:results (y :scs (,to-sc)))
1088                (:arg-types ,from-type)
1089                (:result-types ,to-type)
1090                (:policy :fast-safe)
1091                (:note "inline float coercion")
1092                (:translate ,translate)
1093                (:vop-var vop)
1094                (:save-p :compute-only)
1095                (:generator 2
1096                 (unless (location= x y)
1097                   (sc-case y
1098                     (single-reg (inst xorps y y))
1099                     (double-reg (inst xorpd y y))))
1100                 (note-this-location vop :internal-error)
1101                 (inst ,inst y (sc-case x
1102                                 (,(first from-scs) x)
1103                                 (,(second from-scs) (,ea-func x))))
1104                 ,(when (and (eq from-type 'double-float) ; if the input is wider
1105                             (eq to-type 'single-float))  ; than the output, clear
1106                    `(when (location= x y)                ; noise in the high part
1107                       (inst shufps y y #4r3330)))))))
1108   (frob %single-float/double-float %single-float cvtsd2ss
1109         (double-reg double-stack) double-float ea-for-df-stack
1110         single-reg single-float)
1111
1112   (frob %double-float/single-float %double-float cvtss2sd
1113         (single-reg single-stack) single-float ea-for-sf-stack
1114         double-reg double-float))
1115
1116 (macrolet ((frob (trans inst from-scs from-type ea-func)
1117              `(define-vop (,(symbolicate trans "/" from-type))
1118                (:args (x :scs ,from-scs))
1119                (:results (y :scs (signed-reg)))
1120                (:arg-types ,from-type)
1121                (:result-types signed-num)
1122                (:translate ,trans)
1123                (:policy :fast-safe)
1124                (:note "inline float truncate")
1125                (:vop-var vop)
1126                (:save-p :compute-only)
1127                (:generator 5
1128                  (inst ,inst y (sc-case x
1129                                  (,(first from-scs) x)
1130                                  (,(second from-scs) (,ea-func x))))))))
1131   (frob %unary-truncate/single-float cvttss2si
1132         (single-reg single-stack) single-float ea-for-sf-stack)
1133   (frob %unary-truncate/double-float cvttsd2si
1134         (double-reg double-stack) double-float ea-for-df-stack)
1135
1136   (frob %unary-round cvtss2si
1137         (single-reg single-stack) single-float ea-for-sf-stack)
1138   (frob %unary-round cvtsd2si
1139         (double-reg double-stack) double-float ea-for-df-stack))
1140
1141 (define-vop (make-single-float)
1142   (:args (bits :scs (signed-reg) :target res
1143                :load-if (not (or (and (sc-is bits signed-stack)
1144                                       (sc-is res single-reg))
1145                                  (and (sc-is bits signed-stack)
1146                                       (sc-is res single-stack)
1147                                       (location= bits res))))))
1148   (:results (res :scs (single-reg single-stack)))
1149   (:arg-types signed-num)
1150   (:result-types single-float)
1151   (:translate make-single-float)
1152   (:policy :fast-safe)
1153   (:vop-var vop)
1154   (:generator 4
1155     (sc-case res
1156        (single-stack
1157         (sc-case bits
1158           (signed-reg
1159            (inst mov res bits))
1160           (signed-stack
1161            (aver (location= bits res)))))
1162        (single-reg
1163         (sc-case bits
1164           (signed-reg
1165            (inst movd res bits))
1166           (signed-stack
1167            (inst movd res bits)))))))
1168
1169 (define-vop (make-double-float)
1170   (:args (hi-bits :scs (signed-reg))
1171          (lo-bits :scs (unsigned-reg)))
1172   (:results (res :scs (double-reg)))
1173   (:temporary (:sc unsigned-reg) temp)
1174   (:arg-types signed-num unsigned-num)
1175   (:result-types double-float)
1176   (:translate make-double-float)
1177   (:policy :fast-safe)
1178   (:vop-var vop)
1179   (:generator 2
1180     (move temp hi-bits)
1181     (inst shl temp 32)
1182     (inst or temp lo-bits)
1183     (inst movd res temp)))
1184
1185 (define-vop (single-float-bits)
1186   (:args (float :scs (single-reg descriptor-reg)
1187                 :load-if (not (sc-is float single-stack))))
1188   (:results (bits :scs (signed-reg)))
1189   (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1190   (:arg-types single-float)
1191   (:result-types signed-num)
1192   (:translate single-float-bits)
1193   (:policy :fast-safe)
1194   (:vop-var vop)
1195   (:generator 4
1196     (sc-case bits
1197       (signed-reg
1198        (sc-case float
1199          (single-reg
1200           (inst movss stack-temp float)
1201           (move bits stack-temp))
1202          (single-stack
1203           (move bits float))
1204          (descriptor-reg
1205           (move bits float)
1206           (inst shr bits 32))))
1207       (signed-stack
1208        (sc-case float
1209          (single-reg
1210           (inst movss bits float)))))
1211     ;; Sign-extend
1212     (inst shl bits 32)
1213     (inst sar bits 32)))
1214
1215 (define-vop (double-float-high-bits)
1216   (:args (float :scs (double-reg descriptor-reg)
1217                 :load-if (not (sc-is float double-stack))))
1218   (:results (hi-bits :scs (signed-reg)))
1219   (:temporary (:sc signed-stack :from :argument :to :result) temp)
1220   (:arg-types double-float)
1221   (:result-types signed-num)
1222   (:translate double-float-high-bits)
1223   (:policy :fast-safe)
1224   (:vop-var vop)
1225   (:generator 5
1226      (sc-case float
1227        (double-reg
1228         (inst movsd temp float)
1229         (move hi-bits temp))
1230        (double-stack
1231         (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1232        (descriptor-reg
1233         (loadw hi-bits float double-float-value-slot
1234                other-pointer-lowtag)))
1235      (inst sar hi-bits 32)))
1236
1237 (define-vop (double-float-low-bits)
1238   (:args (float :scs (double-reg descriptor-reg)
1239                 :load-if (not (sc-is float double-stack))))
1240   (:results (lo-bits :scs (unsigned-reg)))
1241   (:temporary (:sc signed-stack :from :argument :to :result) temp)
1242   (:arg-types double-float)
1243   (:result-types unsigned-num)
1244   (:translate double-float-low-bits)
1245   (:policy :fast-safe)
1246   (:vop-var vop)
1247   (:generator 5
1248      (sc-case float
1249        (double-reg
1250         (inst movsd temp float)
1251         (move lo-bits temp))
1252        (double-stack
1253         (loadw lo-bits ebp-tn (frame-word-offset (tn-offset float))))
1254        (descriptor-reg
1255         (loadw lo-bits float double-float-value-slot
1256                other-pointer-lowtag)))
1257      (inst shl lo-bits 32)
1258      (inst shr lo-bits 32)))
1259
1260 \f
1261
1262 ;;;; complex float VOPs
1263
1264 (define-vop (make-complex-single-float)
1265   (:translate complex)
1266   (:args (real :scs (single-reg fp-single-zero)
1267                :target r
1268                :load-if (not (sc-is real fp-single-zero)))
1269          (imag :scs (single-reg fp-single-zero)
1270                :load-if (not (sc-is imag fp-single-zero))))
1271   (:arg-types single-float single-float)
1272   (:results (r :scs (complex-single-reg) :from (:argument 0)))
1273   (:result-types complex-single-float)
1274   (:note "inline complex single-float creation")
1275   (:policy :fast-safe)
1276   (:generator 5
1277     (cond ((sc-is real fp-single-zero)
1278            (inst xorps r r)
1279            (unless (sc-is imag fp-single-zero)
1280              (inst unpcklps r imag)))
1281           ((location= real imag)
1282            (move r real)
1283            (inst unpcklps r r))
1284           (t
1285            (move r real)
1286            (unless (sc-is imag fp-single-zero)
1287              (inst unpcklps r imag))))))
1288
1289 (define-vop (make-complex-double-float)
1290   (:translate complex)
1291   (:args (real :scs (double-reg fp-double-zero)
1292                :target r
1293                :load-if (not (sc-is real fp-double-zero)))
1294          (imag :scs (double-reg fp-double-zero)
1295                :load-if (not (sc-is imag fp-double-zero))))
1296   (:arg-types double-float double-float)
1297   (:results (r :scs (complex-double-reg) :from (:argument 0)))
1298   (:result-types complex-double-float)
1299   (:note "inline complex double-float creation")
1300   (:policy :fast-safe)
1301   (:generator 5
1302     (cond ((sc-is real fp-double-zero)
1303            (inst xorpd r r)
1304            (unless (sc-is imag fp-double-zero)
1305              (inst unpcklpd r imag)))
1306           ((location= real imag)
1307            (move r real)
1308            (inst unpcklpd r r))
1309           (t
1310            (move r real)
1311            (unless (sc-is imag fp-double-zero)
1312              (inst unpcklpd r imag))))))
1313
1314 (define-vop (complex-float-value)
1315   (:args (x :target r))
1316   (:temporary (:sc complex-double-reg) zero)
1317   (:results (r))
1318   (:variant-vars offset)
1319   (:policy :fast-safe)
1320   (:generator 3
1321     (cond ((sc-is x complex-double-reg)
1322            (move r x)
1323            (inst xorpd zero zero)
1324            (ecase offset
1325              (0 (inst unpcklpd r zero))
1326              (1 (inst unpckhpd r zero))))
1327           ((sc-is x complex-single-reg)
1328            (move r x)
1329            (ecase offset
1330              (0 (inst shufps r r #b11111100))
1331              (1 (inst shufps r r #b11111101))))
1332           ((sc-is r single-reg)
1333            (let ((ea (sc-case x
1334                        (complex-single-stack
1335                         (ecase offset
1336                           (0 (ea-for-csf-real-stack x))
1337                           (1 (ea-for-csf-imag-stack x))))
1338                        (descriptor-reg
1339                         (ecase offset
1340                           (0 (ea-for-csf-real-desc x))
1341                           (1 (ea-for-csf-imag-desc x)))))))
1342              (inst movss r ea)))
1343           ((sc-is r double-reg)
1344            (let ((ea (sc-case x
1345                        (complex-double-stack
1346                         (ecase offset
1347                           (0 (ea-for-cdf-real-stack x))
1348                           (1 (ea-for-cdf-imag-stack x))))
1349                        (descriptor-reg
1350                         (ecase offset
1351                           (0 (ea-for-cdf-real-desc x))
1352                           (1 (ea-for-cdf-imag-desc x)))))))
1353              (inst movsd r ea)))
1354           (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
1355
1356 (define-vop (realpart/complex-single-float complex-float-value)
1357   (:translate realpart)
1358   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1359             :target r))
1360   (:arg-types complex-single-float)
1361   (:results (r :scs (single-reg)))
1362   (:result-types single-float)
1363   (:note "complex float realpart")
1364   (:variant 0))
1365
1366 (define-vop (realpart/complex-double-float complex-float-value)
1367   (:translate realpart)
1368   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1369             :target r))
1370   (:arg-types complex-double-float)
1371   (:results (r :scs (double-reg)))
1372   (:result-types double-float)
1373   (:note "complex float realpart")
1374   (:variant 0))
1375
1376 (define-vop (imagpart/complex-single-float complex-float-value)
1377   (:translate imagpart)
1378   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
1379             :target r))
1380   (:arg-types complex-single-float)
1381   (:results (r :scs (single-reg)))
1382   (:result-types single-float)
1383   (:note "complex float imagpart")
1384   (:variant 1))
1385
1386 (define-vop (imagpart/complex-double-float complex-float-value)
1387   (:translate imagpart)
1388   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
1389             :target r))
1390   (:arg-types complex-double-float)
1391   (:results (r :scs (double-reg)))
1392   (:result-types double-float)
1393   (:note "complex float imagpart")
1394   (:variant 1))
1395
1396 \f
1397 ;;; hack dummy VOPs to bias the representation selection of their
1398 ;;; arguments towards a FP register, which can help avoid consing at
1399 ;;; inappropriate locations
1400 (defknown double-float-reg-bias (double-float) (values))
1401 (define-vop (double-float-reg-bias)
1402   (:translate double-float-reg-bias)
1403   (:args (x :scs (double-reg double-stack) :load-if nil))
1404   (:arg-types double-float)
1405   (:policy :fast-safe)
1406   (:note "inline dummy FP register bias")
1407   (:ignore x)
1408   (:generator 0))
1409 (defknown single-float-reg-bias (single-float) (values))
1410 (define-vop (single-float-reg-bias)
1411   (:translate single-float-reg-bias)
1412   (:args (x :scs (single-reg single-stack) :load-if nil))
1413   (:arg-types single-float)
1414   (:policy :fast-safe)
1415   (:note "inline dummy FP register bias")
1416   (:ignore x)
1417   (:generator 0))
1418
1419 (defknown swap-complex ((complex float)) (complex float)
1420     (foldable flushable movable always-translatable))
1421 (defoptimizer (swap-complex derive-type) ((x))
1422   (sb!c::lvar-type x))
1423 (defun swap-complex (x)
1424   (complex (imagpart x) (realpart x)))
1425 (define-vop (swap-complex-single-float)
1426   (:translate swap-complex)
1427   (:policy :fast-safe)
1428   (:args (x :scs (complex-single-reg) :target r))
1429   (:arg-types complex-single-float)
1430   (:results (r :scs (complex-single-reg)))
1431   (:result-types complex-single-float)
1432   (:generator 2
1433      (move r x)
1434      (inst shufps r r #b11110001)))
1435 (define-vop (swap-complex-double-float)
1436   (:translate swap-complex)
1437   (:policy :fast-safe)
1438   (:args (x :scs (complex-double-reg) :target r))
1439   (:arg-types complex-double-float)
1440   (:results (r :scs (complex-double-reg)))
1441   (:result-types complex-double-float)
1442   (:generator 2
1443      (move r x)
1444      (inst shufpd r r #b01)))