b642b5ccb689865b27df4f2982f269636a621977
[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   (:policy :fast-safe)
502   (:vop-var vop)
503   (:save-p :compute-only)
504   (:note "inline float comparison"))
505
506 ;;; comiss and comisd can cope with one or other arg in memory: we
507 ;;; could (should, indeed) extend these to cope with descriptor args
508 ;;; and stack args
509
510 (define-vop (single-float-compare float-compare)
511   (:args (x :scs (single-reg)) (y :scs (single-reg)))
512   (:arg-types single-float single-float))
513 (define-vop (double-float-compare float-compare)
514   (:args (x :scs (double-reg)) (y :scs (double-reg)))
515   (:arg-types double-float double-float))
516
517 (define-vop (=/single-float single-float-compare)
518     (:translate =)
519   (:info)
520   (:conditional not :p :ne)
521   (:vop-var vop)
522   (:generator 3
523     (note-this-location vop :internal-error)
524     (inst comiss x y)
525     ;; if PF&CF, there was a NaN involved => not equal
526     ;; otherwise, ZF => equal
527     ))
528
529 (define-vop (=/double-float double-float-compare)
530     (:translate =)
531   (:info)
532   (:conditional not :p :ne)
533   (:vop-var vop)
534   (:generator 3
535     (note-this-location vop :internal-error)
536     (inst comisd x y)))
537
538 (define-vop (<double-float double-float-compare)
539   (:translate <)
540   (:info)
541   (:conditional not :p :nc)
542   (:generator 3
543     (inst comisd x y)))
544
545 (define-vop (<single-float single-float-compare)
546   (:translate <)
547   (:info)
548   (:conditional not :p :nc)
549   (:generator 3
550     (inst comiss x y)))
551
552 (define-vop (>double-float double-float-compare)
553   (:translate >)
554   (:info)
555   (:conditional not :p :na)
556   (:generator 3
557     (inst comisd x y)))
558
559 (define-vop (>single-float single-float-compare)
560   (:translate >)
561   (:info)
562   (:conditional not :p :na)
563   (:generator 3
564     (inst comiss x y)))
565
566
567 \f
568 ;;;; conversion
569
570 (macrolet ((frob (name translate inst to-sc to-type)
571              `(define-vop (,name)
572                 (:args (x :scs (signed-stack signed-reg) :target temp))
573                 (:temporary (:sc signed-stack) temp)
574                 (:results (y :scs (,to-sc)))
575                 (:arg-types signed-num)
576                 (:result-types ,to-type)
577                 (:policy :fast-safe)
578                 (:note "inline float coercion")
579                 (:translate ,translate)
580                 (:vop-var vop)
581                 (:save-p :compute-only)
582                 (:generator 5
583                   (sc-case x
584                     (signed-reg
585                      (inst mov temp x)
586                      (note-this-location vop :internal-error)
587                      (inst ,inst y temp))
588                     (signed-stack
589                      (note-this-location vop :internal-error)
590                      (inst ,inst y x)))))))
591   (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
592   (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
593
594 (macrolet ((frob (name translate inst from-sc from-type to-sc to-type)
595              `(define-vop (,name)
596                (:args (x :scs (,from-sc) :target y))
597                (:results (y :scs (,to-sc)))
598                (:arg-types ,from-type)
599                (:result-types ,to-type)
600                (:policy :fast-safe)
601                (:note "inline float coercion")
602                (:translate ,translate)
603                (:vop-var vop)
604                (:save-p :compute-only)
605                (:generator 2
606                 (note-this-location vop :internal-error)
607                 (inst ,inst y x)))))
608   (frob %single-float/double-float %single-float cvtsd2ss double-reg
609         double-float single-reg single-float)
610
611   (frob %double-float/single-float %double-float cvtss2sd
612         single-reg single-float double-reg double-float))
613
614 (macrolet ((frob (trans inst from-sc from-type round-p)
615              (declare (ignore round-p))
616              `(define-vop (,(symbolicate trans "/" from-type))
617                (:args (x :scs (,from-sc)))
618                (:temporary (:sc any-reg) temp-reg)
619                (:results (y :scs (signed-reg)))
620                (:arg-types ,from-type)
621                (:result-types signed-num)
622                (:translate ,trans)
623                (:policy :fast-safe)
624                (:note "inline float truncate")
625                (:vop-var vop)
626                (:save-p :compute-only)
627                (:generator 5
628                  (sc-case y
629                           (signed-stack
630                            (inst ,inst temp-reg x)
631                            (move y temp-reg))
632                           (signed-reg
633                            (inst ,inst y x)
634                            ))))))
635   (frob %unary-truncate cvttss2si single-reg single-float nil)
636   (frob %unary-truncate cvttsd2si double-reg double-float nil)
637
638   (frob %unary-round cvtss2si single-reg single-float t)
639   (frob %unary-round cvtsd2si double-reg double-float t))
640
641 (define-vop (make-single-float)
642   (:args (bits :scs (signed-reg) :target res
643                :load-if (not (or (and (sc-is bits signed-stack)
644                                       (sc-is res single-reg))
645                                  (and (sc-is bits signed-stack)
646                                       (sc-is res single-stack)
647                                       (location= bits res))))))
648   (:results (res :scs (single-reg single-stack)))
649   (:arg-types signed-num)
650   (:result-types single-float)
651   (:translate make-single-float)
652   (:policy :fast-safe)
653   (:vop-var vop)
654   (:generator 4
655     (sc-case res
656        (single-stack
657         (sc-case bits
658           (signed-reg
659            (inst mov res bits))
660           (signed-stack
661            (aver (location= bits res)))))
662        (single-reg
663         (sc-case bits
664           (signed-reg
665            (inst movd res bits))
666           (signed-stack
667            (inst movd res bits)))))))
668
669 (define-vop (make-double-float)
670   (:args (hi-bits :scs (signed-reg))
671          (lo-bits :scs (unsigned-reg)))
672   (:results (res :scs (double-reg)))
673   (:temporary (:sc unsigned-reg) temp)
674   (:arg-types signed-num unsigned-num)
675   (:result-types double-float)
676   (:translate make-double-float)
677   (:policy :fast-safe)
678   (:vop-var vop)
679   (:generator 2
680     (move temp hi-bits)
681     (inst shl temp 32)
682     (inst or temp lo-bits)
683     (inst movd res temp)))
684
685 (define-vop (single-float-bits)
686   (:args (float :scs (single-reg descriptor-reg)
687                 :load-if (not (sc-is float single-stack))))
688   (:results (bits :scs (signed-reg)))
689   (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
690   (:arg-types single-float)
691   (:result-types signed-num)
692   (:translate single-float-bits)
693   (:policy :fast-safe)
694   (:vop-var vop)
695   (:generator 4
696     (sc-case bits
697       (signed-reg
698        (sc-case float
699          (single-reg
700           (inst movss stack-temp float)
701           (move bits stack-temp))
702          (single-stack
703           (move bits float))
704          (descriptor-reg
705           (move bits float)
706           (inst shr bits 32))))
707       (signed-stack
708        (sc-case float
709          (single-reg
710           (inst movss bits float)))))
711     ;; Sign-extend
712     (inst shl bits 32)
713     (inst sar bits 32)))
714
715 (define-vop (double-float-high-bits)
716   (:args (float :scs (double-reg descriptor-reg)
717                 :load-if (not (sc-is float double-stack))))
718   (:results (hi-bits :scs (signed-reg)))
719   (:temporary (:sc signed-stack :from :argument :to :result) temp)
720   (:arg-types double-float)
721   (:result-types signed-num)
722   (:translate double-float-high-bits)
723   (:policy :fast-safe)
724   (:vop-var vop)
725   (:generator 5
726      (sc-case float
727        (double-reg
728         (inst movsd temp float)
729         (move hi-bits temp))
730        (double-stack
731         (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
732        (descriptor-reg
733         (loadw hi-bits float double-float-value-slot
734                other-pointer-lowtag)))
735      (inst sar hi-bits 32)))
736
737 (define-vop (double-float-low-bits)
738   (:args (float :scs (double-reg descriptor-reg)
739                 :load-if (not (sc-is float double-stack))))
740   (:results (lo-bits :scs (unsigned-reg)))
741   (:temporary (:sc signed-stack :from :argument :to :result) temp)
742   (:arg-types double-float)
743   (:result-types unsigned-num)
744   (:translate double-float-low-bits)
745   (:policy :fast-safe)
746   (:vop-var vop)
747   (:generator 5
748      (sc-case float
749        (double-reg
750         (inst movsd temp float)
751         (move lo-bits temp))
752        (double-stack
753         (loadw lo-bits ebp-tn (- (1+ (tn-offset float)))))
754        (descriptor-reg
755         (loadw lo-bits float double-float-value-slot
756                other-pointer-lowtag)))
757      (inst shl lo-bits 32)
758      (inst shr lo-bits 32)))
759
760 \f
761
762 ;;;; complex float VOPs
763
764 (define-vop (make-complex-single-float)
765   (:translate complex)
766   (:args (real :scs (single-reg) :to :result :target r
767                :load-if (not (location= real r)))
768          (imag :scs (single-reg) :to :save))
769   (:arg-types single-float single-float)
770   (:results (r :scs (complex-single-reg) :from (:argument 0)
771                :load-if (not (sc-is r complex-single-stack))))
772   (:result-types complex-single-float)
773   (:note "inline complex single-float creation")
774   (:policy :fast-safe)
775   (:generator 5
776     (sc-case r
777       (complex-single-reg
778        (let ((r-real (complex-single-reg-real-tn r)))
779          (unless (location= real r-real)
780            (inst movss r-real real)))
781        (let ((r-imag (complex-single-reg-imag-tn r)))
782          (unless (location= imag r-imag)
783            (inst movss r-imag imag))))
784       (complex-single-stack
785        (unless (location= real r)
786          (inst movss (ea-for-csf-real-stack r) real))
787        (inst movss (ea-for-csf-imag-stack r) imag)))))
788
789 (define-vop (make-complex-double-float)
790   (:translate complex)
791   (:args (real :scs (double-reg) :target r
792                :load-if (not (location= real r)))
793          (imag :scs (double-reg) :to :save))
794   (:arg-types double-float double-float)
795   (:results (r :scs (complex-double-reg) :from (:argument 0)
796                :load-if (not (sc-is r complex-double-stack))))
797   (:result-types complex-double-float)
798   (:note "inline complex double-float creation")
799   (:policy :fast-safe)
800   (:generator 5
801     (sc-case r
802       (complex-double-reg
803        (let ((r-real (complex-double-reg-real-tn r)))
804          (unless (location= real r-real)
805            (inst movsd r-real real)))
806        (let ((r-imag (complex-double-reg-imag-tn r)))
807          (unless (location= imag r-imag)
808            (inst movsd r-imag imag))))
809       (complex-double-stack
810        (unless (location= real r)
811          (inst movsd (ea-for-cdf-real-stack r) real))
812        (inst movsd (ea-for-cdf-imag-stack r) imag)))))
813
814 (define-vop (complex-float-value)
815   (:args (x :target r))
816   (:results (r))
817   (:variant-vars offset)
818   (:policy :fast-safe)
819   (:generator 3
820     (cond ((sc-is x complex-single-reg complex-double-reg)
821            (let ((value-tn
822                   (make-random-tn :kind :normal
823                                   :sc (sc-or-lose 'double-reg)
824                                   :offset (+ offset (tn-offset x)))))
825              (unless (location= value-tn r)
826                (if (sc-is x complex-single-reg)
827                    (inst movss r value-tn)
828                    (inst movsd r value-tn)))))
829           ((sc-is r single-reg)
830            (let ((ea (sc-case x
831                        (complex-single-stack
832                         (ecase offset
833                           (0 (ea-for-csf-real-stack x))
834                           (1 (ea-for-csf-imag-stack x))))
835                        (descriptor-reg
836                         (ecase offset
837                           (0 (ea-for-csf-real-desc x))
838                           (1 (ea-for-csf-imag-desc x)))))))
839              (inst movss r ea)))
840           ((sc-is r double-reg)
841            (let ((ea (sc-case x
842                        (complex-double-stack
843                         (ecase offset
844                           (0 (ea-for-cdf-real-stack x))
845                           (1 (ea-for-cdf-imag-stack x))))
846                        (descriptor-reg
847                         (ecase offset
848                           (0 (ea-for-cdf-real-desc x))
849                           (1 (ea-for-cdf-imag-desc x)))))))
850              (inst movsd r ea)))
851           (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
852
853 (define-vop (realpart/complex-single-float complex-float-value)
854   (:translate realpart)
855   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
856             :target r))
857   (:arg-types complex-single-float)
858   (:results (r :scs (single-reg)))
859   (:result-types single-float)
860   (:note "complex float realpart")
861   (:variant 0))
862
863 (define-vop (realpart/complex-double-float complex-float-value)
864   (:translate realpart)
865   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
866             :target r))
867   (:arg-types complex-double-float)
868   (:results (r :scs (double-reg)))
869   (:result-types double-float)
870   (:note "complex float realpart")
871   (:variant 0))
872
873 (define-vop (imagpart/complex-single-float complex-float-value)
874   (:translate imagpart)
875   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
876             :target r))
877   (:arg-types complex-single-float)
878   (:results (r :scs (single-reg)))
879   (:result-types single-float)
880   (:note "complex float imagpart")
881   (:variant 1))
882
883 (define-vop (imagpart/complex-double-float complex-float-value)
884   (:translate imagpart)
885   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
886             :target r))
887   (:arg-types complex-double-float)
888   (:results (r :scs (double-reg)))
889   (:result-types double-float)
890   (:note "complex float imagpart")
891   (:variant 1))
892
893 \f
894 ;;; hack dummy VOPs to bias the representation selection of their
895 ;;; arguments towards a FP register, which can help avoid consing at
896 ;;; inappropriate locations
897 (defknown double-float-reg-bias (double-float) (values))
898 (define-vop (double-float-reg-bias)
899   (:translate double-float-reg-bias)
900   (:args (x :scs (double-reg double-stack) :load-if nil))
901   (:arg-types double-float)
902   (:policy :fast-safe)
903   (:note "inline dummy FP register bias")
904   (:ignore x)
905   (:generator 0))
906 (defknown single-float-reg-bias (single-float) (values))
907 (define-vop (single-float-reg-bias)
908   (:translate single-float-reg-bias)
909   (:args (x :scs (single-reg single-stack) :load-if nil))
910   (:arg-types single-float)
911   (:policy :fast-safe)
912   (:note "inline dummy FP register bias")
913   (:ignore x)
914   (:generator 0))