0.8.11.9:
[sbcl.git] / src / compiler / x86 / 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                :dword :base ,tn
17                :disp (- (* ,slot n-word-bytes)
18                         other-pointer-lowtag))))
19   (defun ea-for-sf-desc (tn)
20     (ea-for-xf-desc tn single-float-value-slot))
21   (defun ea-for-df-desc (tn)
22     (ea-for-xf-desc tn double-float-value-slot))
23   #!+long-float
24   (defun ea-for-lf-desc (tn)
25     (ea-for-xf-desc tn long-float-value-slot))
26   ;; complex floats
27   (defun ea-for-csf-real-desc (tn)
28     (ea-for-xf-desc tn complex-single-float-real-slot))
29   (defun ea-for-csf-imag-desc (tn)
30     (ea-for-xf-desc tn complex-single-float-imag-slot))
31   (defun ea-for-cdf-real-desc (tn)
32     (ea-for-xf-desc tn complex-double-float-real-slot))
33   (defun ea-for-cdf-imag-desc (tn)
34     (ea-for-xf-desc tn complex-double-float-imag-slot))
35   #!+long-float
36   (defun ea-for-clf-real-desc (tn)
37     (ea-for-xf-desc tn complex-long-float-real-slot))
38   #!+long-float
39   (defun ea-for-clf-imag-desc (tn)
40     (ea-for-xf-desc tn complex-long-float-imag-slot)))
41
42 (macrolet ((ea-for-xf-stack (tn kind)
43              `(make-ea
44                :dword :base ebp-tn
45                :disp (- (* (+ (tn-offset ,tn)
46                               (ecase ,kind (:single 1) (:double 2) (:long 3)))
47                          n-word-bytes)))))
48   (defun ea-for-sf-stack (tn)
49     (ea-for-xf-stack tn :single))
50   (defun ea-for-df-stack (tn)
51     (ea-for-xf-stack tn :double))
52   #!+long-float
53   (defun ea-for-lf-stack (tn)
54     (ea-for-xf-stack tn :long)))
55
56 ;;; Telling the FPU to wait is required in order to make signals occur
57 ;;; at the expected place, but naturally slows things down.
58 ;;;
59 ;;; NODE is the node whose compilation policy controls the decision
60 ;;; whether to just blast through carelessly or carefully emit wait
61 ;;; instructions and whatnot.
62 ;;;
63 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
64 ;;; #'NOTE-NEXT-INSTRUCTION.
65 ;;;
66 ;;; Until 2004-03-15, the implementation of this was buggy; it
67 ;;; unconditionally emitted the WAIT instruction.  It turns out that
68 ;;; this is the right thing to do anyway; omitting them can lead to
69 ;;; system corruption on conforming code.  -- CSR
70 (defun maybe-fp-wait (node &optional note-next-instruction)
71   (declare (ignore node))
72   #+nil
73   (when (policy node (or (= debug 3) (> safety speed))))
74   (when note-next-instruction
75     (note-next-instruction note-next-instruction :internal-error))
76   (inst wait))
77
78 ;;; complex float stack EAs
79 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
80              `(make-ea
81                :dword :base ,base
82                :disp (- (* (+ (tn-offset ,tn)
83                               (* (ecase ,kind
84                                    (:single 1)
85                                    (:double 2)
86                                    (:long 3))
87                                  (ecase ,slot (:real 1) (:imag 2))))
88                          n-word-bytes)))))
89   (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
90     (ea-for-cxf-stack tn :single :real base))
91   (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
92     (ea-for-cxf-stack tn :single :imag base))
93   (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
94     (ea-for-cxf-stack tn :double :real base))
95   (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
96     (ea-for-cxf-stack tn :double :imag base))
97   #!+long-float
98   (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
99     (ea-for-cxf-stack tn :long :real base))
100   #!+long-float
101   (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
102     (ea-for-cxf-stack tn :long :imag base)))
103
104 ;;; Abstract out the copying of a FP register to the FP stack top, and
105 ;;; provide two alternatives for its implementation. Note: it's not
106 ;;; necessary to distinguish between a single or double register move
107 ;;; here.
108 ;;;
109 ;;; Using a Pop then load.
110 (defun copy-fp-reg-to-fr0 (reg)
111   (aver (not (zerop (tn-offset reg))))
112   (inst fstp fr0-tn)
113   (inst fld (make-random-tn :kind :normal
114                             :sc (sc-or-lose 'double-reg)
115                             :offset (1- (tn-offset reg)))))
116 ;;; Using Fxch then Fst to restore the original reg contents.
117 #+nil
118 (defun copy-fp-reg-to-fr0 (reg)
119   (aver (not (zerop (tn-offset reg))))
120   (inst fxch reg)
121   (inst fst  reg))
122
123 ;;; The x86 can't store a long-float to memory without popping the
124 ;;; stack and marking a register as empty, so it is necessary to
125 ;;; restore the register from memory.
126 #!+long-float
127 (defun store-long-float (ea)
128    (inst fstpl ea)
129    (inst fldl ea))
130 \f
131 ;;;; move functions
132
133 ;;; X is source, Y is destination.
134 (define-move-fun (load-single 2) (vop x y)
135   ((single-stack) (single-reg))
136   (with-empty-tn@fp-top(y)
137      (inst fld (ea-for-sf-stack x))))
138
139 (define-move-fun (store-single 2) (vop x y)
140   ((single-reg) (single-stack))
141   (cond ((zerop (tn-offset x))
142          (inst fst (ea-for-sf-stack y)))
143         (t
144          (inst fxch x)
145          (inst fst (ea-for-sf-stack y))
146          ;; This may not be necessary as ST0 is likely invalid now.
147          (inst fxch x))))
148
149 (define-move-fun (load-double 2) (vop x y)
150   ((double-stack) (double-reg))
151   (with-empty-tn@fp-top(y)
152      (inst fldd (ea-for-df-stack x))))
153
154 (define-move-fun (store-double 2) (vop x y)
155   ((double-reg) (double-stack))
156   (cond ((zerop (tn-offset x))
157          (inst fstd (ea-for-df-stack y)))
158         (t
159          (inst fxch x)
160          (inst fstd (ea-for-df-stack y))
161          ;; This may not be necessary as ST0 is likely invalid now.
162          (inst fxch x))))
163
164 #!+long-float
165 (define-move-fun (load-long 2) (vop x y)
166   ((long-stack) (long-reg))
167   (with-empty-tn@fp-top(y)
168      (inst fldl (ea-for-lf-stack x))))
169
170 #!+long-float
171 (define-move-fun (store-long 2) (vop x y)
172   ((long-reg) (long-stack))
173   (cond ((zerop (tn-offset x))
174          (store-long-float (ea-for-lf-stack y)))
175         (t
176          (inst fxch x)
177          (store-long-float (ea-for-lf-stack y))
178          ;; This may not be necessary as ST0 is likely invalid now.
179          (inst fxch x))))
180
181 ;;; The i387 has instructions to load some useful constants. This
182 ;;; doesn't save much time but might cut down on memory access and
183 ;;; reduce the size of the constant vector (CV). Intel claims they are
184 ;;; stored in a more precise form on chip. Anyhow, might as well use
185 ;;; the feature. It can be turned off by hacking the
186 ;;; "immediate-constant-sc" in vm.lisp.
187 (eval-when (:compile-toplevel :execute)
188   (setf *read-default-float-format*
189         #!+long-float 'long-float #!-long-float 'double-float))
190 (define-move-fun (load-fp-constant 2) (vop x y)
191   ((fp-constant) (single-reg double-reg #!+long-float long-reg))
192   (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
193     (with-empty-tn@fp-top(y)
194       (cond ((zerop value)
195              (inst fldz))
196             ((= value 1e0)
197              (inst fld1))
198             ((= value (coerce pi *read-default-float-format*))
199              (inst fldpi))
200             ((= value (log 10e0 2e0))
201              (inst fldl2t))
202             ((= value (log 2.718281828459045235360287471352662e0 2e0))
203              (inst fldl2e))
204             ((= value (log 2e0 10e0))
205              (inst fldlg2))
206             ((= value (log 2e0 2.718281828459045235360287471352662e0))
207              (inst fldln2))
208             (t (warn "ignoring bogus i387 constant ~A" value))))))
209 (eval-when (:compile-toplevel :execute)
210   (setf *read-default-float-format* 'single-float))
211 \f
212 ;;;; complex float move functions
213
214 (defun complex-single-reg-real-tn (x)
215   (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
216                   :offset (tn-offset x)))
217 (defun complex-single-reg-imag-tn (x)
218   (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
219                   :offset (1+ (tn-offset x))))
220
221 (defun complex-double-reg-real-tn (x)
222   (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
223                   :offset (tn-offset x)))
224 (defun complex-double-reg-imag-tn (x)
225   (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
226                   :offset (1+ (tn-offset x))))
227
228 #!+long-float
229 (defun complex-long-reg-real-tn (x)
230   (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
231                   :offset (tn-offset x)))
232 #!+long-float
233 (defun complex-long-reg-imag-tn (x)
234   (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
235                   :offset (1+ (tn-offset x))))
236
237 ;;; X is source, Y is destination.
238 (define-move-fun (load-complex-single 2) (vop x y)
239   ((complex-single-stack) (complex-single-reg))
240   (let ((real-tn (complex-single-reg-real-tn y)))
241     (with-empty-tn@fp-top (real-tn)
242       (inst fld (ea-for-csf-real-stack x))))
243   (let ((imag-tn (complex-single-reg-imag-tn y)))
244     (with-empty-tn@fp-top (imag-tn)
245       (inst fld (ea-for-csf-imag-stack x)))))
246
247 (define-move-fun (store-complex-single 2) (vop x y)
248   ((complex-single-reg) (complex-single-stack))
249   (let ((real-tn (complex-single-reg-real-tn x)))
250     (cond ((zerop (tn-offset real-tn))
251            (inst fst (ea-for-csf-real-stack y)))
252           (t
253            (inst fxch real-tn)
254            (inst fst (ea-for-csf-real-stack y))
255            (inst fxch real-tn))))
256   (let ((imag-tn (complex-single-reg-imag-tn x)))
257     (inst fxch imag-tn)
258     (inst fst (ea-for-csf-imag-stack y))
259     (inst fxch imag-tn)))
260
261 (define-move-fun (load-complex-double 2) (vop x y)
262   ((complex-double-stack) (complex-double-reg))
263   (let ((real-tn (complex-double-reg-real-tn y)))
264     (with-empty-tn@fp-top(real-tn)
265       (inst fldd (ea-for-cdf-real-stack x))))
266   (let ((imag-tn (complex-double-reg-imag-tn y)))
267     (with-empty-tn@fp-top(imag-tn)
268       (inst fldd (ea-for-cdf-imag-stack x)))))
269
270 (define-move-fun (store-complex-double 2) (vop x y)
271   ((complex-double-reg) (complex-double-stack))
272   (let ((real-tn (complex-double-reg-real-tn x)))
273     (cond ((zerop (tn-offset real-tn))
274            (inst fstd (ea-for-cdf-real-stack y)))
275           (t
276            (inst fxch real-tn)
277            (inst fstd (ea-for-cdf-real-stack y))
278            (inst fxch real-tn))))
279   (let ((imag-tn (complex-double-reg-imag-tn x)))
280     (inst fxch imag-tn)
281     (inst fstd (ea-for-cdf-imag-stack y))
282     (inst fxch imag-tn)))
283
284 #!+long-float
285 (define-move-fun (load-complex-long 2) (vop x y)
286   ((complex-long-stack) (complex-long-reg))
287   (let ((real-tn (complex-long-reg-real-tn y)))
288     (with-empty-tn@fp-top(real-tn)
289       (inst fldl (ea-for-clf-real-stack x))))
290   (let ((imag-tn (complex-long-reg-imag-tn y)))
291     (with-empty-tn@fp-top(imag-tn)
292       (inst fldl (ea-for-clf-imag-stack x)))))
293
294 #!+long-float
295 (define-move-fun (store-complex-long 2) (vop x y)
296   ((complex-long-reg) (complex-long-stack))
297   (let ((real-tn (complex-long-reg-real-tn x)))
298     (cond ((zerop (tn-offset real-tn))
299            (store-long-float (ea-for-clf-real-stack y)))
300           (t
301            (inst fxch real-tn)
302            (store-long-float (ea-for-clf-real-stack y))
303            (inst fxch real-tn))))
304   (let ((imag-tn (complex-long-reg-imag-tn x)))
305     (inst fxch imag-tn)
306     (store-long-float (ea-for-clf-imag-stack y))
307     (inst fxch imag-tn)))
308
309 \f
310 ;;;; move VOPs
311
312 ;;; float register to register moves
313 (define-vop (float-move)
314   (:args (x))
315   (:results (y))
316   (:note "float move")
317   (:generator 0
318      (unless (location= x y)
319         (cond ((zerop (tn-offset y))
320                (copy-fp-reg-to-fr0 x))
321               ((zerop (tn-offset x))
322                (inst fstd y))
323               (t
324                (inst fxch x)
325                (inst fstd y)
326                (inst fxch x))))))
327
328 (define-vop (single-move float-move)
329   (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
330   (:results (y :scs (single-reg) :load-if (not (location= x y)))))
331 (define-move-vop single-move :move (single-reg) (single-reg))
332
333 (define-vop (double-move float-move)
334   (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
335   (:results (y :scs (double-reg) :load-if (not (location= x y)))))
336 (define-move-vop double-move :move (double-reg) (double-reg))
337
338 #!+long-float
339 (define-vop (long-move float-move)
340   (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
341   (:results (y :scs (long-reg) :load-if (not (location= x y)))))
342 #!+long-float
343 (define-move-vop long-move :move (long-reg) (long-reg))
344
345 ;;; complex float register to register moves
346 (define-vop (complex-float-move)
347   (:args (x :target y :load-if (not (location= x y))))
348   (:results (y :load-if (not (location= x y))))
349   (:note "complex float move")
350   (:generator 0
351      (unless (location= x y)
352        ;; Note the complex-float-regs are aligned to every second
353        ;; float register so there is not need to worry about overlap.
354        (let ((x-real (complex-double-reg-real-tn x))
355              (y-real (complex-double-reg-real-tn y)))
356          (cond ((zerop (tn-offset y-real))
357                 (copy-fp-reg-to-fr0 x-real))
358                ((zerop (tn-offset x-real))
359                 (inst fstd y-real))
360                (t
361                 (inst fxch x-real)
362                 (inst fstd y-real)
363                 (inst fxch x-real))))
364        (let ((x-imag (complex-double-reg-imag-tn x))
365              (y-imag (complex-double-reg-imag-tn y)))
366          (inst fxch x-imag)
367          (inst fstd y-imag)
368          (inst fxch x-imag)))))
369
370 (define-vop (complex-single-move complex-float-move)
371   (:args (x :scs (complex-single-reg) :target y
372             :load-if (not (location= x y))))
373   (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
374 (define-move-vop complex-single-move :move
375   (complex-single-reg) (complex-single-reg))
376
377 (define-vop (complex-double-move complex-float-move)
378   (:args (x :scs (complex-double-reg)
379             :target y :load-if (not (location= x y))))
380   (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
381 (define-move-vop complex-double-move :move
382   (complex-double-reg) (complex-double-reg))
383
384 #!+long-float
385 (define-vop (complex-long-move complex-float-move)
386   (:args (x :scs (complex-long-reg)
387             :target y :load-if (not (location= x y))))
388   (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
389 #!+long-float
390 (define-move-vop complex-long-move :move
391   (complex-long-reg) (complex-long-reg))
392 \f
393 ;;; Move from float to a descriptor reg. allocating a new float
394 ;;; object in the process.
395 (define-vop (move-from-single)
396   (:args (x :scs (single-reg) :to :save))
397   (:results (y :scs (descriptor-reg)))
398   (:node-var node)
399   (:note "float to pointer coercion")
400   (:generator 13
401      (with-fixed-allocation (y
402                              single-float-widetag
403                              single-float-size node)
404        (with-tn@fp-top(x)
405          (inst fst (ea-for-sf-desc y))))))
406 (define-move-vop move-from-single :move
407   (single-reg) (descriptor-reg))
408
409 (define-vop (move-from-double)
410   (:args (x :scs (double-reg) :to :save))
411   (:results (y :scs (descriptor-reg)))
412   (:node-var node)
413   (:note "float to pointer coercion")
414   (:generator 13
415      (with-fixed-allocation (y
416                              double-float-widetag
417                              double-float-size
418                              node)
419        (with-tn@fp-top(x)
420          (inst fstd (ea-for-df-desc y))))))
421 (define-move-vop move-from-double :move
422   (double-reg) (descriptor-reg))
423
424 #!+long-float
425 (define-vop (move-from-long)
426   (:args (x :scs (long-reg) :to :save))
427   (:results (y :scs (descriptor-reg)))
428   (:node-var node)
429   (:note "float to pointer coercion")
430   (:generator 13
431      (with-fixed-allocation (y
432                              long-float-widetag
433                              long-float-size
434                              node)
435        (with-tn@fp-top(x)
436          (store-long-float (ea-for-lf-desc y))))))
437 #!+long-float
438 (define-move-vop move-from-long :move
439   (long-reg) (descriptor-reg))
440
441 (define-vop (move-from-fp-constant)
442   (:args (x :scs (fp-constant)))
443   (:results (y :scs (descriptor-reg)))
444   (:generator 2
445      (ecase (sb!c::constant-value (sb!c::tn-leaf x))
446        (0f0 (load-symbol-value y *fp-constant-0f0*))
447        (1f0 (load-symbol-value y *fp-constant-1f0*))
448        (0d0 (load-symbol-value y *fp-constant-0d0*))
449        (1d0 (load-symbol-value y *fp-constant-1d0*))
450        #!+long-float
451        (0l0 (load-symbol-value y *fp-constant-0l0*))
452        #!+long-float
453        (1l0 (load-symbol-value y *fp-constant-1l0*))
454        #!+long-float
455        (#.pi (load-symbol-value y *fp-constant-pi*))
456        #!+long-float
457        (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
458        #!+long-float
459        (#.(log 2.718281828459045235360287471352662L0 2l0)
460           (load-symbol-value y *fp-constant-l2e*))
461        #!+long-float
462        (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
463        #!+long-float
464        (#.(log 2l0 2.718281828459045235360287471352662L0)
465           (load-symbol-value y *fp-constant-ln2*)))))
466 (define-move-vop move-from-fp-constant :move
467   (fp-constant) (descriptor-reg))
468
469 ;;; Move from a descriptor to a float register.
470 (define-vop (move-to-single)
471   (:args (x :scs (descriptor-reg)))
472   (:results (y :scs (single-reg)))
473   (:note "pointer to float coercion")
474   (:generator 2
475      (with-empty-tn@fp-top(y)
476        (inst fld (ea-for-sf-desc x)))))
477 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
478
479 (define-vop (move-to-double)
480   (:args (x :scs (descriptor-reg)))
481   (:results (y :scs (double-reg)))
482   (:note "pointer to float coercion")
483   (:generator 2
484      (with-empty-tn@fp-top(y)
485        (inst fldd (ea-for-df-desc x)))))
486 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
487
488 #!+long-float
489 (define-vop (move-to-long)
490   (:args (x :scs (descriptor-reg)))
491   (:results (y :scs (long-reg)))
492   (:note "pointer to float coercion")
493   (:generator 2
494      (with-empty-tn@fp-top(y)
495        (inst fldl (ea-for-lf-desc x)))))
496 #!+long-float
497 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
498 \f
499 ;;; Move from complex float to a descriptor reg. allocating a new
500 ;;; complex float object in the process.
501 (define-vop (move-from-complex-single)
502   (:args (x :scs (complex-single-reg) :to :save))
503   (:results (y :scs (descriptor-reg)))
504   (:node-var node)
505   (:note "complex float to pointer coercion")
506   (:generator 13
507      (with-fixed-allocation (y
508                              complex-single-float-widetag
509                              complex-single-float-size
510                              node)
511        (let ((real-tn (complex-single-reg-real-tn x)))
512          (with-tn@fp-top(real-tn)
513            (inst fst (ea-for-csf-real-desc y))))
514        (let ((imag-tn (complex-single-reg-imag-tn x)))
515          (with-tn@fp-top(imag-tn)
516            (inst fst (ea-for-csf-imag-desc y)))))))
517 (define-move-vop move-from-complex-single :move
518   (complex-single-reg) (descriptor-reg))
519
520 (define-vop (move-from-complex-double)
521   (:args (x :scs (complex-double-reg) :to :save))
522   (:results (y :scs (descriptor-reg)))
523   (:node-var node)
524   (:note "complex float to pointer coercion")
525   (:generator 13
526      (with-fixed-allocation (y
527                              complex-double-float-widetag
528                              complex-double-float-size
529                              node)
530        (let ((real-tn (complex-double-reg-real-tn x)))
531          (with-tn@fp-top(real-tn)
532            (inst fstd (ea-for-cdf-real-desc y))))
533        (let ((imag-tn (complex-double-reg-imag-tn x)))
534          (with-tn@fp-top(imag-tn)
535            (inst fstd (ea-for-cdf-imag-desc y)))))))
536 (define-move-vop move-from-complex-double :move
537   (complex-double-reg) (descriptor-reg))
538
539 #!+long-float
540 (define-vop (move-from-complex-long)
541   (:args (x :scs (complex-long-reg) :to :save))
542   (:results (y :scs (descriptor-reg)))
543   (:node-var node)
544   (:note "complex float to pointer coercion")
545   (:generator 13
546      (with-fixed-allocation (y
547                              complex-long-float-widetag
548                              complex-long-float-size
549                              node)
550        (let ((real-tn (complex-long-reg-real-tn x)))
551          (with-tn@fp-top(real-tn)
552            (store-long-float (ea-for-clf-real-desc y))))
553        (let ((imag-tn (complex-long-reg-imag-tn x)))
554          (with-tn@fp-top(imag-tn)
555            (store-long-float (ea-for-clf-imag-desc y)))))))
556 #!+long-float
557 (define-move-vop move-from-complex-long :move
558   (complex-long-reg) (descriptor-reg))
559
560 ;;; Move from a descriptor to a complex float register.
561 (macrolet ((frob (name sc format)
562              `(progn
563                 (define-vop (,name)
564                   (:args (x :scs (descriptor-reg)))
565                   (:results (y :scs (,sc)))
566                   (:note "pointer to complex float coercion")
567                   (:generator 2
568                     (let ((real-tn (complex-double-reg-real-tn y)))
569                       (with-empty-tn@fp-top(real-tn)
570                         ,@(ecase format
571                            (:single '((inst fld (ea-for-csf-real-desc x))))
572                            (:double '((inst fldd (ea-for-cdf-real-desc x))))
573                            #!+long-float
574                            (:long '((inst fldl (ea-for-clf-real-desc x)))))))
575                     (let ((imag-tn (complex-double-reg-imag-tn y)))
576                       (with-empty-tn@fp-top(imag-tn)
577                         ,@(ecase format
578                            (:single '((inst fld (ea-for-csf-imag-desc x))))
579                            (:double '((inst fldd (ea-for-cdf-imag-desc x))))
580                            #!+long-float
581                            (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
582                 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
583           (frob move-to-complex-single complex-single-reg :single)
584           (frob move-to-complex-double complex-double-reg :double)
585           #!+long-float
586           (frob move-to-complex-double complex-long-reg :long))
587 \f
588 ;;;; the move argument vops
589 ;;;;
590 ;;;; Note these are also used to stuff fp numbers onto the c-call
591 ;;;; stack so the order is different than the lisp-stack.
592
593 ;;; the general MOVE-ARG VOP
594 (macrolet ((frob (name sc stack-sc format)
595              `(progn
596                 (define-vop (,name)
597                   (:args (x :scs (,sc) :target y)
598                          (fp :scs (any-reg)
599                              :load-if (not (sc-is y ,sc))))
600                   (:results (y))
601                   (:note "float argument move")
602                   (:generator ,(case format (:single 2) (:double 3) (:long 4))
603                     (sc-case y
604                       (,sc
605                        (unless (location= x y)
606                           (cond ((zerop (tn-offset y))
607                                  (copy-fp-reg-to-fr0 x))
608                                 ((zerop (tn-offset x))
609                                  (inst fstd y))
610                                 (t
611                                  (inst fxch x)
612                                  (inst fstd y)
613                                  (inst fxch x)))))
614                       (,stack-sc
615                        (if (= (tn-offset fp) esp-offset)
616                            (let* ((offset (* (tn-offset y) n-word-bytes))
617                                   (ea (make-ea :dword :base fp :disp offset)))
618                              (with-tn@fp-top(x)
619                                 ,@(ecase format
620                                          (:single '((inst fst ea)))
621                                          (:double '((inst fstd ea)))
622                                          #!+long-float
623                                          (:long '((store-long-float ea))))))
624                            (let ((ea (make-ea
625                                       :dword :base fp
626                                       :disp (- (* (+ (tn-offset y)
627                                                      ,(case format
628                                                             (:single 1)
629                                                             (:double 2)
630                                                             (:long 3)))
631                                                   n-word-bytes)))))
632                              (with-tn@fp-top(x)
633                                ,@(ecase format
634                                     (:single '((inst fst  ea)))
635                                     (:double '((inst fstd ea)))
636                                     #!+long-float
637                                     (:long '((store-long-float ea)))))))))))
638                 (define-move-vop ,name :move-arg
639                   (,sc descriptor-reg) (,sc)))))
640   (frob move-single-float-arg single-reg single-stack :single)
641   (frob move-double-float-arg double-reg double-stack :double)
642   #!+long-float
643   (frob move-long-float-arg long-reg long-stack :long))
644
645 ;;;; complex float MOVE-ARG VOP
646 (macrolet ((frob (name sc stack-sc format)
647              `(progn
648                 (define-vop (,name)
649                   (:args (x :scs (,sc) :target y)
650                          (fp :scs (any-reg)
651                              :load-if (not (sc-is y ,sc))))
652                   (:results (y))
653                   (:note "complex float argument move")
654                   (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
655                     (sc-case y
656                       (,sc
657                        (unless (location= x y)
658                          (let ((x-real (complex-double-reg-real-tn x))
659                                (y-real (complex-double-reg-real-tn y)))
660                            (cond ((zerop (tn-offset y-real))
661                                   (copy-fp-reg-to-fr0 x-real))
662                                  ((zerop (tn-offset x-real))
663                                   (inst fstd y-real))
664                                  (t
665                                   (inst fxch x-real)
666                                   (inst fstd y-real)
667                                   (inst fxch x-real))))
668                          (let ((x-imag (complex-double-reg-imag-tn x))
669                                (y-imag (complex-double-reg-imag-tn y)))
670                            (inst fxch x-imag)
671                            (inst fstd y-imag)
672                            (inst fxch x-imag))))
673                       (,stack-sc
674                        (let ((real-tn (complex-double-reg-real-tn x)))
675                          (cond ((zerop (tn-offset real-tn))
676                                 ,@(ecase format
677                                     (:single
678                                      '((inst fst
679                                         (ea-for-csf-real-stack y fp))))
680                                     (:double
681                                      '((inst fstd
682                                         (ea-for-cdf-real-stack y fp))))
683                                     #!+long-float
684                                     (:long
685                                      '((store-long-float
686                                         (ea-for-clf-real-stack y fp))))))
687                                (t
688                                 (inst fxch real-tn)
689                                 ,@(ecase format
690                                     (:single
691                                      '((inst fst
692                                         (ea-for-csf-real-stack y fp))))
693                                     (:double
694                                      '((inst fstd
695                                         (ea-for-cdf-real-stack y fp))))
696                                     #!+long-float
697                                     (:long
698                                      '((store-long-float
699                                         (ea-for-clf-real-stack y fp)))))
700                                 (inst fxch real-tn))))
701                        (let ((imag-tn (complex-double-reg-imag-tn x)))
702                          (inst fxch imag-tn)
703                          ,@(ecase format
704                              (:single
705                               '((inst fst (ea-for-csf-imag-stack y fp))))
706                              (:double
707                               '((inst fstd (ea-for-cdf-imag-stack y fp))))
708                              #!+long-float
709                              (:long
710                               '((store-long-float
711                                  (ea-for-clf-imag-stack y fp)))))
712                          (inst fxch imag-tn))))))
713                 (define-move-vop ,name :move-arg
714                   (,sc descriptor-reg) (,sc)))))
715   (frob move-complex-single-float-arg
716         complex-single-reg complex-single-stack :single)
717   (frob move-complex-double-float-arg
718         complex-double-reg complex-double-stack :double)
719   #!+long-float
720   (frob move-complex-long-float-arg
721         complex-long-reg complex-long-stack :long))
722
723 (define-move-vop move-arg :move-arg
724   (single-reg double-reg #!+long-float long-reg
725    complex-single-reg complex-double-reg #!+long-float complex-long-reg)
726   (descriptor-reg))
727
728 \f
729 ;;;; arithmetic VOPs
730
731 ;;; dtc: the floating point arithmetic vops
732 ;;;
733 ;;; Note: Although these can accept x and y on the stack or pointed to
734 ;;; from a descriptor register, they will work with register loading
735 ;;; without these. Same deal with the result - it need only be a
736 ;;; register. When load-tns are needed they will probably be in ST0
737 ;;; and the code below should be able to correctly handle all cases.
738 ;;;
739 ;;; However it seems to produce better code if all arg. and result
740 ;;; options are used; on the P86 there is no extra cost in using a
741 ;;; memory operand to the FP instructions - not so on the PPro.
742 ;;;
743 ;;; It may also be useful to handle constant args?
744 ;;;
745 ;;; 22-Jul-97: descriptor args lose in some simple cases when
746 ;;; a function result computed in a loop. Then Python insists
747 ;;; on consing the intermediate values! For example
748 ;;;
749 ;;; (defun test(a n)
750 ;;;   (declare (type (simple-array double-float (*)) a)
751 ;;;        (fixnum n))
752 ;;;   (let ((sum 0d0))
753 ;;;     (declare (type double-float sum))
754 ;;;   (dotimes (i n)
755 ;;;     (incf sum (* (aref a i)(aref a i))))
756 ;;;     sum))
757 ;;;
758 ;;; So, disabling descriptor args until this can be fixed elsewhere.
759 (macrolet
760     ((frob (op fop-sti fopr-sti
761                fop fopr sname scost
762                fopd foprd dname dcost
763                lname lcost)
764        #!-long-float (declare (ignore lcost lname))
765        `(progn
766          (define-vop (,sname)
767            (:translate ,op)
768            (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
769                      :to :eval)
770                   (y :scs (single-reg single-stack #+nil descriptor-reg)
771                      :to :eval))
772            (:temporary (:sc single-reg :offset fr0-offset
773                             :from :eval :to :result) fr0)
774            (:results (r :scs (single-reg single-stack)))
775            (:arg-types single-float single-float)
776            (:result-types single-float)
777            (:policy :fast-safe)
778            (:note "inline float arithmetic")
779            (:vop-var vop)
780            (:save-p :compute-only)
781            (:node-var node)
782            (:generator ,scost
783              ;; Handle a few special cases
784              (cond
785               ;; x, y, and r are the same register.
786               ((and (sc-is x single-reg) (location= x r) (location= y r))
787                (cond ((zerop (tn-offset r))
788                       (inst ,fop fr0))
789                      (t
790                       (inst fxch r)
791                       (inst ,fop fr0)
792                       ;; XX the source register will not be valid.
793                       (note-next-instruction vop :internal-error)
794                       (inst fxch r))))
795
796               ;; x and r are the same register.
797               ((and (sc-is x single-reg) (location= x r))
798                (cond ((zerop (tn-offset r))
799                       (sc-case y
800                          (single-reg
801                           ;; ST(0) = ST(0) op ST(y)
802                           (inst ,fop y))
803                          (single-stack
804                           ;; ST(0) = ST(0) op Mem
805                           (inst ,fop (ea-for-sf-stack y)))
806                          (descriptor-reg
807                           (inst ,fop (ea-for-sf-desc y)))))
808                      (t
809                       ;; y to ST0
810                       (sc-case y
811                          (single-reg
812                           (unless (zerop (tn-offset y))
813                                   (copy-fp-reg-to-fr0 y)))
814                          ((single-stack descriptor-reg)
815                           (inst fstp fr0)
816                           (if (sc-is y single-stack)
817                               (inst fld (ea-for-sf-stack y))
818                             (inst fld (ea-for-sf-desc y)))))
819                       ;; ST(i) = ST(i) op ST0
820                       (inst ,fop-sti r)))
821                (maybe-fp-wait node vop))
822               ;; y and r are the same register.
823               ((and (sc-is y single-reg) (location= y r))
824                (cond ((zerop (tn-offset r))
825                       (sc-case x
826                          (single-reg
827                           ;; ST(0) = ST(x) op ST(0)
828                           (inst ,fopr x))
829                          (single-stack
830                           ;; ST(0) = Mem op ST(0)
831                           (inst ,fopr (ea-for-sf-stack x)))
832                          (descriptor-reg
833                           (inst ,fopr (ea-for-sf-desc x)))))
834                      (t
835                       ;; x to ST0
836                       (sc-case x
837                         (single-reg
838                          (unless (zerop (tn-offset x))
839                                  (copy-fp-reg-to-fr0 x)))
840                         ((single-stack descriptor-reg)
841                          (inst fstp fr0)
842                          (if (sc-is x single-stack)
843                              (inst fld (ea-for-sf-stack x))
844                            (inst fld (ea-for-sf-desc x)))))
845                       ;; ST(i) = ST(0) op ST(i)
846                       (inst ,fopr-sti r)))
847                (maybe-fp-wait node vop))
848               ;; the default case
849               (t
850                ;; Get the result to ST0.
851
852                ;; Special handling is needed if x or y are in ST0, and
853                ;; simpler code is generated.
854                (cond
855                 ;; x is in ST0
856                 ((and (sc-is x single-reg) (zerop (tn-offset x)))
857                  ;; ST0 = ST0 op y
858                  (sc-case y
859                    (single-reg
860                     (inst ,fop y))
861                    (single-stack
862                     (inst ,fop (ea-for-sf-stack y)))
863                    (descriptor-reg
864                     (inst ,fop (ea-for-sf-desc y)))))
865                 ;; y is in ST0
866                 ((and (sc-is y single-reg) (zerop (tn-offset y)))
867                  ;; ST0 = x op ST0
868                  (sc-case x
869                    (single-reg
870                     (inst ,fopr x))
871                    (single-stack
872                     (inst ,fopr (ea-for-sf-stack x)))
873                    (descriptor-reg
874                     (inst ,fopr (ea-for-sf-desc x)))))
875                 (t
876                  ;; x to ST0
877                  (sc-case x
878                    (single-reg
879                     (copy-fp-reg-to-fr0 x))
880                    (single-stack
881                     (inst fstp fr0)
882                     (inst fld (ea-for-sf-stack x)))
883                    (descriptor-reg
884                     (inst fstp fr0)
885                     (inst fld (ea-for-sf-desc x))))
886                  ;; ST0 = ST0 op y
887                  (sc-case y
888                    (single-reg
889                     (inst ,fop y))
890                    (single-stack
891                     (inst ,fop (ea-for-sf-stack y)))
892                    (descriptor-reg
893                     (inst ,fop (ea-for-sf-desc y))))))
894
895                (note-next-instruction vop :internal-error)
896
897                ;; Finally save the result.
898                (sc-case r
899                  (single-reg
900                   (cond ((zerop (tn-offset r))
901                          (maybe-fp-wait node))
902                         (t
903                          (inst fst r))))
904                  (single-stack
905                   (inst fst (ea-for-sf-stack r))))))))
906
907          (define-vop (,dname)
908            (:translate ,op)
909            (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
910                      :to :eval)
911                   (y :scs (double-reg double-stack #+nil descriptor-reg)
912                      :to :eval))
913            (:temporary (:sc double-reg :offset fr0-offset
914                             :from :eval :to :result) fr0)
915            (:results (r :scs (double-reg double-stack)))
916            (:arg-types double-float double-float)
917            (:result-types double-float)
918            (:policy :fast-safe)
919            (:note "inline float arithmetic")
920            (:vop-var vop)
921            (:save-p :compute-only)
922            (:node-var node)
923            (:generator ,dcost
924              ;; Handle a few special cases.
925              (cond
926               ;; x, y, and r are the same register.
927               ((and (sc-is x double-reg) (location= x r) (location= y r))
928                (cond ((zerop (tn-offset r))
929                       (inst ,fop fr0))
930                      (t
931                       (inst fxch x)
932                       (inst ,fopd fr0)
933                       ;; XX the source register will not be valid.
934                       (note-next-instruction vop :internal-error)
935                       (inst fxch r))))
936
937               ;; x and r are the same register.
938               ((and (sc-is x double-reg) (location= x r))
939                (cond ((zerop (tn-offset r))
940                       (sc-case y
941                          (double-reg
942                           ;; ST(0) = ST(0) op ST(y)
943                           (inst ,fopd y))
944                          (double-stack
945                           ;; ST(0) = ST(0) op Mem
946                           (inst ,fopd (ea-for-df-stack y)))
947                          (descriptor-reg
948                           (inst ,fopd (ea-for-df-desc y)))))
949                      (t
950                       ;; y to ST0
951                       (sc-case y
952                          (double-reg
953                           (unless (zerop (tn-offset y))
954                                   (copy-fp-reg-to-fr0 y)))
955                          ((double-stack descriptor-reg)
956                           (inst fstp fr0)
957                           (if (sc-is y double-stack)
958                               (inst fldd (ea-for-df-stack y))
959                             (inst fldd (ea-for-df-desc y)))))
960                       ;; ST(i) = ST(i) op ST0
961                       (inst ,fop-sti r)))
962                (maybe-fp-wait node vop))
963               ;; y and r are the same register.
964               ((and (sc-is y double-reg) (location= y r))
965                (cond ((zerop (tn-offset r))
966                       (sc-case x
967                          (double-reg
968                           ;; ST(0) = ST(x) op ST(0)
969                           (inst ,foprd x))
970                          (double-stack
971                           ;; ST(0) = Mem op ST(0)
972                           (inst ,foprd (ea-for-df-stack x)))
973                          (descriptor-reg
974                           (inst ,foprd (ea-for-df-desc x)))))
975                      (t
976                       ;; x to ST0
977                       (sc-case x
978                          (double-reg
979                           (unless (zerop (tn-offset x))
980                                   (copy-fp-reg-to-fr0 x)))
981                          ((double-stack descriptor-reg)
982                           (inst fstp fr0)
983                           (if (sc-is x double-stack)
984                               (inst fldd (ea-for-df-stack x))
985                             (inst fldd (ea-for-df-desc x)))))
986                       ;; ST(i) = ST(0) op ST(i)
987                       (inst ,fopr-sti r)))
988                (maybe-fp-wait node vop))
989               ;; the default case
990               (t
991                ;; Get the result to ST0.
992
993                ;; Special handling is needed if x or y are in ST0, and
994                ;; simpler code is generated.
995                (cond
996                 ;; x is in ST0
997                 ((and (sc-is x double-reg) (zerop (tn-offset x)))
998                  ;; ST0 = ST0 op y
999                  (sc-case y
1000                    (double-reg
1001                     (inst ,fopd y))
1002                    (double-stack
1003                     (inst ,fopd (ea-for-df-stack y)))
1004                    (descriptor-reg
1005                     (inst ,fopd (ea-for-df-desc y)))))
1006                 ;; y is in ST0
1007                 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1008                  ;; ST0 = x op ST0
1009                  (sc-case x
1010                    (double-reg
1011                     (inst ,foprd x))
1012                    (double-stack
1013                     (inst ,foprd (ea-for-df-stack x)))
1014                    (descriptor-reg
1015                     (inst ,foprd (ea-for-df-desc x)))))
1016                 (t
1017                  ;; x to ST0
1018                  (sc-case x
1019                    (double-reg
1020                     (copy-fp-reg-to-fr0 x))
1021                    (double-stack
1022                     (inst fstp fr0)
1023                     (inst fldd (ea-for-df-stack x)))
1024                    (descriptor-reg
1025                     (inst fstp fr0)
1026                     (inst fldd (ea-for-df-desc x))))
1027                  ;; ST0 = ST0 op y
1028                  (sc-case y
1029                    (double-reg
1030                     (inst ,fopd y))
1031                    (double-stack
1032                     (inst ,fopd (ea-for-df-stack y)))
1033                    (descriptor-reg
1034                     (inst ,fopd (ea-for-df-desc y))))))
1035
1036                (note-next-instruction vop :internal-error)
1037
1038                ;; Finally save the result.
1039                (sc-case r
1040                  (double-reg
1041                   (cond ((zerop (tn-offset r))
1042                          (maybe-fp-wait node))
1043                         (t
1044                          (inst fst r))))
1045                  (double-stack
1046                   (inst fstd (ea-for-df-stack r))))))))
1047
1048          #!+long-float
1049          (define-vop (,lname)
1050            (:translate ,op)
1051            (:args (x :scs (long-reg) :to :eval)
1052                   (y :scs (long-reg) :to :eval))
1053            (:temporary (:sc long-reg :offset fr0-offset
1054                             :from :eval :to :result) fr0)
1055            (:results (r :scs (long-reg)))
1056            (:arg-types long-float long-float)
1057            (:result-types long-float)
1058            (:policy :fast-safe)
1059            (:note "inline float arithmetic")
1060            (:vop-var vop)
1061            (:save-p :compute-only)
1062            (:node-var node)
1063            (:generator ,lcost
1064              ;; Handle a few special cases.
1065              (cond
1066               ;; x, y, and r are the same register.
1067               ((and (location= x r) (location= y r))
1068                (cond ((zerop (tn-offset r))
1069                       (inst ,fop fr0))
1070                      (t
1071                       (inst fxch x)
1072                       (inst ,fopd fr0)
1073                       ;; XX the source register will not be valid.
1074                       (note-next-instruction vop :internal-error)
1075                       (inst fxch r))))
1076
1077               ;; x and r are the same register.
1078               ((location= x r)
1079                (cond ((zerop (tn-offset r))
1080                       ;; ST(0) = ST(0) op ST(y)
1081                       (inst ,fopd y))
1082                      (t
1083                       ;; y to ST0
1084                       (unless (zerop (tn-offset y))
1085                         (copy-fp-reg-to-fr0 y))
1086                       ;; ST(i) = ST(i) op ST0
1087                       (inst ,fop-sti r)))
1088                (maybe-fp-wait node vop))
1089               ;; y and r are the same register.
1090               ((location= y r)
1091                (cond ((zerop (tn-offset r))
1092                       ;; ST(0) = ST(x) op ST(0)
1093                       (inst ,foprd x))
1094                      (t
1095                       ;; x to ST0
1096                       (unless (zerop (tn-offset x))
1097                         (copy-fp-reg-to-fr0 x))
1098                       ;; ST(i) = ST(0) op ST(i)
1099                       (inst ,fopr-sti r)))
1100                (maybe-fp-wait node vop))
1101               ;; the default case
1102               (t
1103                ;; Get the result to ST0.
1104
1105                ;; Special handling is needed if x or y are in ST0, and
1106                ;; simpler code is generated.
1107                (cond
1108                 ;; x is in ST0.
1109                 ((zerop (tn-offset x))
1110                  ;; ST0 = ST0 op y
1111                  (inst ,fopd y))
1112                 ;; y is in ST0
1113                 ((zerop (tn-offset y))
1114                  ;; ST0 = x op ST0
1115                  (inst ,foprd x))
1116                 (t
1117                  ;; x to ST0
1118                  (copy-fp-reg-to-fr0 x)
1119                  ;; ST0 = ST0 op y
1120                  (inst ,fopd y)))
1121
1122                (note-next-instruction vop :internal-error)
1123
1124                ;; Finally save the result.
1125                (cond ((zerop (tn-offset r))
1126                       (maybe-fp-wait node))
1127                      (t
1128                       (inst fst r))))))))))
1129
1130     (frob + fadd-sti fadd-sti
1131           fadd fadd +/single-float 2
1132           faddd faddd +/double-float 2
1133           +/long-float 2)
1134     (frob - fsub-sti fsubr-sti
1135           fsub fsubr -/single-float 2
1136           fsubd fsubrd -/double-float 2
1137           -/long-float 2)
1138     (frob * fmul-sti fmul-sti
1139           fmul fmul */single-float 3
1140           fmuld fmuld */double-float 3
1141           */long-float 3)
1142     (frob / fdiv-sti fdivr-sti
1143           fdiv fdivr //single-float 12
1144           fdivd fdivrd //double-float 12
1145           //long-float 12))
1146 \f
1147 (macrolet ((frob (name inst translate sc type)
1148              `(define-vop (,name)
1149                (:args (x :scs (,sc) :target fr0))
1150                (:results (y :scs (,sc)))
1151                (:translate ,translate)
1152                (:policy :fast-safe)
1153                (:arg-types ,type)
1154                (:result-types ,type)
1155                (:temporary (:sc double-reg :offset fr0-offset
1156                                 :from :argument :to :result) fr0)
1157                (:ignore fr0)
1158                (:note "inline float arithmetic")
1159                (:vop-var vop)
1160                (:save-p :compute-only)
1161                (:generator 1
1162                 (note-this-location vop :internal-error)
1163                 (unless (zerop (tn-offset x))
1164                   (inst fxch x)         ; x to top of stack
1165                   (unless (location= x y)
1166                     (inst fst x)))      ; Maybe save it.
1167                 (inst ,inst)            ; Clobber st0.
1168                 (unless (zerop (tn-offset y))
1169                   (inst fst y))))))
1170
1171   (frob abs/single-float fabs abs single-reg single-float)
1172   (frob abs/double-float fabs abs double-reg double-float)
1173   #!+long-float
1174   (frob abs/long-float fabs abs long-reg long-float)
1175   (frob %negate/single-float fchs %negate single-reg single-float)
1176   (frob %negate/double-float fchs %negate double-reg double-float)
1177   #!+long-float
1178   (frob %negate/long-float fchs %negate long-reg long-float))
1179 \f
1180 ;;;; comparison
1181
1182 (define-vop (=/float)
1183   (:args (x) (y))
1184   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1185   (:conditional)
1186   (:info target not-p)
1187   (:policy :fast-safe)
1188   (:vop-var vop)
1189   (:save-p :compute-only)
1190   (:note "inline float comparison")
1191   (:ignore temp)
1192   (:generator 3
1193      (note-this-location vop :internal-error)
1194      (cond
1195       ;; x is in ST0; y is in any reg.
1196       ((zerop (tn-offset x))
1197        (inst fucom y))
1198       ;; y is in ST0; x is in another reg.
1199       ((zerop (tn-offset y))
1200        (inst fucom x))
1201       ;; x and y are the same register, not ST0
1202       ((location= x y)
1203        (inst fxch x)
1204        (inst fucom fr0-tn)
1205        (inst fxch x))
1206       ;; x and y are different registers, neither ST0.
1207       (t
1208        (inst fxch x)
1209        (inst fucom y)
1210        (inst fxch x)))
1211      (inst fnstsw)                      ; status word to ax
1212      (inst and ah-tn #x45)              ; C3 C2 C0
1213      (inst cmp ah-tn #x40)
1214      (inst jmp (if not-p :ne :e) target)))
1215
1216 (define-vop (=/single-float =/float)
1217   (:translate =)
1218   (:args (x :scs (single-reg))
1219          (y :scs (single-reg)))
1220   (:arg-types single-float single-float))
1221
1222 (define-vop (=/double-float =/float)
1223   (:translate =)
1224   (:args (x :scs (double-reg))
1225          (y :scs (double-reg)))
1226   (:arg-types double-float double-float))
1227
1228 #!+long-float
1229 (define-vop (=/long-float =/float)
1230   (:translate =)
1231   (:args (x :scs (long-reg))
1232          (y :scs (long-reg)))
1233   (:arg-types long-float long-float))
1234
1235 (define-vop (<single-float)
1236   (:translate <)
1237   (:args (x :scs (single-reg single-stack descriptor-reg))
1238          (y :scs (single-reg single-stack descriptor-reg)))
1239   (:arg-types single-float single-float)
1240   (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1241   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1242   (:conditional)
1243   (:info target not-p)
1244   (:policy :fast-safe)
1245   (:note "inline float comparison")
1246   (:ignore temp)
1247   (:generator 3
1248     ;; Handle a few special cases.
1249     (cond
1250      ;; y is ST0.
1251      ((and (sc-is y single-reg) (zerop (tn-offset y)))
1252       (sc-case x
1253         (single-reg
1254          (inst fcom x))
1255         ((single-stack descriptor-reg)
1256          (if (sc-is x single-stack)
1257              (inst fcom (ea-for-sf-stack x))
1258            (inst fcom (ea-for-sf-desc x)))))
1259       (inst fnstsw)                     ; status word to ax
1260       (inst and ah-tn #x45))
1261
1262      ;; general case when y is not in ST0
1263      (t
1264       ;; x to ST0
1265       (sc-case x
1266          (single-reg
1267           (unless (zerop (tn-offset x))
1268                   (copy-fp-reg-to-fr0 x)))
1269          ((single-stack descriptor-reg)
1270           (inst fstp fr0)
1271           (if (sc-is x single-stack)
1272               (inst fld (ea-for-sf-stack x))
1273             (inst fld (ea-for-sf-desc x)))))
1274       (sc-case y
1275         (single-reg
1276          (inst fcom y))
1277         ((single-stack descriptor-reg)
1278          (if (sc-is y single-stack)
1279              (inst fcom (ea-for-sf-stack y))
1280            (inst fcom (ea-for-sf-desc y)))))
1281       (inst fnstsw)                     ; status word to ax
1282       (inst and ah-tn #x45)             ; C3 C2 C0
1283       (inst cmp ah-tn #x01)))
1284     (inst jmp (if not-p :ne :e) target)))
1285
1286 (define-vop (<double-float)
1287   (:translate <)
1288   (:args (x :scs (double-reg double-stack descriptor-reg))
1289          (y :scs (double-reg double-stack descriptor-reg)))
1290   (:arg-types double-float double-float)
1291   (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1292   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1293   (:conditional)
1294   (:info target not-p)
1295   (:policy :fast-safe)
1296   (:note "inline float comparison")
1297   (:ignore temp)
1298   (:generator 3
1299     ;; Handle a few special cases
1300     (cond
1301      ;; y is ST0.
1302      ((and (sc-is y double-reg) (zerop (tn-offset y)))
1303       (sc-case x
1304         (double-reg
1305          (inst fcomd x))
1306         ((double-stack descriptor-reg)
1307          (if (sc-is x double-stack)
1308              (inst fcomd (ea-for-df-stack x))
1309            (inst fcomd (ea-for-df-desc x)))))
1310       (inst fnstsw)                     ; status word to ax
1311       (inst and ah-tn #x45))
1312
1313      ;; General case when y is not in ST0.
1314      (t
1315       ;; x to ST0
1316       (sc-case x
1317          (double-reg
1318           (unless (zerop (tn-offset x))
1319                   (copy-fp-reg-to-fr0 x)))
1320          ((double-stack descriptor-reg)
1321           (inst fstp fr0)
1322           (if (sc-is x double-stack)
1323               (inst fldd (ea-for-df-stack x))
1324             (inst fldd (ea-for-df-desc x)))))
1325       (sc-case y
1326         (double-reg
1327          (inst fcomd y))
1328         ((double-stack descriptor-reg)
1329          (if (sc-is y double-stack)
1330              (inst fcomd (ea-for-df-stack y))
1331            (inst fcomd (ea-for-df-desc y)))))
1332       (inst fnstsw)                     ; status word to ax
1333       (inst and ah-tn #x45)             ; C3 C2 C0
1334       (inst cmp ah-tn #x01)))
1335     (inst jmp (if not-p :ne :e) target)))
1336
1337 #!+long-float
1338 (define-vop (<long-float)
1339   (:translate <)
1340   (:args (x :scs (long-reg))
1341          (y :scs (long-reg)))
1342   (:arg-types long-float long-float)
1343   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1344   (:conditional)
1345   (:info target not-p)
1346   (:policy :fast-safe)
1347   (:note "inline float comparison")
1348   (:ignore temp)
1349   (:generator 3
1350     (cond
1351       ;; x is in ST0; y is in any reg.
1352       ((zerop (tn-offset x))
1353        (inst fcomd y)
1354        (inst fnstsw)                    ; status word to ax
1355        (inst and ah-tn #x45)            ; C3 C2 C0
1356        (inst cmp ah-tn #x01))
1357       ;; y is in ST0; x is in another reg.
1358       ((zerop (tn-offset y))
1359        (inst fcomd x)
1360        (inst fnstsw)                    ; status word to ax
1361        (inst and ah-tn #x45))
1362       ;; x and y are the same register, not ST0
1363       ;; x and y are different registers, neither ST0.
1364       (t
1365        (inst fxch y)
1366        (inst fcomd x)
1367        (inst fxch y)
1368        (inst fnstsw)                    ; status word to ax
1369        (inst and ah-tn #x45)))          ; C3 C2 C0
1370     (inst jmp (if not-p :ne :e) target)))
1371
1372 (define-vop (>single-float)
1373   (:translate >)
1374   (:args (x :scs (single-reg single-stack descriptor-reg))
1375          (y :scs (single-reg single-stack descriptor-reg)))
1376   (:arg-types single-float single-float)
1377   (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1378   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1379   (:conditional)
1380   (:info target not-p)
1381   (:policy :fast-safe)
1382   (:note "inline float comparison")
1383   (:ignore temp)
1384   (:generator 3
1385     ;; Handle a few special cases.
1386     (cond
1387      ;; y is ST0.
1388      ((and (sc-is y single-reg) (zerop (tn-offset y)))
1389       (sc-case x
1390         (single-reg
1391          (inst fcom x))
1392         ((single-stack descriptor-reg)
1393          (if (sc-is x single-stack)
1394              (inst fcom (ea-for-sf-stack x))
1395            (inst fcom (ea-for-sf-desc x)))))
1396       (inst fnstsw)                     ; status word to ax
1397       (inst and ah-tn #x45)
1398       (inst cmp ah-tn #x01))
1399
1400      ;; general case when y is not in ST0
1401      (t
1402       ;; x to ST0
1403       (sc-case x
1404          (single-reg
1405           (unless (zerop (tn-offset x))
1406                   (copy-fp-reg-to-fr0 x)))
1407          ((single-stack descriptor-reg)
1408           (inst fstp fr0)
1409           (if (sc-is x single-stack)
1410               (inst fld (ea-for-sf-stack x))
1411             (inst fld (ea-for-sf-desc x)))))
1412       (sc-case y
1413         (single-reg
1414          (inst fcom y))
1415         ((single-stack descriptor-reg)
1416          (if (sc-is y single-stack)
1417              (inst fcom (ea-for-sf-stack y))
1418            (inst fcom (ea-for-sf-desc y)))))
1419       (inst fnstsw)                     ; status word to ax
1420       (inst and ah-tn #x45)))
1421     (inst jmp (if not-p :ne :e) target)))
1422
1423 (define-vop (>double-float)
1424   (:translate >)
1425   (:args (x :scs (double-reg double-stack descriptor-reg))
1426          (y :scs (double-reg double-stack descriptor-reg)))
1427   (:arg-types double-float double-float)
1428   (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1429   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1430   (:conditional)
1431   (:info target not-p)
1432   (:policy :fast-safe)
1433   (:note "inline float comparison")
1434   (:ignore temp)
1435   (:generator 3
1436     ;; Handle a few special cases.
1437     (cond
1438      ;; y is ST0.
1439      ((and (sc-is y double-reg) (zerop (tn-offset y)))
1440       (sc-case x
1441         (double-reg
1442          (inst fcomd x))
1443         ((double-stack descriptor-reg)
1444          (if (sc-is x double-stack)
1445              (inst fcomd (ea-for-df-stack x))
1446            (inst fcomd (ea-for-df-desc x)))))
1447       (inst fnstsw)                     ; status word to ax
1448       (inst and ah-tn #x45)
1449       (inst cmp ah-tn #x01))
1450
1451      ;; general case when y is not in ST0
1452      (t
1453       ;; x to ST0
1454       (sc-case x
1455          (double-reg
1456           (unless (zerop (tn-offset x))
1457                   (copy-fp-reg-to-fr0 x)))
1458          ((double-stack descriptor-reg)
1459           (inst fstp fr0)
1460           (if (sc-is x double-stack)
1461               (inst fldd (ea-for-df-stack x))
1462             (inst fldd (ea-for-df-desc x)))))
1463       (sc-case y
1464         (double-reg
1465          (inst fcomd y))
1466         ((double-stack descriptor-reg)
1467          (if (sc-is y double-stack)
1468              (inst fcomd (ea-for-df-stack y))
1469            (inst fcomd (ea-for-df-desc y)))))
1470       (inst fnstsw)                     ; status word to ax
1471       (inst and ah-tn #x45)))
1472     (inst jmp (if not-p :ne :e) target)))
1473
1474 #!+long-float
1475 (define-vop (>long-float)
1476   (:translate >)
1477   (:args (x :scs (long-reg))
1478          (y :scs (long-reg)))
1479   (:arg-types long-float long-float)
1480   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1481   (:conditional)
1482   (:info target not-p)
1483   (:policy :fast-safe)
1484   (:note "inline float comparison")
1485   (:ignore temp)
1486   (:generator 3
1487     (cond
1488       ;; y is in ST0; x is in any reg.
1489       ((zerop (tn-offset y))
1490        (inst fcomd x)
1491        (inst fnstsw)                    ; status word to ax
1492        (inst and ah-tn #x45)
1493        (inst cmp ah-tn #x01))
1494       ;; x is in ST0; y is in another reg.
1495       ((zerop (tn-offset x))
1496        (inst fcomd y)
1497        (inst fnstsw)                    ; status word to ax
1498        (inst and ah-tn #x45))
1499       ;; y and x are the same register, not ST0
1500       ;; y and x are different registers, neither ST0.
1501       (t
1502        (inst fxch x)
1503        (inst fcomd y)
1504        (inst fxch x)
1505        (inst fnstsw)                    ; status word to ax
1506        (inst and ah-tn #x45)))
1507     (inst jmp (if not-p :ne :e) target)))
1508
1509 ;;; Comparisons with 0 can use the FTST instruction.
1510
1511 (define-vop (float-test)
1512   (:args (x))
1513   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1514   (:conditional)
1515   (:info target not-p y)
1516   (:variant-vars code)
1517   (:policy :fast-safe)
1518   (:vop-var vop)
1519   (:save-p :compute-only)
1520   (:note "inline float comparison")
1521   (:ignore temp y)
1522   (:generator 2
1523      (note-this-location vop :internal-error)
1524      (cond
1525       ;; x is in ST0
1526       ((zerop (tn-offset x))
1527        (inst ftst))
1528       ;; x not ST0
1529       (t
1530        (inst fxch x)
1531        (inst ftst)
1532        (inst fxch x)))
1533      (inst fnstsw)                      ; status word to ax
1534      (inst and ah-tn #x45)              ; C3 C2 C0
1535      (unless (zerop code)
1536         (inst cmp ah-tn code))
1537      (inst jmp (if not-p :ne :e) target)))
1538
1539 (define-vop (=0/single-float float-test)
1540   (:translate =)
1541   (:args (x :scs (single-reg)))
1542   (:arg-types single-float (:constant (single-float 0f0 0f0)))
1543   (:variant #x40))
1544 (define-vop (=0/double-float float-test)
1545   (:translate =)
1546   (:args (x :scs (double-reg)))
1547   (:arg-types double-float (:constant (double-float 0d0 0d0)))
1548   (:variant #x40))
1549 #!+long-float
1550 (define-vop (=0/long-float float-test)
1551   (:translate =)
1552   (:args (x :scs (long-reg)))
1553   (:arg-types long-float (:constant (long-float 0l0 0l0)))
1554   (:variant #x40))
1555
1556 (define-vop (<0/single-float float-test)
1557   (:translate <)
1558   (:args (x :scs (single-reg)))
1559   (:arg-types single-float (:constant (single-float 0f0 0f0)))
1560   (:variant #x01))
1561 (define-vop (<0/double-float float-test)
1562   (:translate <)
1563   (:args (x :scs (double-reg)))
1564   (:arg-types double-float (:constant (double-float 0d0 0d0)))
1565   (:variant #x01))
1566 #!+long-float
1567 (define-vop (<0/long-float float-test)
1568   (:translate <)
1569   (:args (x :scs (long-reg)))
1570   (:arg-types long-float (:constant (long-float 0l0 0l0)))
1571   (:variant #x01))
1572
1573 (define-vop (>0/single-float float-test)
1574   (:translate >)
1575   (:args (x :scs (single-reg)))
1576   (:arg-types single-float (:constant (single-float 0f0 0f0)))
1577   (:variant #x00))
1578 (define-vop (>0/double-float float-test)
1579   (:translate >)
1580   (:args (x :scs (double-reg)))
1581   (:arg-types double-float (:constant (double-float 0d0 0d0)))
1582   (:variant #x00))
1583 #!+long-float
1584 (define-vop (>0/long-float float-test)
1585   (:translate >)
1586   (:args (x :scs (long-reg)))
1587   (:arg-types long-float (:constant (long-float 0l0 0l0)))
1588   (:variant #x00))
1589
1590 #!+long-float
1591 (deftransform eql ((x y) (long-float long-float))
1592   `(and (= (long-float-low-bits x) (long-float-low-bits y))
1593         (= (long-float-high-bits x) (long-float-high-bits y))
1594         (= (long-float-exp-bits x) (long-float-exp-bits y))))
1595 \f
1596 ;;;; conversion
1597
1598 (macrolet ((frob (name translate to-sc to-type)
1599              `(define-vop (,name)
1600                 (:args (x :scs (signed-stack signed-reg) :target temp))
1601                 (:temporary (:sc signed-stack) temp)
1602                 (:results (y :scs (,to-sc)))
1603                 (:arg-types signed-num)
1604                 (:result-types ,to-type)
1605                 (:policy :fast-safe)
1606                 (:note "inline float coercion")
1607                 (:translate ,translate)
1608                 (:vop-var vop)
1609                 (:save-p :compute-only)
1610                 (:generator 5
1611                   (sc-case x
1612                     (signed-reg
1613                      (inst mov temp x)
1614                      (with-empty-tn@fp-top(y)
1615                        (note-this-location vop :internal-error)
1616                        (inst fild temp)))
1617                     (signed-stack
1618                      (with-empty-tn@fp-top(y)
1619                        (note-this-location vop :internal-error)
1620                        (inst fild x))))))))
1621   (frob %single-float/signed %single-float single-reg single-float)
1622   (frob %double-float/signed %double-float double-reg double-float)
1623   #!+long-float
1624   (frob %long-float/signed %long-float long-reg long-float))
1625
1626 (macrolet ((frob (name translate to-sc to-type)
1627              `(define-vop (,name)
1628                 (:args (x :scs (unsigned-reg)))
1629                 (:results (y :scs (,to-sc)))
1630                 (:arg-types unsigned-num)
1631                 (:result-types ,to-type)
1632                 (:policy :fast-safe)
1633                 (:note "inline float coercion")
1634                 (:translate ,translate)
1635                 (:vop-var vop)
1636                 (:save-p :compute-only)
1637                 (:generator 6
1638                  (inst push 0)
1639                  (inst push x)
1640                  (with-empty-tn@fp-top(y)
1641                    (note-this-location vop :internal-error)
1642                    (inst fildl (make-ea :dword :base esp-tn)))
1643                  (inst add esp-tn 8)))))
1644   (frob %single-float/unsigned %single-float single-reg single-float)
1645   (frob %double-float/unsigned %double-float double-reg double-float)
1646   #!+long-float
1647   (frob %long-float/unsigned %long-float long-reg long-float))
1648
1649 ;;; These should be no-ops but the compiler might want to move some
1650 ;;; things around.
1651 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1652              `(define-vop (,name)
1653                (:args (x :scs (,from-sc) :target y))
1654                (:results (y :scs (,to-sc)))
1655                (:arg-types ,from-type)
1656                (:result-types ,to-type)
1657                (:policy :fast-safe)
1658                (:note "inline float coercion")
1659                (:translate ,translate)
1660                (:vop-var vop)
1661                (:save-p :compute-only)
1662                (:generator 2
1663                 (note-this-location vop :internal-error)
1664                 (unless (location= x y)
1665                   (cond
1666                    ((zerop (tn-offset x))
1667                     ;; x is in ST0, y is in another reg. not ST0
1668                     (inst fst  y))
1669                    ((zerop (tn-offset y))
1670                     ;; y is in ST0, x is in another reg. not ST0
1671                     (copy-fp-reg-to-fr0 x))
1672                    (t
1673                     ;; Neither x or y are in ST0, and they are not in
1674                     ;; the same reg.
1675                     (inst fxch x)
1676                     (inst fst  y)
1677                     (inst fxch x))))))))
1678
1679   (frob %single-float/double-float %single-float double-reg
1680         double-float single-reg single-float)
1681   #!+long-float
1682   (frob %single-float/long-float %single-float long-reg
1683         long-float single-reg single-float)
1684   (frob %double-float/single-float %double-float single-reg single-float
1685         double-reg double-float)
1686   #!+long-float
1687   (frob %double-float/long-float %double-float long-reg long-float
1688         double-reg double-float)
1689   #!+long-float
1690   (frob %long-float/single-float %long-float single-reg single-float
1691         long-reg long-float)
1692   #!+long-float
1693   (frob %long-float/double-float %long-float double-reg double-float
1694         long-reg long-float))
1695
1696 (macrolet ((frob (trans from-sc from-type round-p)
1697              `(define-vop (,(symbolicate trans "/" from-type))
1698                (:args (x :scs (,from-sc)))
1699                (:temporary (:sc signed-stack) stack-temp)
1700                ,@(unless round-p
1701                        '((:temporary (:sc unsigned-stack) scw)
1702                          (:temporary (:sc any-reg) rcw)))
1703                (:results (y :scs (signed-reg)))
1704                (:arg-types ,from-type)
1705                (:result-types signed-num)
1706                (:translate ,trans)
1707                (:policy :fast-safe)
1708                (:note "inline float truncate")
1709                (:vop-var vop)
1710                (:save-p :compute-only)
1711                (:generator 5
1712                 ,@(unless round-p
1713                    '((note-this-location vop :internal-error)
1714                      ;; Catch any pending FPE exceptions.
1715                      (inst wait)))
1716                 (,(if round-p 'progn 'pseudo-atomic)
1717                  ;; Normal mode (for now) is "round to best".
1718                  (with-tn@fp-top (x)
1719                    ,@(unless round-p
1720                      '((inst fnstcw scw) ; save current control word
1721                        (move rcw scw)   ; into 16-bit register
1722                        (inst or rcw (ash #b11 10)) ; CHOP
1723                        (move stack-temp rcw)
1724                        (inst fldcw stack-temp)))
1725                    (sc-case y
1726                      (signed-stack
1727                       (inst fist y))
1728                      (signed-reg
1729                       (inst fist stack-temp)
1730                       (inst mov y stack-temp)))
1731                    ,@(unless round-p
1732                       '((inst fldcw scw)))))))))
1733   (frob %unary-truncate single-reg single-float nil)
1734   (frob %unary-truncate double-reg double-float nil)
1735   #!+long-float
1736   (frob %unary-truncate long-reg long-float nil)
1737   (frob %unary-round single-reg single-float t)
1738   (frob %unary-round double-reg double-float t)
1739   #!+long-float
1740   (frob %unary-round long-reg long-float t))
1741
1742 (macrolet ((frob (trans from-sc from-type round-p)
1743              `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1744                (:args (x :scs (,from-sc) :target fr0))
1745                (:temporary (:sc double-reg :offset fr0-offset
1746                             :from :argument :to :result) fr0)
1747                ,@(unless round-p
1748                   '((:temporary (:sc unsigned-stack) stack-temp)
1749                     (:temporary (:sc unsigned-stack) scw)
1750                     (:temporary (:sc any-reg) rcw)))
1751                (:results (y :scs (unsigned-reg)))
1752                (:arg-types ,from-type)
1753                (:result-types unsigned-num)
1754                (:translate ,trans)
1755                (:policy :fast-safe)
1756                (:note "inline float truncate")
1757                (:vop-var vop)
1758                (:save-p :compute-only)
1759                (:generator 5
1760                 ,@(unless round-p
1761                    '((note-this-location vop :internal-error)
1762                      ;; Catch any pending FPE exceptions.
1763                      (inst wait)))
1764                 ;; Normal mode (for now) is "round to best".
1765                 (unless (zerop (tn-offset x))
1766                   (copy-fp-reg-to-fr0 x))
1767                 ,@(unless round-p
1768                    '((inst fnstcw scw)  ; save current control word
1769                      (move rcw scw)     ; into 16-bit register
1770                      (inst or rcw (ash #b11 10)) ; CHOP
1771                      (move stack-temp rcw)
1772                      (inst fldcw stack-temp)))
1773                 (inst sub esp-tn 8)
1774                 (inst fistpl (make-ea :dword :base esp-tn))
1775                 (inst pop y)
1776                 (inst fld fr0) ; copy fr0 to at least restore stack.
1777                 (inst add esp-tn 4)
1778                 ,@(unless round-p
1779                    '((inst fldcw scw)))))))
1780   (frob %unary-truncate single-reg single-float nil)
1781   (frob %unary-truncate double-reg double-float nil)
1782   #!+long-float
1783   (frob %unary-truncate long-reg long-float nil)
1784   (frob %unary-round single-reg single-float t)
1785   (frob %unary-round double-reg double-float t)
1786   #!+long-float
1787   (frob %unary-round long-reg long-float t))
1788
1789 (define-vop (make-single-float)
1790   (:args (bits :scs (signed-reg) :target res
1791                :load-if (not (or (and (sc-is bits signed-stack)
1792                                       (sc-is res single-reg))
1793                                  (and (sc-is bits signed-stack)
1794                                       (sc-is res single-stack)
1795                                       (location= bits res))))))
1796   (:results (res :scs (single-reg single-stack)))
1797   (:temporary (:sc signed-stack) stack-temp)
1798   (:arg-types signed-num)
1799   (:result-types single-float)
1800   (:translate make-single-float)
1801   (:policy :fast-safe)
1802   (:vop-var vop)
1803   (:generator 4
1804     (sc-case res
1805        (single-stack
1806         (sc-case bits
1807           (signed-reg
1808            (inst mov res bits))
1809           (signed-stack
1810            (aver (location= bits res)))))
1811        (single-reg
1812         (sc-case bits
1813           (signed-reg
1814            ;; source must be in memory
1815            (inst mov stack-temp bits)
1816            (with-empty-tn@fp-top(res)
1817               (inst fld stack-temp)))
1818           (signed-stack
1819            (with-empty-tn@fp-top(res)
1820               (inst fld bits))))))))
1821
1822 (define-vop (make-double-float)
1823   (:args (hi-bits :scs (signed-reg))
1824          (lo-bits :scs (unsigned-reg)))
1825   (:results (res :scs (double-reg)))
1826   (:temporary (:sc double-stack) temp)
1827   (:arg-types signed-num unsigned-num)
1828   (:result-types double-float)
1829   (:translate make-double-float)
1830   (:policy :fast-safe)
1831   (:vop-var vop)
1832   (:generator 2
1833     (let ((offset (1+ (tn-offset temp))))
1834       (storew hi-bits ebp-tn (- offset))
1835       (storew lo-bits ebp-tn (- (1+ offset)))
1836       (with-empty-tn@fp-top(res)
1837         (inst fldd (make-ea :dword :base ebp-tn
1838                             :disp (- (* (1+ offset) n-word-bytes))))))))
1839
1840 #!+long-float
1841 (define-vop (make-long-float)
1842   (:args (exp-bits :scs (signed-reg))
1843          (hi-bits :scs (unsigned-reg))
1844          (lo-bits :scs (unsigned-reg)))
1845   (:results (res :scs (long-reg)))
1846   (:temporary (:sc long-stack) temp)
1847   (:arg-types signed-num unsigned-num unsigned-num)
1848   (:result-types long-float)
1849   (:translate make-long-float)
1850   (:policy :fast-safe)
1851   (:vop-var vop)
1852   (:generator 3
1853     (let ((offset (1+ (tn-offset temp))))
1854       (storew exp-bits ebp-tn (- offset))
1855       (storew hi-bits ebp-tn (- (1+ offset)))
1856       (storew lo-bits ebp-tn (- (+ offset 2)))
1857       (with-empty-tn@fp-top(res)
1858         (inst fldl (make-ea :dword :base ebp-tn
1859                             :disp (- (* (+ offset 2) n-word-bytes))))))))
1860
1861 (define-vop (single-float-bits)
1862   (:args (float :scs (single-reg descriptor-reg)
1863                 :load-if (not (sc-is float single-stack))))
1864   (:results (bits :scs (signed-reg)))
1865   (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1866   (:arg-types single-float)
1867   (:result-types signed-num)
1868   (:translate single-float-bits)
1869   (:policy :fast-safe)
1870   (:vop-var vop)
1871   (:generator 4
1872     (sc-case bits
1873       (signed-reg
1874        (sc-case float
1875          (single-reg
1876           (with-tn@fp-top(float)
1877             (inst fst stack-temp)
1878             (inst mov bits stack-temp)))
1879          (single-stack
1880           (inst mov bits float))
1881          (descriptor-reg
1882           (loadw
1883            bits float single-float-value-slot
1884            other-pointer-lowtag))))
1885       (signed-stack
1886        (sc-case float
1887          (single-reg
1888           (with-tn@fp-top(float)
1889             (inst fst bits))))))))
1890
1891 (define-vop (double-float-high-bits)
1892   (:args (float :scs (double-reg descriptor-reg)
1893                 :load-if (not (sc-is float double-stack))))
1894   (:results (hi-bits :scs (signed-reg)))
1895   (:temporary (:sc double-stack) temp)
1896   (:arg-types double-float)
1897   (:result-types signed-num)
1898   (:translate double-float-high-bits)
1899   (:policy :fast-safe)
1900   (:vop-var vop)
1901   (:generator 5
1902      (sc-case float
1903        (double-reg
1904         (with-tn@fp-top(float)
1905           (let ((where (make-ea :dword :base ebp-tn
1906                                 :disp (- (* (+ 2 (tn-offset temp))
1907                                             n-word-bytes)))))
1908             (inst fstd where)))
1909         (loadw hi-bits ebp-tn (- (1+ (tn-offset temp)))))
1910        (double-stack
1911         (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
1912        (descriptor-reg
1913         (loadw hi-bits float (1+ double-float-value-slot)
1914                other-pointer-lowtag)))))
1915
1916 (define-vop (double-float-low-bits)
1917   (:args (float :scs (double-reg descriptor-reg)
1918                 :load-if (not (sc-is float double-stack))))
1919   (:results (lo-bits :scs (unsigned-reg)))
1920   (:temporary (:sc double-stack) temp)
1921   (:arg-types double-float)
1922   (:result-types unsigned-num)
1923   (:translate double-float-low-bits)
1924   (:policy :fast-safe)
1925   (:vop-var vop)
1926   (:generator 5
1927      (sc-case float
1928        (double-reg
1929         (with-tn@fp-top(float)
1930           (let ((where (make-ea :dword :base ebp-tn
1931                                 :disp (- (* (+ 2 (tn-offset temp))
1932                                             n-word-bytes)))))
1933             (inst fstd where)))
1934         (loadw lo-bits ebp-tn (- (+ 2 (tn-offset temp)))))
1935        (double-stack
1936         (loadw lo-bits ebp-tn (- (+ 2 (tn-offset float)))))
1937        (descriptor-reg
1938         (loadw lo-bits float double-float-value-slot
1939                other-pointer-lowtag)))))
1940
1941 #!+long-float
1942 (define-vop (long-float-exp-bits)
1943   (:args (float :scs (long-reg descriptor-reg)
1944                 :load-if (not (sc-is float long-stack))))
1945   (:results (exp-bits :scs (signed-reg)))
1946   (:temporary (:sc long-stack) temp)
1947   (:arg-types long-float)
1948   (:result-types signed-num)
1949   (:translate long-float-exp-bits)
1950   (:policy :fast-safe)
1951   (:vop-var vop)
1952   (:generator 5
1953      (sc-case float
1954        (long-reg
1955         (with-tn@fp-top(float)
1956           (let ((where (make-ea :dword :base ebp-tn
1957                                 :disp (- (* (+ 3 (tn-offset temp))
1958                                             n-word-bytes)))))
1959             (store-long-float where)))
1960         (inst movsx exp-bits
1961               (make-ea :word :base ebp-tn
1962                        :disp (* (- (1+ (tn-offset temp))) n-word-bytes))))
1963        (long-stack
1964         (inst movsx exp-bits
1965               (make-ea :word :base ebp-tn
1966                        :disp (* (- (1+ (tn-offset float))) n-word-bytes))))
1967        (descriptor-reg
1968         (inst movsx exp-bits
1969               (make-ea :word :base float
1970                        :disp (- (* (+ 2 long-float-value-slot)
1971                                    n-word-bytes)
1972                                 other-pointer-lowtag)))))))
1973
1974 #!+long-float
1975 (define-vop (long-float-high-bits)
1976   (:args (float :scs (long-reg descriptor-reg)
1977                 :load-if (not (sc-is float long-stack))))
1978   (:results (hi-bits :scs (unsigned-reg)))
1979   (:temporary (:sc long-stack) temp)
1980   (:arg-types long-float)
1981   (:result-types unsigned-num)
1982   (:translate long-float-high-bits)
1983   (:policy :fast-safe)
1984   (:vop-var vop)
1985   (:generator 5
1986      (sc-case float
1987        (long-reg
1988         (with-tn@fp-top(float)
1989           (let ((where (make-ea :dword :base ebp-tn
1990                                 :disp (- (* (+ 3 (tn-offset temp))
1991                                             n-word-bytes)))))
1992             (store-long-float where)))
1993         (loadw hi-bits ebp-tn (- (+ (tn-offset temp) 2))))
1994        (long-stack
1995         (loadw hi-bits ebp-tn (- (+ (tn-offset float) 2))))
1996        (descriptor-reg
1997         (loadw hi-bits float (1+ long-float-value-slot)
1998                other-pointer-lowtag)))))
1999
2000 #!+long-float
2001 (define-vop (long-float-low-bits)
2002   (:args (float :scs (long-reg descriptor-reg)
2003                 :load-if (not (sc-is float long-stack))))
2004   (:results (lo-bits :scs (unsigned-reg)))
2005   (:temporary (:sc long-stack) temp)
2006   (:arg-types long-float)
2007   (:result-types unsigned-num)
2008   (:translate long-float-low-bits)
2009   (:policy :fast-safe)
2010   (:vop-var vop)
2011   (:generator 5
2012      (sc-case float
2013        (long-reg
2014         (with-tn@fp-top(float)
2015           (let ((where (make-ea :dword :base ebp-tn
2016                                 :disp (- (* (+ 3 (tn-offset temp))
2017                                             n-word-bytes)))))
2018             (store-long-float where)))
2019         (loadw lo-bits ebp-tn (- (+ (tn-offset temp) 3))))
2020        (long-stack
2021         (loadw lo-bits ebp-tn (- (+ (tn-offset float) 3))))
2022        (descriptor-reg
2023         (loadw lo-bits float long-float-value-slot
2024                other-pointer-lowtag)))))
2025 \f
2026 ;;;; float mode hackery
2027
2028 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2029 (defknown floating-point-modes () float-modes (flushable))
2030 (defknown ((setf floating-point-modes)) (float-modes)
2031   float-modes)
2032
2033 (def!constant npx-env-size (* 7 n-word-bytes))
2034 (def!constant npx-cw-offset 0)
2035 (def!constant npx-sw-offset 4)
2036
2037 (define-vop (floating-point-modes)
2038   (:results (res :scs (unsigned-reg)))
2039   (:result-types unsigned-num)
2040   (:translate floating-point-modes)
2041   (:policy :fast-safe)
2042   (:temporary (:sc unsigned-reg :offset eax-offset :target res
2043                    :to :result) eax)
2044   (:generator 8
2045    (inst sub esp-tn npx-env-size)       ; Make space on stack.
2046    (inst wait)                          ; Catch any pending FPE exceptions
2047    (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2048    (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2049    ;; Move current status to high word.
2050    (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2051    ;; Move exception mask to low word.
2052    (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2053    (inst add esp-tn npx-env-size)       ; Pop stack.
2054    (inst xor eax #x3f)            ; Flip exception mask to trap enable bits.
2055    (move res eax)))
2056
2057 (define-vop (set-floating-point-modes)
2058   (:args (new :scs (unsigned-reg) :to :result :target res))
2059   (:results (res :scs (unsigned-reg)))
2060   (:arg-types unsigned-num)
2061   (:result-types unsigned-num)
2062   (:translate (setf floating-point-modes))
2063   (:policy :fast-safe)
2064   (:temporary (:sc unsigned-reg :offset eax-offset
2065                    :from :eval :to :result) eax)
2066   (:generator 3
2067    (inst sub esp-tn npx-env-size)       ; Make space on stack.
2068    (inst wait)                          ; Catch any pending FPE exceptions.
2069    (inst fstenv (make-ea :dword :base esp-tn))
2070    (inst mov eax new)
2071    (inst xor eax #x3f)            ; Turn trap enable bits into exception mask.
2072    (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2073    (inst shr eax 16)                    ; position status word
2074    (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2075    (inst fldenv (make-ea :dword :base esp-tn))
2076    (inst add esp-tn npx-env-size)       ; Pop stack.
2077    (move res new)))
2078 \f
2079 #!-long-float
2080 (progn
2081
2082 ;;; Let's use some of the 80387 special functions.
2083 ;;;
2084 ;;; These defs will not take effect unless code/irrat.lisp is modified
2085 ;;; to remove the inlined alien routine def.
2086
2087 (macrolet ((frob (func trans op)
2088              `(define-vop (,func)
2089                (:args (x :scs (double-reg) :target fr0))
2090                (:temporary (:sc double-reg :offset fr0-offset
2091                                 :from :argument :to :result) fr0)
2092                (:ignore fr0)
2093                (:results (y :scs (double-reg)))
2094                (:arg-types double-float)
2095                (:result-types double-float)
2096                (:translate ,trans)
2097                (:policy :fast-safe)
2098                (:note "inline NPX function")
2099                (:vop-var vop)
2100                (:save-p :compute-only)
2101                (:node-var node)
2102                (:generator 5
2103                 (note-this-location vop :internal-error)
2104                 (unless (zerop (tn-offset x))
2105                   (inst fxch x)         ; x to top of stack
2106                   (unless (location= x y)
2107                     (inst fst x)))      ; maybe save it
2108                 (inst ,op)              ; clobber st0
2109                 (cond ((zerop (tn-offset y))
2110                        (maybe-fp-wait node))
2111                       (t
2112                        (inst fst y)))))))
2113
2114   ;; Quick versions of fsin and fcos that require the argument to be
2115   ;; within range 2^63.
2116   (frob fsin-quick %sin-quick fsin)
2117   (frob fcos-quick %cos-quick fcos)
2118   (frob fsqrt %sqrt fsqrt))
2119
2120 ;;; Quick version of ftan that requires the argument to be within
2121 ;;; range 2^63.
2122 (define-vop (ftan-quick)
2123   (:translate %tan-quick)
2124   (:args (x :scs (double-reg) :target fr0))
2125   (:temporary (:sc double-reg :offset fr0-offset
2126                    :from :argument :to :result) fr0)
2127   (:temporary (:sc double-reg :offset fr1-offset
2128                    :from :argument :to :result) fr1)
2129   (:results (y :scs (double-reg)))
2130   (:arg-types double-float)
2131   (:result-types double-float)
2132   (:policy :fast-safe)
2133   (:note "inline tan function")
2134   (:vop-var vop)
2135   (:save-p :compute-only)
2136   (:generator 5
2137     (note-this-location vop :internal-error)
2138     (case (tn-offset x)
2139        (0
2140         (inst fstp fr1))
2141        (1
2142         (inst fstp fr0))
2143        (t
2144         (inst fstp fr0)
2145         (inst fstp fr0)
2146         (inst fldd (make-random-tn :kind :normal
2147                                    :sc (sc-or-lose 'double-reg)
2148                                    :offset (- (tn-offset x) 2)))))
2149     (inst fptan)
2150     ;; Result is in fr1
2151     (case (tn-offset y)
2152        (0
2153         (inst fxch fr1))
2154        (1)
2155        (t
2156         (inst fxch fr1)
2157         (inst fstd y)))))
2158
2159 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2160 ;;; result if the argument is out of range 2^63 and would thus be
2161 ;;; hopelessly inaccurate.
2162 (macrolet ((frob (func trans op)
2163              `(define-vop (,func)
2164                 (:translate ,trans)
2165                 (:args (x :scs (double-reg) :target fr0))
2166                 (:temporary (:sc double-reg :offset fr0-offset
2167                                  :from :argument :to :result) fr0)
2168                 (:temporary (:sc unsigned-reg :offset eax-offset
2169                              :from :argument :to :result) eax)
2170                 (:results (y :scs (double-reg)))
2171                 (:arg-types double-float)
2172                 (:result-types double-float)
2173                 (:policy :fast-safe)
2174                 (:note "inline sin/cos function")
2175                 (:vop-var vop)
2176                 (:save-p :compute-only)
2177                 (:ignore eax)
2178                 (:generator 5
2179                   (note-this-location vop :internal-error)
2180                   (unless (zerop (tn-offset x))
2181                           (inst fxch x)          ; x to top of stack
2182                           (unless (location= x y)
2183                                   (inst fst x))) ; maybe save it
2184                   (inst ,op)
2185                   (inst fnstsw)                  ; status word to ax
2186                   (inst and ah-tn #x04)          ; C2
2187                   (inst jmp :z DONE)
2188                   ;; Else x was out of range so reduce it; ST0 is unchanged.
2189                   (inst fstp fr0)               ; Load 0.0
2190                   (inst fldz)
2191                   DONE
2192                   (unless (zerop (tn-offset y))
2193                           (inst fstd y))))))
2194           (frob fsin  %sin fsin)
2195           (frob fcos  %cos fcos))
2196
2197 (define-vop (ftan)
2198   (:translate %tan)
2199   (:args (x :scs (double-reg) :target fr0))
2200   (:temporary (:sc double-reg :offset fr0-offset
2201                    :from :argument :to :result) fr0)
2202   (:temporary (:sc double-reg :offset fr1-offset
2203                    :from :argument :to :result) fr1)
2204   (:temporary (:sc unsigned-reg :offset eax-offset
2205                    :from :argument :to :result) eax)
2206   (:results (y :scs (double-reg)))
2207   (:arg-types double-float)
2208   (:result-types double-float)
2209   (:ignore eax)
2210   (:policy :fast-safe)
2211   (:note "inline tan function")
2212   (:vop-var vop)
2213   (:save-p :compute-only)
2214   (:ignore eax)
2215   (:generator 5
2216     (note-this-location vop :internal-error)
2217     (case (tn-offset x)
2218        (0
2219         (inst fstp fr1))
2220        (1
2221         (inst fstp fr0))
2222        (t
2223         (inst fstp fr0)
2224         (inst fstp fr0)
2225         (inst fldd (make-random-tn :kind :normal
2226                                    :sc (sc-or-lose 'double-reg)
2227                                    :offset (- (tn-offset x) 2)))))
2228     (inst fptan)
2229     (inst fnstsw)                        ; status word to ax
2230     (inst and ah-tn #x04)                ; C2
2231     (inst jmp :z DONE)
2232     ;; Else x was out of range so load 0.0
2233     (inst fxch fr1)
2234     DONE
2235     ;; Result is in fr1
2236     (case (tn-offset y)
2237        (0
2238         (inst fxch fr1))
2239        (1)
2240        (t
2241         (inst fxch fr1)
2242         (inst fstd y)))))
2243
2244 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2245 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2246 (define-vop (fexp)
2247   (:translate %exp)
2248   (:args (x :scs (double-reg) :target fr0))
2249   (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2250   (:temporary (:sc double-reg :offset fr0-offset
2251                    :from :argument :to :result) fr0)
2252   (:temporary (:sc double-reg :offset fr1-offset
2253                    :from :argument :to :result) fr1)
2254   (:temporary (:sc double-reg :offset fr2-offset
2255                    :from :argument :to :result) fr2)
2256   (:results (y :scs (double-reg)))
2257   (:arg-types double-float)
2258   (:result-types double-float)
2259   (:policy :fast-safe)
2260   (:note "inline exp function")
2261   (:vop-var vop)
2262   (:save-p :compute-only)
2263   (:ignore temp)
2264   (:generator 5
2265      (note-this-location vop :internal-error)
2266      (unless (zerop (tn-offset x))
2267        (inst fxch x)            ; x to top of stack
2268        (unless (location= x y)
2269          (inst fst x))) ; maybe save it
2270      ;; Check for Inf or NaN
2271      (inst fxam)
2272      (inst fnstsw)
2273      (inst sahf)
2274      (inst jmp :nc NOINFNAN)        ; Neither Inf or NaN.
2275      (inst jmp :np NOINFNAN)        ; NaN gives NaN? Continue.
2276      (inst and ah-tn #x02)            ; Test sign of Inf.
2277      (inst jmp :z DONE)          ; +Inf gives +Inf.
2278      (inst fstp fr0)                ; -Inf gives 0
2279      (inst fldz)
2280      (inst jmp-short DONE)
2281      NOINFNAN
2282      (inst fstp fr1)
2283      (inst fldl2e)
2284      (inst fmul fr1)
2285      ;; Now fr0=x log2(e)
2286      (inst fst fr1)
2287      (inst frndint)
2288      (inst fst fr2)
2289      (inst fsubp-sti fr1)
2290      (inst f2xm1)
2291      (inst fld1)
2292      (inst faddp-sti fr1)
2293      (inst fscale)
2294      (inst fld fr0)
2295      DONE
2296      (unless (zerop (tn-offset y))
2297              (inst fstd y))))
2298
2299 ;;; Expm1 = exp(x) - 1.
2300 ;;; Handles the following special cases:
2301 ;;;   expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2302 (define-vop (fexpm1)
2303   (:translate %expm1)
2304   (:args (x :scs (double-reg) :target fr0))
2305   (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2306   (:temporary (:sc double-reg :offset fr0-offset
2307                    :from :argument :to :result) fr0)
2308   (:temporary (:sc double-reg :offset fr1-offset
2309                    :from :argument :to :result) fr1)
2310   (:temporary (:sc double-reg :offset fr2-offset
2311                    :from :argument :to :result) fr2)
2312   (:results (y :scs (double-reg)))
2313   (:arg-types double-float)
2314   (:result-types double-float)
2315   (:policy :fast-safe)
2316   (:note "inline expm1 function")
2317   (:vop-var vop)
2318   (:save-p :compute-only)
2319   (:ignore temp)
2320   (:generator 5
2321      (note-this-location vop :internal-error)
2322      (unless (zerop (tn-offset x))
2323        (inst fxch x)            ; x to top of stack
2324        (unless (location= x y)
2325          (inst fst x))) ; maybe save it
2326      ;; Check for Inf or NaN
2327      (inst fxam)
2328      (inst fnstsw)
2329      (inst sahf)
2330      (inst jmp :nc NOINFNAN)        ; Neither Inf or NaN.
2331      (inst jmp :np NOINFNAN)        ; NaN gives NaN? Continue.
2332      (inst and ah-tn #x02)            ; Test sign of Inf.
2333      (inst jmp :z DONE)          ; +Inf gives +Inf.
2334      (inst fstp fr0)                ; -Inf gives -1.0
2335      (inst fld1)
2336      (inst fchs)
2337      (inst jmp-short DONE)
2338      NOINFNAN
2339      ;; Free two stack slots leaving the argument on top.
2340      (inst fstp fr2)
2341      (inst fstp fr0)
2342      (inst fldl2e)
2343      (inst fmul fr1)    ; Now fr0 = x log2(e)
2344      (inst fst fr1)
2345      (inst frndint)
2346      (inst fsub-sti fr1)
2347      (inst fxch fr1)
2348      (inst f2xm1)
2349      (inst fscale)
2350      (inst fxch fr1)
2351      (inst fld1)
2352      (inst fscale)
2353      (inst fstp fr1)
2354      (inst fld1)
2355      (inst fsub fr1)
2356      (inst fsubr fr2)
2357      DONE
2358      (unless (zerop (tn-offset y))
2359        (inst fstd y))))
2360
2361 (define-vop (flog)
2362   (:translate %log)
2363   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2364   (:temporary (:sc double-reg :offset fr0-offset
2365                    :from :argument :to :result) fr0)
2366   (:temporary (:sc double-reg :offset fr1-offset
2367                    :from :argument :to :result) fr1)
2368   (:results (y :scs (double-reg)))
2369   (:arg-types double-float)
2370   (:result-types double-float)
2371   (:policy :fast-safe)
2372   (:note "inline log function")
2373   (:vop-var vop)
2374   (:save-p :compute-only)
2375   (:generator 5
2376      (note-this-location vop :internal-error)
2377      (sc-case x
2378         (double-reg
2379          (case (tn-offset x)
2380             (0
2381              ;; x is in fr0
2382              (inst fstp fr1)
2383              (inst fldln2)
2384              (inst fxch fr1))
2385             (1
2386              ;; x is in fr1
2387              (inst fstp fr0)
2388              (inst fldln2)
2389              (inst fxch fr1))
2390             (t
2391              ;; x is in a FP reg, not fr0 or fr1
2392              (inst fstp fr0)
2393              (inst fstp fr0)
2394              (inst fldln2)
2395              (inst fldd (make-random-tn :kind :normal
2396                                         :sc (sc-or-lose 'double-reg)
2397                                         :offset (1- (tn-offset x))))))
2398          (inst fyl2x))
2399         ((double-stack descriptor-reg)
2400          (inst fstp fr0)
2401          (inst fstp fr0)
2402          (inst fldln2)
2403          (if (sc-is x double-stack)
2404              (inst fldd (ea-for-df-stack x))
2405              (inst fldd (ea-for-df-desc x)))
2406          (inst fyl2x)))
2407      (inst fld fr0)
2408      (case (tn-offset y)
2409        ((0 1))
2410        (t (inst fstd y)))))
2411
2412 (define-vop (flog10)
2413   (:translate %log10)
2414   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2415   (:temporary (:sc double-reg :offset fr0-offset
2416                    :from :argument :to :result) fr0)
2417   (:temporary (:sc double-reg :offset fr1-offset
2418                    :from :argument :to :result) fr1)
2419   (:results (y :scs (double-reg)))
2420   (:arg-types double-float)
2421   (:result-types double-float)
2422   (:policy :fast-safe)
2423   (:note "inline log10 function")
2424   (:vop-var vop)
2425   (:save-p :compute-only)
2426   (:generator 5
2427      (note-this-location vop :internal-error)
2428      (sc-case x
2429         (double-reg
2430          (case (tn-offset x)
2431             (0
2432              ;; x is in fr0
2433              (inst fstp fr1)
2434              (inst fldlg2)
2435              (inst fxch fr1))
2436             (1
2437              ;; x is in fr1
2438              (inst fstp fr0)
2439              (inst fldlg2)
2440              (inst fxch fr1))
2441             (t
2442              ;; x is in a FP reg, not fr0 or fr1
2443              (inst fstp fr0)
2444              (inst fstp fr0)
2445              (inst fldlg2)
2446              (inst fldd (make-random-tn :kind :normal
2447                                         :sc (sc-or-lose 'double-reg)
2448                                         :offset (1- (tn-offset x))))))
2449          (inst fyl2x))
2450         ((double-stack descriptor-reg)
2451          (inst fstp fr0)
2452          (inst fstp fr0)
2453          (inst fldlg2)
2454          (if (sc-is x double-stack)
2455              (inst fldd (ea-for-df-stack x))
2456              (inst fldd (ea-for-df-desc x)))
2457          (inst fyl2x)))
2458      (inst fld fr0)
2459      (case (tn-offset y)
2460        ((0 1))
2461        (t (inst fstd y)))))
2462
2463 (define-vop (fpow)
2464   (:translate %pow)
2465   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2466          (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2467   (:temporary (:sc double-reg :offset fr0-offset
2468                    :from (:argument 0) :to :result) fr0)
2469   (:temporary (:sc double-reg :offset fr1-offset
2470                    :from (:argument 1) :to :result) fr1)
2471   (:temporary (:sc double-reg :offset fr2-offset
2472                    :from :load :to :result) fr2)
2473   (:results (r :scs (double-reg)))
2474   (:arg-types double-float double-float)
2475   (:result-types double-float)
2476   (:policy :fast-safe)
2477   (:note "inline pow function")
2478   (:vop-var vop)
2479   (:save-p :compute-only)
2480   (:generator 5
2481      (note-this-location vop :internal-error)
2482      ;; Setup x in fr0 and y in fr1
2483      (cond
2484       ;; x in fr0; y in fr1
2485       ((and (sc-is x double-reg) (zerop (tn-offset x))
2486             (sc-is y double-reg) (= 1 (tn-offset y))))
2487       ;; y in fr1; x not in fr0
2488       ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2489        ;; Load x to fr0
2490        (sc-case x
2491           (double-reg
2492            (copy-fp-reg-to-fr0 x))
2493           (double-stack
2494            (inst fstp fr0)
2495            (inst fldd (ea-for-df-stack x)))
2496           (descriptor-reg
2497            (inst fstp fr0)
2498            (inst fldd (ea-for-df-desc x)))))
2499       ;; x in fr0; y not in fr1
2500       ((and (sc-is x double-reg) (zerop (tn-offset x)))
2501        (inst fxch fr1)
2502        ;; Now load y to fr0
2503        (sc-case y
2504           (double-reg
2505            (copy-fp-reg-to-fr0 y))
2506           (double-stack
2507            (inst fstp fr0)
2508            (inst fldd (ea-for-df-stack y)))
2509           (descriptor-reg
2510            (inst fstp fr0)
2511            (inst fldd (ea-for-df-desc y))))
2512        (inst fxch fr1))
2513       ;; x in fr1; y not in fr1
2514       ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2515        ;; Load y to fr0
2516        (sc-case y
2517           (double-reg
2518            (copy-fp-reg-to-fr0 y))
2519           (double-stack
2520            (inst fstp fr0)
2521            (inst fldd (ea-for-df-stack y)))
2522           (descriptor-reg
2523            (inst fstp fr0)
2524            (inst fldd (ea-for-df-desc y))))
2525        (inst fxch fr1))
2526       ;; y in fr0;
2527       ((and (sc-is y double-reg) (zerop (tn-offset y)))
2528        (inst fxch fr1)
2529        ;; Now load x to fr0
2530        (sc-case x
2531           (double-reg
2532            (copy-fp-reg-to-fr0 x))
2533           (double-stack
2534            (inst fstp fr0)
2535            (inst fldd (ea-for-df-stack x)))
2536           (descriptor-reg
2537            (inst fstp fr0)
2538            (inst fldd (ea-for-df-desc x)))))
2539       ;; Neither x or y are in either fr0 or fr1
2540       (t
2541        ;; Load y then x
2542        (inst fstp fr0)
2543        (inst fstp fr0)
2544        (sc-case y
2545           (double-reg
2546            (inst fldd (make-random-tn :kind :normal
2547                                       :sc (sc-or-lose 'double-reg)
2548                                       :offset (- (tn-offset y) 2))))
2549           (double-stack
2550            (inst fldd (ea-for-df-stack y)))
2551           (descriptor-reg
2552            (inst fldd (ea-for-df-desc y))))
2553        ;; Load x to fr0
2554        (sc-case x
2555           (double-reg
2556            (inst fldd (make-random-tn :kind :normal
2557                                       :sc (sc-or-lose 'double-reg)
2558                                       :offset (1- (tn-offset x)))))
2559           (double-stack
2560            (inst fldd (ea-for-df-stack x)))
2561           (descriptor-reg
2562            (inst fldd (ea-for-df-desc x))))))
2563
2564      ;; Now have x at fr0; and y at fr1
2565      (inst fyl2x)
2566      ;; Now fr0=y log2(x)
2567      (inst fld fr0)
2568      (inst frndint)
2569      (inst fst fr2)
2570      (inst fsubp-sti fr1)
2571      (inst f2xm1)
2572      (inst fld1)
2573      (inst faddp-sti fr1)
2574      (inst fscale)
2575      (inst fld fr0)
2576      (case (tn-offset r)
2577        ((0 1))
2578        (t (inst fstd r)))))
2579
2580 (define-vop (fscalen)
2581   (:translate %scalbn)
2582   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2583          (y :scs (signed-stack signed-reg) :target temp))
2584   (:temporary (:sc double-reg :offset fr0-offset
2585                    :from (:argument 0) :to :result) fr0)
2586   (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2587   (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2588   (:results (r :scs (double-reg)))
2589   (:arg-types double-float signed-num)
2590   (:result-types double-float)
2591   (:policy :fast-safe)
2592   (:note "inline scalbn function")
2593   (:generator 5
2594      ;; Setup x in fr0 and y in fr1
2595      (sc-case x
2596        (double-reg
2597         (case (tn-offset x)
2598           (0
2599            (inst fstp fr1)
2600            (sc-case y
2601              (signed-reg
2602               (inst mov temp y)
2603               (inst fild temp))
2604              (signed-stack
2605               (inst fild y)))
2606            (inst fxch fr1))
2607           (1
2608            (inst fstp fr0)
2609            (sc-case y
2610              (signed-reg
2611               (inst mov temp y)
2612               (inst fild temp))
2613              (signed-stack
2614               (inst fild y)))
2615            (inst fxch fr1))
2616           (t
2617            (inst fstp fr0)
2618            (inst fstp fr0)
2619            (sc-case y
2620              (signed-reg
2621               (inst mov temp y)
2622               (inst fild temp))
2623              (signed-stack
2624               (inst fild y)))
2625            (inst fld (make-random-tn :kind :normal
2626                                      :sc (sc-or-lose 'double-reg)
2627                                      :offset (1- (tn-offset x)))))))
2628        ((double-stack descriptor-reg)
2629         (inst fstp fr0)
2630         (inst fstp fr0)
2631         (sc-case y
2632           (signed-reg
2633            (inst mov temp y)
2634            (inst fild temp))
2635           (signed-stack
2636            (inst fild y)))
2637         (if (sc-is x double-stack)
2638             (inst fldd (ea-for-df-stack x))
2639             (inst fldd (ea-for-df-desc x)))))
2640      (inst fscale)
2641      (unless (zerop (tn-offset r))
2642        (inst fstd r))))
2643
2644 (define-vop (fscale)
2645   (:translate %scalb)
2646   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2647          (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2648   (:temporary (:sc double-reg :offset fr0-offset
2649                    :from (:argument 0) :to :result) fr0)
2650   (:temporary (:sc double-reg :offset fr1-offset
2651                    :from (:argument 1) :to :result) fr1)
2652   (:results (r :scs (double-reg)))
2653   (:arg-types double-float double-float)
2654   (:result-types double-float)
2655   (:policy :fast-safe)
2656   (:note "inline scalb function")
2657   (:vop-var vop)
2658   (:save-p :compute-only)
2659   (:generator 5
2660      (note-this-location vop :internal-error)
2661      ;; Setup x in fr0 and y in fr1
2662      (cond
2663       ;; x in fr0; y in fr1
2664       ((and (sc-is x double-reg) (zerop (tn-offset x))
2665             (sc-is y double-reg) (= 1 (tn-offset y))))
2666       ;; y in fr1; x not in fr0
2667       ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2668        ;; Load x to fr0
2669        (sc-case x
2670           (double-reg
2671            (copy-fp-reg-to-fr0 x))
2672           (double-stack
2673            (inst fstp fr0)
2674            (inst fldd (ea-for-df-stack x)))
2675           (descriptor-reg
2676            (inst fstp fr0)
2677            (inst fldd (ea-for-df-desc x)))))
2678       ;; x in fr0; y not in fr1
2679       ((and (sc-is x double-reg) (zerop (tn-offset x)))
2680        (inst fxch fr1)
2681        ;; Now load y to fr0
2682        (sc-case y
2683           (double-reg
2684            (copy-fp-reg-to-fr0 y))
2685           (double-stack
2686            (inst fstp fr0)
2687            (inst fldd (ea-for-df-stack y)))
2688           (descriptor-reg
2689            (inst fstp fr0)
2690            (inst fldd (ea-for-df-desc y))))
2691        (inst fxch fr1))
2692       ;; x in fr1; y not in fr1
2693       ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2694        ;; Load y to fr0
2695        (sc-case y
2696           (double-reg
2697            (copy-fp-reg-to-fr0 y))
2698           (double-stack
2699            (inst fstp fr0)
2700            (inst fldd (ea-for-df-stack y)))
2701           (descriptor-reg
2702            (inst fstp fr0)
2703            (inst fldd (ea-for-df-desc y))))
2704        (inst fxch fr1))
2705       ;; y in fr0;
2706       ((and (sc-is y double-reg) (zerop (tn-offset y)))
2707        (inst fxch fr1)
2708        ;; Now load x to fr0
2709        (sc-case x
2710           (double-reg
2711            (copy-fp-reg-to-fr0 x))
2712           (double-stack
2713            (inst fstp fr0)
2714            (inst fldd (ea-for-df-stack x)))
2715           (descriptor-reg
2716            (inst fstp fr0)
2717            (inst fldd (ea-for-df-desc x)))))
2718       ;; Neither x or y are in either fr0 or fr1
2719       (t
2720        ;; Load y then x
2721        (inst fstp fr0)
2722        (inst fstp fr0)
2723        (sc-case y
2724           (double-reg
2725            (inst fldd (make-random-tn :kind :normal
2726                                       :sc (sc-or-lose 'double-reg)
2727                                       :offset (- (tn-offset y) 2))))
2728           (double-stack
2729            (inst fldd (ea-for-df-stack y)))
2730           (descriptor-reg
2731            (inst fldd (ea-for-df-desc y))))
2732        ;; Load x to fr0
2733        (sc-case x
2734           (double-reg
2735            (inst fldd (make-random-tn :kind :normal
2736                                       :sc (sc-or-lose 'double-reg)
2737                                       :offset (1- (tn-offset x)))))
2738           (double-stack
2739            (inst fldd (ea-for-df-stack x)))
2740           (descriptor-reg
2741            (inst fldd (ea-for-df-desc x))))))
2742
2743      ;; Now have x at fr0; and y at fr1
2744      (inst fscale)
2745      (unless (zerop (tn-offset r))
2746              (inst fstd r))))
2747
2748 (define-vop (flog1p)
2749   (:translate %log1p)
2750   (:args (x :scs (double-reg) :to :result))
2751   (:temporary (:sc double-reg :offset fr0-offset
2752                    :from :argument :to :result) fr0)
2753   (:temporary (:sc double-reg :offset fr1-offset
2754                    :from :argument :to :result) fr1)
2755   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2756   (:results (y :scs (double-reg)))
2757   (:arg-types double-float)
2758   (:result-types double-float)
2759   (:policy :fast-safe)
2760   (:note "inline log1p function")
2761   (:ignore temp)
2762   (:generator 5
2763      ;; x is in a FP reg, not fr0, fr1.
2764      (inst fstp fr0)
2765      (inst fstp fr0)
2766      (inst fldd (make-random-tn :kind :normal
2767                                 :sc (sc-or-lose 'double-reg)
2768                                 :offset (- (tn-offset x) 2)))
2769      ;; Check the range
2770      (inst push #x3e947ae1)     ; Constant 0.29
2771      (inst fabs)
2772      (inst fld (make-ea :dword :base esp-tn))
2773      (inst fcompp)
2774      (inst add esp-tn 4)
2775      (inst fnstsw)                      ; status word to ax
2776      (inst and ah-tn #x45)
2777      (inst jmp :z WITHIN-RANGE)
2778      ;; Out of range for fyl2xp1.
2779      (inst fld1)
2780      (inst faddd (make-random-tn :kind :normal
2781                                  :sc (sc-or-lose 'double-reg)
2782                                  :offset (- (tn-offset x) 1)))
2783      (inst fldln2)
2784      (inst fxch fr1)
2785      (inst fyl2x)
2786      (inst jmp DONE)
2787
2788      WITHIN-RANGE
2789      (inst fldln2)
2790      (inst fldd (make-random-tn :kind :normal
2791                                 :sc (sc-or-lose 'double-reg)
2792                                 :offset (- (tn-offset x) 1)))
2793      (inst fyl2xp1)
2794      DONE
2795      (inst fld fr0)
2796      (case (tn-offset y)
2797        ((0 1))
2798        (t (inst fstd y)))))
2799
2800 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2801 ;;; instruction and a range check can be avoided.
2802 (define-vop (flog1p-pentium)
2803   (:translate %log1p)
2804   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2805   (:temporary (:sc double-reg :offset fr0-offset
2806                    :from :argument :to :result) fr0)
2807   (:temporary (:sc double-reg :offset fr1-offset
2808                    :from :argument :to :result) fr1)
2809   (:results (y :scs (double-reg)))
2810   (:arg-types double-float)
2811   (:result-types double-float)
2812   (:policy :fast-safe)
2813   (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2814   (:note "inline log1p with limited x range function")
2815   (:vop-var vop)
2816   (:save-p :compute-only)
2817   (:generator 4
2818      (note-this-location vop :internal-error)
2819      (sc-case x
2820         (double-reg
2821          (case (tn-offset x)
2822             (0
2823              ;; x is in fr0
2824              (inst fstp fr1)
2825              (inst fldln2)
2826              (inst fxch fr1))
2827             (1
2828              ;; x is in fr1
2829              (inst fstp fr0)
2830              (inst fldln2)
2831              (inst fxch fr1))
2832             (t
2833              ;; x is in a FP reg, not fr0 or fr1
2834              (inst fstp fr0)
2835              (inst fstp fr0)
2836              (inst fldln2)
2837              (inst fldd (make-random-tn :kind :normal
2838                                         :sc (sc-or-lose 'double-reg)
2839                                         :offset (1- (tn-offset x)))))))
2840         ((double-stack descriptor-reg)
2841          (inst fstp fr0)
2842          (inst fstp fr0)
2843          (inst fldln2)
2844          (if (sc-is x double-stack)
2845              (inst fldd (ea-for-df-stack x))
2846            (inst fldd (ea-for-df-desc x)))))
2847      (inst fyl2xp1)
2848      (inst fld fr0)
2849      (case (tn-offset y)
2850        ((0 1))
2851        (t (inst fstd y)))))
2852
2853 (define-vop (flogb)
2854   (:translate %logb)
2855   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2856   (:temporary (:sc double-reg :offset fr0-offset
2857                    :from :argument :to :result) fr0)
2858   (:temporary (:sc double-reg :offset fr1-offset
2859                    :from :argument :to :result) fr1)
2860   (:results (y :scs (double-reg)))
2861   (:arg-types double-float)
2862   (:result-types double-float)
2863   (:policy :fast-safe)
2864   (:note "inline logb function")
2865   (:vop-var vop)
2866   (:save-p :compute-only)
2867   (:generator 5
2868      (note-this-location vop :internal-error)
2869      (sc-case x
2870         (double-reg
2871          (case (tn-offset x)
2872             (0
2873              ;; x is in fr0
2874              (inst fstp fr1))
2875             (1
2876              ;; x is in fr1
2877              (inst fstp fr0))
2878             (t
2879              ;; x is in a FP reg, not fr0 or fr1
2880              (inst fstp fr0)
2881              (inst fstp fr0)
2882              (inst fldd (make-random-tn :kind :normal
2883                                         :sc (sc-or-lose 'double-reg)
2884                                         :offset (- (tn-offset x) 2))))))
2885         ((double-stack descriptor-reg)
2886          (inst fstp fr0)
2887          (inst fstp fr0)
2888          (if (sc-is x double-stack)
2889              (inst fldd (ea-for-df-stack x))
2890            (inst fldd (ea-for-df-desc x)))))
2891      (inst fxtract)
2892      (case (tn-offset y)
2893        (0
2894         (inst fxch fr1))
2895        (1)
2896        (t (inst fxch fr1)
2897           (inst fstd y)))))
2898
2899 (define-vop (fatan)
2900   (:translate %atan)
2901   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2902   (:temporary (:sc double-reg :offset fr0-offset
2903                    :from (:argument 0) :to :result) fr0)
2904   (:temporary (:sc double-reg :offset fr1-offset
2905                    :from (:argument 0) :to :result) fr1)
2906   (:results (r :scs (double-reg)))
2907   (:arg-types double-float)
2908   (:result-types double-float)
2909   (:policy :fast-safe)
2910   (:note "inline atan function")
2911   (:vop-var vop)
2912   (:save-p :compute-only)
2913   (:generator 5
2914      (note-this-location vop :internal-error)
2915      ;; Setup x in fr1 and 1.0 in fr0
2916      (cond
2917       ;; x in fr0
2918       ((and (sc-is x double-reg) (zerop (tn-offset x)))
2919        (inst fstp fr1))
2920       ;; x in fr1
2921       ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2922        (inst fstp fr0))
2923       ;; x not in fr0 or fr1
2924       (t
2925        ;; Load x then 1.0
2926        (inst fstp fr0)
2927        (inst fstp fr0)
2928        (sc-case x
2929           (double-reg
2930            (inst fldd (make-random-tn :kind :normal
2931                                       :sc (sc-or-lose 'double-reg)
2932                                       :offset (- (tn-offset x) 2))))
2933           (double-stack
2934            (inst fldd (ea-for-df-stack x)))
2935           (descriptor-reg
2936            (inst fldd (ea-for-df-desc x))))))
2937      (inst fld1)
2938      ;; Now have x at fr1; and 1.0 at fr0
2939      (inst fpatan)
2940      (inst fld fr0)
2941      (case (tn-offset r)
2942        ((0 1))
2943        (t (inst fstd r)))))
2944
2945 (define-vop (fatan2)
2946   (:translate %atan2)
2947   (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2948          (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2949   (:temporary (:sc double-reg :offset fr0-offset
2950                    :from (:argument 1) :to :result) fr0)
2951   (:temporary (:sc double-reg :offset fr1-offset
2952                    :from (:argument 0) :to :result) fr1)
2953   (:results (r :scs (double-reg)))
2954   (:arg-types double-float double-float)
2955   (:result-types double-float)
2956   (:policy :fast-safe)
2957   (:note "inline atan2 function")
2958   (:vop-var vop)
2959   (:save-p :compute-only)
2960   (:generator 5
2961      (note-this-location vop :internal-error)
2962      ;; Setup x in fr1 and y in fr0
2963      (cond
2964       ;; y in fr0; x in fr1
2965       ((and (sc-is y double-reg) (zerop (tn-offset y))
2966             (sc-is x double-reg) (= 1 (tn-offset x))))
2967       ;; x in fr1; y not in fr0
2968       ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2969        ;; Load y to fr0
2970        (sc-case y
2971           (double-reg
2972            (copy-fp-reg-to-fr0 y))
2973           (double-stack
2974            (inst fstp fr0)
2975            (inst fldd (ea-for-df-stack y)))
2976           (descriptor-reg
2977            (inst fstp fr0)
2978            (inst fldd (ea-for-df-desc y)))))
2979       ((and (sc-is x double-reg) (zerop (tn-offset x))
2980             (sc-is y double-reg) (zerop (tn-offset x)))
2981        ;; copy x to fr1
2982        (inst fst fr1))
2983       ;; y in fr0; x not in fr1
2984       ((and (sc-is y double-reg) (zerop (tn-offset y)))
2985        (inst fxch fr1)
2986        ;; Now load x to fr0
2987        (sc-case x
2988           (double-reg
2989            (copy-fp-reg-to-fr0 x))
2990           (double-stack
2991            (inst fstp fr0)
2992            (inst fldd (ea-for-df-stack x)))
2993           (descriptor-reg
2994            (inst fstp fr0)
2995            (inst fldd (ea-for-df-desc x))))
2996        (inst fxch fr1))
2997       ;; y in fr1; x not in fr1
2998       ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2999        ;; Load x to fr0
3000        (sc-case x
3001           (double-reg
3002            (copy-fp-reg-to-fr0 x))
3003           (double-stack
3004            (inst fstp fr0)
3005            (inst fldd (ea-for-df-stack x)))
3006           (descriptor-reg
3007            (inst fstp fr0)
3008            (inst fldd (ea-for-df-desc x))))
3009        (inst fxch fr1))
3010       ;; x in fr0;
3011       ((and (sc-is x double-reg) (zerop (tn-offset x)))
3012        (inst fxch fr1)
3013        ;; Now load y to fr0
3014        (sc-case y
3015           (double-reg
3016            (copy-fp-reg-to-fr0 y))
3017           (double-stack
3018            (inst fstp fr0)
3019            (inst fldd (ea-for-df-stack y)))
3020           (descriptor-reg
3021            (inst fstp fr0)
3022            (inst fldd (ea-for-df-desc y)))))
3023       ;; Neither y or x are in either fr0 or fr1
3024       (t
3025        ;; Load x then y
3026        (inst fstp fr0)
3027        (inst fstp fr0)
3028        (sc-case x
3029           (double-reg
3030            (inst fldd (make-random-tn :kind :normal
3031                                       :sc (sc-or-lose 'double-reg)
3032                                       :offset (- (tn-offset x) 2))))
3033           (double-stack
3034            (inst fldd (ea-for-df-stack x)))
3035           (descriptor-reg
3036            (inst fldd (ea-for-df-desc x))))
3037        ;; Load y to fr0
3038        (sc-case y
3039           (double-reg
3040            (inst fldd (make-random-tn :kind :normal
3041                                       :sc (sc-or-lose 'double-reg)
3042                                       :offset (1- (tn-offset y)))))
3043           (double-stack
3044            (inst fldd (ea-for-df-stack y)))
3045           (descriptor-reg
3046            (inst fldd (ea-for-df-desc y))))))
3047
3048      ;; Now have y at fr0; and x at fr1
3049      (inst fpatan)
3050      (inst fld fr0)
3051      (case (tn-offset r)
3052        ((0 1))
3053        (t (inst fstd r)))))
3054 ) ; PROGN #!-LONG-FLOAT
3055 \f
3056 #!+long-float
3057 (progn
3058
3059 ;;; Lets use some of the 80387 special functions.
3060 ;;;
3061 ;;; These defs will not take effect unless code/irrat.lisp is modified
3062 ;;; to remove the inlined alien routine def.
3063
3064 (macrolet ((frob (func trans op)
3065              `(define-vop (,func)
3066                (:args (x :scs (long-reg) :target fr0))
3067                (:temporary (:sc long-reg :offset fr0-offset
3068                                 :from :argument :to :result) fr0)
3069                (:ignore fr0)
3070                (:results (y :scs (long-reg)))
3071                (:arg-types long-float)
3072                (:result-types long-float)
3073                (:translate ,trans)
3074                (:policy :fast-safe)
3075                (:note "inline NPX function")
3076                (:vop-var vop)
3077                (:save-p :compute-only)
3078                (:node-var node)
3079                (:generator 5
3080                 (note-this-location vop :internal-error)
3081                 (unless (zerop (tn-offset x))
3082                   (inst fxch x)         ; x to top of stack
3083                   (unless (location= x y)
3084                     (inst fst x)))      ; maybe save it
3085                 (inst ,op)              ; clobber st0
3086                 (cond ((zerop (tn-offset y))
3087                        (maybe-fp-wait node))
3088                       (t
3089                        (inst fst y)))))))
3090
3091   ;; Quick versions of FSIN and FCOS that require the argument to be
3092   ;; within range 2^63.
3093   (frob fsin-quick %sin-quick fsin)
3094   (frob fcos-quick %cos-quick fcos)
3095   (frob fsqrt %sqrt fsqrt))
3096
3097 ;;; Quick version of ftan that requires the argument to be within
3098 ;;; range 2^63.
3099 (define-vop (ftan-quick)
3100   (:translate %tan-quick)
3101   (:args (x :scs (long-reg) :target fr0))
3102   (:temporary (:sc long-reg :offset fr0-offset
3103                    :from :argument :to :result) fr0)
3104   (:temporary (:sc long-reg :offset fr1-offset
3105                    :from :argument :to :result) fr1)
3106   (:results (y :scs (long-reg)))
3107   (:arg-types long-float)
3108   (:result-types long-float)
3109   (:policy :fast-safe)
3110   (:note "inline tan function")
3111   (:vop-var vop)
3112   (:save-p :compute-only)
3113   (:generator 5
3114     (note-this-location vop :internal-error)
3115     (case (tn-offset x)
3116        (0
3117         (inst fstp fr1))
3118        (1
3119         (inst fstp fr0))
3120        (t
3121         (inst fstp fr0)
3122         (inst fstp fr0)
3123         (inst fldd (make-random-tn :kind :normal
3124                                    :sc (sc-or-lose 'double-reg)
3125                                    :offset (- (tn-offset x) 2)))))
3126     (inst fptan)
3127     ;; Result is in fr1
3128     (case (tn-offset y)
3129        (0
3130         (inst fxch fr1))
3131        (1)
3132        (t
3133         (inst fxch fr1)
3134         (inst fstd y)))))
3135
3136 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3137 ;;; the argument is out of range 2^63 and would thus be hopelessly
3138 ;;; inaccurate.
3139 (macrolet ((frob (func trans op)
3140              `(define-vop (,func)
3141                 (:translate ,trans)
3142                 (:args (x :scs (long-reg) :target fr0))
3143                 (:temporary (:sc long-reg :offset fr0-offset
3144                                  :from :argument :to :result) fr0)
3145                 (:temporary (:sc unsigned-reg :offset eax-offset
3146                              :from :argument :to :result) eax)
3147                 (:results (y :scs (long-reg)))
3148                 (:arg-types long-float)
3149                 (:result-types long-float)
3150                 (:policy :fast-safe)
3151                 (:note "inline sin/cos function")
3152                 (:vop-var vop)
3153                 (:save-p :compute-only)
3154                 (:ignore eax)
3155                 (:generator 5
3156                   (note-this-location vop :internal-error)
3157                   (unless (zerop (tn-offset x))
3158                           (inst fxch x)          ; x to top of stack
3159                           (unless (location= x y)
3160                                   (inst fst x))) ; maybe save it
3161                   (inst ,op)
3162                   (inst fnstsw)                  ; status word to ax
3163                   (inst and ah-tn #x04)          ; C2
3164                   (inst jmp :z DONE)
3165                   ;; Else x was out of range so reduce it; ST0 is unchanged.
3166                   (inst fstp fr0)               ; Load 0.0
3167                   (inst fldz)
3168                   DONE
3169                   (unless (zerop (tn-offset y))
3170                           (inst fstd y))))))
3171           (frob fsin  %sin fsin)
3172           (frob fcos  %cos fcos))
3173
3174 (define-vop (ftan)
3175   (:translate %tan)
3176   (:args (x :scs (long-reg) :target fr0))
3177   (:temporary (:sc long-reg :offset fr0-offset
3178                    :from :argument :to :result) fr0)
3179   (:temporary (:sc long-reg :offset fr1-offset
3180                    :from :argument :to :result) fr1)
3181   (:temporary (:sc unsigned-reg :offset eax-offset
3182                    :from :argument :to :result) eax)
3183   (:results (y :scs (long-reg)))
3184   (:arg-types long-float)
3185   (:result-types long-float)
3186   (:ignore eax)
3187   (:policy :fast-safe)
3188   (:note "inline tan function")
3189   (:vop-var vop)
3190   (:save-p :compute-only)
3191   (:ignore eax)
3192   (:generator 5
3193     (note-this-location vop :internal-error)
3194     (case (tn-offset x)
3195        (0
3196         (inst fstp fr1))
3197        (1
3198         (inst fstp fr0))
3199        (t
3200         (inst fstp fr0)
3201         (inst fstp fr0)
3202         (inst fldd (make-random-tn :kind :normal
3203                                    :sc (sc-or-lose 'double-reg)
3204                                    :offset (- (tn-offset x) 2)))))
3205     (inst fptan)
3206     (inst fnstsw)                        ; status word to ax
3207     (inst and ah-tn #x04)                ; C2
3208     (inst jmp :z DONE)
3209     ;; Else x was out of range so reduce it; ST0 is unchanged.
3210     (inst fldz)                  ; Load 0.0
3211     (inst fxch fr1)
3212     DONE
3213     ;; Result is in fr1
3214     (case (tn-offset y)
3215        (0
3216         (inst fxch fr1))
3217        (1)
3218        (t
3219         (inst fxch fr1)
3220         (inst fstd y)))))
3221
3222 ;;; Modified exp that handles the following special cases:
3223 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3224 (define-vop (fexp)
3225   (:translate %exp)
3226   (:args (x :scs (long-reg) :target fr0))
3227   (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3228   (:temporary (:sc long-reg :offset fr0-offset
3229                    :from :argument :to :result) fr0)
3230   (:temporary (:sc long-reg :offset fr1-offset
3231                    :from :argument :to :result) fr1)
3232   (:temporary (:sc long-reg :offset fr2-offset
3233                    :from :argument :to :result) fr2)
3234   (:results (y :scs (long-reg)))
3235   (:arg-types long-float)
3236   (:result-types long-float)
3237   (:policy :fast-safe)
3238   (:note "inline exp function")
3239   (:vop-var vop)
3240   (:save-p :compute-only)
3241   (:ignore temp)
3242   (:generator 5
3243      (note-this-location vop :internal-error)
3244      (unless (zerop (tn-offset x))
3245              (inst fxch x)              ; x to top of stack
3246              (unless (location= x y)
3247                      (inst fst x)))     ; maybe save it
3248      ;; Check for Inf or NaN
3249      (inst fxam)
3250      (inst fnstsw)
3251      (inst sahf)
3252      (inst jmp :nc NOINFNAN)        ; Neither Inf or NaN.
3253      (inst jmp :np NOINFNAN)        ; NaN gives NaN? Continue.
3254      (inst and ah-tn #x02)            ; Test sign of Inf.
3255      (inst jmp :z DONE)          ; +Inf gives +Inf.
3256      (inst fstp fr0)                ; -Inf gives 0
3257      (inst fldz)
3258      (inst jmp-short DONE)
3259      NOINFNAN
3260      (inst fstp fr1)
3261      (inst fldl2e)
3262      (inst fmul fr1)
3263      ;; Now fr0=x log2(e)
3264      (inst fst fr1)
3265      (inst frndint)
3266      (inst fst fr2)
3267      (inst fsubp-sti fr1)
3268      (inst f2xm1)
3269      (inst fld1)
3270      (inst faddp-sti fr1)
3271      (inst fscale)
3272      (inst fld fr0)
3273      DONE
3274      (unless (zerop (tn-offset y))
3275              (inst fstd y))))
3276
3277 ;;; Expm1 = exp(x) - 1.
3278 ;;; Handles the following special cases:
3279 ;;;   expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3280 (define-vop (fexpm1)
3281   (:translate %expm1)
3282   (:args (x :scs (long-reg) :target fr0))
3283   (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3284   (:temporary (:sc long-reg :offset fr0-offset
3285                    :from :argument :to :result) fr0)
3286   (:temporary (:sc long-reg :offset fr1-offset
3287                    :from :argument :to :result) fr1)
3288   (:temporary (:sc long-reg :offset fr2-offset
3289                    :from :argument :to :result) fr2)
3290   (:results (y :scs (long-reg)))
3291   (:arg-types long-float)
3292   (:result-types long-float)
3293   (:policy :fast-safe)
3294   (:note "inline expm1 function")
3295   (:vop-var vop)
3296   (:save-p :compute-only)
3297   (:ignore temp)
3298   (:generator 5
3299      (note-this-location vop :internal-error)
3300      (unless (zerop (tn-offset x))
3301        (inst fxch x)            ; x to top of stack
3302        (unless (location= x y)
3303          (inst fst x))) ; maybe save it
3304      ;; Check for Inf or NaN
3305      (inst fxam)
3306      (inst fnstsw)
3307      (inst sahf)
3308      (inst jmp :nc NOINFNAN)        ; Neither Inf or NaN.
3309      (inst jmp :np NOINFNAN)        ; NaN gives NaN? Continue.
3310      (inst and ah-tn #x02)            ; Test sign of Inf.
3311      (inst jmp :z DONE)          ; +Inf gives +Inf.
3312      (inst fstp fr0)                ; -Inf gives -1.0
3313      (inst fld1)
3314      (inst fchs)
3315      (inst jmp-short DONE)
3316      NOINFNAN
3317      ;; Free two stack slots leaving the argument on top.
3318      (inst fstp fr2)
3319      (inst fstp fr0)
3320      (inst fldl2e)
3321      (inst fmul fr1)    ; Now fr0 = x log2(e)
3322      (inst fst fr1)
3323      (inst frndint)
3324      (inst fsub-sti fr1)
3325      (inst fxch fr1)
3326      (inst f2xm1)
3327      (inst fscale)
3328      (inst fxch fr1)
3329      (inst fld1)
3330      (inst fscale)
3331      (inst fstp fr1)
3332      (inst fld1)
3333      (inst fsub fr1)
3334      (inst fsubr fr2)
3335      DONE
3336      (unless (zerop (tn-offset y))
3337        (inst fstd y))))
3338
3339 (define-vop (flog)
3340   (:translate %log)
3341   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3342   (:temporary (:sc long-reg :offset fr0-offset
3343                    :from :argument :to :result) fr0)
3344   (:temporary (:sc long-reg :offset fr1-offset
3345                    :from :argument :to :result) fr1)
3346   (:results (y :scs (long-reg)))
3347   (:arg-types long-float)
3348   (:result-types long-float)
3349   (:policy :fast-safe)
3350   (:note "inline log function")
3351   (:vop-var vop)
3352   (:save-p :compute-only)
3353   (:generator 5
3354      (note-this-location vop :internal-error)
3355      (sc-case x
3356         (long-reg
3357          (case (tn-offset x)
3358             (0
3359              ;; x is in fr0
3360              (inst fstp fr1)
3361              (inst fldln2)
3362              (inst fxch fr1))
3363             (1
3364              ;; x is in fr1
3365              (inst fstp fr0)
3366              (inst fldln2)
3367              (inst fxch fr1))
3368             (t
3369              ;; x is in a FP reg, not fr0 or fr1
3370              (inst fstp fr0)
3371              (inst fstp fr0)
3372              (inst fldln2)
3373              (inst fldd (make-random-tn :kind :normal
3374                                         :sc (sc-or-lose 'double-reg)
3375                                         :offset (1- (tn-offset x))))))
3376          (inst fyl2x))
3377         ((long-stack descriptor-reg)
3378          (inst fstp fr0)
3379          (inst fstp fr0)
3380          (inst fldln2)
3381          (if (sc-is x long-stack)
3382              (inst fldl (ea-for-lf-stack x))
3383              (inst fldl (ea-for-lf-desc x)))
3384          (inst fyl2x)))
3385      (inst fld fr0)
3386      (case (tn-offset y)
3387        ((0 1))
3388        (t (inst fstd y)))))
3389
3390 (define-vop (flog10)
3391   (:translate %log10)
3392   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3393   (:temporary (:sc long-reg :offset fr0-offset
3394                    :from :argument :to :result) fr0)
3395   (:temporary (:sc long-reg :offset fr1-offset
3396                    :from :argument :to :result) fr1)
3397   (:results (y :scs (long-reg)))
3398   (:arg-types long-float)
3399   (:result-types long-float)
3400   (:policy :fast-safe)
3401   (:note "inline log10 function")
3402   (:vop-var vop)
3403   (:save-p :compute-only)
3404   (:generator 5
3405      (note-this-location vop :internal-error)
3406      (sc-case x
3407         (long-reg
3408          (case (tn-offset x)
3409             (0
3410              ;; x is in fr0
3411              (inst fstp fr1)
3412              (inst fldlg2)
3413              (inst fxch fr1))
3414             (1
3415              ;; x is in fr1
3416              (inst fstp fr0)
3417              (inst fldlg2)
3418              (inst fxch fr1))
3419             (t
3420              ;; x is in a FP reg, not fr0 or fr1
3421              (inst fstp fr0)
3422              (inst fstp fr0)
3423              (inst fldlg2)
3424              (inst fldd (make-random-tn :kind :normal
3425                                         :sc (sc-or-lose 'double-reg)
3426                                         :offset (1- (tn-offset x))))))
3427          (inst fyl2x))
3428         ((long-stack descriptor-reg)
3429          (inst fstp fr0)
3430          (inst fstp fr0)
3431          (inst fldlg2)
3432          (if (sc-is x long-stack)
3433              (inst fldl (ea-for-lf-stack x))
3434              (inst fldl (ea-for-lf-desc x)))
3435          (inst fyl2x)))
3436      (inst fld fr0)
3437      (case (tn-offset y)
3438        ((0 1))
3439        (t (inst fstd y)))))
3440
3441 (define-vop (fpow)
3442   (:translate %pow)
3443   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3444          (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3445   (:temporary (:sc long-reg :offset fr0-offset
3446                    :from (:argument 0) :to :result) fr0)
3447   (:temporary (:sc long-reg :offset fr1-offset
3448                    :from (:argument 1) :to :result) fr1)
3449   (:temporary (:sc long-reg :offset fr2-offset
3450                    :from :load :to :result) fr2)
3451   (:results (r :scs (long-reg)))
3452   (:arg-types long-float long-float)
3453   (:result-types long-float)
3454   (:policy :fast-safe)
3455   (:note "inline pow function")
3456   (:vop-var vop)
3457   (:save-p :compute-only)
3458   (:generator 5
3459      (note-this-location vop :internal-error)
3460      ;; Setup x in fr0 and y in fr1
3461      (cond
3462       ;; x in fr0; y in fr1
3463       ((and (sc-is x long-reg) (zerop (tn-offset x))
3464             (sc-is y long-reg) (= 1 (tn-offset y))))
3465       ;; y in fr1; x not in fr0
3466       ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3467        ;; Load x to fr0
3468        (sc-case x
3469           (long-reg
3470            (copy-fp-reg-to-fr0 x))
3471           (long-stack
3472            (inst fstp fr0)
3473            (inst fldl (ea-for-lf-stack x)))
3474           (descriptor-reg
3475            (inst fstp fr0)
3476            (inst fldl (ea-for-lf-desc x)))))
3477       ;; x in fr0; y not in fr1
3478       ((and (sc-is x long-reg) (zerop (tn-offset x)))
3479        (inst fxch fr1)
3480        ;; Now load y to fr0
3481        (sc-case y
3482           (long-reg
3483            (copy-fp-reg-to-fr0 y))
3484           (long-stack
3485            (inst fstp fr0)
3486            (inst fldl (ea-for-lf-stack y)))
3487           (descriptor-reg
3488            (inst fstp fr0)
3489            (inst fldl (ea-for-lf-desc y))))
3490        (inst fxch fr1))
3491       ;; x in fr1; y not in fr1
3492       ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3493        ;; Load y to fr0
3494        (sc-case y
3495           (long-reg
3496            (copy-fp-reg-to-fr0 y))
3497           (long-stack
3498            (inst fstp fr0)
3499            (inst fldl (ea-for-lf-stack y)))
3500           (descriptor-reg
3501            (inst fstp fr0)
3502            (inst fldl (ea-for-lf-desc y))))
3503        (inst fxch fr1))
3504       ;; y in fr0;
3505       ((and (sc-is y long-reg) (zerop (tn-offset y)))
3506        (inst fxch fr1)
3507        ;; Now load x to fr0
3508        (sc-case x
3509           (long-reg
3510            (copy-fp-reg-to-fr0 x))
3511           (long-stack
3512            (inst fstp fr0)
3513            (inst fldl (ea-for-lf-stack x)))
3514           (descriptor-reg
3515            (inst fstp fr0)
3516            (inst fldl (ea-for-lf-desc x)))))
3517       ;; Neither x or y are in either fr0 or fr1
3518       (t
3519        ;; Load y then x
3520        (inst fstp fr0)
3521        (inst fstp fr0)
3522        (sc-case y
3523           (long-reg
3524            (inst fldd (make-random-tn :kind :normal
3525                                       :sc (sc-or-lose 'double-reg)
3526                                       :offset (- (tn-offset y) 2))))
3527           (long-stack
3528            (inst fldl (ea-for-lf-stack y)))
3529           (descriptor-reg
3530            (inst fldl (ea-for-lf-desc y))))
3531        ;; Load x to fr0
3532        (sc-case x
3533           (long-reg
3534            (inst fldd (make-random-tn :kind :normal
3535                                       :sc (sc-or-lose 'double-reg)
3536                                       :offset (1- (tn-offset x)))))
3537           (long-stack
3538            (inst fldl (ea-for-lf-stack x)))
3539           (descriptor-reg
3540            (inst fldl (ea-for-lf-desc x))))))
3541
3542      ;; Now have x at fr0; and y at fr1
3543      (inst fyl2x)
3544      ;; Now fr0=y log2(x)
3545      (inst fld fr0)
3546      (inst frndint)
3547      (inst fst fr2)
3548      (inst fsubp-sti fr1)
3549      (inst f2xm1)
3550      (inst fld1)
3551      (inst faddp-sti fr1)
3552      (inst fscale)
3553      (inst fld fr0)
3554      (case (tn-offset r)
3555        ((0 1))
3556        (t (inst fstd r)))))
3557
3558 (define-vop (fscalen)
3559   (:translate %scalbn)
3560   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3561          (y :scs (signed-stack signed-reg) :target temp))
3562   (:temporary (:sc long-reg :offset fr0-offset
3563                    :from (:argument 0) :to :result) fr0)
3564   (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3565   (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3566   (:results (r :scs (long-reg)))
3567   (:arg-types long-float signed-num)
3568   (:result-types long-float)
3569   (:policy :fast-safe)
3570   (:note "inline scalbn function")
3571   (:generator 5
3572      ;; Setup x in fr0 and y in fr1
3573      (sc-case x
3574        (long-reg
3575         (case (tn-offset x)
3576           (0
3577            (inst fstp fr1)
3578            (sc-case y
3579              (signed-reg
3580               (inst mov temp y)
3581               (inst fild temp))
3582              (signed-stack
3583               (inst fild y)))
3584            (inst fxch fr1))
3585           (1
3586            (inst fstp fr0)
3587            (sc-case y
3588              (signed-reg
3589               (inst mov temp y)
3590               (inst fild temp))
3591              (signed-stack
3592               (inst fild y)))
3593            (inst fxch fr1))
3594           (t
3595            (inst fstp fr0)
3596            (inst fstp fr0)
3597            (sc-case y
3598              (signed-reg
3599               (inst mov temp y)
3600               (inst fild temp))
3601              (signed-stack
3602               (inst fild y)))
3603            (inst fld (make-random-tn :kind :normal
3604                                      :sc (sc-or-lose 'double-reg)
3605                                      :offset (1- (tn-offset x)))))))
3606        ((long-stack descriptor-reg)
3607         (inst fstp fr0)
3608         (inst fstp fr0)
3609         (sc-case y
3610           (signed-reg
3611            (inst mov temp y)
3612            (inst fild temp))
3613           (signed-stack
3614            (inst fild y)))
3615         (if (sc-is x long-stack)
3616             (inst fldl (ea-for-lf-stack x))
3617             (inst fldl (ea-for-lf-desc x)))))
3618      (inst fscale)
3619      (unless (zerop (tn-offset r))
3620        (inst fstd r))))
3621
3622 (define-vop (fscale)
3623   (:translate %scalb)
3624   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3625          (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3626   (:temporary (:sc long-reg :offset fr0-offset
3627                    :from (:argument 0) :to :result) fr0)
3628   (:temporary (:sc long-reg :offset fr1-offset
3629                    :from (:argument 1) :to :result) fr1)
3630   (:results (r :scs (long-reg)))
3631   (:arg-types long-float long-float)
3632   (:result-types long-float)
3633   (:policy :fast-safe)
3634   (:note "inline scalb function")
3635   (:vop-var vop)
3636   (:save-p :compute-only)
3637   (:generator 5
3638      (note-this-location vop :internal-error)
3639      ;; Setup x in fr0 and y in fr1
3640      (cond
3641       ;; x in fr0; y in fr1
3642       ((and (sc-is x long-reg) (zerop (tn-offset x))
3643             (sc-is y long-reg) (= 1 (tn-offset y))))
3644       ;; y in fr1; x not in fr0
3645       ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3646        ;; Load x to fr0
3647        (sc-case x
3648           (long-reg
3649            (copy-fp-reg-to-fr0 x))
3650           (long-stack
3651            (inst fstp fr0)
3652            (inst fldl (ea-for-lf-stack x)))
3653           (descriptor-reg
3654            (inst fstp fr0)
3655            (inst fldl (ea-for-lf-desc x)))))
3656       ;; x in fr0; y not in fr1
3657       ((and (sc-is x long-reg) (zerop (tn-offset x)))
3658        (inst fxch fr1)
3659        ;; Now load y to fr0
3660        (sc-case y
3661           (long-reg
3662            (copy-fp-reg-to-fr0 y))
3663           (long-stack
3664            (inst fstp fr0)
3665            (inst fldl (ea-for-lf-stack y)))
3666           (descriptor-reg
3667            (inst fstp fr0)
3668            (inst fldl (ea-for-lf-desc y))))
3669        (inst fxch fr1))
3670       ;; x in fr1; y not in fr1
3671       ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3672        ;; Load y to fr0
3673        (sc-case y
3674           (long-reg
3675            (copy-fp-reg-to-fr0 y))
3676           (long-stack
3677            (inst fstp fr0)
3678            (inst fldl (ea-for-lf-stack y)))
3679           (descriptor-reg
3680            (inst fstp fr0)
3681            (inst fldl (ea-for-lf-desc y))))
3682        (inst fxch fr1))
3683       ;; y in fr0;
3684       ((and (sc-is y long-reg) (zerop (tn-offset y)))
3685        (inst fxch fr1)
3686        ;; Now load x to fr0
3687        (sc-case x
3688           (long-reg
3689            (copy-fp-reg-to-fr0 x))
3690           (long-stack
3691            (inst fstp fr0)
3692            (inst fldl (ea-for-lf-stack x)))
3693           (descriptor-reg
3694            (inst fstp fr0)
3695            (inst fldl (ea-for-lf-desc x)))))
3696       ;; Neither x or y are in either fr0 or fr1
3697       (t
3698        ;; Load y then x
3699        (inst fstp fr0)
3700        (inst fstp fr0)
3701        (sc-case y
3702           (long-reg
3703            (inst fldd (make-random-tn :kind :normal
3704                                       :sc (sc-or-lose 'double-reg)
3705                                       :offset (- (tn-offset y) 2))))
3706           (long-stack
3707            (inst fldl (ea-for-lf-stack y)))
3708           (descriptor-reg
3709            (inst fldl (ea-for-lf-desc y))))
3710        ;; Load x to fr0
3711        (sc-case x
3712           (long-reg
3713            (inst fldd (make-random-tn :kind :normal
3714                                       :sc (sc-or-lose 'double-reg)
3715                                       :offset (1- (tn-offset x)))))
3716           (long-stack
3717            (inst fldl (ea-for-lf-stack x)))
3718           (descriptor-reg
3719            (inst fldl (ea-for-lf-desc x))))))
3720
3721      ;; Now have x at fr0; and y at fr1
3722      (inst fscale)
3723      (unless (zerop (tn-offset r))
3724              (inst fstd r))))
3725
3726 (define-vop (flog1p)
3727   (:translate %log1p)
3728   (:args (x :scs (long-reg) :to :result))
3729   (:temporary (:sc long-reg :offset fr0-offset
3730                    :from :argument :to :result) fr0)
3731   (:temporary (:sc long-reg :offset fr1-offset
3732                    :from :argument :to :result) fr1)
3733   (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3734   (:results (y :scs (long-reg)))
3735   (:arg-types long-float)
3736   (:result-types long-float)
3737   (:policy :fast-safe)
3738   ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3739   ;;   Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3740   ;;   an enormous PROGN above. Still, it would be probably be good to
3741   ;;   add some code to warn about redefining VOPs.
3742   (:note "inline log1p function")
3743   (:ignore temp)
3744   (:generator 5
3745      ;; x is in a FP reg, not fr0, fr1.
3746      (inst fstp fr0)
3747      (inst fstp fr0)
3748      (inst fldd (make-random-tn :kind :normal
3749                                 :sc (sc-or-lose 'double-reg)
3750                                 :offset (- (tn-offset x) 2)))
3751      ;; Check the range
3752      (inst push #x3e947ae1)     ; Constant 0.29
3753      (inst fabs)
3754      (inst fld (make-ea :dword :base esp-tn))
3755      (inst fcompp)
3756      (inst add esp-tn 4)
3757      (inst fnstsw)                      ; status word to ax
3758      (inst and ah-tn #x45)
3759      (inst jmp :z WITHIN-RANGE)
3760      ;; Out of range for fyl2xp1.
3761      (inst fld1)
3762      (inst faddd (make-random-tn :kind :normal
3763                                  :sc (sc-or-lose 'double-reg)
3764                                  :offset (- (tn-offset x) 1)))
3765      (inst fldln2)
3766      (inst fxch fr1)
3767      (inst fyl2x)
3768      (inst jmp DONE)
3769
3770      WITHIN-RANGE
3771      (inst fldln2)
3772      (inst fldd (make-random-tn :kind :normal
3773                                 :sc (sc-or-lose 'double-reg)
3774                                 :offset (- (tn-offset x) 1)))
3775      (inst fyl2xp1)
3776      DONE
3777      (inst fld fr0)
3778      (case (tn-offset y)
3779        ((0 1))
3780        (t (inst fstd y)))))
3781
3782 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3783 ;;; instruction and a range check can be avoided.
3784 (define-vop (flog1p-pentium)
3785   (:translate %log1p)
3786   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3787   (:temporary (:sc long-reg :offset fr0-offset
3788                    :from :argument :to :result) fr0)
3789   (:temporary (:sc long-reg :offset fr1-offset
3790                    :from :argument :to :result) fr1)
3791   (:results (y :scs (long-reg)))
3792   (:arg-types long-float)
3793   (:result-types long-float)
3794   (:policy :fast-safe)
3795   (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3796   (:note "inline log1p function")
3797   (:generator 5
3798      (sc-case x
3799         (long-reg
3800          (case (tn-offset x)
3801             (0
3802              ;; x is in fr0
3803              (inst fstp fr1)
3804              (inst fldln2)
3805              (inst fxch fr1))
3806             (1
3807              ;; x is in fr1
3808              (inst fstp fr0)
3809              (inst fldln2)
3810              (inst fxch fr1))
3811             (t
3812              ;; x is in a FP reg, not fr0 or fr1
3813              (inst fstp fr0)
3814              (inst fstp fr0)
3815              (inst fldln2)
3816              (inst fldd (make-random-tn :kind :normal
3817                                         :sc (sc-or-lose 'double-reg)
3818                                         :offset (1- (tn-offset x)))))))
3819         ((long-stack descriptor-reg)
3820          (inst fstp fr0)
3821          (inst fstp fr0)
3822          (inst fldln2)
3823          (if (sc-is x long-stack)
3824              (inst fldl (ea-for-lf-stack x))
3825            (inst fldl (ea-for-lf-desc x)))))
3826      (inst fyl2xp1)
3827      (inst fld fr0)
3828      (case (tn-offset y)
3829        ((0 1))
3830        (t (inst fstd y)))))
3831
3832 (define-vop (flogb)
3833   (:translate %logb)
3834   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3835   (:temporary (:sc long-reg :offset fr0-offset
3836                    :from :argument :to :result) fr0)
3837   (:temporary (:sc long-reg :offset fr1-offset
3838                    :from :argument :to :result) fr1)
3839   (:results (y :scs (long-reg)))
3840   (:arg-types long-float)
3841   (:result-types long-float)
3842   (:policy :fast-safe)
3843   (:note "inline logb function")
3844   (:vop-var vop)
3845   (:save-p :compute-only)
3846   (:generator 5
3847      (note-this-location vop :internal-error)
3848      (sc-case x
3849         (long-reg
3850          (case (tn-offset x)
3851             (0
3852              ;; x is in fr0
3853              (inst fstp fr1))
3854             (1
3855              ;; x is in fr1
3856              (inst fstp fr0))
3857             (t
3858              ;; x is in a FP reg, not fr0 or fr1
3859              (inst fstp fr0)
3860              (inst fstp fr0)
3861              (inst fldd (make-random-tn :kind :normal
3862                                         :sc (sc-or-lose 'double-reg)
3863                                         :offset (- (tn-offset x) 2))))))
3864         ((long-stack descriptor-reg)
3865          (inst fstp fr0)
3866          (inst fstp fr0)
3867          (if (sc-is x long-stack)
3868              (inst fldl (ea-for-lf-stack x))
3869            (inst fldl (ea-for-lf-desc x)))))
3870      (inst fxtract)
3871      (case (tn-offset y)
3872        (0
3873         (inst fxch fr1))
3874        (1)
3875        (t (inst fxch fr1)
3876           (inst fstd y)))))
3877
3878 (define-vop (fatan)
3879   (:translate %atan)
3880   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3881   (:temporary (:sc long-reg :offset fr0-offset
3882                    :from (:argument 0) :to :result) fr0)
3883   (:temporary (:sc long-reg :offset fr1-offset
3884                    :from (:argument 0) :to :result) fr1)
3885   (:results (r :scs (long-reg)))
3886   (:arg-types long-float)
3887   (:result-types long-float)
3888   (:policy :fast-safe)
3889   (:note "inline atan function")
3890   (:vop-var vop)
3891   (:save-p :compute-only)
3892   (:generator 5
3893      (note-this-location vop :internal-error)
3894      ;; Setup x in fr1 and 1.0 in fr0
3895      (cond
3896       ;; x in fr0
3897       ((and (sc-is x long-reg) (zerop (tn-offset x)))
3898        (inst fstp fr1))
3899       ;; x in fr1
3900       ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3901        (inst fstp fr0))
3902       ;; x not in fr0 or fr1
3903       (t
3904        ;; Load x then 1.0
3905        (inst fstp fr0)
3906        (inst fstp fr0)
3907        (sc-case x
3908           (long-reg
3909            (inst fldd (make-random-tn :kind :normal
3910                                       :sc (sc-or-lose 'double-reg)
3911                                       :offset (- (tn-offset x) 2))))
3912           (long-stack
3913            (inst fldl (ea-for-lf-stack x)))
3914           (descriptor-reg
3915            (inst fldl (ea-for-lf-desc x))))))
3916      (inst fld1)
3917      ;; Now have x at fr1; and 1.0 at fr0
3918      (inst fpatan)
3919      (inst fld fr0)
3920      (case (tn-offset r)
3921        ((0 1))
3922        (t (inst fstd r)))))
3923
3924 (define-vop (fatan2)
3925   (:translate %atan2)
3926   (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3927          (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3928   (:temporary (:sc long-reg :offset fr0-offset
3929                    :from (:argument 1) :to :result) fr0)
3930   (:temporary (:sc long-reg :offset fr1-offset
3931                    :from (:argument 0) :to :result) fr1)
3932   (:results (r :scs (long-reg)))
3933   (:arg-types long-float long-float)
3934   (:result-types long-float)
3935   (:policy :fast-safe)
3936   (:note "inline atan2 function")
3937   (:vop-var vop)
3938   (:save-p :compute-only)
3939   (:generator 5
3940      (note-this-location vop :internal-error)
3941      ;; Setup x in fr1 and y in fr0
3942      (cond
3943       ;; y in fr0; x in fr1
3944       ((and (sc-is y long-reg) (zerop (tn-offset y))
3945             (sc-is x long-reg) (= 1 (tn-offset x))))
3946       ;; x in fr1; y not in fr0
3947       ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3948        ;; Load y to fr0
3949        (sc-case y
3950           (long-reg
3951            (copy-fp-reg-to-fr0 y))
3952           (long-stack
3953            (inst fstp fr0)
3954            (inst fldl (ea-for-lf-stack y)))
3955           (descriptor-reg
3956            (inst fstp fr0)
3957            (inst fldl (ea-for-lf-desc y)))))
3958       ;; y in fr0; x not in fr1
3959       ((and (sc-is y long-reg) (zerop (tn-offset y)))
3960        (inst fxch fr1)
3961        ;; Now load x to fr0
3962        (sc-case x
3963           (long-reg
3964            (copy-fp-reg-to-fr0 x))
3965           (long-stack
3966            (inst fstp fr0)
3967            (inst fldl (ea-for-lf-stack x)))
3968           (descriptor-reg
3969            (inst fstp fr0)
3970            (inst fldl (ea-for-lf-desc x))))
3971        (inst fxch fr1))
3972       ;; y in fr1; x not in fr1
3973       ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3974        ;; Load x to fr0
3975        (sc-case x
3976           (long-reg
3977            (copy-fp-reg-to-fr0 x))
3978           (long-stack
3979            (inst fstp fr0)
3980            (inst fldl (ea-for-lf-stack x)))
3981           (descriptor-reg
3982            (inst fstp fr0)
3983            (inst fldl (ea-for-lf-desc x))))
3984        (inst fxch fr1))
3985       ;; x in fr0;
3986       ((and (sc-is x long-reg) (zerop (tn-offset x)))
3987        (inst fxch fr1)
3988        ;; Now load y to fr0
3989        (sc-case y
3990           (long-reg
3991            (copy-fp-reg-to-fr0 y))
3992           (long-stack
3993            (inst fstp fr0)
3994            (inst fldl (ea-for-lf-stack y)))
3995           (descriptor-reg
3996            (inst fstp fr0)
3997            (inst fldl (ea-for-lf-desc y)))))
3998       ;; Neither y or x are in either fr0 or fr1
3999       (t
4000        ;; Load x then y
4001        (inst fstp fr0)
4002        (inst fstp fr0)
4003        (sc-case x
4004           (long-reg
4005            (inst fldd (make-random-tn :kind :normal
4006                                       :sc (sc-or-lose 'double-reg)
4007                                       :offset (- (tn-offset x) 2))))
4008           (long-stack
4009            (inst fldl (ea-for-lf-stack x)))
4010           (descriptor-reg
4011            (inst fldl (ea-for-lf-desc x))))
4012        ;; Load y to fr0
4013        (sc-case y
4014           (long-reg
4015            (inst fldd (make-random-tn :kind :normal
4016                                       :sc (sc-or-lose 'double-reg)
4017                                       :offset (1- (tn-offset y)))))
4018           (long-stack
4019            (inst fldl (ea-for-lf-stack y)))
4020           (descriptor-reg
4021            (inst fldl (ea-for-lf-desc y))))))
4022
4023      ;; Now have y at fr0; and x at fr1
4024      (inst fpatan)
4025      (inst fld fr0)
4026      (case (tn-offset r)
4027        ((0 1))
4028        (t (inst fstd r)))))
4029
4030 ) ; PROGN #!+LONG-FLOAT
4031 \f
4032 ;;;; complex float VOPs
4033
4034 (define-vop (make-complex-single-float)
4035   (:translate complex)
4036   (:args (real :scs (single-reg) :to :result :target r
4037                :load-if (not (location= real r)))
4038          (imag :scs (single-reg) :to :save))
4039   (:arg-types single-float single-float)
4040   (:results (r :scs (complex-single-reg) :from (:argument 0)
4041                :load-if (not (sc-is r complex-single-stack))))
4042   (:result-types complex-single-float)
4043   (:note "inline complex single-float creation")
4044   (:policy :fast-safe)
4045   (:generator 5
4046     (sc-case r
4047       (complex-single-reg
4048        (let ((r-real (complex-double-reg-real-tn r)))
4049          (unless (location= real r-real)
4050            (cond ((zerop (tn-offset r-real))
4051                   (copy-fp-reg-to-fr0 real))
4052                  ((zerop (tn-offset real))
4053                   (inst fstd r-real))
4054                  (t
4055                   (inst fxch real)
4056                   (inst fstd r-real)
4057                   (inst fxch real)))))
4058        (let ((r-imag (complex-double-reg-imag-tn r)))
4059          (unless (location= imag r-imag)
4060            (cond ((zerop (tn-offset imag))
4061                   (inst fstd r-imag))
4062                  (t
4063                   (inst fxch imag)
4064                   (inst fstd r-imag)
4065                   (inst fxch imag))))))
4066       (complex-single-stack
4067        (unless (location= real r)
4068          (cond ((zerop (tn-offset real))
4069                 (inst fst (ea-for-csf-real-stack r)))
4070                (t
4071                 (inst fxch real)
4072                 (inst fst (ea-for-csf-real-stack r))
4073                 (inst fxch real))))
4074        (inst fxch imag)
4075        (inst fst (ea-for-csf-imag-stack r))
4076        (inst fxch imag)))))
4077
4078 (define-vop (make-complex-double-float)
4079   (:translate complex)
4080   (:args (real :scs (double-reg) :target r
4081                :load-if (not (location= real r)))
4082          (imag :scs (double-reg) :to :save))
4083   (:arg-types double-float double-float)
4084   (:results (r :scs (complex-double-reg) :from (:argument 0)
4085                :load-if (not (sc-is r complex-double-stack))))
4086   (:result-types complex-double-float)
4087   (:note "inline complex double-float creation")
4088   (:policy :fast-safe)
4089   (:generator 5
4090     (sc-case r
4091       (complex-double-reg
4092        (let ((r-real (complex-double-reg-real-tn r)))
4093          (unless (location= real r-real)
4094            (cond ((zerop (tn-offset r-real))
4095                   (copy-fp-reg-to-fr0 real))
4096                  ((zerop (tn-offset real))
4097                   (inst fstd r-real))
4098                  (t
4099                   (inst fxch real)
4100                   (inst fstd r-real)
4101                   (inst fxch real)))))
4102        (let ((r-imag (complex-double-reg-imag-tn r)))
4103          (unless (location= imag r-imag)
4104            (cond ((zerop (tn-offset imag))
4105                   (inst fstd r-imag))
4106                  (t
4107                   (inst fxch imag)
4108                   (inst fstd r-imag)
4109                   (inst fxch imag))))))
4110       (complex-double-stack
4111        (unless (location= real r)
4112          (cond ((zerop (tn-offset real))
4113                 (inst fstd (ea-for-cdf-real-stack r)))
4114                (t
4115                 (inst fxch real)
4116                 (inst fstd (ea-for-cdf-real-stack r))
4117                 (inst fxch real))))
4118        (inst fxch imag)
4119        (inst fstd (ea-for-cdf-imag-stack r))
4120        (inst fxch imag)))))
4121
4122 #!+long-float
4123 (define-vop (make-complex-long-float)
4124   (:translate complex)
4125   (:args (real :scs (long-reg) :target r
4126                :load-if (not (location= real r)))
4127          (imag :scs (long-reg) :to :save))
4128   (:arg-types long-float long-float)
4129   (:results (r :scs (complex-long-reg) :from (:argument 0)
4130                :load-if (not (sc-is r complex-long-stack))))
4131   (:result-types complex-long-float)
4132   (:note "inline complex long-float creation")
4133   (:policy :fast-safe)
4134   (:generator 5
4135     (sc-case r
4136       (complex-long-reg
4137        (let ((r-real (complex-double-reg-real-tn r)))
4138          (unless (location= real r-real)
4139            (cond ((zerop (tn-offset r-real))
4140                   (copy-fp-reg-to-fr0 real))
4141                  ((zerop (tn-offset real))
4142                   (inst fstd r-real))
4143                  (t
4144                   (inst fxch real)
4145                   (inst fstd r-real)
4146                   (inst fxch real)))))
4147        (let ((r-imag (complex-double-reg-imag-tn r)))
4148          (unless (location= imag r-imag)
4149            (cond ((zerop (tn-offset imag))
4150                   (inst fstd r-imag))
4151                  (t
4152                   (inst fxch imag)
4153                   (inst fstd r-imag)
4154                   (inst fxch imag))))))
4155       (complex-long-stack
4156        (unless (location= real r)
4157          (cond ((zerop (tn-offset real))
4158                 (store-long-float (ea-for-clf-real-stack r)))
4159                (t
4160                 (inst fxch real)
4161                 (store-long-float (ea-for-clf-real-stack r))
4162                 (inst fxch real))))
4163        (inst fxch imag)
4164        (store-long-float (ea-for-clf-imag-stack r))
4165        (inst fxch imag)))))
4166
4167
4168 (define-vop (complex-float-value)
4169   (:args (x :target r))
4170   (:results (r))
4171   (:variant-vars offset)
4172   (:policy :fast-safe)
4173   (:generator 3
4174     (cond ((sc-is x complex-single-reg complex-double-reg
4175                   #!+long-float complex-long-reg)
4176            (let ((value-tn
4177                   (make-random-tn :kind :normal
4178                                   :sc (sc-or-lose 'double-reg)
4179                                   :offset (+ offset (tn-offset x)))))
4180              (unless (location= value-tn r)
4181                (cond ((zerop (tn-offset r))
4182                       (copy-fp-reg-to-fr0 value-tn))
4183                      ((zerop (tn-offset value-tn))
4184                       (inst fstd r))
4185                      (t
4186                       (inst fxch value-tn)
4187                       (inst fstd r)
4188                       (inst fxch value-tn))))))
4189           ((sc-is r single-reg)
4190            (let ((ea (sc-case x
4191                        (complex-single-stack
4192                         (ecase offset
4193                           (0 (ea-for-csf-real-stack x))
4194                           (1 (ea-for-csf-imag-stack x))))
4195                        (descriptor-reg
4196                         (ecase offset
4197                           (0 (ea-for-csf-real-desc x))
4198                           (1 (ea-for-csf-imag-desc x)))))))
4199              (with-empty-tn@fp-top(r)
4200                (inst fld ea))))
4201           ((sc-is r double-reg)
4202            (let ((ea (sc-case x
4203                        (complex-double-stack
4204                         (ecase offset
4205                           (0 (ea-for-cdf-real-stack x))
4206                           (1 (ea-for-cdf-imag-stack x))))
4207                        (descriptor-reg
4208                         (ecase offset
4209                           (0 (ea-for-cdf-real-desc x))
4210                           (1 (ea-for-cdf-imag-desc x)))))))
4211              (with-empty-tn@fp-top(r)
4212                (inst fldd ea))))
4213           #!+long-float
4214           ((sc-is r long-reg)
4215            (let ((ea (sc-case x
4216                        (complex-long-stack
4217                         (ecase offset
4218                           (0 (ea-for-clf-real-stack x))
4219                           (1 (ea-for-clf-imag-stack x))))
4220                        (descriptor-reg
4221                         (ecase offset
4222                           (0 (ea-for-clf-real-desc x))
4223                           (1 (ea-for-clf-imag-desc x)))))))
4224              (with-empty-tn@fp-top(r)
4225                (inst fldl ea))))
4226           (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4227
4228 (define-vop (realpart/complex-single-float complex-float-value)
4229   (:translate realpart)
4230   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4231             :target r))
4232   (:arg-types complex-single-float)
4233   (:results (r :scs (single-reg)))
4234   (:result-types single-float)
4235   (:note "complex float realpart")
4236   (:variant 0))
4237
4238 (define-vop (realpart/complex-double-float complex-float-value)
4239   (:translate realpart)
4240   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4241             :target r))
4242   (:arg-types complex-double-float)
4243   (:results (r :scs (double-reg)))
4244   (:result-types double-float)
4245   (:note "complex float realpart")
4246   (:variant 0))
4247
4248 #!+long-float
4249 (define-vop (realpart/complex-long-float complex-float-value)
4250   (:translate realpart)
4251   (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4252             :target r))
4253   (:arg-types complex-long-float)
4254   (:results (r :scs (long-reg)))
4255   (:result-types long-float)
4256   (:note "complex float realpart")
4257   (:variant 0))
4258
4259 (define-vop (imagpart/complex-single-float complex-float-value)
4260   (:translate imagpart)
4261   (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4262             :target r))
4263   (:arg-types complex-single-float)
4264   (:results (r :scs (single-reg)))
4265   (:result-types single-float)
4266   (:note "complex float imagpart")
4267   (:variant 1))
4268
4269 (define-vop (imagpart/complex-double-float complex-float-value)
4270   (:translate imagpart)
4271   (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4272             :target r))
4273   (:arg-types complex-double-float)
4274   (:results (r :scs (double-reg)))
4275   (:result-types double-float)
4276   (:note "complex float imagpart")
4277   (:variant 1))
4278
4279 #!+long-float
4280 (define-vop (imagpart/complex-long-float complex-float-value)
4281   (:translate imagpart)
4282   (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4283             :target r))
4284   (:arg-types complex-long-float)
4285   (:results (r :scs (long-reg)))
4286   (:result-types long-float)
4287   (:note "complex float imagpart")
4288   (:variant 1))
4289 \f
4290 ;;; hack dummy VOPs to bias the representation selection of their
4291 ;;; arguments towards a FP register, which can help avoid consing at
4292 ;;; inappropriate locations
4293 (defknown double-float-reg-bias (double-float) (values))
4294 (define-vop (double-float-reg-bias)
4295   (:translate double-float-reg-bias)
4296   (:args (x :scs (double-reg double-stack) :load-if nil))
4297   (:arg-types double-float)
4298   (:policy :fast-safe)
4299   (:note "inline dummy FP register bias")
4300   (:ignore x)
4301   (:generator 0))
4302 (defknown single-float-reg-bias (single-float) (values))
4303 (define-vop (single-float-reg-bias)
4304   (:translate single-float-reg-bias)
4305   (:args (x :scs (single-reg single-stack) :load-if nil))
4306   (:arg-types single-float)
4307   (:policy :fast-safe)
4308   (:note "inline dummy FP register bias")
4309   (:ignore x)
4310   (:generator 0))