1 ;;;; floating point support for the x86
3 ;;;; This software is part of the SBCL system. See the README file for
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.
14 (macrolet ((ea-for-xf-desc (tn slot)
15 `(make-ea-for-object-slot ,tn ,slot other-pointer-lowtag)))
16 (defun ea-for-sf-desc (tn)
17 (ea-for-xf-desc tn single-float-value-slot))
18 (defun ea-for-df-desc (tn)
19 (ea-for-xf-desc tn double-float-value-slot))
21 (defun ea-for-lf-desc (tn)
22 (ea-for-xf-desc tn long-float-value-slot))
24 (defun ea-for-csf-real-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-real-slot))
26 (defun ea-for-csf-imag-desc (tn)
27 (ea-for-xf-desc tn complex-single-float-imag-slot))
28 (defun ea-for-cdf-real-desc (tn)
29 (ea-for-xf-desc tn complex-double-float-real-slot))
30 (defun ea-for-cdf-imag-desc (tn)
31 (ea-for-xf-desc tn complex-double-float-imag-slot))
33 (defun ea-for-clf-real-desc (tn)
34 (ea-for-xf-desc tn complex-long-float-real-slot))
36 (defun ea-for-clf-imag-desc (tn)
37 (ea-for-xf-desc tn complex-long-float-imag-slot)))
39 (macrolet ((ea-for-xf-stack (tn kind)
42 :disp (frame-byte-offset
44 (ecase ,kind (:single 0) (:double 1) (:long 2)))))))
45 (defun ea-for-sf-stack (tn)
46 (ea-for-xf-stack tn :single))
47 (defun ea-for-df-stack (tn)
48 (ea-for-xf-stack tn :double))
50 (defun ea-for-lf-stack (tn)
51 (ea-for-xf-stack tn :long)))
53 ;;; Telling the FPU to wait is required in order to make signals occur
54 ;;; at the expected place, but naturally slows things down.
56 ;;; NODE is the node whose compilation policy controls the decision
57 ;;; whether to just blast through carelessly or carefully emit wait
58 ;;; instructions and whatnot.
60 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
61 ;;; #'NOTE-NEXT-INSTRUCTION.
63 ;;; Until 2004-03-15, the implementation of this was buggy; it
64 ;;; unconditionally emitted the WAIT instruction. It turns out that
65 ;;; this is the right thing to do anyway; omitting them can lead to
66 ;;; system corruption on conforming code. -- CSR
67 (defun maybe-fp-wait (node &optional note-next-instruction)
68 (declare (ignore node))
70 (when (policy node (or (= debug 3) (> safety speed))))
71 (when note-next-instruction
72 (note-next-instruction note-next-instruction :internal-error))
75 ;;; complex float stack EAs
76 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
79 :disp (frame-byte-offset
86 (ecase ,slot (:real 1) (:imag 2))))))))
87 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
88 (ea-for-cxf-stack tn :single :real base))
89 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
90 (ea-for-cxf-stack tn :single :imag base))
91 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
92 (ea-for-cxf-stack tn :double :real base))
93 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
94 (ea-for-cxf-stack tn :double :imag base))
96 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
97 (ea-for-cxf-stack tn :long :real base))
99 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
100 (ea-for-cxf-stack tn :long :imag base)))
102 ;;; Abstract out the copying of a FP register to the FP stack top, and
103 ;;; provide two alternatives for its implementation. Note: it's not
104 ;;; necessary to distinguish between a single or double register move
107 ;;; Using a Pop then load.
108 (defun copy-fp-reg-to-fr0 (reg)
109 (aver (not (zerop (tn-offset reg))))
111 (inst fld (make-random-tn :kind :normal
112 :sc (sc-or-lose 'double-reg)
113 :offset (1- (tn-offset reg)))))
114 ;;; Using Fxch then Fst to restore the original reg contents.
116 (defun copy-fp-reg-to-fr0 (reg)
117 (aver (not (zerop (tn-offset reg))))
121 ;;; The x86 can't store a long-float to memory without popping the
122 ;;; stack and marking a register as empty, so it is necessary to
123 ;;; restore the register from memory.
125 (defun store-long-float (ea)
131 ;;; X is source, Y is destination.
132 (define-move-fun (load-single 2) (vop x y)
133 ((single-stack) (single-reg))
134 (with-empty-tn@fp-top(y)
135 (inst fld (ea-for-sf-stack x))))
137 (define-move-fun (store-single 2) (vop x y)
138 ((single-reg) (single-stack))
139 (cond ((zerop (tn-offset x))
140 (inst fst (ea-for-sf-stack y)))
143 (inst fst (ea-for-sf-stack y))
144 ;; This may not be necessary as ST0 is likely invalid now.
147 (define-move-fun (load-double 2) (vop x y)
148 ((double-stack) (double-reg))
149 (with-empty-tn@fp-top(y)
150 (inst fldd (ea-for-df-stack x))))
152 (define-move-fun (store-double 2) (vop x y)
153 ((double-reg) (double-stack))
154 (cond ((zerop (tn-offset x))
155 (inst fstd (ea-for-df-stack y)))
158 (inst fstd (ea-for-df-stack y))
159 ;; This may not be necessary as ST0 is likely invalid now.
163 (define-move-fun (load-long 2) (vop x y)
164 ((long-stack) (long-reg))
165 (with-empty-tn@fp-top(y)
166 (inst fldl (ea-for-lf-stack x))))
169 (define-move-fun (store-long 2) (vop x y)
170 ((long-reg) (long-stack))
171 (cond ((zerop (tn-offset x))
172 (store-long-float (ea-for-lf-stack y)))
175 (store-long-float (ea-for-lf-stack y))
176 ;; This may not be necessary as ST0 is likely invalid now.
179 ;;; The i387 has instructions to load some useful constants. This
180 ;;; doesn't save much time but might cut down on memory access and
181 ;;; reduce the size of the constant vector (CV). Intel claims they are
182 ;;; stored in a more precise form on chip. Anyhow, might as well use
183 ;;; the feature. It can be turned off by hacking the
184 ;;; "immediate-constant-sc" in vm.lisp.
185 (eval-when (:compile-toplevel :execute)
186 (setf *read-default-float-format*
187 #!+long-float 'long-float #!-long-float 'double-float))
188 (define-move-fun (load-fp-constant 2) (vop x y)
189 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
190 (let ((value (tn-value x)))
191 (with-empty-tn@fp-top(y)
192 (cond ((or (eql value 0f0) (eql value 0d0) #!+long-float (eql value 0l0))
197 ((= value (coerce pi *read-default-float-format*))
200 ((= value (log 10e0 2e0))
203 ((= value (log 2.718281828459045235360287471352662e0 2e0))
206 ((= value (log 2e0 10e0))
209 ((= value (log 2e0 2.718281828459045235360287471352662e0))
211 (t (warn "ignoring bogus i387 constant ~A" value))))))
213 (define-move-fun (load-fp-immediate 2) (vop x y)
214 ((fp-single-immediate) (single-reg)
215 (fp-double-immediate) (double-reg))
216 (let ((value (register-inline-constant (tn-value x))))
217 (with-empty-tn@fp-top(y)
222 (inst fldd value))))))
223 (eval-when (:compile-toplevel :execute)
224 (setf *read-default-float-format* 'single-float))
226 ;;;; complex float move functions
228 (defun complex-single-reg-real-tn (x)
229 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
230 :offset (tn-offset x)))
231 (defun complex-single-reg-imag-tn (x)
232 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
233 :offset (1+ (tn-offset x))))
235 (defun complex-double-reg-real-tn (x)
236 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
237 :offset (tn-offset x)))
238 (defun complex-double-reg-imag-tn (x)
239 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
240 :offset (1+ (tn-offset x))))
243 (defun complex-long-reg-real-tn (x)
244 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
245 :offset (tn-offset x)))
247 (defun complex-long-reg-imag-tn (x)
248 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
249 :offset (1+ (tn-offset x))))
251 ;;; X is source, Y is destination.
252 (define-move-fun (load-complex-single 2) (vop x y)
253 ((complex-single-stack) (complex-single-reg))
254 (let ((real-tn (complex-single-reg-real-tn y)))
255 (with-empty-tn@fp-top (real-tn)
256 (inst fld (ea-for-csf-real-stack x))))
257 (let ((imag-tn (complex-single-reg-imag-tn y)))
258 (with-empty-tn@fp-top (imag-tn)
259 (inst fld (ea-for-csf-imag-stack x)))))
261 (define-move-fun (store-complex-single 2) (vop x y)
262 ((complex-single-reg) (complex-single-stack))
263 (let ((real-tn (complex-single-reg-real-tn x)))
264 (cond ((zerop (tn-offset real-tn))
265 (inst fst (ea-for-csf-real-stack y)))
268 (inst fst (ea-for-csf-real-stack y))
269 (inst fxch real-tn))))
270 (let ((imag-tn (complex-single-reg-imag-tn x)))
272 (inst fst (ea-for-csf-imag-stack y))
273 (inst fxch imag-tn)))
275 (define-move-fun (load-complex-double 2) (vop x y)
276 ((complex-double-stack) (complex-double-reg))
277 (let ((real-tn (complex-double-reg-real-tn y)))
278 (with-empty-tn@fp-top(real-tn)
279 (inst fldd (ea-for-cdf-real-stack x))))
280 (let ((imag-tn (complex-double-reg-imag-tn y)))
281 (with-empty-tn@fp-top(imag-tn)
282 (inst fldd (ea-for-cdf-imag-stack x)))))
284 (define-move-fun (store-complex-double 2) (vop x y)
285 ((complex-double-reg) (complex-double-stack))
286 (let ((real-tn (complex-double-reg-real-tn x)))
287 (cond ((zerop (tn-offset real-tn))
288 (inst fstd (ea-for-cdf-real-stack y)))
291 (inst fstd (ea-for-cdf-real-stack y))
292 (inst fxch real-tn))))
293 (let ((imag-tn (complex-double-reg-imag-tn x)))
295 (inst fstd (ea-for-cdf-imag-stack y))
296 (inst fxch imag-tn)))
299 (define-move-fun (load-complex-long 2) (vop x y)
300 ((complex-long-stack) (complex-long-reg))
301 (let ((real-tn (complex-long-reg-real-tn y)))
302 (with-empty-tn@fp-top(real-tn)
303 (inst fldl (ea-for-clf-real-stack x))))
304 (let ((imag-tn (complex-long-reg-imag-tn y)))
305 (with-empty-tn@fp-top(imag-tn)
306 (inst fldl (ea-for-clf-imag-stack x)))))
309 (define-move-fun (store-complex-long 2) (vop x y)
310 ((complex-long-reg) (complex-long-stack))
311 (let ((real-tn (complex-long-reg-real-tn x)))
312 (cond ((zerop (tn-offset real-tn))
313 (store-long-float (ea-for-clf-real-stack y)))
316 (store-long-float (ea-for-clf-real-stack y))
317 (inst fxch real-tn))))
318 (let ((imag-tn (complex-long-reg-imag-tn x)))
320 (store-long-float (ea-for-clf-imag-stack y))
321 (inst fxch imag-tn)))
326 ;;; float register to register moves
327 (define-vop (float-move)
332 (unless (location= x y)
333 (cond ((zerop (tn-offset y))
334 (copy-fp-reg-to-fr0 x))
335 ((zerop (tn-offset x))
342 (define-vop (single-move float-move)
343 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
344 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
345 (define-move-vop single-move :move (single-reg) (single-reg))
347 (define-vop (double-move float-move)
348 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
349 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
350 (define-move-vop double-move :move (double-reg) (double-reg))
353 (define-vop (long-move float-move)
354 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
355 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
357 (define-move-vop long-move :move (long-reg) (long-reg))
359 ;;; complex float register to register moves
360 (define-vop (complex-float-move)
361 (:args (x :target y :load-if (not (location= x y))))
362 (:results (y :load-if (not (location= x y))))
363 (:note "complex float move")
365 (unless (location= x y)
366 ;; Note the complex-float-regs are aligned to every second
367 ;; float register so there is not need to worry about overlap.
368 (let ((x-real (complex-double-reg-real-tn x))
369 (y-real (complex-double-reg-real-tn y)))
370 (cond ((zerop (tn-offset y-real))
371 (copy-fp-reg-to-fr0 x-real))
372 ((zerop (tn-offset x-real))
377 (inst fxch x-real))))
378 (let ((x-imag (complex-double-reg-imag-tn x))
379 (y-imag (complex-double-reg-imag-tn y)))
382 (inst fxch x-imag)))))
384 (define-vop (complex-single-move complex-float-move)
385 (:args (x :scs (complex-single-reg) :target y
386 :load-if (not (location= x y))))
387 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
388 (define-move-vop complex-single-move :move
389 (complex-single-reg) (complex-single-reg))
391 (define-vop (complex-double-move complex-float-move)
392 (:args (x :scs (complex-double-reg)
393 :target y :load-if (not (location= x y))))
394 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
395 (define-move-vop complex-double-move :move
396 (complex-double-reg) (complex-double-reg))
399 (define-vop (complex-long-move complex-float-move)
400 (:args (x :scs (complex-long-reg)
401 :target y :load-if (not (location= x y))))
402 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
404 (define-move-vop complex-long-move :move
405 (complex-long-reg) (complex-long-reg))
407 ;;; Move from float to a descriptor reg. allocating a new float
408 ;;; object in the process.
409 (define-vop (move-from-single)
410 (:args (x :scs (single-reg) :to :save))
411 (:results (y :scs (descriptor-reg)))
413 (:note "float to pointer coercion")
415 (with-fixed-allocation (y
417 single-float-size node)
419 (inst fst (ea-for-sf-desc y))))))
420 (define-move-vop move-from-single :move
421 (single-reg) (descriptor-reg))
423 (define-vop (move-from-double)
424 (:args (x :scs (double-reg) :to :save))
425 (:results (y :scs (descriptor-reg)))
427 (:note "float to pointer coercion")
429 (with-fixed-allocation (y
434 (inst fstd (ea-for-df-desc y))))))
435 (define-move-vop move-from-double :move
436 (double-reg) (descriptor-reg))
439 (define-vop (move-from-long)
440 (:args (x :scs (long-reg) :to :save))
441 (:results (y :scs (descriptor-reg)))
443 (:note "float to pointer coercion")
445 (with-fixed-allocation (y
450 (store-long-float (ea-for-lf-desc y))))))
452 (define-move-vop move-from-long :move
453 (long-reg) (descriptor-reg))
455 (define-vop (move-from-fp-constant)
456 (:args (x :scs (fp-constant)))
457 (:results (y :scs (descriptor-reg)))
459 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
460 (0f0 (load-symbol-value y *fp-constant-0f0*))
461 (1f0 (load-symbol-value y *fp-constant-1f0*))
462 (0d0 (load-symbol-value y *fp-constant-0d0*))
463 (1d0 (load-symbol-value y *fp-constant-1d0*))
465 (0l0 (load-symbol-value y *fp-constant-0l0*))
467 (1l0 (load-symbol-value y *fp-constant-1l0*))
469 (#.pi (load-symbol-value y *fp-constant-pi*))
471 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
473 (#.(log 2.718281828459045235360287471352662L0 2l0)
474 (load-symbol-value y *fp-constant-l2e*))
476 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
478 (#.(log 2l0 2.718281828459045235360287471352662L0)
479 (load-symbol-value y *fp-constant-ln2*)))))
480 (define-move-vop move-from-fp-constant :move
481 (fp-constant) (descriptor-reg))
483 ;;; Move from a descriptor to a float register.
484 (define-vop (move-to-single)
485 (:args (x :scs (descriptor-reg)))
486 (:results (y :scs (single-reg)))
487 (:note "pointer to float coercion")
489 (with-empty-tn@fp-top(y)
490 (inst fld (ea-for-sf-desc x)))))
491 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
493 (define-vop (move-to-double)
494 (:args (x :scs (descriptor-reg)))
495 (:results (y :scs (double-reg)))
496 (:note "pointer to float coercion")
498 (with-empty-tn@fp-top(y)
499 (inst fldd (ea-for-df-desc x)))))
500 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
503 (define-vop (move-to-long)
504 (:args (x :scs (descriptor-reg)))
505 (:results (y :scs (long-reg)))
506 (:note "pointer to float coercion")
508 (with-empty-tn@fp-top(y)
509 (inst fldl (ea-for-lf-desc x)))))
511 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
513 ;;; Move from complex float to a descriptor reg. allocating a new
514 ;;; complex float object in the process.
515 (define-vop (move-from-complex-single)
516 (:args (x :scs (complex-single-reg) :to :save))
517 (:results (y :scs (descriptor-reg)))
519 (:note "complex float to pointer coercion")
521 (with-fixed-allocation (y
522 complex-single-float-widetag
523 complex-single-float-size
525 (let ((real-tn (complex-single-reg-real-tn x)))
526 (with-tn@fp-top(real-tn)
527 (inst fst (ea-for-csf-real-desc y))))
528 (let ((imag-tn (complex-single-reg-imag-tn x)))
529 (with-tn@fp-top(imag-tn)
530 (inst fst (ea-for-csf-imag-desc y)))))))
531 (define-move-vop move-from-complex-single :move
532 (complex-single-reg) (descriptor-reg))
534 (define-vop (move-from-complex-double)
535 (:args (x :scs (complex-double-reg) :to :save))
536 (:results (y :scs (descriptor-reg)))
538 (:note "complex float to pointer coercion")
540 (with-fixed-allocation (y
541 complex-double-float-widetag
542 complex-double-float-size
544 (let ((real-tn (complex-double-reg-real-tn x)))
545 (with-tn@fp-top(real-tn)
546 (inst fstd (ea-for-cdf-real-desc y))))
547 (let ((imag-tn (complex-double-reg-imag-tn x)))
548 (with-tn@fp-top(imag-tn)
549 (inst fstd (ea-for-cdf-imag-desc y)))))))
550 (define-move-vop move-from-complex-double :move
551 (complex-double-reg) (descriptor-reg))
554 (define-vop (move-from-complex-long)
555 (:args (x :scs (complex-long-reg) :to :save))
556 (:results (y :scs (descriptor-reg)))
558 (:note "complex float to pointer coercion")
560 (with-fixed-allocation (y
561 complex-long-float-widetag
562 complex-long-float-size
564 (let ((real-tn (complex-long-reg-real-tn x)))
565 (with-tn@fp-top(real-tn)
566 (store-long-float (ea-for-clf-real-desc y))))
567 (let ((imag-tn (complex-long-reg-imag-tn x)))
568 (with-tn@fp-top(imag-tn)
569 (store-long-float (ea-for-clf-imag-desc y)))))))
571 (define-move-vop move-from-complex-long :move
572 (complex-long-reg) (descriptor-reg))
574 ;;; Move from a descriptor to a complex float register.
575 (macrolet ((frob (name sc format)
578 (:args (x :scs (descriptor-reg)))
579 (:results (y :scs (,sc)))
580 (:note "pointer to complex float coercion")
582 (let ((real-tn (complex-double-reg-real-tn y)))
583 (with-empty-tn@fp-top(real-tn)
585 (:single '((inst fld (ea-for-csf-real-desc x))))
586 (:double '((inst fldd (ea-for-cdf-real-desc x))))
588 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
589 (let ((imag-tn (complex-double-reg-imag-tn y)))
590 (with-empty-tn@fp-top(imag-tn)
592 (:single '((inst fld (ea-for-csf-imag-desc x))))
593 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
595 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
596 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
597 (frob move-to-complex-single complex-single-reg :single)
598 (frob move-to-complex-double complex-double-reg :double)
600 (frob move-to-complex-double complex-long-reg :long))
602 ;;;; the move argument vops
604 ;;;; Note these are also used to stuff fp numbers onto the c-call
605 ;;;; stack so the order is different than the lisp-stack.
607 ;;; the general MOVE-ARG VOP
608 (macrolet ((frob (name sc stack-sc format)
611 (:args (x :scs (,sc) :target y)
613 :load-if (not (sc-is y ,sc))))
615 (:note "float argument move")
616 (:generator ,(case format (:single 2) (:double 3) (:long 4))
619 (unless (location= x y)
620 (cond ((zerop (tn-offset y))
621 (copy-fp-reg-to-fr0 x))
622 ((zerop (tn-offset x))
629 (if (= (tn-offset fp) esp-offset)
631 (let* ((offset (* (tn-offset y) n-word-bytes))
632 (ea (make-ea :dword :base fp :disp offset)))
635 (:single '((inst fst ea)))
636 (:double '((inst fstd ea)))
638 (:long '((store-long-float ea))))))
642 :disp (frame-byte-offset
650 (:single '((inst fst ea)))
651 (:double '((inst fstd ea)))
653 (:long '((store-long-float ea)))))))))))
654 (define-move-vop ,name :move-arg
655 (,sc descriptor-reg) (,sc)))))
656 (frob move-single-float-arg single-reg single-stack :single)
657 (frob move-double-float-arg double-reg double-stack :double)
659 (frob move-long-float-arg long-reg long-stack :long))
661 ;;;; complex float MOVE-ARG VOP
662 (macrolet ((frob (name sc stack-sc format)
665 (:args (x :scs (,sc) :target y)
667 :load-if (not (sc-is y ,sc))))
669 (:note "complex float argument move")
670 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
673 (unless (location= x y)
674 (let ((x-real (complex-double-reg-real-tn x))
675 (y-real (complex-double-reg-real-tn y)))
676 (cond ((zerop (tn-offset y-real))
677 (copy-fp-reg-to-fr0 x-real))
678 ((zerop (tn-offset x-real))
683 (inst fxch x-real))))
684 (let ((x-imag (complex-double-reg-imag-tn x))
685 (y-imag (complex-double-reg-imag-tn y)))
688 (inst fxch x-imag))))
690 (let ((real-tn (complex-double-reg-real-tn x)))
691 (cond ((zerop (tn-offset real-tn))
695 (ea-for-csf-real-stack y fp))))
698 (ea-for-cdf-real-stack y fp))))
702 (ea-for-clf-real-stack y fp))))))
708 (ea-for-csf-real-stack y fp))))
711 (ea-for-cdf-real-stack y fp))))
715 (ea-for-clf-real-stack y fp)))))
716 (inst fxch real-tn))))
717 (let ((imag-tn (complex-double-reg-imag-tn x)))
721 '((inst fst (ea-for-csf-imag-stack y fp))))
723 '((inst fstd (ea-for-cdf-imag-stack y fp))))
727 (ea-for-clf-imag-stack y fp)))))
728 (inst fxch imag-tn))))))
729 (define-move-vop ,name :move-arg
730 (,sc descriptor-reg) (,sc)))))
731 (frob move-complex-single-float-arg
732 complex-single-reg complex-single-stack :single)
733 (frob move-complex-double-float-arg
734 complex-double-reg complex-double-stack :double)
736 (frob move-complex-long-float-arg
737 complex-long-reg complex-long-stack :long))
739 (define-move-vop move-arg :move-arg
740 (single-reg double-reg #!+long-float long-reg
741 complex-single-reg complex-double-reg #!+long-float complex-long-reg)
747 ;;; dtc: the floating point arithmetic vops
749 ;;; Note: Although these can accept x and y on the stack or pointed to
750 ;;; from a descriptor register, they will work with register loading
751 ;;; without these. Same deal with the result - it need only be a
752 ;;; register. When load-tns are needed they will probably be in ST0
753 ;;; and the code below should be able to correctly handle all cases.
755 ;;; However it seems to produce better code if all arg. and result
756 ;;; options are used; on the P86 there is no extra cost in using a
757 ;;; memory operand to the FP instructions - not so on the PPro.
759 ;;; It may also be useful to handle constant args?
761 ;;; 22-Jul-97: descriptor args lose in some simple cases when
762 ;;; a function result computed in a loop. Then Python insists
763 ;;; on consing the intermediate values! For example
766 ;;; (declare (type (simple-array double-float (*)) a)
769 ;;; (declare (type double-float sum))
771 ;;; (incf sum (* (aref a i)(aref a i))))
774 ;;; So, disabling descriptor args until this can be fixed elsewhere.
776 ((frob (op fop-sti fopr-sti
778 fopd foprd dname dcost
780 #!-long-float (declare (ignore lcost lname))
784 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
786 (y :scs (single-reg single-stack #+nil descriptor-reg)
788 (:temporary (:sc single-reg :offset fr0-offset
789 :from :eval :to :result) fr0)
790 (:results (r :scs (single-reg single-stack)))
791 (:arg-types single-float single-float)
792 (:result-types single-float)
794 (:note "inline float arithmetic")
796 (:save-p :compute-only)
799 ;; Handle a few special cases
801 ;; x, y, and r are the same register.
802 ((and (sc-is x single-reg) (location= x r) (location= y r))
803 (cond ((zerop (tn-offset r))
808 ;; XX the source register will not be valid.
809 (note-next-instruction vop :internal-error)
812 ;; x and r are the same register.
813 ((and (sc-is x single-reg) (location= x r))
814 (cond ((zerop (tn-offset r))
817 ;; ST(0) = ST(0) op ST(y)
820 ;; ST(0) = ST(0) op Mem
821 (inst ,fop (ea-for-sf-stack y)))
823 (inst ,fop (ea-for-sf-desc y)))))
828 (unless (zerop (tn-offset y))
829 (copy-fp-reg-to-fr0 y)))
830 ((single-stack descriptor-reg)
832 (if (sc-is y single-stack)
833 (inst fld (ea-for-sf-stack y))
834 (inst fld (ea-for-sf-desc y)))))
835 ;; ST(i) = ST(i) op ST0
837 (maybe-fp-wait node vop))
838 ;; y and r are the same register.
839 ((and (sc-is y single-reg) (location= y r))
840 (cond ((zerop (tn-offset r))
843 ;; ST(0) = ST(x) op ST(0)
846 ;; ST(0) = Mem op ST(0)
847 (inst ,fopr (ea-for-sf-stack x)))
849 (inst ,fopr (ea-for-sf-desc x)))))
854 (unless (zerop (tn-offset x))
855 (copy-fp-reg-to-fr0 x)))
856 ((single-stack descriptor-reg)
858 (if (sc-is x single-stack)
859 (inst fld (ea-for-sf-stack x))
860 (inst fld (ea-for-sf-desc x)))))
861 ;; ST(i) = ST(0) op ST(i)
863 (maybe-fp-wait node vop))
866 ;; Get the result to ST0.
868 ;; Special handling is needed if x or y are in ST0, and
869 ;; simpler code is generated.
872 ((and (sc-is x single-reg) (zerop (tn-offset x)))
878 (inst ,fop (ea-for-sf-stack y)))
880 (inst ,fop (ea-for-sf-desc y)))))
882 ((and (sc-is y single-reg) (zerop (tn-offset y)))
888 (inst ,fopr (ea-for-sf-stack x)))
890 (inst ,fopr (ea-for-sf-desc x)))))
895 (copy-fp-reg-to-fr0 x))
898 (inst fld (ea-for-sf-stack x)))
901 (inst fld (ea-for-sf-desc x))))
907 (inst ,fop (ea-for-sf-stack y)))
909 (inst ,fop (ea-for-sf-desc y))))))
911 (note-next-instruction vop :internal-error)
913 ;; Finally save the result.
916 (cond ((zerop (tn-offset r))
917 (maybe-fp-wait node))
921 (inst fst (ea-for-sf-stack r))))))))
925 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
927 (y :scs (double-reg double-stack #+nil descriptor-reg)
929 (:temporary (:sc double-reg :offset fr0-offset
930 :from :eval :to :result) fr0)
931 (:results (r :scs (double-reg double-stack)))
932 (:arg-types double-float double-float)
933 (:result-types double-float)
935 (:note "inline float arithmetic")
937 (:save-p :compute-only)
940 ;; Handle a few special cases.
942 ;; x, y, and r are the same register.
943 ((and (sc-is x double-reg) (location= x r) (location= y r))
944 (cond ((zerop (tn-offset r))
949 ;; XX the source register will not be valid.
950 (note-next-instruction vop :internal-error)
953 ;; x and r are the same register.
954 ((and (sc-is x double-reg) (location= x r))
955 (cond ((zerop (tn-offset r))
958 ;; ST(0) = ST(0) op ST(y)
961 ;; ST(0) = ST(0) op Mem
962 (inst ,fopd (ea-for-df-stack y)))
964 (inst ,fopd (ea-for-df-desc y)))))
969 (unless (zerop (tn-offset y))
970 (copy-fp-reg-to-fr0 y)))
971 ((double-stack descriptor-reg)
973 (if (sc-is y double-stack)
974 (inst fldd (ea-for-df-stack y))
975 (inst fldd (ea-for-df-desc y)))))
976 ;; ST(i) = ST(i) op ST0
978 (maybe-fp-wait node vop))
979 ;; y and r are the same register.
980 ((and (sc-is y double-reg) (location= y r))
981 (cond ((zerop (tn-offset r))
984 ;; ST(0) = ST(x) op ST(0)
987 ;; ST(0) = Mem op ST(0)
988 (inst ,foprd (ea-for-df-stack x)))
990 (inst ,foprd (ea-for-df-desc x)))))
995 (unless (zerop (tn-offset x))
996 (copy-fp-reg-to-fr0 x)))
997 ((double-stack descriptor-reg)
999 (if (sc-is x double-stack)
1000 (inst fldd (ea-for-df-stack x))
1001 (inst fldd (ea-for-df-desc x)))))
1002 ;; ST(i) = ST(0) op ST(i)
1003 (inst ,fopr-sti r)))
1004 (maybe-fp-wait node vop))
1007 ;; Get the result to ST0.
1009 ;; Special handling is needed if x or y are in ST0, and
1010 ;; simpler code is generated.
1013 ((and (sc-is x double-reg) (zerop (tn-offset x)))
1019 (inst ,fopd (ea-for-df-stack y)))
1021 (inst ,fopd (ea-for-df-desc y)))))
1023 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1029 (inst ,foprd (ea-for-df-stack x)))
1031 (inst ,foprd (ea-for-df-desc x)))))
1036 (copy-fp-reg-to-fr0 x))
1039 (inst fldd (ea-for-df-stack x)))
1042 (inst fldd (ea-for-df-desc x))))
1048 (inst ,fopd (ea-for-df-stack y)))
1050 (inst ,fopd (ea-for-df-desc y))))))
1052 (note-next-instruction vop :internal-error)
1054 ;; Finally save the result.
1057 (cond ((zerop (tn-offset r))
1058 (maybe-fp-wait node))
1062 (inst fstd (ea-for-df-stack r))))))))
1065 (define-vop (,lname)
1067 (:args (x :scs (long-reg) :to :eval)
1068 (y :scs (long-reg) :to :eval))
1069 (:temporary (:sc long-reg :offset fr0-offset
1070 :from :eval :to :result) fr0)
1071 (:results (r :scs (long-reg)))
1072 (:arg-types long-float long-float)
1073 (:result-types long-float)
1074 (:policy :fast-safe)
1075 (:note "inline float arithmetic")
1077 (:save-p :compute-only)
1080 ;; Handle a few special cases.
1082 ;; x, y, and r are the same register.
1083 ((and (location= x r) (location= y r))
1084 (cond ((zerop (tn-offset r))
1089 ;; XX the source register will not be valid.
1090 (note-next-instruction vop :internal-error)
1093 ;; x and r are the same register.
1095 (cond ((zerop (tn-offset r))
1096 ;; ST(0) = ST(0) op ST(y)
1100 (unless (zerop (tn-offset y))
1101 (copy-fp-reg-to-fr0 y))
1102 ;; ST(i) = ST(i) op ST0
1104 (maybe-fp-wait node vop))
1105 ;; y and r are the same register.
1107 (cond ((zerop (tn-offset r))
1108 ;; ST(0) = ST(x) op ST(0)
1112 (unless (zerop (tn-offset x))
1113 (copy-fp-reg-to-fr0 x))
1114 ;; ST(i) = ST(0) op ST(i)
1115 (inst ,fopr-sti r)))
1116 (maybe-fp-wait node vop))
1119 ;; Get the result to ST0.
1121 ;; Special handling is needed if x or y are in ST0, and
1122 ;; simpler code is generated.
1125 ((zerop (tn-offset x))
1129 ((zerop (tn-offset y))
1134 (copy-fp-reg-to-fr0 x)
1138 (note-next-instruction vop :internal-error)
1140 ;; Finally save the result.
1141 (cond ((zerop (tn-offset r))
1142 (maybe-fp-wait node))
1144 (inst fst r))))))))))
1146 (frob + fadd-sti fadd-sti
1147 fadd fadd +/single-float 2
1148 faddd faddd +/double-float 2
1150 (frob - fsub-sti fsubr-sti
1151 fsub fsubr -/single-float 2
1152 fsubd fsubrd -/double-float 2
1154 (frob * fmul-sti fmul-sti
1155 fmul fmul */single-float 3
1156 fmuld fmuld */double-float 3
1158 (frob / fdiv-sti fdivr-sti
1159 fdiv fdivr //single-float 12
1160 fdivd fdivrd //double-float 12
1163 (macrolet ((frob (name inst translate sc type)
1164 `(define-vop (,name)
1165 (:args (x :scs (,sc) :target fr0))
1166 (:results (y :scs (,sc)))
1167 (:translate ,translate)
1168 (:policy :fast-safe)
1170 (:result-types ,type)
1171 (:temporary (:sc double-reg :offset fr0-offset
1172 :from :argument :to :result) fr0)
1174 (:note "inline float arithmetic")
1176 (:save-p :compute-only)
1178 (note-this-location vop :internal-error)
1179 (unless (zerop (tn-offset x))
1180 (inst fxch x) ; x to top of stack
1181 (unless (location= x y)
1182 (inst fst x))) ; Maybe save it.
1183 (inst ,inst) ; Clobber st0.
1184 (unless (zerop (tn-offset y))
1187 (frob abs/single-float fabs abs single-reg single-float)
1188 (frob abs/double-float fabs abs double-reg double-float)
1190 (frob abs/long-float fabs abs long-reg long-float)
1191 (frob %negate/single-float fchs %negate single-reg single-float)
1192 (frob %negate/double-float fchs %negate double-reg double-float)
1194 (frob %negate/long-float fchs %negate long-reg long-float))
1198 (define-vop (=/float)
1200 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1202 (:policy :fast-safe)
1204 (:save-p :compute-only)
1205 (:note "inline float comparison")
1208 (note-this-location vop :internal-error)
1210 ;; x is in ST0; y is in any reg.
1211 ((zerop (tn-offset x))
1213 ;; y is in ST0; x is in another reg.
1214 ((zerop (tn-offset y))
1216 ;; x and y are the same register, not ST0
1221 ;; x and y are different registers, neither ST0.
1226 (inst fnstsw) ; status word to ax
1227 (inst and ah-tn #x45) ; C3 C2 C0
1228 (inst cmp ah-tn #x40)))
1230 (define-vop (=/single-float =/float)
1232 (:args (x :scs (single-reg))
1233 (y :scs (single-reg)))
1234 (:arg-types single-float single-float))
1236 (define-vop (=/double-float =/float)
1238 (:args (x :scs (double-reg))
1239 (y :scs (double-reg)))
1240 (:arg-types double-float double-float))
1243 (define-vop (=/long-float =/float)
1245 (:args (x :scs (long-reg))
1246 (y :scs (long-reg)))
1247 (:arg-types long-float long-float))
1249 (define-vop (<single-float)
1251 (:args (x :scs (single-reg single-stack descriptor-reg))
1252 (y :scs (single-reg single-stack descriptor-reg)))
1253 (:arg-types single-float single-float)
1254 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1255 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1257 (:policy :fast-safe)
1258 (:note "inline float comparison")
1261 ;; Handle a few special cases.
1264 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1268 ((single-stack descriptor-reg)
1269 (if (sc-is x single-stack)
1270 (inst fcom (ea-for-sf-stack x))
1271 (inst fcom (ea-for-sf-desc x)))))
1272 (inst fnstsw) ; status word to ax
1273 (inst and ah-tn #x45))
1275 ;; general case when y is not in ST0
1280 (unless (zerop (tn-offset x))
1281 (copy-fp-reg-to-fr0 x)))
1282 ((single-stack descriptor-reg)
1284 (if (sc-is x single-stack)
1285 (inst fld (ea-for-sf-stack x))
1286 (inst fld (ea-for-sf-desc x)))))
1290 ((single-stack descriptor-reg)
1291 (if (sc-is y single-stack)
1292 (inst fcom (ea-for-sf-stack y))
1293 (inst fcom (ea-for-sf-desc y)))))
1294 (inst fnstsw) ; status word to ax
1295 (inst and ah-tn #x45) ; C3 C2 C0
1296 (inst cmp ah-tn #x01)))))
1298 (define-vop (<double-float)
1300 (:args (x :scs (double-reg double-stack descriptor-reg))
1301 (y :scs (double-reg double-stack descriptor-reg)))
1302 (:arg-types double-float double-float)
1303 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1304 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1306 (:policy :fast-safe)
1307 (:note "inline float comparison")
1310 ;; Handle a few special cases
1313 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1317 ((double-stack descriptor-reg)
1318 (if (sc-is x double-stack)
1319 (inst fcomd (ea-for-df-stack x))
1320 (inst fcomd (ea-for-df-desc x)))))
1321 (inst fnstsw) ; status word to ax
1322 (inst and ah-tn #x45))
1324 ;; General case when y is not in ST0.
1329 (unless (zerop (tn-offset x))
1330 (copy-fp-reg-to-fr0 x)))
1331 ((double-stack descriptor-reg)
1333 (if (sc-is x double-stack)
1334 (inst fldd (ea-for-df-stack x))
1335 (inst fldd (ea-for-df-desc x)))))
1339 ((double-stack descriptor-reg)
1340 (if (sc-is y double-stack)
1341 (inst fcomd (ea-for-df-stack y))
1342 (inst fcomd (ea-for-df-desc y)))))
1343 (inst fnstsw) ; status word to ax
1344 (inst and ah-tn #x45) ; C3 C2 C0
1345 (inst cmp ah-tn #x01)))))
1348 (define-vop (<long-float)
1350 (:args (x :scs (long-reg))
1351 (y :scs (long-reg)))
1352 (:arg-types long-float long-float)
1353 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1355 (:policy :fast-safe)
1356 (:note "inline float comparison")
1360 ;; x is in ST0; y is in any reg.
1361 ((zerop (tn-offset x))
1363 (inst fnstsw) ; status word to ax
1364 (inst and ah-tn #x45) ; C3 C2 C0
1365 (inst cmp ah-tn #x01))
1366 ;; y is in ST0; x is in another reg.
1367 ((zerop (tn-offset y))
1369 (inst fnstsw) ; status word to ax
1370 (inst and ah-tn #x45))
1371 ;; x and y are the same register, not ST0
1372 ;; x and y are different registers, neither ST0.
1377 (inst fnstsw) ; status word to ax
1378 (inst and ah-tn #x45))))) ; C3 C2 C0
1381 (define-vop (>single-float)
1383 (:args (x :scs (single-reg single-stack descriptor-reg))
1384 (y :scs (single-reg single-stack descriptor-reg)))
1385 (:arg-types single-float single-float)
1386 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1387 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1389 (:policy :fast-safe)
1390 (:note "inline float comparison")
1393 ;; Handle a few special cases.
1396 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1400 ((single-stack descriptor-reg)
1401 (if (sc-is x single-stack)
1402 (inst fcom (ea-for-sf-stack x))
1403 (inst fcom (ea-for-sf-desc x)))))
1404 (inst fnstsw) ; status word to ax
1405 (inst and ah-tn #x45)
1406 (inst cmp ah-tn #x01))
1408 ;; general case when y is not in ST0
1413 (unless (zerop (tn-offset x))
1414 (copy-fp-reg-to-fr0 x)))
1415 ((single-stack descriptor-reg)
1417 (if (sc-is x single-stack)
1418 (inst fld (ea-for-sf-stack x))
1419 (inst fld (ea-for-sf-desc x)))))
1423 ((single-stack descriptor-reg)
1424 (if (sc-is y single-stack)
1425 (inst fcom (ea-for-sf-stack y))
1426 (inst fcom (ea-for-sf-desc y)))))
1427 (inst fnstsw) ; status word to ax
1428 (inst and ah-tn #x45)))))
1430 (define-vop (>double-float)
1432 (:args (x :scs (double-reg double-stack descriptor-reg))
1433 (y :scs (double-reg double-stack descriptor-reg)))
1434 (:arg-types double-float double-float)
1435 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1436 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1438 (:policy :fast-safe)
1439 (:note "inline float comparison")
1442 ;; Handle a few special cases.
1445 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1449 ((double-stack descriptor-reg)
1450 (if (sc-is x double-stack)
1451 (inst fcomd (ea-for-df-stack x))
1452 (inst fcomd (ea-for-df-desc x)))))
1453 (inst fnstsw) ; status word to ax
1454 (inst and ah-tn #x45)
1455 (inst cmp ah-tn #x01))
1457 ;; general case when y is not in ST0
1462 (unless (zerop (tn-offset x))
1463 (copy-fp-reg-to-fr0 x)))
1464 ((double-stack descriptor-reg)
1466 (if (sc-is x double-stack)
1467 (inst fldd (ea-for-df-stack x))
1468 (inst fldd (ea-for-df-desc x)))))
1472 ((double-stack descriptor-reg)
1473 (if (sc-is y double-stack)
1474 (inst fcomd (ea-for-df-stack y))
1475 (inst fcomd (ea-for-df-desc y)))))
1476 (inst fnstsw) ; status word to ax
1477 (inst and ah-tn #x45)))))
1480 (define-vop (>long-float)
1482 (:args (x :scs (long-reg))
1483 (y :scs (long-reg)))
1484 (:arg-types long-float long-float)
1485 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1487 (:policy :fast-safe)
1488 (:note "inline float comparison")
1492 ;; y is in ST0; x is in any reg.
1493 ((zerop (tn-offset y))
1495 (inst fnstsw) ; status word to ax
1496 (inst and ah-tn #x45)
1497 (inst cmp ah-tn #x01))
1498 ;; x is in ST0; y is in another reg.
1499 ((zerop (tn-offset x))
1501 (inst fnstsw) ; status word to ax
1502 (inst and ah-tn #x45))
1503 ;; y and x are the same register, not ST0
1504 ;; y and x are different registers, neither ST0.
1509 (inst fnstsw) ; status word to ax
1510 (inst and ah-tn #x45)))))
1512 ;;; Comparisons with 0 can use the FTST instruction.
1514 (define-vop (float-test)
1516 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1519 (:variant-vars code)
1520 (:policy :fast-safe)
1522 (:save-p :compute-only)
1523 (:note "inline float comparison")
1526 (note-this-location vop :internal-error)
1529 ((zerop (tn-offset x))
1536 (inst fnstsw) ; status word to ax
1537 (inst and ah-tn #x45) ; C3 C2 C0
1538 (unless (zerop code)
1539 (inst cmp ah-tn code))))
1541 (define-vop (=0/single-float float-test)
1543 (:args (x :scs (single-reg)))
1544 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1546 (define-vop (=0/double-float float-test)
1548 (:args (x :scs (double-reg)))
1549 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1552 (define-vop (=0/long-float float-test)
1554 (:args (x :scs (long-reg)))
1555 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1558 (define-vop (<0/single-float float-test)
1560 (:args (x :scs (single-reg)))
1561 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1563 (define-vop (<0/double-float float-test)
1565 (:args (x :scs (double-reg)))
1566 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1569 (define-vop (<0/long-float float-test)
1571 (:args (x :scs (long-reg)))
1572 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1575 (define-vop (>0/single-float float-test)
1577 (:args (x :scs (single-reg)))
1578 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1580 (define-vop (>0/double-float float-test)
1582 (:args (x :scs (double-reg)))
1583 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1586 (define-vop (>0/long-float float-test)
1588 (:args (x :scs (long-reg)))
1589 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1593 (deftransform eql ((x y) (long-float long-float))
1594 `(and (= (long-float-low-bits x) (long-float-low-bits y))
1595 (= (long-float-high-bits x) (long-float-high-bits y))
1596 (= (long-float-exp-bits x) (long-float-exp-bits y))))
1600 (macrolet ((frob (name translate to-sc to-type)
1601 `(define-vop (,name)
1602 (:args (x :scs (signed-stack signed-reg) :target temp))
1603 (:temporary (:sc signed-stack) temp)
1604 (:results (y :scs (,to-sc)))
1605 (:arg-types signed-num)
1606 (:result-types ,to-type)
1607 (:policy :fast-safe)
1608 (:note "inline float coercion")
1609 (:translate ,translate)
1611 (:save-p :compute-only)
1616 (with-empty-tn@fp-top(y)
1617 (note-this-location vop :internal-error)
1620 (with-empty-tn@fp-top(y)
1621 (note-this-location vop :internal-error)
1622 (inst fild x))))))))
1623 (frob %single-float/signed %single-float single-reg single-float)
1624 (frob %double-float/signed %double-float double-reg double-float)
1626 (frob %long-float/signed %long-float long-reg long-float))
1628 (macrolet ((frob (name translate to-sc to-type)
1629 `(define-vop (,name)
1630 (:args (x :scs (unsigned-reg)))
1631 (:results (y :scs (,to-sc)))
1632 (:arg-types unsigned-num)
1633 (:result-types ,to-type)
1634 (:policy :fast-safe)
1635 (:note "inline float coercion")
1636 (:translate ,translate)
1638 (:save-p :compute-only)
1642 (with-empty-tn@fp-top(y)
1643 (note-this-location vop :internal-error)
1644 (inst fildl (make-ea :dword :base esp-tn)))
1645 (inst add esp-tn 8)))))
1646 (frob %single-float/unsigned %single-float single-reg single-float)
1647 (frob %double-float/unsigned %double-float double-reg double-float)
1649 (frob %long-float/unsigned %long-float long-reg long-float))
1651 ;;; These should be no-ops but the compiler might want to move some
1653 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1654 `(define-vop (,name)
1655 (:args (x :scs (,from-sc) :target y))
1656 (:results (y :scs (,to-sc)))
1657 (:arg-types ,from-type)
1658 (:result-types ,to-type)
1659 (:policy :fast-safe)
1660 (:note "inline float coercion")
1661 (:translate ,translate)
1663 (:save-p :compute-only)
1665 (note-this-location vop :internal-error)
1666 (unless (location= x y)
1668 ((zerop (tn-offset x))
1669 ;; x is in ST0, y is in another reg. not ST0
1671 ((zerop (tn-offset y))
1672 ;; y is in ST0, x is in another reg. not ST0
1673 (copy-fp-reg-to-fr0 x))
1675 ;; Neither x or y are in ST0, and they are not in
1679 (inst fxch x))))))))
1681 (frob %single-float/double-float %single-float double-reg
1682 double-float single-reg single-float)
1684 (frob %single-float/long-float %single-float long-reg
1685 long-float single-reg single-float)
1686 (frob %double-float/single-float %double-float single-reg single-float
1687 double-reg double-float)
1689 (frob %double-float/long-float %double-float long-reg long-float
1690 double-reg double-float)
1692 (frob %long-float/single-float %long-float single-reg single-float
1693 long-reg long-float)
1695 (frob %long-float/double-float %long-float double-reg double-float
1696 long-reg long-float))
1698 (macrolet ((frob (trans from-sc from-type round-p)
1699 `(define-vop (,(symbolicate trans "/" from-type))
1700 (:args (x :scs (,from-sc)))
1701 (:temporary (:sc signed-stack) stack-temp)
1703 '((:temporary (:sc unsigned-stack) scw)
1704 (:temporary (:sc any-reg) rcw)))
1705 (:results (y :scs (signed-reg)))
1706 (:arg-types ,from-type)
1707 (:result-types signed-num)
1709 (:policy :fast-safe)
1710 (:note "inline float truncate")
1712 (:save-p :compute-only)
1715 '((note-this-location vop :internal-error)
1716 ;; Catch any pending FPE exceptions.
1718 (,(if round-p 'progn 'pseudo-atomic)
1719 ;; Normal mode (for now) is "round to best".
1722 '((inst fnstcw scw) ; save current control word
1723 (move rcw scw) ; into 16-bit register
1724 (inst or rcw (ash #b11 10)) ; CHOP
1725 (move stack-temp rcw)
1726 (inst fldcw stack-temp)))
1731 (inst fist stack-temp)
1732 (inst mov y stack-temp)))
1734 '((inst fldcw scw)))))))))
1735 (frob %unary-truncate/single-float single-reg single-float nil)
1736 (frob %unary-truncate/double-float double-reg double-float nil)
1738 (frob %unary-truncate/long-float long-reg long-float nil)
1739 (frob %unary-round single-reg single-float t)
1740 (frob %unary-round double-reg double-float t)
1742 (frob %unary-round long-reg long-float t))
1744 (macrolet ((frob (trans from-sc from-type round-p)
1745 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1746 (:args (x :scs (,from-sc) :target fr0))
1747 (:temporary (:sc double-reg :offset fr0-offset
1748 :from :argument :to :result) fr0)
1750 '((:temporary (:sc unsigned-stack) stack-temp)
1751 (:temporary (:sc unsigned-stack) scw)
1752 (:temporary (:sc any-reg) rcw)))
1753 (:results (y :scs (unsigned-reg)))
1754 (:arg-types ,from-type)
1755 (:result-types unsigned-num)
1757 (:policy :fast-safe)
1758 (:note "inline float truncate")
1760 (:save-p :compute-only)
1763 '((note-this-location vop :internal-error)
1764 ;; Catch any pending FPE exceptions.
1766 ;; Normal mode (for now) is "round to best".
1767 (unless (zerop (tn-offset x))
1768 (copy-fp-reg-to-fr0 x))
1770 '((inst fnstcw scw) ; save current control word
1771 (move rcw scw) ; into 16-bit register
1772 (inst or rcw (ash #b11 10)) ; CHOP
1773 (move stack-temp rcw)
1774 (inst fldcw stack-temp)))
1776 (inst fistpl (make-ea :dword :base esp-tn))
1778 (inst fld fr0) ; copy fr0 to at least restore stack.
1781 '((inst fldcw scw)))))))
1782 (frob %unary-truncate/single-float single-reg single-float nil)
1783 (frob %unary-truncate/double-float double-reg double-float nil)
1785 (frob %unary-truncate/long-float long-reg long-float nil)
1786 (frob %unary-round single-reg single-float t)
1787 (frob %unary-round double-reg double-float t)
1789 (frob %unary-round long-reg long-float t))
1791 (define-vop (make-single-float)
1792 (:args (bits :scs (signed-reg) :target res
1793 :load-if (not (or (and (sc-is bits signed-stack)
1794 (sc-is res single-reg))
1795 (and (sc-is bits signed-stack)
1796 (sc-is res single-stack)
1797 (location= bits res))))))
1798 (:results (res :scs (single-reg single-stack)))
1799 (:temporary (:sc signed-stack) stack-temp)
1800 (:arg-types signed-num)
1801 (:result-types single-float)
1802 (:translate make-single-float)
1803 (:policy :fast-safe)
1810 (inst mov res bits))
1812 (aver (location= bits res)))))
1816 ;; source must be in memory
1817 (inst mov stack-temp bits)
1818 (with-empty-tn@fp-top(res)
1819 (inst fld stack-temp)))
1821 (with-empty-tn@fp-top(res)
1822 (inst fld bits))))))))
1824 (define-vop (make-double-float)
1825 (:args (hi-bits :scs (signed-reg))
1826 (lo-bits :scs (unsigned-reg)))
1827 (:results (res :scs (double-reg)))
1828 (:temporary (:sc double-stack) temp)
1829 (:arg-types signed-num unsigned-num)
1830 (:result-types double-float)
1831 (:translate make-double-float)
1832 (:policy :fast-safe)
1835 (let ((offset (tn-offset temp)))
1836 (storew hi-bits ebp-tn (frame-word-offset offset))
1837 (storew lo-bits ebp-tn (frame-word-offset (1+ offset)))
1838 (with-empty-tn@fp-top(res)
1839 (inst fldd (make-ea :dword :base ebp-tn
1840 :disp (frame-byte-offset (1+ offset))))))))
1843 (define-vop (make-long-float)
1844 (:args (exp-bits :scs (signed-reg))
1845 (hi-bits :scs (unsigned-reg))
1846 (lo-bits :scs (unsigned-reg)))
1847 (:results (res :scs (long-reg)))
1848 (:temporary (:sc long-stack) temp)
1849 (:arg-types signed-num unsigned-num unsigned-num)
1850 (:result-types long-float)
1851 (:translate make-long-float)
1852 (:policy :fast-safe)
1855 (let ((offset (tn-offset temp)))
1856 (storew exp-bits ebp-tn (frame-word-offset offset))
1857 (storew hi-bits ebp-tn (frame-word-offset (1+ offset)))
1858 (storew lo-bits ebp-tn (frame-word-offset (+ offset 2)))
1859 (with-empty-tn@fp-top(res)
1860 (inst fldl (make-ea :dword :base ebp-tn
1861 :disp (frame-byte-offset (+ offset 2))))))))
1863 (define-vop (single-float-bits)
1864 (:args (float :scs (single-reg descriptor-reg)
1865 :load-if (not (sc-is float single-stack))))
1866 (:results (bits :scs (signed-reg)))
1867 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1868 (:arg-types single-float)
1869 (:result-types signed-num)
1870 (:translate single-float-bits)
1871 (:policy :fast-safe)
1878 (with-tn@fp-top(float)
1879 (inst fst stack-temp)
1880 (inst mov bits stack-temp)))
1882 (inst mov bits float))
1885 bits float single-float-value-slot
1886 other-pointer-lowtag))))
1890 (with-tn@fp-top(float)
1891 (inst fst bits))))))))
1893 (define-vop (double-float-high-bits)
1894 (:args (float :scs (double-reg descriptor-reg)
1895 :load-if (not (sc-is float double-stack))))
1896 (:results (hi-bits :scs (signed-reg)))
1897 (:temporary (:sc double-stack) temp)
1898 (:arg-types double-float)
1899 (:result-types signed-num)
1900 (:translate double-float-high-bits)
1901 (:policy :fast-safe)
1906 (with-tn@fp-top(float)
1907 (let ((where (make-ea :dword :base ebp-tn
1908 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1910 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset temp))))
1912 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1914 (loadw hi-bits float (1+ double-float-value-slot)
1915 other-pointer-lowtag)))))
1917 (define-vop (double-float-low-bits)
1918 (:args (float :scs (double-reg descriptor-reg)
1919 :load-if (not (sc-is float double-stack))))
1920 (:results (lo-bits :scs (unsigned-reg)))
1921 (:temporary (:sc double-stack) temp)
1922 (:arg-types double-float)
1923 (:result-types unsigned-num)
1924 (:translate double-float-low-bits)
1925 (:policy :fast-safe)
1930 (with-tn@fp-top(float)
1931 (let ((where (make-ea :dword :base ebp-tn
1932 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1934 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1936 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset float)))))
1938 (loadw lo-bits float double-float-value-slot
1939 other-pointer-lowtag)))))
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)
1955 (with-tn@fp-top(float)
1956 (let ((where (make-ea :dword :base ebp-tn
1957 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1958 (store-long-float where)))
1959 (inst movsx exp-bits
1960 (make-ea :word :base ebp-tn
1961 :disp (frame-byte-offset (tn-offset temp)))))
1963 (inst movsx exp-bits
1964 (make-ea :word :base ebp-tn
1965 :disp (frame-byte-offset (tn-offset temp)))))
1967 (inst movsx exp-bits
1968 (make-ea-for-object-slot float (+ 2 long-float-value-slot)
1969 other-pointer-lowtag :word))))))
1972 (define-vop (long-float-high-bits)
1973 (:args (float :scs (long-reg descriptor-reg)
1974 :load-if (not (sc-is float long-stack))))
1975 (:results (hi-bits :scs (unsigned-reg)))
1976 (:temporary (:sc long-stack) temp)
1977 (:arg-types long-float)
1978 (:result-types unsigned-num)
1979 (:translate long-float-high-bits)
1980 (:policy :fast-safe)
1985 (with-tn@fp-top(float)
1986 (let ((where (make-ea :dword :base ebp-tn
1987 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1988 (store-long-float where)))
1989 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1991 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1993 (loadw hi-bits float (1+ long-float-value-slot)
1994 other-pointer-lowtag)))))
1997 (define-vop (long-float-low-bits)
1998 (:args (float :scs (long-reg descriptor-reg)
1999 :load-if (not (sc-is float long-stack))))
2000 (:results (lo-bits :scs (unsigned-reg)))
2001 (:temporary (:sc long-stack) temp)
2002 (:arg-types long-float)
2003 (:result-types unsigned-num)
2004 (:translate long-float-low-bits)
2005 (:policy :fast-safe)
2010 (with-tn@fp-top(float)
2011 (let ((where (make-ea :dword :base ebp-tn
2012 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2013 (store-long-float where)))
2014 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset temp) 2))))
2016 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset float) 2))))
2018 (loadw lo-bits float long-float-value-slot
2019 other-pointer-lowtag)))))
2021 ;;;; float mode hackery
2023 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2024 (defknown floating-point-modes () float-modes (flushable))
2025 (defknown ((setf floating-point-modes)) (float-modes)
2028 (def!constant npx-env-size (* 7 n-word-bytes))
2029 (def!constant npx-cw-offset 0)
2030 (def!constant npx-sw-offset 4)
2032 (define-vop (floating-point-modes)
2033 (:results (res :scs (unsigned-reg)))
2034 (:result-types unsigned-num)
2035 (:translate floating-point-modes)
2036 (:policy :fast-safe)
2037 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2040 (inst sub esp-tn npx-env-size) ; Make space on stack.
2041 (inst wait) ; Catch any pending FPE exceptions
2042 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2043 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2044 ;; Move current status to high word.
2045 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2046 ;; Move exception mask to low word.
2047 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2048 (inst add esp-tn npx-env-size) ; Pop stack.
2049 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2052 (define-vop (set-floating-point-modes)
2053 (:args (new :scs (unsigned-reg) :to :result :target res))
2054 (:results (res :scs (unsigned-reg)))
2055 (:arg-types unsigned-num)
2056 (:result-types unsigned-num)
2057 (:translate (setf floating-point-modes))
2058 (:policy :fast-safe)
2059 (:temporary (:sc unsigned-reg :offset eax-offset
2060 :from :eval :to :result) eax)
2062 (inst sub esp-tn npx-env-size) ; Make space on stack.
2063 (inst wait) ; Catch any pending FPE exceptions.
2064 (inst fstenv (make-ea :dword :base esp-tn))
2066 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2067 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2068 (inst shr eax 16) ; position status word
2069 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2070 (inst fldenv (make-ea :dword :base esp-tn))
2071 (inst add esp-tn npx-env-size) ; Pop stack.
2077 ;;; Let's use some of the 80387 special functions.
2079 ;;; These defs will not take effect unless code/irrat.lisp is modified
2080 ;;; to remove the inlined alien routine def.
2082 (macrolet ((frob (func trans op)
2083 `(define-vop (,func)
2084 (:args (x :scs (double-reg) :target fr0))
2085 (:temporary (:sc double-reg :offset fr0-offset
2086 :from :argument :to :result) fr0)
2088 (:results (y :scs (double-reg)))
2089 (:arg-types double-float)
2090 (:result-types double-float)
2092 (:policy :fast-safe)
2093 (:note "inline NPX function")
2095 (:save-p :compute-only)
2098 (note-this-location vop :internal-error)
2099 (unless (zerop (tn-offset x))
2100 (inst fxch x) ; x to top of stack
2101 (unless (location= x y)
2102 (inst fst x))) ; maybe save it
2103 (inst ,op) ; clobber st0
2104 (cond ((zerop (tn-offset y))
2105 (maybe-fp-wait node))
2109 ;; Quick versions of fsin and fcos that require the argument to be
2110 ;; within range 2^63.
2111 (frob fsin-quick %sin-quick fsin)
2112 (frob fcos-quick %cos-quick fcos)
2113 (frob fsqrt %sqrt fsqrt))
2115 ;;; Quick version of ftan that requires the argument to be within
2117 (define-vop (ftan-quick)
2118 (:translate %tan-quick)
2119 (:args (x :scs (double-reg) :target fr0))
2120 (:temporary (:sc double-reg :offset fr0-offset
2121 :from :argument :to :result) fr0)
2122 (:temporary (:sc double-reg :offset fr1-offset
2123 :from :argument :to :result) fr1)
2124 (:results (y :scs (double-reg)))
2125 (:arg-types double-float)
2126 (:result-types double-float)
2127 (:policy :fast-safe)
2128 (:note "inline tan function")
2130 (:save-p :compute-only)
2132 (note-this-location vop :internal-error)
2141 (inst fldd (make-random-tn :kind :normal
2142 :sc (sc-or-lose 'double-reg)
2143 :offset (- (tn-offset x) 2)))))
2154 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2155 ;;; result if the argument is out of range 2^63 and would thus be
2156 ;;; hopelessly inaccurate.
2157 (macrolet ((frob (func trans op)
2158 `(define-vop (,func)
2160 (:args (x :scs (double-reg) :target fr0))
2161 (:temporary (:sc double-reg :offset fr0-offset
2162 :from :argument :to :result) fr0)
2163 ;; FIXME: make that an arbitrary location and
2164 ;; FXCH only when range reduction needed
2165 (:temporary (:sc double-reg :offset fr1-offset
2166 :from :argument :to :result) fr1)
2167 (:temporary (:sc unsigned-reg :offset eax-offset
2168 :from :argument :to :result) eax)
2169 (:results (y :scs (double-reg)))
2170 (:arg-types double-float)
2171 (:result-types double-float)
2172 (:policy :fast-safe)
2173 (:note "inline sin/cos function")
2175 (:save-p :compute-only)
2178 (let ((DONE (gen-label))
2179 (REDUCE (gen-label))
2180 (REDUCE-LOOP (gen-label)))
2181 (note-this-location vop :internal-error)
2182 (unless (zerop (tn-offset x))
2183 (inst fxch x) ; x to top of stack
2184 (unless (location= x y)
2185 (inst fst x))) ; maybe save it
2187 (inst fnstsw) ; status word to ax
2188 (inst and ah-tn #x04) ; C2
2189 (inst jmp :nz REDUCE)
2191 (unless (zerop (tn-offset y))
2193 (assemble (*elsewhere*)
2195 ;; Else x was out of range so reduce it; ST0 is unchanged.
2196 (with-empty-tn@fp-top (fr1)
2199 (emit-label REDUCE-LOOP)
2202 (inst and ah-tn #x04)
2203 (inst jmp :nz REDUCE-LOOP)
2205 (inst jmp DONE)))))))
2206 (frob fsin %sin fsin)
2207 (frob fcos %cos fcos))
2211 (:args (x :scs (double-reg) :target fr0))
2212 (:temporary (:sc double-reg :offset fr0-offset
2213 :from :argument :to :result) fr0)
2214 (:temporary (:sc double-reg :offset fr1-offset
2215 :from :argument :to :result) fr1)
2216 (:temporary (:sc unsigned-reg :offset eax-offset
2217 :from :argument :to :result) eax)
2218 (:results (y :scs (double-reg)))
2219 (:arg-types double-float)
2220 (:result-types double-float)
2222 (:policy :fast-safe)
2223 (:note "inline tan function")
2225 (:save-p :compute-only)
2228 (note-this-location vop :internal-error)
2237 (inst fldd (make-random-tn :kind :normal
2238 :sc (sc-or-lose 'double-reg)
2239 :offset (- (tn-offset x) 2)))))
2241 (let ((REDUCE (gen-label))
2242 (REDUCE-LOOP (gen-label)))
2243 (inst fnstsw) ; status word to ax
2244 (inst and ah-tn #x04) ; C2
2245 (inst jmp :nz REDUCE)
2246 (assemble (*elsewhere*)
2248 ;; Else x was out of range so reduce it; ST0 is unchanged.
2249 (with-empty-tn@fp-top (fr1)
2252 (emit-label REDUCE-LOOP)
2255 (inst and ah-tn #x04)
2256 (inst jmp :nz REDUCE-LOOP)
2269 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2270 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2273 (:args (x :scs (double-reg) :target fr0))
2274 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2275 (:temporary (:sc double-reg :offset fr0-offset
2276 :from :argument :to :result) fr0)
2277 (:temporary (:sc double-reg :offset fr1-offset
2278 :from :argument :to :result) fr1)
2279 (:temporary (:sc double-reg :offset fr2-offset
2280 :from :argument :to :result) fr2)
2281 (:results (y :scs (double-reg)))
2282 (:arg-types double-float)
2283 (:result-types double-float)
2284 (:policy :fast-safe)
2285 (:note "inline exp function")
2287 (:save-p :compute-only)
2290 (note-this-location vop :internal-error)
2291 (unless (zerop (tn-offset x))
2292 (inst fxch x) ; x to top of stack
2293 (unless (location= x y)
2294 (inst fst x))) ; maybe save it
2295 ;; Check for Inf or NaN
2299 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2300 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2301 (inst and ah-tn #x02) ; Test sign of Inf.
2302 (inst jmp :z DONE) ; +Inf gives +Inf.
2303 (inst fstp fr0) ; -Inf gives 0
2305 (inst jmp-short DONE)
2310 ;; Now fr0=x log2(e)
2314 (inst fsubp-sti fr1)
2317 (inst faddp-sti fr1)
2321 (unless (zerop (tn-offset y))
2324 ;;; Expm1 = exp(x) - 1.
2325 ;;; Handles the following special cases:
2326 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2327 (define-vop (fexpm1)
2329 (:args (x :scs (double-reg) :target fr0))
2330 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2331 (:temporary (:sc double-reg :offset fr0-offset
2332 :from :argument :to :result) fr0)
2333 (:temporary (:sc double-reg :offset fr1-offset
2334 :from :argument :to :result) fr1)
2335 (:temporary (:sc double-reg :offset fr2-offset
2336 :from :argument :to :result) fr2)
2337 (:results (y :scs (double-reg)))
2338 (:arg-types double-float)
2339 (:result-types double-float)
2340 (:policy :fast-safe)
2341 (:note "inline expm1 function")
2343 (:save-p :compute-only)
2346 (note-this-location vop :internal-error)
2347 (unless (zerop (tn-offset x))
2348 (inst fxch x) ; x to top of stack
2349 (unless (location= x y)
2350 (inst fst x))) ; maybe save it
2351 ;; Check for Inf or NaN
2355 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2356 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2357 (inst and ah-tn #x02) ; Test sign of Inf.
2358 (inst jmp :z DONE) ; +Inf gives +Inf.
2359 (inst fstp fr0) ; -Inf gives -1.0
2362 (inst jmp-short DONE)
2364 ;; Free two stack slots leaving the argument on top.
2368 (inst fmul fr1) ; Now fr0 = x log2(e)
2383 (unless (zerop (tn-offset y))
2388 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2389 (:temporary (:sc double-reg :offset fr0-offset
2390 :from :argument :to :result) fr0)
2391 (:temporary (:sc double-reg :offset fr1-offset
2392 :from :argument :to :result) fr1)
2393 (:results (y :scs (double-reg)))
2394 (:arg-types double-float)
2395 (:result-types double-float)
2396 (:policy :fast-safe)
2397 (:note "inline log function")
2399 (:save-p :compute-only)
2401 (note-this-location vop :internal-error)
2416 ;; x is in a FP reg, not fr0 or fr1
2420 (inst fldd (make-random-tn :kind :normal
2421 :sc (sc-or-lose 'double-reg)
2422 :offset (1- (tn-offset x))))))
2424 ((double-stack descriptor-reg)
2428 (if (sc-is x double-stack)
2429 (inst fldd (ea-for-df-stack x))
2430 (inst fldd (ea-for-df-desc x)))
2435 (t (inst fstd y)))))
2437 (define-vop (flog10)
2439 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2440 (:temporary (:sc double-reg :offset fr0-offset
2441 :from :argument :to :result) fr0)
2442 (:temporary (:sc double-reg :offset fr1-offset
2443 :from :argument :to :result) fr1)
2444 (:results (y :scs (double-reg)))
2445 (:arg-types double-float)
2446 (:result-types double-float)
2447 (:policy :fast-safe)
2448 (:note "inline log10 function")
2450 (:save-p :compute-only)
2452 (note-this-location vop :internal-error)
2467 ;; x is in a FP reg, not fr0 or fr1
2471 (inst fldd (make-random-tn :kind :normal
2472 :sc (sc-or-lose 'double-reg)
2473 :offset (1- (tn-offset x))))))
2475 ((double-stack descriptor-reg)
2479 (if (sc-is x double-stack)
2480 (inst fldd (ea-for-df-stack x))
2481 (inst fldd (ea-for-df-desc x)))
2486 (t (inst fstd y)))))
2490 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2491 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2492 (:temporary (:sc double-reg :offset fr0-offset
2493 :from (:argument 0) :to :result) fr0)
2494 (:temporary (:sc double-reg :offset fr1-offset
2495 :from (:argument 1) :to :result) fr1)
2496 (:temporary (:sc double-reg :offset fr2-offset
2497 :from :load :to :result) fr2)
2498 (:results (r :scs (double-reg)))
2499 (:arg-types double-float double-float)
2500 (:result-types double-float)
2501 (:policy :fast-safe)
2502 (:note "inline pow function")
2504 (:save-p :compute-only)
2506 (note-this-location vop :internal-error)
2507 ;; Setup x in fr0 and y in fr1
2509 ;; x in fr0; y in fr1
2510 ((and (sc-is x double-reg) (zerop (tn-offset x))
2511 (sc-is y double-reg) (= 1 (tn-offset y))))
2512 ;; y in fr1; x not in fr0
2513 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2517 (copy-fp-reg-to-fr0 x))
2520 (inst fldd (ea-for-df-stack x)))
2523 (inst fldd (ea-for-df-desc x)))))
2524 ;; x in fr0; y not in fr1
2525 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2527 ;; Now load y to fr0
2530 (copy-fp-reg-to-fr0 y))
2533 (inst fldd (ea-for-df-stack y)))
2536 (inst fldd (ea-for-df-desc y))))
2538 ;; x in fr1; y not in fr1
2539 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2543 (copy-fp-reg-to-fr0 y))
2546 (inst fldd (ea-for-df-stack y)))
2549 (inst fldd (ea-for-df-desc y))))
2552 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2554 ;; Now load x to fr0
2557 (copy-fp-reg-to-fr0 x))
2560 (inst fldd (ea-for-df-stack x)))
2563 (inst fldd (ea-for-df-desc x)))))
2564 ;; Neither x or y are in either fr0 or fr1
2571 (inst fldd (make-random-tn :kind :normal
2572 :sc (sc-or-lose 'double-reg)
2573 :offset (- (tn-offset y) 2))))
2575 (inst fldd (ea-for-df-stack y)))
2577 (inst fldd (ea-for-df-desc y))))
2581 (inst fldd (make-random-tn :kind :normal
2582 :sc (sc-or-lose 'double-reg)
2583 :offset (1- (tn-offset x)))))
2585 (inst fldd (ea-for-df-stack x)))
2587 (inst fldd (ea-for-df-desc x))))))
2589 ;; Now have x at fr0; and y at fr1
2591 ;; Now fr0=y log2(x)
2595 (inst fsubp-sti fr1)
2598 (inst faddp-sti fr1)
2603 (t (inst fstd r)))))
2605 (define-vop (fscalen)
2606 (:translate %scalbn)
2607 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2608 (y :scs (signed-stack signed-reg) :target temp))
2609 (:temporary (:sc double-reg :offset fr0-offset
2610 :from (:argument 0) :to :result) fr0)
2611 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2612 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2613 (:results (r :scs (double-reg)))
2614 (:arg-types double-float signed-num)
2615 (:result-types double-float)
2616 (:policy :fast-safe)
2617 (:note "inline scalbn function")
2619 ;; Setup x in fr0 and y in fr1
2650 (inst fld (make-random-tn :kind :normal
2651 :sc (sc-or-lose 'double-reg)
2652 :offset (1- (tn-offset x)))))))
2653 ((double-stack descriptor-reg)
2662 (if (sc-is x double-stack)
2663 (inst fldd (ea-for-df-stack x))
2664 (inst fldd (ea-for-df-desc x)))))
2666 (unless (zerop (tn-offset r))
2669 (define-vop (fscale)
2671 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2672 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2673 (:temporary (:sc double-reg :offset fr0-offset
2674 :from (:argument 0) :to :result) fr0)
2675 (:temporary (:sc double-reg :offset fr1-offset
2676 :from (:argument 1) :to :result) fr1)
2677 (:results (r :scs (double-reg)))
2678 (:arg-types double-float double-float)
2679 (:result-types double-float)
2680 (:policy :fast-safe)
2681 (:note "inline scalb function")
2683 (:save-p :compute-only)
2685 (note-this-location vop :internal-error)
2686 ;; Setup x in fr0 and y in fr1
2688 ;; x in fr0; y in fr1
2689 ((and (sc-is x double-reg) (zerop (tn-offset x))
2690 (sc-is y double-reg) (= 1 (tn-offset y))))
2691 ;; y in fr1; x not in fr0
2692 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2696 (copy-fp-reg-to-fr0 x))
2699 (inst fldd (ea-for-df-stack x)))
2702 (inst fldd (ea-for-df-desc x)))))
2703 ;; x in fr0; y not in fr1
2704 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2706 ;; Now load y to fr0
2709 (copy-fp-reg-to-fr0 y))
2712 (inst fldd (ea-for-df-stack y)))
2715 (inst fldd (ea-for-df-desc y))))
2717 ;; x in fr1; y not in fr1
2718 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2722 (copy-fp-reg-to-fr0 y))
2725 (inst fldd (ea-for-df-stack y)))
2728 (inst fldd (ea-for-df-desc y))))
2731 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2733 ;; Now load x to fr0
2736 (copy-fp-reg-to-fr0 x))
2739 (inst fldd (ea-for-df-stack x)))
2742 (inst fldd (ea-for-df-desc x)))))
2743 ;; Neither x or y are in either fr0 or fr1
2750 (inst fldd (make-random-tn :kind :normal
2751 :sc (sc-or-lose 'double-reg)
2752 :offset (- (tn-offset y) 2))))
2754 (inst fldd (ea-for-df-stack y)))
2756 (inst fldd (ea-for-df-desc y))))
2760 (inst fldd (make-random-tn :kind :normal
2761 :sc (sc-or-lose 'double-reg)
2762 :offset (1- (tn-offset x)))))
2764 (inst fldd (ea-for-df-stack x)))
2766 (inst fldd (ea-for-df-desc x))))))
2768 ;; Now have x at fr0; and y at fr1
2770 (unless (zerop (tn-offset r))
2773 (define-vop (flog1p)
2775 (:args (x :scs (double-reg) :to :result))
2776 (:temporary (:sc double-reg :offset fr0-offset
2777 :from :argument :to :result) fr0)
2778 (:temporary (:sc double-reg :offset fr1-offset
2779 :from :argument :to :result) fr1)
2780 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2781 (:results (y :scs (double-reg)))
2782 (:arg-types double-float)
2783 (:result-types double-float)
2784 (:policy :fast-safe)
2785 (:note "inline log1p function")
2788 ;; x is in a FP reg, not fr0, fr1.
2791 (inst fldd (make-random-tn :kind :normal
2792 :sc (sc-or-lose 'double-reg)
2793 :offset (- (tn-offset x) 2)))
2795 (inst push #x3e947ae1) ; Constant 0.29
2797 (inst fld (make-ea :dword :base esp-tn))
2800 (inst fnstsw) ; status word to ax
2801 (inst and ah-tn #x45)
2802 (inst jmp :z WITHIN-RANGE)
2803 ;; Out of range for fyl2xp1.
2805 (inst faddd (make-random-tn :kind :normal
2806 :sc (sc-or-lose 'double-reg)
2807 :offset (- (tn-offset x) 1)))
2815 (inst fldd (make-random-tn :kind :normal
2816 :sc (sc-or-lose 'double-reg)
2817 :offset (- (tn-offset x) 1)))
2823 (t (inst fstd y)))))
2825 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2826 ;;; instruction and a range check can be avoided.
2827 (define-vop (flog1p-pentium)
2829 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2830 (:temporary (:sc double-reg :offset fr0-offset
2831 :from :argument :to :result) fr0)
2832 (:temporary (:sc double-reg :offset fr1-offset
2833 :from :argument :to :result) fr1)
2834 (:results (y :scs (double-reg)))
2835 (:arg-types double-float)
2836 (:result-types double-float)
2837 (:policy :fast-safe)
2838 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2839 (:note "inline log1p with limited x range function")
2841 (:save-p :compute-only)
2843 (note-this-location vop :internal-error)
2858 ;; x is in a FP reg, not fr0 or fr1
2862 (inst fldd (make-random-tn :kind :normal
2863 :sc (sc-or-lose 'double-reg)
2864 :offset (1- (tn-offset x)))))))
2865 ((double-stack descriptor-reg)
2869 (if (sc-is x double-stack)
2870 (inst fldd (ea-for-df-stack x))
2871 (inst fldd (ea-for-df-desc x)))))
2876 (t (inst fstd y)))))
2880 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2881 (:temporary (:sc double-reg :offset fr0-offset
2882 :from :argument :to :result) fr0)
2883 (:temporary (:sc double-reg :offset fr1-offset
2884 :from :argument :to :result) fr1)
2885 (:results (y :scs (double-reg)))
2886 (:arg-types double-float)
2887 (:result-types double-float)
2888 (:policy :fast-safe)
2889 (:note "inline logb function")
2891 (:save-p :compute-only)
2893 (note-this-location vop :internal-error)
2904 ;; x is in a FP reg, not fr0 or fr1
2907 (inst fldd (make-random-tn :kind :normal
2908 :sc (sc-or-lose 'double-reg)
2909 :offset (- (tn-offset x) 2))))))
2910 ((double-stack descriptor-reg)
2913 (if (sc-is x double-stack)
2914 (inst fldd (ea-for-df-stack x))
2915 (inst fldd (ea-for-df-desc x)))))
2926 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2927 (:temporary (:sc double-reg :offset fr0-offset
2928 :from (:argument 0) :to :result) fr0)
2929 (:temporary (:sc double-reg :offset fr1-offset
2930 :from (:argument 0) :to :result) fr1)
2931 (:results (r :scs (double-reg)))
2932 (:arg-types double-float)
2933 (:result-types double-float)
2934 (:policy :fast-safe)
2935 (:note "inline atan function")
2937 (:save-p :compute-only)
2939 (note-this-location vop :internal-error)
2940 ;; Setup x in fr1 and 1.0 in fr0
2943 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2946 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2948 ;; x not in fr0 or fr1
2955 (inst fldd (make-random-tn :kind :normal
2956 :sc (sc-or-lose 'double-reg)
2957 :offset (- (tn-offset x) 2))))
2959 (inst fldd (ea-for-df-stack x)))
2961 (inst fldd (ea-for-df-desc x))))))
2963 ;; Now have x at fr1; and 1.0 at fr0
2968 (t (inst fstd r)))))
2970 (define-vop (fatan2)
2972 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2973 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2974 (:temporary (:sc double-reg :offset fr0-offset
2975 :from (:argument 1) :to :result) fr0)
2976 (:temporary (:sc double-reg :offset fr1-offset
2977 :from (:argument 0) :to :result) fr1)
2978 (:results (r :scs (double-reg)))
2979 (:arg-types double-float double-float)
2980 (:result-types double-float)
2981 (:policy :fast-safe)
2982 (:note "inline atan2 function")
2984 (:save-p :compute-only)
2986 (note-this-location vop :internal-error)
2987 ;; Setup x in fr1 and y in fr0
2989 ;; y in fr0; x in fr1
2990 ((and (sc-is y double-reg) (zerop (tn-offset y))
2991 (sc-is x double-reg) (= 1 (tn-offset x))))
2992 ;; x in fr1; y not in fr0
2993 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2997 (copy-fp-reg-to-fr0 y))
3000 (inst fldd (ea-for-df-stack y)))
3003 (inst fldd (ea-for-df-desc y)))))
3004 ((and (sc-is x double-reg) (zerop (tn-offset x))
3005 (sc-is y double-reg) (zerop (tn-offset x)))
3008 ;; y in fr0; x not in fr1
3009 ((and (sc-is y double-reg) (zerop (tn-offset y)))
3011 ;; Now load x to fr0
3014 (copy-fp-reg-to-fr0 x))
3017 (inst fldd (ea-for-df-stack x)))
3020 (inst fldd (ea-for-df-desc x))))
3022 ;; y in fr1; x not in fr1
3023 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3027 (copy-fp-reg-to-fr0 x))
3030 (inst fldd (ea-for-df-stack x)))
3033 (inst fldd (ea-for-df-desc x))))
3036 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3038 ;; Now load y to fr0
3041 (copy-fp-reg-to-fr0 y))
3044 (inst fldd (ea-for-df-stack y)))
3047 (inst fldd (ea-for-df-desc y)))))
3048 ;; Neither y or x are in either fr0 or fr1
3055 (inst fldd (make-random-tn :kind :normal
3056 :sc (sc-or-lose 'double-reg)
3057 :offset (- (tn-offset x) 2))))
3059 (inst fldd (ea-for-df-stack x)))
3061 (inst fldd (ea-for-df-desc x))))
3065 (inst fldd (make-random-tn :kind :normal
3066 :sc (sc-or-lose 'double-reg)
3067 :offset (1- (tn-offset y)))))
3069 (inst fldd (ea-for-df-stack y)))
3071 (inst fldd (ea-for-df-desc y))))))
3073 ;; Now have y at fr0; and x at fr1
3078 (t (inst fstd r)))))
3079 ) ; PROGN #!-LONG-FLOAT
3084 ;;; Lets use some of the 80387 special functions.
3086 ;;; These defs will not take effect unless code/irrat.lisp is modified
3087 ;;; to remove the inlined alien routine def.
3089 (macrolet ((frob (func trans op)
3090 `(define-vop (,func)
3091 (:args (x :scs (long-reg) :target fr0))
3092 (:temporary (:sc long-reg :offset fr0-offset
3093 :from :argument :to :result) fr0)
3095 (:results (y :scs (long-reg)))
3096 (:arg-types long-float)
3097 (:result-types long-float)
3099 (:policy :fast-safe)
3100 (:note "inline NPX function")
3102 (:save-p :compute-only)
3105 (note-this-location vop :internal-error)
3106 (unless (zerop (tn-offset x))
3107 (inst fxch x) ; x to top of stack
3108 (unless (location= x y)
3109 (inst fst x))) ; maybe save it
3110 (inst ,op) ; clobber st0
3111 (cond ((zerop (tn-offset y))
3112 (maybe-fp-wait node))
3116 ;; Quick versions of FSIN and FCOS that require the argument to be
3117 ;; within range 2^63.
3118 (frob fsin-quick %sin-quick fsin)
3119 (frob fcos-quick %cos-quick fcos)
3120 (frob fsqrt %sqrt fsqrt))
3122 ;;; Quick version of ftan that requires the argument to be within
3124 (define-vop (ftan-quick)
3125 (:translate %tan-quick)
3126 (:args (x :scs (long-reg) :target fr0))
3127 (:temporary (:sc long-reg :offset fr0-offset
3128 :from :argument :to :result) fr0)
3129 (:temporary (:sc long-reg :offset fr1-offset
3130 :from :argument :to :result) fr1)
3131 (:results (y :scs (long-reg)))
3132 (:arg-types long-float)
3133 (:result-types long-float)
3134 (:policy :fast-safe)
3135 (:note "inline tan function")
3137 (:save-p :compute-only)
3139 (note-this-location vop :internal-error)
3148 (inst fldd (make-random-tn :kind :normal
3149 :sc (sc-or-lose 'double-reg)
3150 :offset (- (tn-offset x) 2)))))
3161 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3162 ;;; the argument is out of range 2^63 and would thus be hopelessly
3164 (macrolet ((frob (func trans op)
3165 `(define-vop (,func)
3167 (:args (x :scs (long-reg) :target fr0))
3168 (:temporary (:sc long-reg :offset fr0-offset
3169 :from :argument :to :result) fr0)
3170 (:temporary (:sc unsigned-reg :offset eax-offset
3171 :from :argument :to :result) eax)
3172 (:results (y :scs (long-reg)))
3173 (:arg-types long-float)
3174 (:result-types long-float)
3175 (:policy :fast-safe)
3176 (:note "inline sin/cos function")
3178 (:save-p :compute-only)
3181 (note-this-location vop :internal-error)
3182 (unless (zerop (tn-offset x))
3183 (inst fxch x) ; x to top of stack
3184 (unless (location= x y)
3185 (inst fst x))) ; maybe save it
3187 (inst fnstsw) ; status word to ax
3188 (inst and ah-tn #x04) ; C2
3190 ;; Else x was out of range so reduce it; ST0 is unchanged.
3191 (inst fstp fr0) ; Load 0.0
3194 (unless (zerop (tn-offset y))
3196 (frob fsin %sin fsin)
3197 (frob fcos %cos fcos))
3201 (:args (x :scs (long-reg) :target fr0))
3202 (:temporary (:sc long-reg :offset fr0-offset
3203 :from :argument :to :result) fr0)
3204 (:temporary (:sc long-reg :offset fr1-offset
3205 :from :argument :to :result) fr1)
3206 (:temporary (:sc unsigned-reg :offset eax-offset
3207 :from :argument :to :result) eax)
3208 (:results (y :scs (long-reg)))
3209 (:arg-types long-float)
3210 (:result-types long-float)
3212 (:policy :fast-safe)
3213 (:note "inline tan function")
3215 (:save-p :compute-only)
3218 (note-this-location vop :internal-error)
3227 (inst fldd (make-random-tn :kind :normal
3228 :sc (sc-or-lose 'double-reg)
3229 :offset (- (tn-offset x) 2)))))
3231 (inst fnstsw) ; status word to ax
3232 (inst and ah-tn #x04) ; C2
3234 ;; Else x was out of range so reduce it; ST0 is unchanged.
3235 (inst fldz) ; Load 0.0
3247 ;;; Modified exp that handles the following special cases:
3248 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3251 (:args (x :scs (long-reg) :target fr0))
3252 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3253 (:temporary (:sc long-reg :offset fr0-offset
3254 :from :argument :to :result) fr0)
3255 (:temporary (:sc long-reg :offset fr1-offset
3256 :from :argument :to :result) fr1)
3257 (:temporary (:sc long-reg :offset fr2-offset
3258 :from :argument :to :result) fr2)
3259 (:results (y :scs (long-reg)))
3260 (:arg-types long-float)
3261 (:result-types long-float)
3262 (:policy :fast-safe)
3263 (:note "inline exp function")
3265 (:save-p :compute-only)
3268 (note-this-location vop :internal-error)
3269 (unless (zerop (tn-offset x))
3270 (inst fxch x) ; x to top of stack
3271 (unless (location= x y)
3272 (inst fst x))) ; maybe save it
3273 ;; Check for Inf or NaN
3277 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3278 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3279 (inst and ah-tn #x02) ; Test sign of Inf.
3280 (inst jmp :z DONE) ; +Inf gives +Inf.
3281 (inst fstp fr0) ; -Inf gives 0
3283 (inst jmp-short DONE)
3288 ;; Now fr0=x log2(e)
3292 (inst fsubp-sti fr1)
3295 (inst faddp-sti fr1)
3299 (unless (zerop (tn-offset y))
3302 ;;; Expm1 = exp(x) - 1.
3303 ;;; Handles the following special cases:
3304 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3305 (define-vop (fexpm1)
3307 (:args (x :scs (long-reg) :target fr0))
3308 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3309 (:temporary (:sc long-reg :offset fr0-offset
3310 :from :argument :to :result) fr0)
3311 (:temporary (:sc long-reg :offset fr1-offset
3312 :from :argument :to :result) fr1)
3313 (:temporary (:sc long-reg :offset fr2-offset
3314 :from :argument :to :result) fr2)
3315 (:results (y :scs (long-reg)))
3316 (:arg-types long-float)
3317 (:result-types long-float)
3318 (:policy :fast-safe)
3319 (:note "inline expm1 function")
3321 (:save-p :compute-only)
3324 (note-this-location vop :internal-error)
3325 (unless (zerop (tn-offset x))
3326 (inst fxch x) ; x to top of stack
3327 (unless (location= x y)
3328 (inst fst x))) ; maybe save it
3329 ;; Check for Inf or NaN
3333 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3334 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3335 (inst and ah-tn #x02) ; Test sign of Inf.
3336 (inst jmp :z DONE) ; +Inf gives +Inf.
3337 (inst fstp fr0) ; -Inf gives -1.0
3340 (inst jmp-short DONE)
3342 ;; Free two stack slots leaving the argument on top.
3346 (inst fmul fr1) ; Now fr0 = x log2(e)
3361 (unless (zerop (tn-offset y))
3366 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3367 (:temporary (:sc long-reg :offset fr0-offset
3368 :from :argument :to :result) fr0)
3369 (:temporary (:sc long-reg :offset fr1-offset
3370 :from :argument :to :result) fr1)
3371 (:results (y :scs (long-reg)))
3372 (:arg-types long-float)
3373 (:result-types long-float)
3374 (:policy :fast-safe)
3375 (:note "inline log function")
3377 (:save-p :compute-only)
3379 (note-this-location vop :internal-error)
3394 ;; x is in a FP reg, not fr0 or fr1
3398 (inst fldd (make-random-tn :kind :normal
3399 :sc (sc-or-lose 'double-reg)
3400 :offset (1- (tn-offset x))))))
3402 ((long-stack descriptor-reg)
3406 (if (sc-is x long-stack)
3407 (inst fldl (ea-for-lf-stack x))
3408 (inst fldl (ea-for-lf-desc x)))
3413 (t (inst fstd y)))))
3415 (define-vop (flog10)
3417 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3418 (:temporary (:sc long-reg :offset fr0-offset
3419 :from :argument :to :result) fr0)
3420 (:temporary (:sc long-reg :offset fr1-offset
3421 :from :argument :to :result) fr1)
3422 (:results (y :scs (long-reg)))
3423 (:arg-types long-float)
3424 (:result-types long-float)
3425 (:policy :fast-safe)
3426 (:note "inline log10 function")
3428 (:save-p :compute-only)
3430 (note-this-location vop :internal-error)
3445 ;; x is in a FP reg, not fr0 or fr1
3449 (inst fldd (make-random-tn :kind :normal
3450 :sc (sc-or-lose 'double-reg)
3451 :offset (1- (tn-offset x))))))
3453 ((long-stack descriptor-reg)
3457 (if (sc-is x long-stack)
3458 (inst fldl (ea-for-lf-stack x))
3459 (inst fldl (ea-for-lf-desc x)))
3464 (t (inst fstd y)))))
3468 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3469 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3470 (:temporary (:sc long-reg :offset fr0-offset
3471 :from (:argument 0) :to :result) fr0)
3472 (:temporary (:sc long-reg :offset fr1-offset
3473 :from (:argument 1) :to :result) fr1)
3474 (:temporary (:sc long-reg :offset fr2-offset
3475 :from :load :to :result) fr2)
3476 (:results (r :scs (long-reg)))
3477 (:arg-types long-float long-float)
3478 (:result-types long-float)
3479 (:policy :fast-safe)
3480 (:note "inline pow function")
3482 (:save-p :compute-only)
3484 (note-this-location vop :internal-error)
3485 ;; Setup x in fr0 and y in fr1
3487 ;; x in fr0; y in fr1
3488 ((and (sc-is x long-reg) (zerop (tn-offset x))
3489 (sc-is y long-reg) (= 1 (tn-offset y))))
3490 ;; y in fr1; x not in fr0
3491 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3495 (copy-fp-reg-to-fr0 x))
3498 (inst fldl (ea-for-lf-stack x)))
3501 (inst fldl (ea-for-lf-desc x)))))
3502 ;; x in fr0; y not in fr1
3503 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3505 ;; Now load y to fr0
3508 (copy-fp-reg-to-fr0 y))
3511 (inst fldl (ea-for-lf-stack y)))
3514 (inst fldl (ea-for-lf-desc y))))
3516 ;; x in fr1; y not in fr1
3517 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3521 (copy-fp-reg-to-fr0 y))
3524 (inst fldl (ea-for-lf-stack y)))
3527 (inst fldl (ea-for-lf-desc y))))
3530 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3532 ;; Now load x to fr0
3535 (copy-fp-reg-to-fr0 x))
3538 (inst fldl (ea-for-lf-stack x)))
3541 (inst fldl (ea-for-lf-desc x)))))
3542 ;; Neither x or y are in either fr0 or fr1
3549 (inst fldd (make-random-tn :kind :normal
3550 :sc (sc-or-lose 'double-reg)
3551 :offset (- (tn-offset y) 2))))
3553 (inst fldl (ea-for-lf-stack y)))
3555 (inst fldl (ea-for-lf-desc y))))
3559 (inst fldd (make-random-tn :kind :normal
3560 :sc (sc-or-lose 'double-reg)
3561 :offset (1- (tn-offset x)))))
3563 (inst fldl (ea-for-lf-stack x)))
3565 (inst fldl (ea-for-lf-desc x))))))
3567 ;; Now have x at fr0; and y at fr1
3569 ;; Now fr0=y log2(x)
3573 (inst fsubp-sti fr1)
3576 (inst faddp-sti fr1)
3581 (t (inst fstd r)))))
3583 (define-vop (fscalen)
3584 (:translate %scalbn)
3585 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3586 (y :scs (signed-stack signed-reg) :target temp))
3587 (:temporary (:sc long-reg :offset fr0-offset
3588 :from (:argument 0) :to :result) fr0)
3589 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3590 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3591 (:results (r :scs (long-reg)))
3592 (:arg-types long-float signed-num)
3593 (:result-types long-float)
3594 (:policy :fast-safe)
3595 (:note "inline scalbn function")
3597 ;; Setup x in fr0 and y in fr1
3628 (inst fld (make-random-tn :kind :normal
3629 :sc (sc-or-lose 'double-reg)
3630 :offset (1- (tn-offset x)))))))
3631 ((long-stack descriptor-reg)
3640 (if (sc-is x long-stack)
3641 (inst fldl (ea-for-lf-stack x))
3642 (inst fldl (ea-for-lf-desc x)))))
3644 (unless (zerop (tn-offset r))
3647 (define-vop (fscale)
3649 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3650 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3651 (:temporary (:sc long-reg :offset fr0-offset
3652 :from (:argument 0) :to :result) fr0)
3653 (:temporary (:sc long-reg :offset fr1-offset
3654 :from (:argument 1) :to :result) fr1)
3655 (:results (r :scs (long-reg)))
3656 (:arg-types long-float long-float)
3657 (:result-types long-float)
3658 (:policy :fast-safe)
3659 (:note "inline scalb function")
3661 (:save-p :compute-only)
3663 (note-this-location vop :internal-error)
3664 ;; Setup x in fr0 and y in fr1
3666 ;; x in fr0; y in fr1
3667 ((and (sc-is x long-reg) (zerop (tn-offset x))
3668 (sc-is y long-reg) (= 1 (tn-offset y))))
3669 ;; y in fr1; x not in fr0
3670 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3674 (copy-fp-reg-to-fr0 x))
3677 (inst fldl (ea-for-lf-stack x)))
3680 (inst fldl (ea-for-lf-desc x)))))
3681 ;; x in fr0; y not in fr1
3682 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3684 ;; Now load y to fr0
3687 (copy-fp-reg-to-fr0 y))
3690 (inst fldl (ea-for-lf-stack y)))
3693 (inst fldl (ea-for-lf-desc y))))
3695 ;; x in fr1; y not in fr1
3696 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3700 (copy-fp-reg-to-fr0 y))
3703 (inst fldl (ea-for-lf-stack y)))
3706 (inst fldl (ea-for-lf-desc y))))
3709 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3711 ;; Now load x to fr0
3714 (copy-fp-reg-to-fr0 x))
3717 (inst fldl (ea-for-lf-stack x)))
3720 (inst fldl (ea-for-lf-desc x)))))
3721 ;; Neither x or y are in either fr0 or fr1
3728 (inst fldd (make-random-tn :kind :normal
3729 :sc (sc-or-lose 'double-reg)
3730 :offset (- (tn-offset y) 2))))
3732 (inst fldl (ea-for-lf-stack y)))
3734 (inst fldl (ea-for-lf-desc y))))
3738 (inst fldd (make-random-tn :kind :normal
3739 :sc (sc-or-lose 'double-reg)
3740 :offset (1- (tn-offset x)))))
3742 (inst fldl (ea-for-lf-stack x)))
3744 (inst fldl (ea-for-lf-desc x))))))
3746 ;; Now have x at fr0; and y at fr1
3748 (unless (zerop (tn-offset r))
3751 (define-vop (flog1p)
3753 (:args (x :scs (long-reg) :to :result))
3754 (:temporary (:sc long-reg :offset fr0-offset
3755 :from :argument :to :result) fr0)
3756 (:temporary (:sc long-reg :offset fr1-offset
3757 :from :argument :to :result) fr1)
3758 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3759 (:results (y :scs (long-reg)))
3760 (:arg-types long-float)
3761 (:result-types long-float)
3762 (:policy :fast-safe)
3763 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3764 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3765 ;; an enormous PROGN above. Still, it would be probably be good to
3766 ;; add some code to warn about redefining VOPs.
3767 (:note "inline log1p function")
3770 ;; x is in a FP reg, not fr0, fr1.
3773 (inst fldd (make-random-tn :kind :normal
3774 :sc (sc-or-lose 'double-reg)
3775 :offset (- (tn-offset x) 2)))
3777 (inst push #x3e947ae1) ; Constant 0.29
3779 (inst fld (make-ea :dword :base esp-tn))
3782 (inst fnstsw) ; status word to ax
3783 (inst and ah-tn #x45)
3784 (inst jmp :z WITHIN-RANGE)
3785 ;; Out of range for fyl2xp1.
3787 (inst faddd (make-random-tn :kind :normal
3788 :sc (sc-or-lose 'double-reg)
3789 :offset (- (tn-offset x) 1)))
3797 (inst fldd (make-random-tn :kind :normal
3798 :sc (sc-or-lose 'double-reg)
3799 :offset (- (tn-offset x) 1)))
3805 (t (inst fstd y)))))
3807 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3808 ;;; instruction and a range check can be avoided.
3809 (define-vop (flog1p-pentium)
3811 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3812 (:temporary (:sc long-reg :offset fr0-offset
3813 :from :argument :to :result) fr0)
3814 (:temporary (:sc long-reg :offset fr1-offset
3815 :from :argument :to :result) fr1)
3816 (:results (y :scs (long-reg)))
3817 (:arg-types long-float)
3818 (:result-types long-float)
3819 (:policy :fast-safe)
3820 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3821 (:note "inline log1p function")
3837 ;; x is in a FP reg, not fr0 or fr1
3841 (inst fldd (make-random-tn :kind :normal
3842 :sc (sc-or-lose 'double-reg)
3843 :offset (1- (tn-offset x)))))))
3844 ((long-stack descriptor-reg)
3848 (if (sc-is x long-stack)
3849 (inst fldl (ea-for-lf-stack x))
3850 (inst fldl (ea-for-lf-desc x)))))
3855 (t (inst fstd y)))))
3859 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3860 (:temporary (:sc long-reg :offset fr0-offset
3861 :from :argument :to :result) fr0)
3862 (:temporary (:sc long-reg :offset fr1-offset
3863 :from :argument :to :result) fr1)
3864 (:results (y :scs (long-reg)))
3865 (:arg-types long-float)
3866 (:result-types long-float)
3867 (:policy :fast-safe)
3868 (:note "inline logb function")
3870 (:save-p :compute-only)
3872 (note-this-location vop :internal-error)
3883 ;; x is in a FP reg, not fr0 or fr1
3886 (inst fldd (make-random-tn :kind :normal
3887 :sc (sc-or-lose 'double-reg)
3888 :offset (- (tn-offset x) 2))))))
3889 ((long-stack descriptor-reg)
3892 (if (sc-is x long-stack)
3893 (inst fldl (ea-for-lf-stack x))
3894 (inst fldl (ea-for-lf-desc x)))))
3905 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3906 (:temporary (:sc long-reg :offset fr0-offset
3907 :from (:argument 0) :to :result) fr0)
3908 (:temporary (:sc long-reg :offset fr1-offset
3909 :from (:argument 0) :to :result) fr1)
3910 (:results (r :scs (long-reg)))
3911 (:arg-types long-float)
3912 (:result-types long-float)
3913 (:policy :fast-safe)
3914 (:note "inline atan function")
3916 (:save-p :compute-only)
3918 (note-this-location vop :internal-error)
3919 ;; Setup x in fr1 and 1.0 in fr0
3922 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3925 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3927 ;; x not in fr0 or fr1
3934 (inst fldd (make-random-tn :kind :normal
3935 :sc (sc-or-lose 'double-reg)
3936 :offset (- (tn-offset x) 2))))
3938 (inst fldl (ea-for-lf-stack x)))
3940 (inst fldl (ea-for-lf-desc x))))))
3942 ;; Now have x at fr1; and 1.0 at fr0
3947 (t (inst fstd r)))))
3949 (define-vop (fatan2)
3951 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3952 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3953 (:temporary (:sc long-reg :offset fr0-offset
3954 :from (:argument 1) :to :result) fr0)
3955 (:temporary (:sc long-reg :offset fr1-offset
3956 :from (:argument 0) :to :result) fr1)
3957 (:results (r :scs (long-reg)))
3958 (:arg-types long-float long-float)
3959 (:result-types long-float)
3960 (:policy :fast-safe)
3961 (:note "inline atan2 function")
3963 (:save-p :compute-only)
3965 (note-this-location vop :internal-error)
3966 ;; Setup x in fr1 and y in fr0
3968 ;; y in fr0; x in fr1
3969 ((and (sc-is y long-reg) (zerop (tn-offset y))
3970 (sc-is x long-reg) (= 1 (tn-offset x))))
3971 ;; x in fr1; y not in fr0
3972 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3976 (copy-fp-reg-to-fr0 y))
3979 (inst fldl (ea-for-lf-stack y)))
3982 (inst fldl (ea-for-lf-desc y)))))
3983 ;; y in fr0; x not in fr1
3984 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3986 ;; Now load x to fr0
3989 (copy-fp-reg-to-fr0 x))
3992 (inst fldl (ea-for-lf-stack x)))
3995 (inst fldl (ea-for-lf-desc x))))
3997 ;; y in fr1; x not in fr1
3998 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
4002 (copy-fp-reg-to-fr0 x))
4005 (inst fldl (ea-for-lf-stack x)))
4008 (inst fldl (ea-for-lf-desc x))))
4011 ((and (sc-is x long-reg) (zerop (tn-offset x)))
4013 ;; Now load y to fr0
4016 (copy-fp-reg-to-fr0 y))
4019 (inst fldl (ea-for-lf-stack y)))
4022 (inst fldl (ea-for-lf-desc y)))))
4023 ;; Neither y or x are in either fr0 or fr1
4030 (inst fldd (make-random-tn :kind :normal
4031 :sc (sc-or-lose 'double-reg)
4032 :offset (- (tn-offset x) 2))))
4034 (inst fldl (ea-for-lf-stack x)))
4036 (inst fldl (ea-for-lf-desc x))))
4040 (inst fldd (make-random-tn :kind :normal
4041 :sc (sc-or-lose 'double-reg)
4042 :offset (1- (tn-offset y)))))
4044 (inst fldl (ea-for-lf-stack y)))
4046 (inst fldl (ea-for-lf-desc y))))))
4048 ;; Now have y at fr0; and x at fr1
4053 (t (inst fstd r)))))
4055 ) ; PROGN #!+LONG-FLOAT
4057 ;;;; complex float VOPs
4059 (define-vop (make-complex-single-float)
4060 (:translate complex)
4061 (:args (real :scs (single-reg) :to :result :target r
4062 :load-if (not (location= real r)))
4063 (imag :scs (single-reg) :to :save))
4064 (:arg-types single-float single-float)
4065 (:results (r :scs (complex-single-reg) :from (:argument 0)
4066 :load-if (not (sc-is r complex-single-stack))))
4067 (:result-types complex-single-float)
4068 (:note "inline complex single-float creation")
4069 (:policy :fast-safe)
4073 (let ((r-real (complex-double-reg-real-tn r)))
4074 (unless (location= real r-real)
4075 (cond ((zerop (tn-offset r-real))
4076 (copy-fp-reg-to-fr0 real))
4077 ((zerop (tn-offset real))
4082 (inst fxch real)))))
4083 (let ((r-imag (complex-double-reg-imag-tn r)))
4084 (unless (location= imag r-imag)
4085 (cond ((zerop (tn-offset imag))
4090 (inst fxch imag))))))
4091 (complex-single-stack
4092 (unless (location= real r)
4093 (cond ((zerop (tn-offset real))
4094 (inst fst (ea-for-csf-real-stack r)))
4097 (inst fst (ea-for-csf-real-stack r))
4100 (inst fst (ea-for-csf-imag-stack r))
4101 (inst fxch imag)))))
4103 (define-vop (make-complex-double-float)
4104 (:translate complex)
4105 (:args (real :scs (double-reg) :target r
4106 :load-if (not (location= real r)))
4107 (imag :scs (double-reg) :to :save))
4108 (:arg-types double-float double-float)
4109 (:results (r :scs (complex-double-reg) :from (:argument 0)
4110 :load-if (not (sc-is r complex-double-stack))))
4111 (:result-types complex-double-float)
4112 (:note "inline complex double-float creation")
4113 (:policy :fast-safe)
4117 (let ((r-real (complex-double-reg-real-tn r)))
4118 (unless (location= real r-real)
4119 (cond ((zerop (tn-offset r-real))
4120 (copy-fp-reg-to-fr0 real))
4121 ((zerop (tn-offset real))
4126 (inst fxch real)))))
4127 (let ((r-imag (complex-double-reg-imag-tn r)))
4128 (unless (location= imag r-imag)
4129 (cond ((zerop (tn-offset imag))
4134 (inst fxch imag))))))
4135 (complex-double-stack
4136 (unless (location= real r)
4137 (cond ((zerop (tn-offset real))
4138 (inst fstd (ea-for-cdf-real-stack r)))
4141 (inst fstd (ea-for-cdf-real-stack r))
4144 (inst fstd (ea-for-cdf-imag-stack r))
4145 (inst fxch imag)))))
4148 (define-vop (make-complex-long-float)
4149 (:translate complex)
4150 (:args (real :scs (long-reg) :target r
4151 :load-if (not (location= real r)))
4152 (imag :scs (long-reg) :to :save))
4153 (:arg-types long-float long-float)
4154 (:results (r :scs (complex-long-reg) :from (:argument 0)
4155 :load-if (not (sc-is r complex-long-stack))))
4156 (:result-types complex-long-float)
4157 (:note "inline complex long-float creation")
4158 (:policy :fast-safe)
4162 (let ((r-real (complex-double-reg-real-tn r)))
4163 (unless (location= real r-real)
4164 (cond ((zerop (tn-offset r-real))
4165 (copy-fp-reg-to-fr0 real))
4166 ((zerop (tn-offset real))
4171 (inst fxch real)))))
4172 (let ((r-imag (complex-double-reg-imag-tn r)))
4173 (unless (location= imag r-imag)
4174 (cond ((zerop (tn-offset imag))
4179 (inst fxch imag))))))
4181 (unless (location= real r)
4182 (cond ((zerop (tn-offset real))
4183 (store-long-float (ea-for-clf-real-stack r)))
4186 (store-long-float (ea-for-clf-real-stack r))
4189 (store-long-float (ea-for-clf-imag-stack r))
4190 (inst fxch imag)))))
4193 (define-vop (complex-float-value)
4194 (:args (x :target r))
4196 (:variant-vars offset)
4197 (:policy :fast-safe)
4199 (cond ((sc-is x complex-single-reg complex-double-reg
4200 #!+long-float complex-long-reg)
4202 (make-random-tn :kind :normal
4203 :sc (sc-or-lose 'double-reg)
4204 :offset (+ offset (tn-offset x)))))
4205 (unless (location= value-tn r)
4206 (cond ((zerop (tn-offset r))
4207 (copy-fp-reg-to-fr0 value-tn))
4208 ((zerop (tn-offset value-tn))
4211 (inst fxch value-tn)
4213 (inst fxch value-tn))))))
4214 ((sc-is r single-reg)
4215 (let ((ea (sc-case x
4216 (complex-single-stack
4218 (0 (ea-for-csf-real-stack x))
4219 (1 (ea-for-csf-imag-stack x))))
4222 (0 (ea-for-csf-real-desc x))
4223 (1 (ea-for-csf-imag-desc x)))))))
4224 (with-empty-tn@fp-top(r)
4226 ((sc-is r double-reg)
4227 (let ((ea (sc-case x
4228 (complex-double-stack
4230 (0 (ea-for-cdf-real-stack x))
4231 (1 (ea-for-cdf-imag-stack x))))
4234 (0 (ea-for-cdf-real-desc x))
4235 (1 (ea-for-cdf-imag-desc x)))))))
4236 (with-empty-tn@fp-top(r)
4240 (let ((ea (sc-case x
4243 (0 (ea-for-clf-real-stack x))
4244 (1 (ea-for-clf-imag-stack x))))
4247 (0 (ea-for-clf-real-desc x))
4248 (1 (ea-for-clf-imag-desc x)))))))
4249 (with-empty-tn@fp-top(r)
4251 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4253 (define-vop (realpart/complex-single-float complex-float-value)
4254 (:translate realpart)
4255 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4257 (:arg-types complex-single-float)
4258 (:results (r :scs (single-reg)))
4259 (:result-types single-float)
4260 (:note "complex float realpart")
4263 (define-vop (realpart/complex-double-float complex-float-value)
4264 (:translate realpart)
4265 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4267 (:arg-types complex-double-float)
4268 (:results (r :scs (double-reg)))
4269 (:result-types double-float)
4270 (:note "complex float realpart")
4274 (define-vop (realpart/complex-long-float complex-float-value)
4275 (:translate realpart)
4276 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4278 (:arg-types complex-long-float)
4279 (:results (r :scs (long-reg)))
4280 (:result-types long-float)
4281 (:note "complex float realpart")
4284 (define-vop (imagpart/complex-single-float complex-float-value)
4285 (:translate imagpart)
4286 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4288 (:arg-types complex-single-float)
4289 (:results (r :scs (single-reg)))
4290 (:result-types single-float)
4291 (:note "complex float imagpart")
4294 (define-vop (imagpart/complex-double-float complex-float-value)
4295 (:translate imagpart)
4296 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4298 (:arg-types complex-double-float)
4299 (:results (r :scs (double-reg)))
4300 (:result-types double-float)
4301 (:note "complex float imagpart")
4305 (define-vop (imagpart/complex-long-float complex-float-value)
4306 (:translate imagpart)
4307 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4309 (:arg-types complex-long-float)
4310 (:results (r :scs (long-reg)))
4311 (:result-types long-float)
4312 (:note "complex float imagpart")
4315 ;;; hack dummy VOPs to bias the representation selection of their
4316 ;;; arguments towards a FP register, which can help avoid consing at
4317 ;;; inappropriate locations
4318 (defknown double-float-reg-bias (double-float) (values))
4319 (define-vop (double-float-reg-bias)
4320 (:translate double-float-reg-bias)
4321 (:args (x :scs (double-reg double-stack) :load-if nil))
4322 (:arg-types double-float)
4323 (:policy :fast-safe)
4324 (:note "inline dummy FP register bias")
4327 (defknown single-float-reg-bias (single-float) (values))
4328 (define-vop (single-float-reg-bias)
4329 (:translate single-float-reg-bias)
4330 (:args (x :scs (single-reg single-stack) :load-if nil))
4331 (:arg-types single-float)
4332 (:policy :fast-safe)
4333 (:note "inline dummy FP register bias")