63ae04004b73aa9202f219579e3c8f74f6b040df
[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-real-desc (tn)
23     (ea-for-xf-desc tn complex-single-float-real-slot))
24   (defun ea-for-csf-imag-desc (tn)
25     (ea-for-xf-desc tn complex-single-float-imag-slot))
26   (defun ea-for-cdf-real-desc (tn)
27     (ea-for-xf-desc tn complex-double-float-real-slot))
28   (defun ea-for-cdf-imag-desc (tn)
29     (ea-for-xf-desc tn complex-double-float-imag-slot)))
30
31 (macrolet ((ea-for-xf-stack (tn kind)
32              (declare (ignore kind))
33              `(make-ea
34                :qword :base rbp-tn
35                :disp (- (* (+ (tn-offset ,tn) 1)
36                            n-word-bytes)))))
37   (defun ea-for-sf-stack (tn)
38     (ea-for-xf-stack tn :single))
39   (defun ea-for-df-stack (tn)
40     (ea-for-xf-stack tn :double)))
41
42 ;;; complex float stack EAs
43 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
44              (declare (ignore kind))
45              `(make-ea
46                :qword :base ,base
47                :disp (- (* (+ (tn-offset ,tn)
48                               (* 1 (ecase ,slot (:real 1) (:imag 2))))
49                            n-word-bytes)))))
50   (defun ea-for-csf-real-stack (tn &optional (base rbp-tn))
51     (ea-for-cxf-stack tn :single :real base))
52   (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn))
53     (ea-for-cxf-stack tn :single :imag base))
54   (defun ea-for-cdf-real-stack (tn &optional (base rbp-tn))
55     (ea-for-cxf-stack tn :double :real base))
56   (defun ea-for-cdf-imag-stack (tn &optional (base rbp-tn))
57     (ea-for-cxf-stack tn :double :imag base)))
58
59 \f
60 ;;;; move functions
61
62 ;;; X is source, Y is destination.
63
64 (define-move-fun (load-fp-zero 1) (vop x y)
65   ((fp-single-zero) (single-reg)
66    (fp-double-zero) (double-reg))
67   (identity x)
68   (sc-case y
69     (single-reg (inst xorps y y))
70     (double-reg (inst xorpd y y))))
71
72 (define-move-fun (load-single 2) (vop x y)
73   ((single-stack) (single-reg))
74   (inst movss y (ea-for-sf-stack x)))
75
76 (define-move-fun (store-single 2) (vop x y)
77   ((single-reg) (single-stack))
78   (inst movss (ea-for-sf-stack y) x))
79
80 (define-move-fun (load-double 2) (vop x y)
81   ((double-stack) (double-reg))
82   (inst movsd y (ea-for-df-stack x)))
83
84 (define-move-fun (store-double 2) (vop x y)
85   ((double-reg) (double-stack))
86   (inst movsd  (ea-for-df-stack y) x))
87
88 (eval-when (:compile-toplevel :execute)
89   (setf *read-default-float-format* 'single-float))
90 \f
91 ;;;; complex float move functions
92
93 (defun complex-single-reg-real-tn (x)
94   (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
95                   :offset (tn-offset x)))
96 (defun complex-single-reg-imag-tn (x)
97   (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
98                   :offset (1+ (tn-offset x))))
99
100 (defun complex-double-reg-real-tn (x)
101   (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
102                   :offset (tn-offset x)))
103 (defun complex-double-reg-imag-tn (x)
104   (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
105                   :offset (1+ (tn-offset x))))
106
107 ;;; X is source, Y is destination.
108 (define-move-fun (load-complex-single 2) (vop x y)
109   ((complex-single-stack) (complex-single-reg))
110   (let ((real-tn (complex-single-reg-real-tn y)))
111     (inst movss real-tn (ea-for-csf-real-stack x)))
112   (let ((imag-tn (complex-single-reg-imag-tn y)))
113     (inst movss imag-tn (ea-for-csf-imag-stack x))))
114
115 (define-move-fun (store-complex-single 2) (vop x y)
116   ((complex-single-reg) (complex-single-stack))
117   (let ((real-tn (complex-single-reg-real-tn x))
118         (imag-tn (complex-single-reg-imag-tn x)))
119     (inst movss (ea-for-csf-real-stack y) real-tn)
120     (inst movss (ea-for-csf-imag-stack y) imag-tn)))
121
122 (define-move-fun (load-complex-double 2) (vop x y)
123   ((complex-double-stack) (complex-double-reg))
124   (let ((real-tn (complex-double-reg-real-tn y)))
125     (inst movsd real-tn (ea-for-cdf-real-stack x)))
126   (let ((imag-tn (complex-double-reg-imag-tn y)))
127     (inst movsd imag-tn (ea-for-cdf-imag-stack x))))
128
129 (define-move-fun (store-complex-double 2) (vop x y)
130   ((complex-double-reg) (complex-double-stack))
131   (let ((real-tn (complex-double-reg-real-tn x))
132         (imag-tn (complex-double-reg-imag-tn x)))
133     (inst movsd (ea-for-cdf-real-stack y) real-tn)
134     (inst movsd (ea-for-cdf-imag-stack y) imag-tn)))
135
136 \f
137 ;;;; move VOPs
138
139 ;;; float register to register moves
140 (macrolet ((frob (vop sc)
141              `(progn
142                 (define-vop (,vop)
143                   (:args (x :scs (,sc)
144                             :target y
145                             :load-if (not (location= x y))))
146                   (:results (y :scs (,sc)
147                                :load-if (not (location= x y))))
148                   (:note "float move")
149                   (:generator 0
150                     (unless (location= y x)
151                       (inst movq y x))))
152                 (define-move-vop ,vop :move (,sc) (,sc)))))
153   (frob single-move single-reg)
154   (frob double-move double-reg))
155
156 ;;; complex float register to register moves
157 (define-vop (complex-float-move)
158   (:args (x :target y :load-if (not (location= x y))))
159   (:results (y :load-if (not (location= x y))))
160   (:note "complex float move")
161   (:generator 0
162      (unless (location= x y)
163        ;; Note the complex-float-regs are aligned to every second
164        ;; float register so there is not need to worry about overlap.
165        ;; (It would be better to put the imagpart in the top half of the
166        ;; register, or something, but let's worry about that later)
167        (let ((x-real (complex-single-reg-real-tn x))
168              (y-real (complex-single-reg-real-tn y)))
169          (inst movq y-real x-real))
170        (let ((x-imag (complex-single-reg-imag-tn x))
171              (y-imag (complex-single-reg-imag-tn y)))
172          (inst movq y-imag x-imag)))))
173
174 (define-vop (complex-single-move complex-float-move)
175   (:args (x :scs (complex-single-reg) :target y
176             :load-if (not (location= x y))))
177   (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
178 (define-move-vop complex-single-move :move
179   (complex-single-reg) (complex-single-reg))
180
181 (define-vop (complex-double-move complex-float-move)
182   (:args (x :scs (complex-double-reg)
183             :target y :load-if (not (location= x y))))
184   (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
185 (define-move-vop complex-double-move :move
186   (complex-double-reg) (complex-double-reg))
187
188 \f
189 ;;; Move from float to a descriptor reg. allocating a new float
190 ;;; object in the process.
191 (define-vop (move-from-single)
192   (:args (x :scs (single-reg) :to :save))
193   (:results (y :scs (descriptor-reg)))
194   (:note "float to pointer coercion")
195   (:generator 4
196     (inst movd y x)
197     (inst shl y 32)
198     (inst or y single-float-widetag)))
199
200 (define-move-vop move-from-single :move
201   (single-reg) (descriptor-reg))
202
203 (define-vop (move-from-double)
204   (:args (x :scs (double-reg) :to :save))
205   (:results (y :scs (descriptor-reg)))
206   (:node-var node)
207   (:note "float to pointer coercion")
208   (:generator 13
209      (with-fixed-allocation (y
210                              double-float-widetag
211                              double-float-size
212                              node)
213        (inst movsd (ea-for-df-desc y) x))))
214 (define-move-vop move-from-double :move
215   (double-reg) (descriptor-reg))
216
217 ;;; Move from a descriptor to a float register.
218 (define-vop (move-to-single)
219   (:args (x :scs (descriptor-reg) :target tmp))
220   (:temporary (:sc unsigned-reg) tmp)
221   (:results (y :scs (single-reg)))
222   (:note "pointer to float coercion")
223   (:generator 2
224     (move tmp x)
225     (inst shr tmp 32)
226     (inst movd y tmp)))
227
228 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
229
230 (define-vop (move-to-double)
231   (:args (x :scs (descriptor-reg)))
232   (:results (y :scs (double-reg)))
233   (:note "pointer to float coercion")
234   (:generator 2
235     (inst movsd y (ea-for-df-desc x))))
236 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
237
238 \f
239 ;;; Move from complex float to a descriptor reg. allocating a new
240 ;;; complex float object in the process.
241 (define-vop (move-from-complex-single)
242   (:args (x :scs (complex-single-reg) :to :save))
243   (:results (y :scs (descriptor-reg)))
244   (:node-var node)
245   (:note "complex float to pointer coercion")
246   (:generator 13
247      (with-fixed-allocation (y
248                              complex-single-float-widetag
249                              complex-single-float-size
250                              node)
251        (let ((real-tn (complex-single-reg-real-tn x)))
252          (inst movss (ea-for-csf-real-desc y) real-tn))
253        (let ((imag-tn (complex-single-reg-imag-tn x)))
254          (inst movss (ea-for-csf-imag-desc y) imag-tn)))))
255 (define-move-vop move-from-complex-single :move
256   (complex-single-reg) (descriptor-reg))
257
258 (define-vop (move-from-complex-double)
259   (:args (x :scs (complex-double-reg) :to :save))
260   (:results (y :scs (descriptor-reg)))
261   (:node-var node)
262   (:note "complex float to pointer coercion")
263   (:generator 13
264      (with-fixed-allocation (y
265                              complex-double-float-widetag
266                              complex-double-float-size
267                              node)
268        (let ((real-tn (complex-double-reg-real-tn x)))
269          (inst movsd (ea-for-cdf-real-desc y) real-tn))
270        (let ((imag-tn (complex-double-reg-imag-tn x)))
271          (inst movsd (ea-for-cdf-imag-desc y) imag-tn)))))
272 (define-move-vop move-from-complex-double :move
273   (complex-double-reg) (descriptor-reg))
274
275 ;;; Move from a descriptor to a complex float register.
276 (macrolet ((frob (name sc format)
277              `(progn
278                 (define-vop (,name)
279                   (:args (x :scs (descriptor-reg)))
280                   (:results (y :scs (,sc)))
281                   (:note "pointer to complex float coercion")
282                   (:generator 2
283                     (let ((real-tn (complex-double-reg-real-tn y)))
284                       ,@(ecase
285                          format
286                          (:single
287                           '((inst movss real-tn (ea-for-csf-real-desc x))))
288                          (:double
289                           '((inst movsd real-tn (ea-for-cdf-real-desc x))))))
290                     (let ((imag-tn (complex-double-reg-imag-tn y)))
291                       ,@(ecase
292                          format
293                          (:single
294                           '((inst movss imag-tn (ea-for-csf-imag-desc x))))
295                          (:double
296                           '((inst movsd imag-tn (ea-for-cdf-imag-desc x))))))))
297                 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
298   (frob move-to-complex-single complex-single-reg :single)
299   (frob move-to-complex-double complex-double-reg :double))
300 \f
301 ;;;; the move argument vops
302 ;;;;
303 ;;;; Note these are also used to stuff fp numbers onto the c-call
304 ;;;; stack so the order is different than the lisp-stack.
305
306 ;;; the general MOVE-ARG VOP
307 (macrolet ((frob (name sc stack-sc format)
308              `(progn
309                 (define-vop (,name)
310                   (:args (x :scs (,sc) :target y)
311                          (fp :scs (any-reg)
312                              :load-if (not (sc-is y ,sc))))
313                   (:results (y))
314                   (:note "float argument move")
315                   (:generator ,(case format (:single 2) (:double 3) )
316                     (sc-case y
317                       (,sc
318                        (unless (location= x y)
319                          (inst movq y x)))
320                       (,stack-sc
321                        (if (= (tn-offset fp) esp-offset)
322                            (let* ((offset (* (tn-offset y) n-word-bytes))
323                                   (ea (make-ea :dword :base fp :disp offset)))
324                              ,@(ecase format
325                                       (:single '((inst movss ea x)))
326                                       (:double '((inst movsd ea x)))))
327                            (let ((ea (make-ea
328                                       :dword :base fp
329                                       :disp (- (* (1+ (tn-offset y))
330                                                   n-word-bytes)))))
331                              ,@(ecase format
332                                  (:single '((inst movss ea x)))
333                                  (:double '((inst movsd ea x))))))))))
334                 (define-move-vop ,name :move-arg
335                   (,sc descriptor-reg) (,sc)))))
336   (frob move-single-float-arg single-reg single-stack :single)
337   (frob move-double-float-arg double-reg double-stack :double))
338
339 ;;;; complex float MOVE-ARG VOP
340 (macrolet ((frob (name sc stack-sc format)
341              `(progn
342                 (define-vop (,name)
343                   (:args (x :scs (,sc) :target y)
344                          (fp :scs (any-reg)
345                              :load-if (not (sc-is y ,sc))))
346                   (:results (y))
347                   (:note "complex float argument move")
348                   (:generator ,(ecase format (:single 2) (:double 3))
349                     (sc-case y
350                       (,sc
351                        (unless (location= x y)
352                          (let ((x-real (complex-double-reg-real-tn x))
353                                (y-real (complex-double-reg-real-tn y)))
354                            (inst movsd y-real x-real))
355                          (let ((x-imag (complex-double-reg-imag-tn x))
356                                (y-imag (complex-double-reg-imag-tn y)))
357                            (inst movsd y-imag x-imag))))
358                       (,stack-sc
359                        (let ((real-tn (complex-double-reg-real-tn x)))
360                          ,@(ecase format
361                                   (:single
362                                    '((inst movss
363                                       (ea-for-csf-real-stack y fp)
364                                       real-tn)))
365                                   (:double
366                                    '((inst movsd
367                                       (ea-for-cdf-real-stack y fp)
368                                       real-tn)))))
369                        (let ((imag-tn (complex-double-reg-imag-tn x)))
370                          ,@(ecase format
371                                   (:single
372                                    '((inst movss
373                                       (ea-for-csf-imag-stack y fp) imag-tn)))
374                                   (:double
375                                    '((inst movsd
376                                       (ea-for-cdf-imag-stack y fp) imag-tn)))))))))
377                 (define-move-vop ,name :move-arg
378                   (,sc descriptor-reg) (,sc)))))
379   (frob move-complex-single-float-arg
380         complex-single-reg complex-single-stack :single)
381   (frob move-complex-double-float-arg
382         complex-double-reg complex-double-stack :double))
383
384 (define-move-vop move-arg :move-arg
385   (single-reg double-reg
386    complex-single-reg complex-double-reg)
387   (descriptor-reg))
388
389 \f
390 ;;;; arithmetic VOPs
391
392 (define-vop (float-op)
393   (:args (x) (y))
394   (:results (r))
395   (:policy :fast-safe)
396   (:note "inline float arithmetic")
397   (:vop-var vop)
398   (:save-p :compute-only))
399
400 (macrolet ((frob (name sc ptype)
401              `(define-vop (,name float-op)
402                 (:args (x :scs (,sc) :target r)
403                        (y :scs (,sc)))
404                 (:results (r :scs (,sc)))
405                 (:arg-types ,ptype ,ptype)
406                 (:result-types ,ptype))))
407   (frob single-float-op single-reg single-float)
408   (frob double-float-op double-reg double-float))
409
410 (macrolet ((generate (movinst opinst commutative)
411              `(progn
412                 (cond
413                   ((location= x r)
414                    (inst ,opinst x y))
415                   ((and ,commutative (location= y r))
416                    (inst ,opinst y x))
417                   ((not (location= r y))
418                    (inst ,movinst r x)
419                    (inst ,opinst r y))
420                   (t
421                    (inst ,movinst tmp x)
422                    (inst ,opinst tmp y)
423                    (inst ,movinst r tmp)))))
424            (frob (op sinst sname scost dinst dname dcost commutative)
425              `(progn
426                 (define-vop (,sname single-float-op)
427                     (:translate ,op)
428                   (:temporary (:sc single-reg) tmp)
429                   (:generator ,scost
430                     (generate movss ,sinst ,commutative)))
431                 (define-vop (,dname double-float-op)
432                   (:translate ,op)
433                   (:temporary (:sc single-reg) tmp)
434                   (:generator ,dcost
435                     (generate movsd ,dinst ,commutative))))))
436   (frob + addss +/single-float 2 addsd +/double-float 2 t)
437   (frob - subss -/single-float 2 subsd -/double-float 2 nil)
438   (frob * mulss */single-float 4 mulsd */double-float 5 t)
439   (frob / divss //single-float 12 divsd //double-float 19 nil))
440
441 (define-vop (fsqrt)
442   (:args (x :scs (double-reg)))
443   (:results (y :scs (double-reg)))
444   (:translate %sqrt)
445   (:policy :fast-safe)
446   (:arg-types double-float)
447   (:result-types double-float)
448   (:note "inline float arithmetic")
449   (:vop-var vop)
450   (:save-p :compute-only)
451   (:generator 1
452      (note-this-location vop :internal-error)
453      (inst sqrtsd y x)))
454 \f
455 (macrolet ((frob ((name translate sc type) &body body)
456              `(define-vop (,name)
457                   (:args (x :scs (,sc)))
458                 (:results (y :scs (,sc)))
459                 (:translate ,translate)
460                 (:policy :fast-safe)
461                 (:arg-types ,type)
462                 (:result-types ,type)
463                 (:temporary (:sc any-reg) hex8)
464                 (:temporary
465                  (:sc ,sc) xmm)
466                 (:note "inline float arithmetic")
467                 (:vop-var vop)
468                 (:save-p :compute-only)
469                 (:generator 1
470                             (note-this-location vop :internal-error)
471                             ;; we should be able to do this better.  what we
472                             ;; really would like to do is use the target as the
473                             ;; temp whenever it's not also the source
474                             (unless (location= x y)
475                               (inst movq y x))
476                             ,@body))))
477   (frob (%negate/double-float %negate double-reg double-float)
478         (inst lea hex8 (make-ea :qword :disp 1))
479         (inst ror hex8 1)               ; #x8000000000000000
480         (inst movd xmm hex8)
481         (inst xorpd y xmm))
482   (frob (%negate/single-float %negate single-reg single-float)
483         (inst lea hex8 (make-ea :qword :disp 1))
484         (inst rol hex8 31)
485         (inst movd xmm hex8)
486         (inst xorps y xmm))
487   (frob (abs/double-float abs  double-reg double-float)
488         (inst mov hex8 -1)
489         (inst shr hex8 1)
490         (inst movd xmm hex8)
491         (inst andpd y xmm))
492   (frob (abs/single-float abs  single-reg single-float)
493         (inst mov hex8 -1)
494         (inst shr hex8 33)
495         (inst movd xmm hex8)
496         (inst andps y xmm)))
497 \f
498 ;;;; comparison
499
500 (define-vop (float-compare)
501   (:conditional)
502   (:info target not-p)
503   (:policy :fast-safe)
504   (:vop-var vop)
505   (:save-p :compute-only)
506   (:note "inline float comparison"))
507
508 ;;; comiss and comisd can cope with one or other arg in memory: we
509 ;;; could (should, indeed) extend these to cope with descriptor args
510 ;;; and stack args
511
512 (define-vop (single-float-compare float-compare)
513   (:args (x :scs (single-reg)) (y :scs (single-reg)))
514   (:conditional)
515   (:arg-types single-float single-float))
516 (define-vop (double-float-compare float-compare)
517   (:args (x :scs (double-reg)) (y :scs (double-reg)))
518   (:conditional)
519   (:arg-types double-float double-float))
520
521 (define-vop (=/single-float single-float-compare)
522     (:translate =)
523   (:info target not-p)
524   (:vop-var vop)
525   (:generator 3
526     (note-this-location vop :internal-error)
527     (inst comiss x y)
528     ;; if PF&CF, there was a NaN involved => not equal
529     ;; otherwise, ZF => equal
530     (cond (not-p
531            (inst jmp :p target)
532            (inst jmp :ne target))
533           (t
534            (let ((not-lab (gen-label)))
535              (inst jmp :p not-lab)
536              (inst jmp :e target)
537              (emit-label not-lab))))))
538
539 (define-vop (=/double-float double-float-compare)
540     (:translate =)
541   (:info target not-p)
542   (:vop-var vop)
543   (:generator 3
544     (note-this-location vop :internal-error)
545     (inst comisd x y)
546     (cond (not-p
547            (inst jmp :p target)
548            (inst jmp :ne target))
549           (t
550            (let ((not-lab (gen-label)))
551              (inst jmp :p not-lab)
552              (inst jmp :e target)
553              (emit-label not-lab))))))
554
555 ;; XXX all of these probably have bad NaN behaviour
556 (define-vop (<double-float double-float-compare)
557   (:translate <)
558   (:info target not-p)
559   (:generator 2
560     (inst comisd x y)
561     (inst jmp (if not-p :nc :c) target)))
562
563 (define-vop (<single-float single-float-compare)
564   (:translate <)
565   (:info target not-p)
566   (:generator 2
567     (inst comiss x y)
568     (inst jmp (if not-p :nc :c) target)))
569
570 (define-vop (>double-float double-float-compare)
571   (:translate >)
572   (:info target not-p)
573   (:generator 2
574     (inst comisd x y)
575     (inst jmp (if not-p :na :a) target)))
576
577 (define-vop (>single-float single-float-compare)
578   (:translate >)
579   (:info target not-p)
580   (:generator 2
581     (inst comiss x y)
582     (inst jmp (if not-p :na :a) target)))
583
584
585 \f
586 ;;;; conversion
587
588 (macrolet ((frob (name translate inst to-sc to-type)
589              `(define-vop (,name)
590                 (:args (x :scs (signed-stack signed-reg) :target temp))
591                 (:temporary (:sc signed-stack) temp)
592                 (:results (y :scs (,to-sc)))
593                 (:arg-types signed-num)
594                 (:result-types ,to-type)
595                 (:policy :fast-safe)
596                 (:note "inline float coercion")
597                 (:translate ,translate)
598                 (:vop-var vop)
599                 (:save-p :compute-only)
600                 (:generator 5
601                   (sc-case x
602                     (signed-reg
603                      (inst mov temp x)
604                      (note-this-location vop :internal-error)
605                      (inst ,inst y temp))
606                     (signed-stack
607                      (note-this-location vop :internal-error)
608                      (inst ,inst y x)))))))
609   (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
610   (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
611
612 (macrolet ((frob (name translate inst from-sc from-type to-sc to-type)
613              `(define-vop (,name)
614                (:args (x :scs (,from-sc) :target y))
615                (:results (y :scs (,to-sc)))
616                (:arg-types ,from-type)
617                (:result-types ,to-type)
618                (:policy :fast-safe)
619                (:note "inline float coercion")
620                (:translate ,translate)
621                (:vop-var vop)
622                (:save-p :compute-only)
623                (:generator 2
624                 (note-this-location vop :internal-error)
625                 (inst ,inst y x)))))
626   (frob %single-float/double-float %single-float cvtsd2ss double-reg
627         double-float single-reg single-float)
628
629   (frob %double-float/single-float %double-float cvtss2sd
630         single-reg single-float double-reg double-float))
631
632 (macrolet ((frob (trans inst from-sc from-type round-p)
633              (declare (ignore round-p))
634              `(define-vop (,(symbolicate trans "/" from-type))
635                (:args (x :scs (,from-sc)))
636                (:temporary (:sc any-reg) temp-reg)
637                (:results (y :scs (signed-reg)))
638                (:arg-types ,from-type)
639                (:result-types signed-num)
640                (:translate ,trans)
641                (:policy :fast-safe)
642                (:note "inline float truncate")
643                (:vop-var vop)
644                (:save-p :compute-only)
645                (:generator 5
646                  (sc-case y
647                           (signed-stack
648                            (inst ,inst temp-reg x)
649                            (move y temp-reg))
650                           (signed-reg
651                            (inst ,inst y x)
652                            ))))))
653   (frob %unary-truncate cvttss2si single-reg single-float nil)
654   (frob %unary-truncate cvttsd2si double-reg double-float nil)
655
656   (frob %unary-round cvtss2si single-reg single-float t)
657   (frob %unary-round cvtsd2si double-reg double-float t))
658
659 (define-vop (make-single-float)
660   (:args (bits :scs (signed-reg) :target res
661                :load-if (not (or (and (sc-is bits signed-stack)
662                                       (sc-is res single-reg))
663                                  (and (sc-is bits signed-stack)
664                                       (sc-is res single-stack)
665                                       (location= bits res))))))
666   (:results (res :scs (single-reg single-stack)))
667   (:arg-types signed-num)
668   (:result-types single-float)
669   (:translate make-single-float)
670   (:policy :fast-safe)
671   (:vop-var vop)
672   (:generator 4
673     (sc-case res
674        (single-stack
675         (sc-case bits
676           (signed-reg
677            (inst mov res bits))
678           (signed-stack
679            (aver (location= bits res)))))
680        (single-reg
681         (sc-case bits
682           (signed-reg
683            (inst movd res bits))
684           (signed-stack
685            (inst movd res bits)))))))
686
687 (define-vop (make-double-float)
688   (:args (hi-bits :scs (signed-reg))
689          (lo-bits :scs (unsigned-reg)))
690   (:results (res :scs (double-reg)))
691   (:temporary (:sc unsigned-reg) temp)
692   (:arg-types signed-num unsigned-num)
693   (:result-types double-float)
694   (:translate make-double-float)
695   (:policy :fast-safe)
696   (:vop-var vop)
697   (:generator 2
698     (move temp hi-bits)
699     (inst shl temp 32)
700     (inst or temp lo-bits)
701     (inst movd res temp)))
702
703 (define-vop (single-float-bits)
704   (:args (float :scs (single-reg descriptor-reg)
705                 :load-if (not (sc-is float single-stack))))
706   (:results (bits :scs (signed-reg)))
707   (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
708   (:arg-types single-float)
709   (:result-types signed-num)
710   (:translate single-float-bits)
711   (:policy :fast-safe)
712   (:vop-var vop)
713   (:generator 4
714     (sc-case bits
715       (signed-reg
716        (sc-case float
717          (single-reg
718           (inst movss stack-temp float)
719           (move bits stack-temp))
720          (single-stack
721           (move bits float))
722          (descriptor-reg
723           (move bits float)
724           (inst shr bits 32))))
725       (signed-stack
726        (sc-case float
727          (single-reg
728           (inst movss bits float)))))
729     ;; Sign-extend
730     (inst shl bits 32)
731     (inst sar bits 32)))
732
733 (define-vop (double-float-high-bits)
734   (:args (float :scs (double-reg descriptor-reg)
735                 :load-if (not (sc-is float double-stack))))
736   (:results (hi-bits :scs (signed-reg)))
737   (:temporary (:sc signed-stack :from :argument :to :result) temp)
738   (:arg-types double-float)
739   (:result-types signed-num)
740   (:translate double-float-high-bits)
741   (:policy :fast-safe)
742   (:vop-var vop)
743   (:generator 5
744      (sc-case float
745        (double-reg
746         (inst movsd temp float)
747         (move hi-bits temp))
748        (double-stack
749         (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
750        (descriptor-reg
751         (loadw hi-bits float double-float-value-slot
752                other-pointer-lowtag)))
753      (inst sar hi-bits 32)))
754
755 (define-vop (double-float-low-bits)
756   (:args (float :scs (double-reg descriptor-reg)
757                 :load-if (not (sc-is float double-stack))))
758   (:results (lo-bits :scs (unsigned-reg)))
759   (:temporary (:sc signed-stack :from :argument :to :result) temp)
760   (:arg-types double-float)
761   (:result-types unsigned-num)
762   (:translate double-float-low-bits)
763   (:policy :fast-safe)
764   (:vop-var vop)
765   (:generator 5
766      (sc-case float
767        (double-reg
768         (inst movsd temp float)
769         (move lo-bits temp))
770        (double-stack
771         (loadw lo-bits ebp-tn (- (1+ (tn-offset float)))))
772        (descriptor-reg
773         (loadw lo-bits float double-float-value-slot
774                other-pointer-lowtag)))
775      (inst shl lo-bits 32)
776      (inst shr lo-bits 32)))
777
778 \f
779
780 ;;;; complex float VOPs
781
782 (define-vop (make-complex-single-float)
783   (:translate complex)
784   (:args (real :scs (single-reg) :to :result :target r
785                :load-if (not (location= real r)))
786          (imag :scs (single-reg) :to :save))
787   (:arg-types single-float single-float)
788   (:results (r :scs (complex-single-reg) :from (:argument 0)
789                :load-if (not (sc-is r complex-single-stack))))
790   (:result-types complex-single-float)
791   (:note "inline complex single-float creation")
792   (:policy :fast-safe)
793   (:generator 5
794     (sc-case r
795       (complex-single-reg
796        (let ((r-real (complex-single-reg-real-tn r)))
797          (unless (location= real r-real)
798            (inst movss r-real real)))
799        (let ((r-imag (complex-single-reg-imag-tn r)))
800          (unless (location= imag r-imag)
801            (inst movss r-imag imag))))
802       (complex-single-stack
803        (unless (location= real r)
804          (inst movss (ea-for-csf-real-stack r) real))
805        (inst movss (ea-for-csf-imag-stack r) imag)))))
806
807 (define-vop (make-complex-double-float)
808   (:translate complex)
809   (:args (real :scs (double-reg) :target r
810                :load-if (not (location= real r)))
811          (imag :scs (double-reg) :to :save))
812   (:arg-types double-float double-float)
813   (:results (r :scs (complex-double-reg) :from (:argument 0)
814                :load-if (not (sc-is r complex-double-stack))))
815   (:result-types complex-double-float)
816   (:note "inline complex double-float creation")
817   (:policy :fast-safe)
818   (:generator 5
819     (sc-case r
820       (complex-double-reg
821        (let ((r-real (complex-double-reg-real-tn r)))
822          (unless (location= real r-real)
823            (inst movsd r-real real)))
824        (let ((r-imag (complex-double-reg-imag-tn r)))
825          (unless (location= imag r-imag)
826            (inst movsd r-imag imag))))
827       (complex-double-stack
828        (unless (location= real r)
829          (inst movsd (ea-for-cdf-real-stack r) real))
830        (inst movsd (ea-for-cdf-imag-stack r) imag)))))
831
832 (define-vop (complex-float-value)
833   (:args (x :target r))
834   (:results (r))
835   (:variant-vars offset)
836   (:policy :fast-safe)
837   (:generator 3
838     (cond ((sc-is x complex-single-reg complex-double-reg)
839            (let ((value-tn
840                   (make-random-tn :kind :normal
841                                   :sc (sc-or-lose 'double-reg)
842                                   :offset (+ offset (tn-offset x)))))
843              (unless (location= value-tn r)
844                (if (sc-is x complex-single-reg)
845                    (inst movss r value-tn)
846                    (inst movsd r value-tn)))))
847           ((sc-is r single-reg)
848            (let ((ea (sc-case x
849                        (complex-single-stack
850                         (ecase offset
851                           (0 (ea-for-csf-real-stack x))
852                           (1 (ea-for-csf-imag-stack x))))
853                        (descriptor-reg
854                         (ecase offset
855                           (0 (ea-for-csf-real-desc x))
856                           (1 (ea-for-csf-imag-desc x)))))))
857              (inst movss r ea)))
858           ((sc-is r double-reg)
859            (let ((ea (sc-case x
860                        (complex-double-stack
861                         (ecase offset
862                           (0 (ea-for-cdf-real-stack x))
863                           (1 (ea-for-cdf-imag-stack x))))
864                        (descriptor-reg
865                         (ecase offset
866                           (0 (ea-for-cdf-real-desc x))
867                           (1 (ea-for-cdf-imag-desc x)))))))
868              (inst movsd r ea)))
869           (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
870
871 (define-vop (realpart/complex-single-float complex-float-value)
872   (:translate realpart)
873   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
874             :target r))
875   (:arg-types complex-single-float)
876   (:results (r :scs (single-reg)))
877   (:result-types single-float)
878   (:note "complex float realpart")
879   (:variant 0))
880
881 (define-vop (realpart/complex-double-float complex-float-value)
882   (:translate realpart)
883   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
884             :target r))
885   (:arg-types complex-double-float)
886   (:results (r :scs (double-reg)))
887   (:result-types double-float)
888   (:note "complex float realpart")
889   (:variant 0))
890
891 (define-vop (imagpart/complex-single-float complex-float-value)
892   (:translate imagpart)
893   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
894             :target r))
895   (:arg-types complex-single-float)
896   (:results (r :scs (single-reg)))
897   (:result-types single-float)
898   (:note "complex float imagpart")
899   (:variant 1))
900
901 (define-vop (imagpart/complex-double-float complex-float-value)
902   (:translate imagpart)
903   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
904             :target r))
905   (:arg-types complex-double-float)
906   (:results (r :scs (double-reg)))
907   (:result-types double-float)
908   (:note "complex float imagpart")
909   (:variant 1))
910
911 \f
912 ;;; hack dummy VOPs to bias the representation selection of their
913 ;;; arguments towards a FP register, which can help avoid consing at
914 ;;; inappropriate locations
915 (defknown double-float-reg-bias (double-float) (values))
916 (define-vop (double-float-reg-bias)
917   (:translate double-float-reg-bias)
918   (:args (x :scs (double-reg double-stack) :load-if nil))
919   (:arg-types double-float)
920   (:policy :fast-safe)
921   (:note "inline dummy FP register bias")
922   (:ignore x)
923   (:generator 0))
924 (defknown single-float-reg-bias (single-float) (values))
925 (define-vop (single-float-reg-bias)
926   (:translate single-float-reg-bias)
927   (:args (x :scs (single-reg single-stack) :load-if nil))
928   (:arg-types single-float)
929   (:policy :fast-safe)
930   (:note "inline dummy FP register bias")
931   (:ignore x)
932   (:generator 0))