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 (:temporary (:sc unsigned-reg :offset eax-offset
2164 :from :argument :to :result) eax)
2165 (:results (y :scs (double-reg)))
2166 (:arg-types double-float)
2167 (:result-types double-float)
2168 (:policy :fast-safe)
2169 (:note "inline sin/cos function")
2171 (:save-p :compute-only)
2174 (note-this-location vop :internal-error)
2175 (unless (zerop (tn-offset x))
2176 (inst fxch x) ; x to top of stack
2177 (unless (location= x y)
2178 (inst fst x))) ; maybe save it
2180 (inst fnstsw) ; status word to ax
2181 (inst and ah-tn #x04) ; C2
2183 ;; Else x was out of range so reduce it; ST0 is unchanged.
2184 (inst fstp fr0) ; Load 0.0
2187 (unless (zerop (tn-offset y))
2189 (frob fsin %sin fsin)
2190 (frob fcos %cos fcos))
2194 (:args (x :scs (double-reg) :target fr0))
2195 (:temporary (:sc double-reg :offset fr0-offset
2196 :from :argument :to :result) fr0)
2197 (:temporary (:sc double-reg :offset fr1-offset
2198 :from :argument :to :result) fr1)
2199 (:temporary (:sc unsigned-reg :offset eax-offset
2200 :from :argument :to :result) eax)
2201 (:results (y :scs (double-reg)))
2202 (:arg-types double-float)
2203 (:result-types double-float)
2205 (:policy :fast-safe)
2206 (:note "inline tan function")
2208 (:save-p :compute-only)
2211 (note-this-location vop :internal-error)
2220 (inst fldd (make-random-tn :kind :normal
2221 :sc (sc-or-lose 'double-reg)
2222 :offset (- (tn-offset x) 2)))))
2224 (inst fnstsw) ; status word to ax
2225 (inst and ah-tn #x04) ; C2
2227 ;; Else x was out of range so load 0.0
2239 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2240 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2243 (:args (x :scs (double-reg) :target fr0))
2244 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2245 (:temporary (:sc double-reg :offset fr0-offset
2246 :from :argument :to :result) fr0)
2247 (:temporary (:sc double-reg :offset fr1-offset
2248 :from :argument :to :result) fr1)
2249 (:temporary (:sc double-reg :offset fr2-offset
2250 :from :argument :to :result) fr2)
2251 (:results (y :scs (double-reg)))
2252 (:arg-types double-float)
2253 (:result-types double-float)
2254 (:policy :fast-safe)
2255 (:note "inline exp function")
2257 (:save-p :compute-only)
2260 (note-this-location vop :internal-error)
2261 (unless (zerop (tn-offset x))
2262 (inst fxch x) ; x to top of stack
2263 (unless (location= x y)
2264 (inst fst x))) ; maybe save it
2265 ;; Check for Inf or NaN
2269 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2270 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2271 (inst and ah-tn #x02) ; Test sign of Inf.
2272 (inst jmp :z DONE) ; +Inf gives +Inf.
2273 (inst fstp fr0) ; -Inf gives 0
2275 (inst jmp-short DONE)
2280 ;; Now fr0=x log2(e)
2284 (inst fsubp-sti fr1)
2287 (inst faddp-sti fr1)
2291 (unless (zerop (tn-offset y))
2294 ;;; Expm1 = exp(x) - 1.
2295 ;;; Handles the following special cases:
2296 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2297 (define-vop (fexpm1)
2299 (:args (x :scs (double-reg) :target fr0))
2300 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2301 (:temporary (:sc double-reg :offset fr0-offset
2302 :from :argument :to :result) fr0)
2303 (:temporary (:sc double-reg :offset fr1-offset
2304 :from :argument :to :result) fr1)
2305 (:temporary (:sc double-reg :offset fr2-offset
2306 :from :argument :to :result) fr2)
2307 (:results (y :scs (double-reg)))
2308 (:arg-types double-float)
2309 (:result-types double-float)
2310 (:policy :fast-safe)
2311 (:note "inline expm1 function")
2313 (:save-p :compute-only)
2316 (note-this-location vop :internal-error)
2317 (unless (zerop (tn-offset x))
2318 (inst fxch x) ; x to top of stack
2319 (unless (location= x y)
2320 (inst fst x))) ; maybe save it
2321 ;; Check for Inf or NaN
2325 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2326 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2327 (inst and ah-tn #x02) ; Test sign of Inf.
2328 (inst jmp :z DONE) ; +Inf gives +Inf.
2329 (inst fstp fr0) ; -Inf gives -1.0
2332 (inst jmp-short DONE)
2334 ;; Free two stack slots leaving the argument on top.
2338 (inst fmul fr1) ; Now fr0 = x log2(e)
2353 (unless (zerop (tn-offset y))
2358 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2359 (:temporary (:sc double-reg :offset fr0-offset
2360 :from :argument :to :result) fr0)
2361 (:temporary (:sc double-reg :offset fr1-offset
2362 :from :argument :to :result) fr1)
2363 (:results (y :scs (double-reg)))
2364 (:arg-types double-float)
2365 (:result-types double-float)
2366 (:policy :fast-safe)
2367 (:note "inline log function")
2369 (:save-p :compute-only)
2371 (note-this-location vop :internal-error)
2386 ;; x is in a FP reg, not fr0 or fr1
2390 (inst fldd (make-random-tn :kind :normal
2391 :sc (sc-or-lose 'double-reg)
2392 :offset (1- (tn-offset x))))))
2394 ((double-stack descriptor-reg)
2398 (if (sc-is x double-stack)
2399 (inst fldd (ea-for-df-stack x))
2400 (inst fldd (ea-for-df-desc x)))
2405 (t (inst fstd y)))))
2407 (define-vop (flog10)
2409 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2410 (:temporary (:sc double-reg :offset fr0-offset
2411 :from :argument :to :result) fr0)
2412 (:temporary (:sc double-reg :offset fr1-offset
2413 :from :argument :to :result) fr1)
2414 (:results (y :scs (double-reg)))
2415 (:arg-types double-float)
2416 (:result-types double-float)
2417 (:policy :fast-safe)
2418 (:note "inline log10 function")
2420 (:save-p :compute-only)
2422 (note-this-location vop :internal-error)
2437 ;; x is in a FP reg, not fr0 or fr1
2441 (inst fldd (make-random-tn :kind :normal
2442 :sc (sc-or-lose 'double-reg)
2443 :offset (1- (tn-offset x))))))
2445 ((double-stack descriptor-reg)
2449 (if (sc-is x double-stack)
2450 (inst fldd (ea-for-df-stack x))
2451 (inst fldd (ea-for-df-desc x)))
2456 (t (inst fstd y)))))
2460 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2461 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2462 (:temporary (:sc double-reg :offset fr0-offset
2463 :from (:argument 0) :to :result) fr0)
2464 (:temporary (:sc double-reg :offset fr1-offset
2465 :from (:argument 1) :to :result) fr1)
2466 (:temporary (:sc double-reg :offset fr2-offset
2467 :from :load :to :result) fr2)
2468 (:results (r :scs (double-reg)))
2469 (:arg-types double-float double-float)
2470 (:result-types double-float)
2471 (:policy :fast-safe)
2472 (:note "inline pow function")
2474 (:save-p :compute-only)
2476 (note-this-location vop :internal-error)
2477 ;; Setup x in fr0 and y in fr1
2479 ;; x in fr0; y in fr1
2480 ((and (sc-is x double-reg) (zerop (tn-offset x))
2481 (sc-is y double-reg) (= 1 (tn-offset y))))
2482 ;; y in fr1; x not in fr0
2483 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2487 (copy-fp-reg-to-fr0 x))
2490 (inst fldd (ea-for-df-stack x)))
2493 (inst fldd (ea-for-df-desc x)))))
2494 ;; x in fr0; y not in fr1
2495 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2497 ;; Now load y to fr0
2500 (copy-fp-reg-to-fr0 y))
2503 (inst fldd (ea-for-df-stack y)))
2506 (inst fldd (ea-for-df-desc y))))
2508 ;; x in fr1; y not in fr1
2509 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2513 (copy-fp-reg-to-fr0 y))
2516 (inst fldd (ea-for-df-stack y)))
2519 (inst fldd (ea-for-df-desc y))))
2522 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2524 ;; Now load x to fr0
2527 (copy-fp-reg-to-fr0 x))
2530 (inst fldd (ea-for-df-stack x)))
2533 (inst fldd (ea-for-df-desc x)))))
2534 ;; Neither x or y are in either fr0 or fr1
2541 (inst fldd (make-random-tn :kind :normal
2542 :sc (sc-or-lose 'double-reg)
2543 :offset (- (tn-offset y) 2))))
2545 (inst fldd (ea-for-df-stack y)))
2547 (inst fldd (ea-for-df-desc y))))
2551 (inst fldd (make-random-tn :kind :normal
2552 :sc (sc-or-lose 'double-reg)
2553 :offset (1- (tn-offset x)))))
2555 (inst fldd (ea-for-df-stack x)))
2557 (inst fldd (ea-for-df-desc x))))))
2559 ;; Now have x at fr0; and y at fr1
2561 ;; Now fr0=y log2(x)
2565 (inst fsubp-sti fr1)
2568 (inst faddp-sti fr1)
2573 (t (inst fstd r)))))
2575 (define-vop (fscalen)
2576 (:translate %scalbn)
2577 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2578 (y :scs (signed-stack signed-reg) :target temp))
2579 (:temporary (:sc double-reg :offset fr0-offset
2580 :from (:argument 0) :to :result) fr0)
2581 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2582 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2583 (:results (r :scs (double-reg)))
2584 (:arg-types double-float signed-num)
2585 (:result-types double-float)
2586 (:policy :fast-safe)
2587 (:note "inline scalbn function")
2589 ;; Setup x in fr0 and y in fr1
2620 (inst fld (make-random-tn :kind :normal
2621 :sc (sc-or-lose 'double-reg)
2622 :offset (1- (tn-offset x)))))))
2623 ((double-stack descriptor-reg)
2632 (if (sc-is x double-stack)
2633 (inst fldd (ea-for-df-stack x))
2634 (inst fldd (ea-for-df-desc x)))))
2636 (unless (zerop (tn-offset r))
2639 (define-vop (fscale)
2641 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2642 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2643 (:temporary (:sc double-reg :offset fr0-offset
2644 :from (:argument 0) :to :result) fr0)
2645 (:temporary (:sc double-reg :offset fr1-offset
2646 :from (:argument 1) :to :result) fr1)
2647 (:results (r :scs (double-reg)))
2648 (:arg-types double-float double-float)
2649 (:result-types double-float)
2650 (:policy :fast-safe)
2651 (:note "inline scalb function")
2653 (:save-p :compute-only)
2655 (note-this-location vop :internal-error)
2656 ;; Setup x in fr0 and y in fr1
2658 ;; x in fr0; y in fr1
2659 ((and (sc-is x double-reg) (zerop (tn-offset x))
2660 (sc-is y double-reg) (= 1 (tn-offset y))))
2661 ;; y in fr1; x not in fr0
2662 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2666 (copy-fp-reg-to-fr0 x))
2669 (inst fldd (ea-for-df-stack x)))
2672 (inst fldd (ea-for-df-desc x)))))
2673 ;; x in fr0; y not in fr1
2674 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2676 ;; Now load y to fr0
2679 (copy-fp-reg-to-fr0 y))
2682 (inst fldd (ea-for-df-stack y)))
2685 (inst fldd (ea-for-df-desc y))))
2687 ;; x in fr1; y not in fr1
2688 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2692 (copy-fp-reg-to-fr0 y))
2695 (inst fldd (ea-for-df-stack y)))
2698 (inst fldd (ea-for-df-desc y))))
2701 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2703 ;; Now load x to fr0
2706 (copy-fp-reg-to-fr0 x))
2709 (inst fldd (ea-for-df-stack x)))
2712 (inst fldd (ea-for-df-desc x)))))
2713 ;; Neither x or y are in either fr0 or fr1
2720 (inst fldd (make-random-tn :kind :normal
2721 :sc (sc-or-lose 'double-reg)
2722 :offset (- (tn-offset y) 2))))
2724 (inst fldd (ea-for-df-stack y)))
2726 (inst fldd (ea-for-df-desc y))))
2730 (inst fldd (make-random-tn :kind :normal
2731 :sc (sc-or-lose 'double-reg)
2732 :offset (1- (tn-offset x)))))
2734 (inst fldd (ea-for-df-stack x)))
2736 (inst fldd (ea-for-df-desc x))))))
2738 ;; Now have x at fr0; and y at fr1
2740 (unless (zerop (tn-offset r))
2743 (define-vop (flog1p)
2745 (:args (x :scs (double-reg) :to :result))
2746 (:temporary (:sc double-reg :offset fr0-offset
2747 :from :argument :to :result) fr0)
2748 (:temporary (:sc double-reg :offset fr1-offset
2749 :from :argument :to :result) fr1)
2750 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2751 (:results (y :scs (double-reg)))
2752 (:arg-types double-float)
2753 (:result-types double-float)
2754 (:policy :fast-safe)
2755 (:note "inline log1p function")
2758 ;; x is in a FP reg, not fr0, fr1.
2761 (inst fldd (make-random-tn :kind :normal
2762 :sc (sc-or-lose 'double-reg)
2763 :offset (- (tn-offset x) 2)))
2765 (inst push #x3e947ae1) ; Constant 0.29
2767 (inst fld (make-ea :dword :base esp-tn))
2770 (inst fnstsw) ; status word to ax
2771 (inst and ah-tn #x45)
2772 (inst jmp :z WITHIN-RANGE)
2773 ;; Out of range for fyl2xp1.
2775 (inst faddd (make-random-tn :kind :normal
2776 :sc (sc-or-lose 'double-reg)
2777 :offset (- (tn-offset x) 1)))
2785 (inst fldd (make-random-tn :kind :normal
2786 :sc (sc-or-lose 'double-reg)
2787 :offset (- (tn-offset x) 1)))
2793 (t (inst fstd y)))))
2795 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2796 ;;; instruction and a range check can be avoided.
2797 (define-vop (flog1p-pentium)
2799 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2800 (:temporary (:sc double-reg :offset fr0-offset
2801 :from :argument :to :result) fr0)
2802 (:temporary (:sc double-reg :offset fr1-offset
2803 :from :argument :to :result) fr1)
2804 (:results (y :scs (double-reg)))
2805 (:arg-types double-float)
2806 (:result-types double-float)
2807 (:policy :fast-safe)
2808 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2809 (:note "inline log1p with limited x range function")
2811 (:save-p :compute-only)
2813 (note-this-location vop :internal-error)
2828 ;; x is in a FP reg, not fr0 or fr1
2832 (inst fldd (make-random-tn :kind :normal
2833 :sc (sc-or-lose 'double-reg)
2834 :offset (1- (tn-offset x)))))))
2835 ((double-stack descriptor-reg)
2839 (if (sc-is x double-stack)
2840 (inst fldd (ea-for-df-stack x))
2841 (inst fldd (ea-for-df-desc x)))))
2846 (t (inst fstd y)))))
2850 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2851 (:temporary (:sc double-reg :offset fr0-offset
2852 :from :argument :to :result) fr0)
2853 (:temporary (:sc double-reg :offset fr1-offset
2854 :from :argument :to :result) fr1)
2855 (:results (y :scs (double-reg)))
2856 (:arg-types double-float)
2857 (:result-types double-float)
2858 (:policy :fast-safe)
2859 (:note "inline logb function")
2861 (:save-p :compute-only)
2863 (note-this-location vop :internal-error)
2874 ;; x is in a FP reg, not fr0 or fr1
2877 (inst fldd (make-random-tn :kind :normal
2878 :sc (sc-or-lose 'double-reg)
2879 :offset (- (tn-offset x) 2))))))
2880 ((double-stack descriptor-reg)
2883 (if (sc-is x double-stack)
2884 (inst fldd (ea-for-df-stack x))
2885 (inst fldd (ea-for-df-desc x)))))
2896 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2897 (:temporary (:sc double-reg :offset fr0-offset
2898 :from (:argument 0) :to :result) fr0)
2899 (:temporary (:sc double-reg :offset fr1-offset
2900 :from (:argument 0) :to :result) fr1)
2901 (:results (r :scs (double-reg)))
2902 (:arg-types double-float)
2903 (:result-types double-float)
2904 (:policy :fast-safe)
2905 (:note "inline atan function")
2907 (:save-p :compute-only)
2909 (note-this-location vop :internal-error)
2910 ;; Setup x in fr1 and 1.0 in fr0
2913 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2916 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2918 ;; x not in fr0 or fr1
2925 (inst fldd (make-random-tn :kind :normal
2926 :sc (sc-or-lose 'double-reg)
2927 :offset (- (tn-offset x) 2))))
2929 (inst fldd (ea-for-df-stack x)))
2931 (inst fldd (ea-for-df-desc x))))))
2933 ;; Now have x at fr1; and 1.0 at fr0
2938 (t (inst fstd r)))))
2940 (define-vop (fatan2)
2942 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2943 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2944 (:temporary (:sc double-reg :offset fr0-offset
2945 :from (:argument 1) :to :result) fr0)
2946 (:temporary (:sc double-reg :offset fr1-offset
2947 :from (:argument 0) :to :result) fr1)
2948 (:results (r :scs (double-reg)))
2949 (:arg-types double-float double-float)
2950 (:result-types double-float)
2951 (:policy :fast-safe)
2952 (:note "inline atan2 function")
2954 (:save-p :compute-only)
2956 (note-this-location vop :internal-error)
2957 ;; Setup x in fr1 and y in fr0
2959 ;; y in fr0; x in fr1
2960 ((and (sc-is y double-reg) (zerop (tn-offset y))
2961 (sc-is x double-reg) (= 1 (tn-offset x))))
2962 ;; x in fr1; y not in fr0
2963 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2967 (copy-fp-reg-to-fr0 y))
2970 (inst fldd (ea-for-df-stack y)))
2973 (inst fldd (ea-for-df-desc y)))))
2974 ((and (sc-is x double-reg) (zerop (tn-offset x))
2975 (sc-is y double-reg) (zerop (tn-offset x)))
2978 ;; y in fr0; x not in fr1
2979 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2981 ;; Now load x to fr0
2984 (copy-fp-reg-to-fr0 x))
2987 (inst fldd (ea-for-df-stack x)))
2990 (inst fldd (ea-for-df-desc x))))
2992 ;; y in fr1; x not in fr1
2993 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2997 (copy-fp-reg-to-fr0 x))
3000 (inst fldd (ea-for-df-stack x)))
3003 (inst fldd (ea-for-df-desc x))))
3006 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3008 ;; Now load y to fr0
3011 (copy-fp-reg-to-fr0 y))
3014 (inst fldd (ea-for-df-stack y)))
3017 (inst fldd (ea-for-df-desc y)))))
3018 ;; Neither y or x are in either fr0 or fr1
3025 (inst fldd (make-random-tn :kind :normal
3026 :sc (sc-or-lose 'double-reg)
3027 :offset (- (tn-offset x) 2))))
3029 (inst fldd (ea-for-df-stack x)))
3031 (inst fldd (ea-for-df-desc x))))
3035 (inst fldd (make-random-tn :kind :normal
3036 :sc (sc-or-lose 'double-reg)
3037 :offset (1- (tn-offset y)))))
3039 (inst fldd (ea-for-df-stack y)))
3041 (inst fldd (ea-for-df-desc y))))))
3043 ;; Now have y at fr0; and x at fr1
3048 (t (inst fstd r)))))
3049 ) ; PROGN #!-LONG-FLOAT
3054 ;;; Lets use some of the 80387 special functions.
3056 ;;; These defs will not take effect unless code/irrat.lisp is modified
3057 ;;; to remove the inlined alien routine def.
3059 (macrolet ((frob (func trans op)
3060 `(define-vop (,func)
3061 (:args (x :scs (long-reg) :target fr0))
3062 (:temporary (:sc long-reg :offset fr0-offset
3063 :from :argument :to :result) fr0)
3065 (:results (y :scs (long-reg)))
3066 (:arg-types long-float)
3067 (:result-types long-float)
3069 (:policy :fast-safe)
3070 (:note "inline NPX function")
3072 (:save-p :compute-only)
3075 (note-this-location vop :internal-error)
3076 (unless (zerop (tn-offset x))
3077 (inst fxch x) ; x to top of stack
3078 (unless (location= x y)
3079 (inst fst x))) ; maybe save it
3080 (inst ,op) ; clobber st0
3081 (cond ((zerop (tn-offset y))
3082 (maybe-fp-wait node))
3086 ;; Quick versions of FSIN and FCOS that require the argument to be
3087 ;; within range 2^63.
3088 (frob fsin-quick %sin-quick fsin)
3089 (frob fcos-quick %cos-quick fcos)
3090 (frob fsqrt %sqrt fsqrt))
3092 ;;; Quick version of ftan that requires the argument to be within
3094 (define-vop (ftan-quick)
3095 (:translate %tan-quick)
3096 (:args (x :scs (long-reg) :target fr0))
3097 (:temporary (:sc long-reg :offset fr0-offset
3098 :from :argument :to :result) fr0)
3099 (:temporary (:sc long-reg :offset fr1-offset
3100 :from :argument :to :result) fr1)
3101 (:results (y :scs (long-reg)))
3102 (:arg-types long-float)
3103 (:result-types long-float)
3104 (:policy :fast-safe)
3105 (:note "inline tan function")
3107 (:save-p :compute-only)
3109 (note-this-location vop :internal-error)
3118 (inst fldd (make-random-tn :kind :normal
3119 :sc (sc-or-lose 'double-reg)
3120 :offset (- (tn-offset x) 2)))))
3131 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3132 ;;; the argument is out of range 2^63 and would thus be hopelessly
3134 (macrolet ((frob (func trans op)
3135 `(define-vop (,func)
3137 (:args (x :scs (long-reg) :target fr0))
3138 (:temporary (:sc long-reg :offset fr0-offset
3139 :from :argument :to :result) fr0)
3140 (:temporary (:sc unsigned-reg :offset eax-offset
3141 :from :argument :to :result) eax)
3142 (:results (y :scs (long-reg)))
3143 (:arg-types long-float)
3144 (:result-types long-float)
3145 (:policy :fast-safe)
3146 (:note "inline sin/cos function")
3148 (:save-p :compute-only)
3151 (note-this-location vop :internal-error)
3152 (unless (zerop (tn-offset x))
3153 (inst fxch x) ; x to top of stack
3154 (unless (location= x y)
3155 (inst fst x))) ; maybe save it
3157 (inst fnstsw) ; status word to ax
3158 (inst and ah-tn #x04) ; C2
3160 ;; Else x was out of range so reduce it; ST0 is unchanged.
3161 (inst fstp fr0) ; Load 0.0
3164 (unless (zerop (tn-offset y))
3166 (frob fsin %sin fsin)
3167 (frob fcos %cos fcos))
3171 (:args (x :scs (long-reg) :target fr0))
3172 (:temporary (:sc long-reg :offset fr0-offset
3173 :from :argument :to :result) fr0)
3174 (:temporary (:sc long-reg :offset fr1-offset
3175 :from :argument :to :result) fr1)
3176 (:temporary (:sc unsigned-reg :offset eax-offset
3177 :from :argument :to :result) eax)
3178 (:results (y :scs (long-reg)))
3179 (:arg-types long-float)
3180 (:result-types long-float)
3182 (:policy :fast-safe)
3183 (:note "inline tan function")
3185 (:save-p :compute-only)
3188 (note-this-location vop :internal-error)
3197 (inst fldd (make-random-tn :kind :normal
3198 :sc (sc-or-lose 'double-reg)
3199 :offset (- (tn-offset x) 2)))))
3201 (inst fnstsw) ; status word to ax
3202 (inst and ah-tn #x04) ; C2
3204 ;; Else x was out of range so reduce it; ST0 is unchanged.
3205 (inst fldz) ; Load 0.0
3217 ;;; Modified exp that handles the following special cases:
3218 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3221 (:args (x :scs (long-reg) :target fr0))
3222 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3223 (:temporary (:sc long-reg :offset fr0-offset
3224 :from :argument :to :result) fr0)
3225 (:temporary (:sc long-reg :offset fr1-offset
3226 :from :argument :to :result) fr1)
3227 (:temporary (:sc long-reg :offset fr2-offset
3228 :from :argument :to :result) fr2)
3229 (:results (y :scs (long-reg)))
3230 (:arg-types long-float)
3231 (:result-types long-float)
3232 (:policy :fast-safe)
3233 (:note "inline exp function")
3235 (:save-p :compute-only)
3238 (note-this-location vop :internal-error)
3239 (unless (zerop (tn-offset x))
3240 (inst fxch x) ; x to top of stack
3241 (unless (location= x y)
3242 (inst fst x))) ; maybe save it
3243 ;; Check for Inf or NaN
3247 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3248 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3249 (inst and ah-tn #x02) ; Test sign of Inf.
3250 (inst jmp :z DONE) ; +Inf gives +Inf.
3251 (inst fstp fr0) ; -Inf gives 0
3253 (inst jmp-short DONE)
3258 ;; Now fr0=x log2(e)
3262 (inst fsubp-sti fr1)
3265 (inst faddp-sti fr1)
3269 (unless (zerop (tn-offset y))
3272 ;;; Expm1 = exp(x) - 1.
3273 ;;; Handles the following special cases:
3274 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3275 (define-vop (fexpm1)
3277 (:args (x :scs (long-reg) :target fr0))
3278 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3279 (:temporary (:sc long-reg :offset fr0-offset
3280 :from :argument :to :result) fr0)
3281 (:temporary (:sc long-reg :offset fr1-offset
3282 :from :argument :to :result) fr1)
3283 (:temporary (:sc long-reg :offset fr2-offset
3284 :from :argument :to :result) fr2)
3285 (:results (y :scs (long-reg)))
3286 (:arg-types long-float)
3287 (:result-types long-float)
3288 (:policy :fast-safe)
3289 (:note "inline expm1 function")
3291 (:save-p :compute-only)
3294 (note-this-location vop :internal-error)
3295 (unless (zerop (tn-offset x))
3296 (inst fxch x) ; x to top of stack
3297 (unless (location= x y)
3298 (inst fst x))) ; maybe save it
3299 ;; Check for Inf or NaN
3303 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3304 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3305 (inst and ah-tn #x02) ; Test sign of Inf.
3306 (inst jmp :z DONE) ; +Inf gives +Inf.
3307 (inst fstp fr0) ; -Inf gives -1.0
3310 (inst jmp-short DONE)
3312 ;; Free two stack slots leaving the argument on top.
3316 (inst fmul fr1) ; Now fr0 = x log2(e)
3331 (unless (zerop (tn-offset y))
3336 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3337 (:temporary (:sc long-reg :offset fr0-offset
3338 :from :argument :to :result) fr0)
3339 (:temporary (:sc long-reg :offset fr1-offset
3340 :from :argument :to :result) fr1)
3341 (:results (y :scs (long-reg)))
3342 (:arg-types long-float)
3343 (:result-types long-float)
3344 (:policy :fast-safe)
3345 (:note "inline log function")
3347 (:save-p :compute-only)
3349 (note-this-location vop :internal-error)
3364 ;; x is in a FP reg, not fr0 or fr1
3368 (inst fldd (make-random-tn :kind :normal
3369 :sc (sc-or-lose 'double-reg)
3370 :offset (1- (tn-offset x))))))
3372 ((long-stack descriptor-reg)
3376 (if (sc-is x long-stack)
3377 (inst fldl (ea-for-lf-stack x))
3378 (inst fldl (ea-for-lf-desc x)))
3383 (t (inst fstd y)))))
3385 (define-vop (flog10)
3387 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3388 (:temporary (:sc long-reg :offset fr0-offset
3389 :from :argument :to :result) fr0)
3390 (:temporary (:sc long-reg :offset fr1-offset
3391 :from :argument :to :result) fr1)
3392 (:results (y :scs (long-reg)))
3393 (:arg-types long-float)
3394 (:result-types long-float)
3395 (:policy :fast-safe)
3396 (:note "inline log10 function")
3398 (:save-p :compute-only)
3400 (note-this-location vop :internal-error)
3415 ;; x is in a FP reg, not fr0 or fr1
3419 (inst fldd (make-random-tn :kind :normal
3420 :sc (sc-or-lose 'double-reg)
3421 :offset (1- (tn-offset x))))))
3423 ((long-stack descriptor-reg)
3427 (if (sc-is x long-stack)
3428 (inst fldl (ea-for-lf-stack x))
3429 (inst fldl (ea-for-lf-desc x)))
3434 (t (inst fstd y)))))
3438 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3439 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3440 (:temporary (:sc long-reg :offset fr0-offset
3441 :from (:argument 0) :to :result) fr0)
3442 (:temporary (:sc long-reg :offset fr1-offset
3443 :from (:argument 1) :to :result) fr1)
3444 (:temporary (:sc long-reg :offset fr2-offset
3445 :from :load :to :result) fr2)
3446 (:results (r :scs (long-reg)))
3447 (:arg-types long-float long-float)
3448 (:result-types long-float)
3449 (:policy :fast-safe)
3450 (:note "inline pow function")
3452 (:save-p :compute-only)
3454 (note-this-location vop :internal-error)
3455 ;; Setup x in fr0 and y in fr1
3457 ;; x in fr0; y in fr1
3458 ((and (sc-is x long-reg) (zerop (tn-offset x))
3459 (sc-is y long-reg) (= 1 (tn-offset y))))
3460 ;; y in fr1; x not in fr0
3461 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3465 (copy-fp-reg-to-fr0 x))
3468 (inst fldl (ea-for-lf-stack x)))
3471 (inst fldl (ea-for-lf-desc x)))))
3472 ;; x in fr0; y not in fr1
3473 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3475 ;; Now load y to fr0
3478 (copy-fp-reg-to-fr0 y))
3481 (inst fldl (ea-for-lf-stack y)))
3484 (inst fldl (ea-for-lf-desc y))))
3486 ;; x in fr1; y not in fr1
3487 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3491 (copy-fp-reg-to-fr0 y))
3494 (inst fldl (ea-for-lf-stack y)))
3497 (inst fldl (ea-for-lf-desc y))))
3500 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3502 ;; Now load x to fr0
3505 (copy-fp-reg-to-fr0 x))
3508 (inst fldl (ea-for-lf-stack x)))
3511 (inst fldl (ea-for-lf-desc x)))))
3512 ;; Neither x or y are in either fr0 or fr1
3519 (inst fldd (make-random-tn :kind :normal
3520 :sc (sc-or-lose 'double-reg)
3521 :offset (- (tn-offset y) 2))))
3523 (inst fldl (ea-for-lf-stack y)))
3525 (inst fldl (ea-for-lf-desc y))))
3529 (inst fldd (make-random-tn :kind :normal
3530 :sc (sc-or-lose 'double-reg)
3531 :offset (1- (tn-offset x)))))
3533 (inst fldl (ea-for-lf-stack x)))
3535 (inst fldl (ea-for-lf-desc x))))))
3537 ;; Now have x at fr0; and y at fr1
3539 ;; Now fr0=y log2(x)
3543 (inst fsubp-sti fr1)
3546 (inst faddp-sti fr1)
3551 (t (inst fstd r)))))
3553 (define-vop (fscalen)
3554 (:translate %scalbn)
3555 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3556 (y :scs (signed-stack signed-reg) :target temp))
3557 (:temporary (:sc long-reg :offset fr0-offset
3558 :from (:argument 0) :to :result) fr0)
3559 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3560 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3561 (:results (r :scs (long-reg)))
3562 (:arg-types long-float signed-num)
3563 (:result-types long-float)
3564 (:policy :fast-safe)
3565 (:note "inline scalbn function")
3567 ;; Setup x in fr0 and y in fr1
3598 (inst fld (make-random-tn :kind :normal
3599 :sc (sc-or-lose 'double-reg)
3600 :offset (1- (tn-offset x)))))))
3601 ((long-stack descriptor-reg)
3610 (if (sc-is x long-stack)
3611 (inst fldl (ea-for-lf-stack x))
3612 (inst fldl (ea-for-lf-desc x)))))
3614 (unless (zerop (tn-offset r))
3617 (define-vop (fscale)
3619 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3620 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3621 (:temporary (:sc long-reg :offset fr0-offset
3622 :from (:argument 0) :to :result) fr0)
3623 (:temporary (:sc long-reg :offset fr1-offset
3624 :from (:argument 1) :to :result) fr1)
3625 (:results (r :scs (long-reg)))
3626 (:arg-types long-float long-float)
3627 (:result-types long-float)
3628 (:policy :fast-safe)
3629 (:note "inline scalb function")
3631 (:save-p :compute-only)
3633 (note-this-location vop :internal-error)
3634 ;; Setup x in fr0 and y in fr1
3636 ;; x in fr0; y in fr1
3637 ((and (sc-is x long-reg) (zerop (tn-offset x))
3638 (sc-is y long-reg) (= 1 (tn-offset y))))
3639 ;; y in fr1; x not in fr0
3640 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3644 (copy-fp-reg-to-fr0 x))
3647 (inst fldl (ea-for-lf-stack x)))
3650 (inst fldl (ea-for-lf-desc x)))))
3651 ;; x in fr0; y not in fr1
3652 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3654 ;; Now load y to fr0
3657 (copy-fp-reg-to-fr0 y))
3660 (inst fldl (ea-for-lf-stack y)))
3663 (inst fldl (ea-for-lf-desc y))))
3665 ;; x in fr1; y not in fr1
3666 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3670 (copy-fp-reg-to-fr0 y))
3673 (inst fldl (ea-for-lf-stack y)))
3676 (inst fldl (ea-for-lf-desc y))))
3679 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3681 ;; Now load x to fr0
3684 (copy-fp-reg-to-fr0 x))
3687 (inst fldl (ea-for-lf-stack x)))
3690 (inst fldl (ea-for-lf-desc x)))))
3691 ;; Neither x or y are in either fr0 or fr1
3698 (inst fldd (make-random-tn :kind :normal
3699 :sc (sc-or-lose 'double-reg)
3700 :offset (- (tn-offset y) 2))))
3702 (inst fldl (ea-for-lf-stack y)))
3704 (inst fldl (ea-for-lf-desc y))))
3708 (inst fldd (make-random-tn :kind :normal
3709 :sc (sc-or-lose 'double-reg)
3710 :offset (1- (tn-offset x)))))
3712 (inst fldl (ea-for-lf-stack x)))
3714 (inst fldl (ea-for-lf-desc x))))))
3716 ;; Now have x at fr0; and y at fr1
3718 (unless (zerop (tn-offset r))
3721 (define-vop (flog1p)
3723 (:args (x :scs (long-reg) :to :result))
3724 (:temporary (:sc long-reg :offset fr0-offset
3725 :from :argument :to :result) fr0)
3726 (:temporary (:sc long-reg :offset fr1-offset
3727 :from :argument :to :result) fr1)
3728 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3729 (:results (y :scs (long-reg)))
3730 (:arg-types long-float)
3731 (:result-types long-float)
3732 (:policy :fast-safe)
3733 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3734 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3735 ;; an enormous PROGN above. Still, it would be probably be good to
3736 ;; add some code to warn about redefining VOPs.
3737 (:note "inline log1p function")
3740 ;; x is in a FP reg, not fr0, fr1.
3743 (inst fldd (make-random-tn :kind :normal
3744 :sc (sc-or-lose 'double-reg)
3745 :offset (- (tn-offset x) 2)))
3747 (inst push #x3e947ae1) ; Constant 0.29
3749 (inst fld (make-ea :dword :base esp-tn))
3752 (inst fnstsw) ; status word to ax
3753 (inst and ah-tn #x45)
3754 (inst jmp :z WITHIN-RANGE)
3755 ;; Out of range for fyl2xp1.
3757 (inst faddd (make-random-tn :kind :normal
3758 :sc (sc-or-lose 'double-reg)
3759 :offset (- (tn-offset x) 1)))
3767 (inst fldd (make-random-tn :kind :normal
3768 :sc (sc-or-lose 'double-reg)
3769 :offset (- (tn-offset x) 1)))
3775 (t (inst fstd y)))))
3777 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3778 ;;; instruction and a range check can be avoided.
3779 (define-vop (flog1p-pentium)
3781 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3782 (:temporary (:sc long-reg :offset fr0-offset
3783 :from :argument :to :result) fr0)
3784 (:temporary (:sc long-reg :offset fr1-offset
3785 :from :argument :to :result) fr1)
3786 (:results (y :scs (long-reg)))
3787 (:arg-types long-float)
3788 (:result-types long-float)
3789 (:policy :fast-safe)
3790 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3791 (:note "inline log1p function")
3807 ;; x is in a FP reg, not fr0 or fr1
3811 (inst fldd (make-random-tn :kind :normal
3812 :sc (sc-or-lose 'double-reg)
3813 :offset (1- (tn-offset x)))))))
3814 ((long-stack descriptor-reg)
3818 (if (sc-is x long-stack)
3819 (inst fldl (ea-for-lf-stack x))
3820 (inst fldl (ea-for-lf-desc x)))))
3825 (t (inst fstd y)))))
3829 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3830 (:temporary (:sc long-reg :offset fr0-offset
3831 :from :argument :to :result) fr0)
3832 (:temporary (:sc long-reg :offset fr1-offset
3833 :from :argument :to :result) fr1)
3834 (:results (y :scs (long-reg)))
3835 (:arg-types long-float)
3836 (:result-types long-float)
3837 (:policy :fast-safe)
3838 (:note "inline logb function")
3840 (:save-p :compute-only)
3842 (note-this-location vop :internal-error)
3853 ;; x is in a FP reg, not fr0 or fr1
3856 (inst fldd (make-random-tn :kind :normal
3857 :sc (sc-or-lose 'double-reg)
3858 :offset (- (tn-offset x) 2))))))
3859 ((long-stack descriptor-reg)
3862 (if (sc-is x long-stack)
3863 (inst fldl (ea-for-lf-stack x))
3864 (inst fldl (ea-for-lf-desc x)))))
3875 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3876 (:temporary (:sc long-reg :offset fr0-offset
3877 :from (:argument 0) :to :result) fr0)
3878 (:temporary (:sc long-reg :offset fr1-offset
3879 :from (:argument 0) :to :result) fr1)
3880 (:results (r :scs (long-reg)))
3881 (:arg-types long-float)
3882 (:result-types long-float)
3883 (:policy :fast-safe)
3884 (:note "inline atan function")
3886 (:save-p :compute-only)
3888 (note-this-location vop :internal-error)
3889 ;; Setup x in fr1 and 1.0 in fr0
3892 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3895 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3897 ;; x not in fr0 or fr1
3904 (inst fldd (make-random-tn :kind :normal
3905 :sc (sc-or-lose 'double-reg)
3906 :offset (- (tn-offset x) 2))))
3908 (inst fldl (ea-for-lf-stack x)))
3910 (inst fldl (ea-for-lf-desc x))))))
3912 ;; Now have x at fr1; and 1.0 at fr0
3917 (t (inst fstd r)))))
3919 (define-vop (fatan2)
3921 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3922 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3923 (:temporary (:sc long-reg :offset fr0-offset
3924 :from (:argument 1) :to :result) fr0)
3925 (:temporary (:sc long-reg :offset fr1-offset
3926 :from (:argument 0) :to :result) fr1)
3927 (:results (r :scs (long-reg)))
3928 (:arg-types long-float long-float)
3929 (:result-types long-float)
3930 (:policy :fast-safe)
3931 (:note "inline atan2 function")
3933 (:save-p :compute-only)
3935 (note-this-location vop :internal-error)
3936 ;; Setup x in fr1 and y in fr0
3938 ;; y in fr0; x in fr1
3939 ((and (sc-is y long-reg) (zerop (tn-offset y))
3940 (sc-is x long-reg) (= 1 (tn-offset x))))
3941 ;; x in fr1; y not in fr0
3942 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3946 (copy-fp-reg-to-fr0 y))
3949 (inst fldl (ea-for-lf-stack y)))
3952 (inst fldl (ea-for-lf-desc y)))))
3953 ;; y in fr0; x not in fr1
3954 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3956 ;; Now load x to fr0
3959 (copy-fp-reg-to-fr0 x))
3962 (inst fldl (ea-for-lf-stack x)))
3965 (inst fldl (ea-for-lf-desc x))))
3967 ;; y in fr1; x not in fr1
3968 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3972 (copy-fp-reg-to-fr0 x))
3975 (inst fldl (ea-for-lf-stack x)))
3978 (inst fldl (ea-for-lf-desc x))))
3981 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3983 ;; Now load y to fr0
3986 (copy-fp-reg-to-fr0 y))
3989 (inst fldl (ea-for-lf-stack y)))
3992 (inst fldl (ea-for-lf-desc y)))))
3993 ;; Neither y or x are in either fr0 or fr1
4000 (inst fldd (make-random-tn :kind :normal
4001 :sc (sc-or-lose 'double-reg)
4002 :offset (- (tn-offset x) 2))))
4004 (inst fldl (ea-for-lf-stack x)))
4006 (inst fldl (ea-for-lf-desc x))))
4010 (inst fldd (make-random-tn :kind :normal
4011 :sc (sc-or-lose 'double-reg)
4012 :offset (1- (tn-offset y)))))
4014 (inst fldl (ea-for-lf-stack y)))
4016 (inst fldl (ea-for-lf-desc y))))))
4018 ;; Now have y at fr0; and x at fr1
4023 (t (inst fstd r)))))
4025 ) ; PROGN #!+LONG-FLOAT
4027 ;;;; complex float VOPs
4029 (define-vop (make-complex-single-float)
4030 (:translate complex)
4031 (:args (real :scs (single-reg) :to :result :target r
4032 :load-if (not (location= real r)))
4033 (imag :scs (single-reg) :to :save))
4034 (:arg-types single-float single-float)
4035 (:results (r :scs (complex-single-reg) :from (:argument 0)
4036 :load-if (not (sc-is r complex-single-stack))))
4037 (:result-types complex-single-float)
4038 (:note "inline complex single-float creation")
4039 (:policy :fast-safe)
4043 (let ((r-real (complex-double-reg-real-tn r)))
4044 (unless (location= real r-real)
4045 (cond ((zerop (tn-offset r-real))
4046 (copy-fp-reg-to-fr0 real))
4047 ((zerop (tn-offset real))
4052 (inst fxch real)))))
4053 (let ((r-imag (complex-double-reg-imag-tn r)))
4054 (unless (location= imag r-imag)
4055 (cond ((zerop (tn-offset imag))
4060 (inst fxch imag))))))
4061 (complex-single-stack
4062 (unless (location= real r)
4063 (cond ((zerop (tn-offset real))
4064 (inst fst (ea-for-csf-real-stack r)))
4067 (inst fst (ea-for-csf-real-stack r))
4070 (inst fst (ea-for-csf-imag-stack r))
4071 (inst fxch imag)))))
4073 (define-vop (make-complex-double-float)
4074 (:translate complex)
4075 (:args (real :scs (double-reg) :target r
4076 :load-if (not (location= real r)))
4077 (imag :scs (double-reg) :to :save))
4078 (:arg-types double-float double-float)
4079 (:results (r :scs (complex-double-reg) :from (:argument 0)
4080 :load-if (not (sc-is r complex-double-stack))))
4081 (:result-types complex-double-float)
4082 (:note "inline complex double-float creation")
4083 (:policy :fast-safe)
4087 (let ((r-real (complex-double-reg-real-tn r)))
4088 (unless (location= real r-real)
4089 (cond ((zerop (tn-offset r-real))
4090 (copy-fp-reg-to-fr0 real))
4091 ((zerop (tn-offset real))
4096 (inst fxch real)))))
4097 (let ((r-imag (complex-double-reg-imag-tn r)))
4098 (unless (location= imag r-imag)
4099 (cond ((zerop (tn-offset imag))
4104 (inst fxch imag))))))
4105 (complex-double-stack
4106 (unless (location= real r)
4107 (cond ((zerop (tn-offset real))
4108 (inst fstd (ea-for-cdf-real-stack r)))
4111 (inst fstd (ea-for-cdf-real-stack r))
4114 (inst fstd (ea-for-cdf-imag-stack r))
4115 (inst fxch imag)))))
4118 (define-vop (make-complex-long-float)
4119 (:translate complex)
4120 (:args (real :scs (long-reg) :target r
4121 :load-if (not (location= real r)))
4122 (imag :scs (long-reg) :to :save))
4123 (:arg-types long-float long-float)
4124 (:results (r :scs (complex-long-reg) :from (:argument 0)
4125 :load-if (not (sc-is r complex-long-stack))))
4126 (:result-types complex-long-float)
4127 (:note "inline complex long-float creation")
4128 (:policy :fast-safe)
4132 (let ((r-real (complex-double-reg-real-tn r)))
4133 (unless (location= real r-real)
4134 (cond ((zerop (tn-offset r-real))
4135 (copy-fp-reg-to-fr0 real))
4136 ((zerop (tn-offset real))
4141 (inst fxch real)))))
4142 (let ((r-imag (complex-double-reg-imag-tn r)))
4143 (unless (location= imag r-imag)
4144 (cond ((zerop (tn-offset imag))
4149 (inst fxch imag))))))
4151 (unless (location= real r)
4152 (cond ((zerop (tn-offset real))
4153 (store-long-float (ea-for-clf-real-stack r)))
4156 (store-long-float (ea-for-clf-real-stack r))
4159 (store-long-float (ea-for-clf-imag-stack r))
4160 (inst fxch imag)))))
4163 (define-vop (complex-float-value)
4164 (:args (x :target r))
4166 (:variant-vars offset)
4167 (:policy :fast-safe)
4169 (cond ((sc-is x complex-single-reg complex-double-reg
4170 #!+long-float complex-long-reg)
4172 (make-random-tn :kind :normal
4173 :sc (sc-or-lose 'double-reg)
4174 :offset (+ offset (tn-offset x)))))
4175 (unless (location= value-tn r)
4176 (cond ((zerop (tn-offset r))
4177 (copy-fp-reg-to-fr0 value-tn))
4178 ((zerop (tn-offset value-tn))
4181 (inst fxch value-tn)
4183 (inst fxch value-tn))))))
4184 ((sc-is r single-reg)
4185 (let ((ea (sc-case x
4186 (complex-single-stack
4188 (0 (ea-for-csf-real-stack x))
4189 (1 (ea-for-csf-imag-stack x))))
4192 (0 (ea-for-csf-real-desc x))
4193 (1 (ea-for-csf-imag-desc x)))))))
4194 (with-empty-tn@fp-top(r)
4196 ((sc-is r double-reg)
4197 (let ((ea (sc-case x
4198 (complex-double-stack
4200 (0 (ea-for-cdf-real-stack x))
4201 (1 (ea-for-cdf-imag-stack x))))
4204 (0 (ea-for-cdf-real-desc x))
4205 (1 (ea-for-cdf-imag-desc x)))))))
4206 (with-empty-tn@fp-top(r)
4210 (let ((ea (sc-case x
4213 (0 (ea-for-clf-real-stack x))
4214 (1 (ea-for-clf-imag-stack x))))
4217 (0 (ea-for-clf-real-desc x))
4218 (1 (ea-for-clf-imag-desc x)))))))
4219 (with-empty-tn@fp-top(r)
4221 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4223 (define-vop (realpart/complex-single-float complex-float-value)
4224 (:translate realpart)
4225 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4227 (:arg-types complex-single-float)
4228 (:results (r :scs (single-reg)))
4229 (:result-types single-float)
4230 (:note "complex float realpart")
4233 (define-vop (realpart/complex-double-float complex-float-value)
4234 (:translate realpart)
4235 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4237 (:arg-types complex-double-float)
4238 (:results (r :scs (double-reg)))
4239 (:result-types double-float)
4240 (:note "complex float realpart")
4244 (define-vop (realpart/complex-long-float complex-float-value)
4245 (:translate realpart)
4246 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4248 (:arg-types complex-long-float)
4249 (:results (r :scs (long-reg)))
4250 (:result-types long-float)
4251 (:note "complex float realpart")
4254 (define-vop (imagpart/complex-single-float complex-float-value)
4255 (:translate imagpart)
4256 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4258 (:arg-types complex-single-float)
4259 (:results (r :scs (single-reg)))
4260 (:result-types single-float)
4261 (:note "complex float imagpart")
4264 (define-vop (imagpart/complex-double-float complex-float-value)
4265 (:translate imagpart)
4266 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4268 (:arg-types complex-double-float)
4269 (:results (r :scs (double-reg)))
4270 (:result-types double-float)
4271 (:note "complex float imagpart")
4275 (define-vop (imagpart/complex-long-float complex-float-value)
4276 (:translate imagpart)
4277 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4279 (:arg-types complex-long-float)
4280 (:results (r :scs (long-reg)))
4281 (:result-types long-float)
4282 (:note "complex float imagpart")
4285 ;;; hack dummy VOPs to bias the representation selection of their
4286 ;;; arguments towards a FP register, which can help avoid consing at
4287 ;;; inappropriate locations
4288 (defknown double-float-reg-bias (double-float) (values))
4289 (define-vop (double-float-reg-bias)
4290 (:translate double-float-reg-bias)
4291 (:args (x :scs (double-reg double-stack) :load-if nil))
4292 (:arg-types double-float)
4293 (:policy :fast-safe)
4294 (:note "inline dummy FP register bias")
4297 (defknown single-float-reg-bias (single-float) (values))
4298 (define-vop (single-float-reg-bias)
4299 (:translate single-float-reg-bias)
4300 (:args (x :scs (single-reg single-stack) :load-if nil))
4301 (:arg-types single-float)
4302 (:policy :fast-safe)
4303 (:note "inline dummy FP register bias")