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