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