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