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)
17 :disp (- (* ,slot n-word-bytes)
18 other-pointer-lowtag))))
19 (defun ea-for-sf-desc (tn)
20 (ea-for-xf-desc tn single-float-value-slot))
21 (defun ea-for-df-desc (tn)
22 (ea-for-xf-desc tn double-float-value-slot))
24 (defun ea-for-lf-desc (tn)
25 (ea-for-xf-desc tn long-float-value-slot))
27 (defun ea-for-csf-real-desc (tn)
28 (ea-for-xf-desc tn complex-single-float-real-slot))
29 (defun ea-for-csf-imag-desc (tn)
30 (ea-for-xf-desc tn complex-single-float-imag-slot))
31 (defun ea-for-cdf-real-desc (tn)
32 (ea-for-xf-desc tn complex-double-float-real-slot))
33 (defun ea-for-cdf-imag-desc (tn)
34 (ea-for-xf-desc tn complex-double-float-imag-slot))
36 (defun ea-for-clf-real-desc (tn)
37 (ea-for-xf-desc tn complex-long-float-real-slot))
39 (defun ea-for-clf-imag-desc (tn)
40 (ea-for-xf-desc tn complex-long-float-imag-slot)))
42 (macrolet ((ea-for-xf-stack (tn kind)
45 :disp (frame-byte-offset
47 (ecase ,kind (:single 0) (:double 1) (:long 2)))))))
48 (defun ea-for-sf-stack (tn)
49 (ea-for-xf-stack tn :single))
50 (defun ea-for-df-stack (tn)
51 (ea-for-xf-stack tn :double))
53 (defun ea-for-lf-stack (tn)
54 (ea-for-xf-stack tn :long)))
56 ;;; Telling the FPU to wait is required in order to make signals occur
57 ;;; at the expected place, but naturally slows things down.
59 ;;; NODE is the node whose compilation policy controls the decision
60 ;;; whether to just blast through carelessly or carefully emit wait
61 ;;; instructions and whatnot.
63 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
64 ;;; #'NOTE-NEXT-INSTRUCTION.
66 ;;; Until 2004-03-15, the implementation of this was buggy; it
67 ;;; unconditionally emitted the WAIT instruction. It turns out that
68 ;;; this is the right thing to do anyway; omitting them can lead to
69 ;;; system corruption on conforming code. -- CSR
70 (defun maybe-fp-wait (node &optional note-next-instruction)
71 (declare (ignore node))
73 (when (policy node (or (= debug 3) (> safety speed))))
74 (when note-next-instruction
75 (note-next-instruction note-next-instruction :internal-error))
78 ;;; complex float stack EAs
79 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
82 :disp (frame-byte-offset
89 (ecase ,slot (:real 1) (:imag 2))))))))
90 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
91 (ea-for-cxf-stack tn :single :real base))
92 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
93 (ea-for-cxf-stack tn :single :imag base))
94 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
95 (ea-for-cxf-stack tn :double :real base))
96 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
97 (ea-for-cxf-stack tn :double :imag base))
99 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
100 (ea-for-cxf-stack tn :long :real base))
102 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
103 (ea-for-cxf-stack tn :long :imag base)))
105 ;;; Abstract out the copying of a FP register to the FP stack top, and
106 ;;; provide two alternatives for its implementation. Note: it's not
107 ;;; necessary to distinguish between a single or double register move
110 ;;; Using a Pop then load.
111 (defun copy-fp-reg-to-fr0 (reg)
112 (aver (not (zerop (tn-offset reg))))
114 (inst fld (make-random-tn :kind :normal
115 :sc (sc-or-lose 'double-reg)
116 :offset (1- (tn-offset reg)))))
117 ;;; Using Fxch then Fst to restore the original reg contents.
119 (defun copy-fp-reg-to-fr0 (reg)
120 (aver (not (zerop (tn-offset reg))))
124 ;;; The x86 can't store a long-float to memory without popping the
125 ;;; stack and marking a register as empty, so it is necessary to
126 ;;; restore the register from memory.
128 (defun store-long-float (ea)
134 ;;; X is source, Y is destination.
135 (define-move-fun (load-single 2) (vop x y)
136 ((single-stack) (single-reg))
137 (with-empty-tn@fp-top(y)
138 (inst fld (ea-for-sf-stack x))))
140 (define-move-fun (store-single 2) (vop x y)
141 ((single-reg) (single-stack))
142 (cond ((zerop (tn-offset x))
143 (inst fst (ea-for-sf-stack y)))
146 (inst fst (ea-for-sf-stack y))
147 ;; This may not be necessary as ST0 is likely invalid now.
150 (define-move-fun (load-double 2) (vop x y)
151 ((double-stack) (double-reg))
152 (with-empty-tn@fp-top(y)
153 (inst fldd (ea-for-df-stack x))))
155 (define-move-fun (store-double 2) (vop x y)
156 ((double-reg) (double-stack))
157 (cond ((zerop (tn-offset x))
158 (inst fstd (ea-for-df-stack y)))
161 (inst fstd (ea-for-df-stack y))
162 ;; This may not be necessary as ST0 is likely invalid now.
166 (define-move-fun (load-long 2) (vop x y)
167 ((long-stack) (long-reg))
168 (with-empty-tn@fp-top(y)
169 (inst fldl (ea-for-lf-stack x))))
172 (define-move-fun (store-long 2) (vop x y)
173 ((long-reg) (long-stack))
174 (cond ((zerop (tn-offset x))
175 (store-long-float (ea-for-lf-stack y)))
178 (store-long-float (ea-for-lf-stack y))
179 ;; This may not be necessary as ST0 is likely invalid now.
182 ;;; The i387 has instructions to load some useful constants. This
183 ;;; doesn't save much time but might cut down on memory access and
184 ;;; reduce the size of the constant vector (CV). Intel claims they are
185 ;;; stored in a more precise form on chip. Anyhow, might as well use
186 ;;; the feature. It can be turned off by hacking the
187 ;;; "immediate-constant-sc" in vm.lisp.
188 (eval-when (:compile-toplevel :execute)
189 (setf *read-default-float-format*
190 #!+long-float 'long-float #!-long-float 'double-float))
191 (define-move-fun (load-fp-constant 2) (vop x y)
192 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
193 (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
194 (with-empty-tn@fp-top(y)
199 ((= value (coerce pi *read-default-float-format*))
201 ((= value (log 10e0 2e0))
203 ((= value (log 2.718281828459045235360287471352662e0 2e0))
205 ((= value (log 2e0 10e0))
207 ((= value (log 2e0 2.718281828459045235360287471352662e0))
209 (t (warn "ignoring bogus i387 constant ~A" value))))))
210 (eval-when (:compile-toplevel :execute)
211 (setf *read-default-float-format* 'single-float))
213 ;;;; complex float move functions
215 (defun complex-single-reg-real-tn (x)
216 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
217 :offset (tn-offset x)))
218 (defun complex-single-reg-imag-tn (x)
219 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
220 :offset (1+ (tn-offset x))))
222 (defun complex-double-reg-real-tn (x)
223 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
224 :offset (tn-offset x)))
225 (defun complex-double-reg-imag-tn (x)
226 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
227 :offset (1+ (tn-offset x))))
230 (defun complex-long-reg-real-tn (x)
231 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
232 :offset (tn-offset x)))
234 (defun complex-long-reg-imag-tn (x)
235 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
236 :offset (1+ (tn-offset x))))
238 ;;; X is source, Y is destination.
239 (define-move-fun (load-complex-single 2) (vop x y)
240 ((complex-single-stack) (complex-single-reg))
241 (let ((real-tn (complex-single-reg-real-tn y)))
242 (with-empty-tn@fp-top (real-tn)
243 (inst fld (ea-for-csf-real-stack x))))
244 (let ((imag-tn (complex-single-reg-imag-tn y)))
245 (with-empty-tn@fp-top (imag-tn)
246 (inst fld (ea-for-csf-imag-stack x)))))
248 (define-move-fun (store-complex-single 2) (vop x y)
249 ((complex-single-reg) (complex-single-stack))
250 (let ((real-tn (complex-single-reg-real-tn x)))
251 (cond ((zerop (tn-offset real-tn))
252 (inst fst (ea-for-csf-real-stack y)))
255 (inst fst (ea-for-csf-real-stack y))
256 (inst fxch real-tn))))
257 (let ((imag-tn (complex-single-reg-imag-tn x)))
259 (inst fst (ea-for-csf-imag-stack y))
260 (inst fxch imag-tn)))
262 (define-move-fun (load-complex-double 2) (vop x y)
263 ((complex-double-stack) (complex-double-reg))
264 (let ((real-tn (complex-double-reg-real-tn y)))
265 (with-empty-tn@fp-top(real-tn)
266 (inst fldd (ea-for-cdf-real-stack x))))
267 (let ((imag-tn (complex-double-reg-imag-tn y)))
268 (with-empty-tn@fp-top(imag-tn)
269 (inst fldd (ea-for-cdf-imag-stack x)))))
271 (define-move-fun (store-complex-double 2) (vop x y)
272 ((complex-double-reg) (complex-double-stack))
273 (let ((real-tn (complex-double-reg-real-tn x)))
274 (cond ((zerop (tn-offset real-tn))
275 (inst fstd (ea-for-cdf-real-stack y)))
278 (inst fstd (ea-for-cdf-real-stack y))
279 (inst fxch real-tn))))
280 (let ((imag-tn (complex-double-reg-imag-tn x)))
282 (inst fstd (ea-for-cdf-imag-stack y))
283 (inst fxch imag-tn)))
286 (define-move-fun (load-complex-long 2) (vop x y)
287 ((complex-long-stack) (complex-long-reg))
288 (let ((real-tn (complex-long-reg-real-tn y)))
289 (with-empty-tn@fp-top(real-tn)
290 (inst fldl (ea-for-clf-real-stack x))))
291 (let ((imag-tn (complex-long-reg-imag-tn y)))
292 (with-empty-tn@fp-top(imag-tn)
293 (inst fldl (ea-for-clf-imag-stack x)))))
296 (define-move-fun (store-complex-long 2) (vop x y)
297 ((complex-long-reg) (complex-long-stack))
298 (let ((real-tn (complex-long-reg-real-tn x)))
299 (cond ((zerop (tn-offset real-tn))
300 (store-long-float (ea-for-clf-real-stack y)))
303 (store-long-float (ea-for-clf-real-stack y))
304 (inst fxch real-tn))))
305 (let ((imag-tn (complex-long-reg-imag-tn x)))
307 (store-long-float (ea-for-clf-imag-stack y))
308 (inst fxch imag-tn)))
313 ;;; float register to register moves
314 (define-vop (float-move)
319 (unless (location= x y)
320 (cond ((zerop (tn-offset y))
321 (copy-fp-reg-to-fr0 x))
322 ((zerop (tn-offset x))
329 (define-vop (single-move float-move)
330 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
331 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
332 (define-move-vop single-move :move (single-reg) (single-reg))
334 (define-vop (double-move float-move)
335 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
336 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
337 (define-move-vop double-move :move (double-reg) (double-reg))
340 (define-vop (long-move float-move)
341 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
342 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
344 (define-move-vop long-move :move (long-reg) (long-reg))
346 ;;; complex float register to register moves
347 (define-vop (complex-float-move)
348 (:args (x :target y :load-if (not (location= x y))))
349 (:results (y :load-if (not (location= x y))))
350 (:note "complex float move")
352 (unless (location= x y)
353 ;; Note the complex-float-regs are aligned to every second
354 ;; float register so there is not need to worry about overlap.
355 (let ((x-real (complex-double-reg-real-tn x))
356 (y-real (complex-double-reg-real-tn y)))
357 (cond ((zerop (tn-offset y-real))
358 (copy-fp-reg-to-fr0 x-real))
359 ((zerop (tn-offset x-real))
364 (inst fxch x-real))))
365 (let ((x-imag (complex-double-reg-imag-tn x))
366 (y-imag (complex-double-reg-imag-tn y)))
369 (inst fxch x-imag)))))
371 (define-vop (complex-single-move complex-float-move)
372 (:args (x :scs (complex-single-reg) :target y
373 :load-if (not (location= x y))))
374 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
375 (define-move-vop complex-single-move :move
376 (complex-single-reg) (complex-single-reg))
378 (define-vop (complex-double-move complex-float-move)
379 (:args (x :scs (complex-double-reg)
380 :target y :load-if (not (location= x y))))
381 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
382 (define-move-vop complex-double-move :move
383 (complex-double-reg) (complex-double-reg))
386 (define-vop (complex-long-move complex-float-move)
387 (:args (x :scs (complex-long-reg)
388 :target y :load-if (not (location= x y))))
389 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
391 (define-move-vop complex-long-move :move
392 (complex-long-reg) (complex-long-reg))
394 ;;; Move from float to a descriptor reg. allocating a new float
395 ;;; object in the process.
396 (define-vop (move-from-single)
397 (:args (x :scs (single-reg) :to :save))
398 (:results (y :scs (descriptor-reg)))
400 (:note "float to pointer coercion")
402 (with-fixed-allocation (y
404 single-float-size node)
406 (inst fst (ea-for-sf-desc y))))))
407 (define-move-vop move-from-single :move
408 (single-reg) (descriptor-reg))
410 (define-vop (move-from-double)
411 (:args (x :scs (double-reg) :to :save))
412 (:results (y :scs (descriptor-reg)))
414 (:note "float to pointer coercion")
416 (with-fixed-allocation (y
421 (inst fstd (ea-for-df-desc y))))))
422 (define-move-vop move-from-double :move
423 (double-reg) (descriptor-reg))
426 (define-vop (move-from-long)
427 (:args (x :scs (long-reg) :to :save))
428 (:results (y :scs (descriptor-reg)))
430 (:note "float to pointer coercion")
432 (with-fixed-allocation (y
437 (store-long-float (ea-for-lf-desc y))))))
439 (define-move-vop move-from-long :move
440 (long-reg) (descriptor-reg))
442 (define-vop (move-from-fp-constant)
443 (:args (x :scs (fp-constant)))
444 (:results (y :scs (descriptor-reg)))
446 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
447 (0f0 (load-symbol-value y *fp-constant-0f0*))
448 (1f0 (load-symbol-value y *fp-constant-1f0*))
449 (0d0 (load-symbol-value y *fp-constant-0d0*))
450 (1d0 (load-symbol-value y *fp-constant-1d0*))
452 (0l0 (load-symbol-value y *fp-constant-0l0*))
454 (1l0 (load-symbol-value y *fp-constant-1l0*))
456 (#.pi (load-symbol-value y *fp-constant-pi*))
458 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
460 (#.(log 2.718281828459045235360287471352662L0 2l0)
461 (load-symbol-value y *fp-constant-l2e*))
463 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
465 (#.(log 2l0 2.718281828459045235360287471352662L0)
466 (load-symbol-value y *fp-constant-ln2*)))))
467 (define-move-vop move-from-fp-constant :move
468 (fp-constant) (descriptor-reg))
470 ;;; Move from a descriptor to a float register.
471 (define-vop (move-to-single)
472 (:args (x :scs (descriptor-reg)))
473 (:results (y :scs (single-reg)))
474 (:note "pointer to float coercion")
476 (with-empty-tn@fp-top(y)
477 (inst fld (ea-for-sf-desc x)))))
478 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
480 (define-vop (move-to-double)
481 (:args (x :scs (descriptor-reg)))
482 (:results (y :scs (double-reg)))
483 (:note "pointer to float coercion")
485 (with-empty-tn@fp-top(y)
486 (inst fldd (ea-for-df-desc x)))))
487 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
490 (define-vop (move-to-long)
491 (:args (x :scs (descriptor-reg)))
492 (:results (y :scs (long-reg)))
493 (:note "pointer to float coercion")
495 (with-empty-tn@fp-top(y)
496 (inst fldl (ea-for-lf-desc x)))))
498 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
500 ;;; Move from complex float to a descriptor reg. allocating a new
501 ;;; complex float object in the process.
502 (define-vop (move-from-complex-single)
503 (:args (x :scs (complex-single-reg) :to :save))
504 (:results (y :scs (descriptor-reg)))
506 (:note "complex float to pointer coercion")
508 (with-fixed-allocation (y
509 complex-single-float-widetag
510 complex-single-float-size
512 (let ((real-tn (complex-single-reg-real-tn x)))
513 (with-tn@fp-top(real-tn)
514 (inst fst (ea-for-csf-real-desc y))))
515 (let ((imag-tn (complex-single-reg-imag-tn x)))
516 (with-tn@fp-top(imag-tn)
517 (inst fst (ea-for-csf-imag-desc y)))))))
518 (define-move-vop move-from-complex-single :move
519 (complex-single-reg) (descriptor-reg))
521 (define-vop (move-from-complex-double)
522 (:args (x :scs (complex-double-reg) :to :save))
523 (:results (y :scs (descriptor-reg)))
525 (:note "complex float to pointer coercion")
527 (with-fixed-allocation (y
528 complex-double-float-widetag
529 complex-double-float-size
531 (let ((real-tn (complex-double-reg-real-tn x)))
532 (with-tn@fp-top(real-tn)
533 (inst fstd (ea-for-cdf-real-desc y))))
534 (let ((imag-tn (complex-double-reg-imag-tn x)))
535 (with-tn@fp-top(imag-tn)
536 (inst fstd (ea-for-cdf-imag-desc y)))))))
537 (define-move-vop move-from-complex-double :move
538 (complex-double-reg) (descriptor-reg))
541 (define-vop (move-from-complex-long)
542 (:args (x :scs (complex-long-reg) :to :save))
543 (:results (y :scs (descriptor-reg)))
545 (:note "complex float to pointer coercion")
547 (with-fixed-allocation (y
548 complex-long-float-widetag
549 complex-long-float-size
551 (let ((real-tn (complex-long-reg-real-tn x)))
552 (with-tn@fp-top(real-tn)
553 (store-long-float (ea-for-clf-real-desc y))))
554 (let ((imag-tn (complex-long-reg-imag-tn x)))
555 (with-tn@fp-top(imag-tn)
556 (store-long-float (ea-for-clf-imag-desc y)))))))
558 (define-move-vop move-from-complex-long :move
559 (complex-long-reg) (descriptor-reg))
561 ;;; Move from a descriptor to a complex float register.
562 (macrolet ((frob (name sc format)
565 (:args (x :scs (descriptor-reg)))
566 (:results (y :scs (,sc)))
567 (:note "pointer to complex float coercion")
569 (let ((real-tn (complex-double-reg-real-tn y)))
570 (with-empty-tn@fp-top(real-tn)
572 (:single '((inst fld (ea-for-csf-real-desc x))))
573 (:double '((inst fldd (ea-for-cdf-real-desc x))))
575 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
576 (let ((imag-tn (complex-double-reg-imag-tn y)))
577 (with-empty-tn@fp-top(imag-tn)
579 (:single '((inst fld (ea-for-csf-imag-desc x))))
580 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
582 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
583 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
584 (frob move-to-complex-single complex-single-reg :single)
585 (frob move-to-complex-double complex-double-reg :double)
587 (frob move-to-complex-double complex-long-reg :long))
589 ;;;; the move argument vops
591 ;;;; Note these are also used to stuff fp numbers onto the c-call
592 ;;;; stack so the order is different than the lisp-stack.
594 ;;; the general MOVE-ARG VOP
595 (macrolet ((frob (name sc stack-sc format)
598 (:args (x :scs (,sc) :target y)
600 :load-if (not (sc-is y ,sc))))
602 (:note "float argument move")
603 (:generator ,(case format (:single 2) (:double 3) (:long 4))
606 (unless (location= x y)
607 (cond ((zerop (tn-offset y))
608 (copy-fp-reg-to-fr0 x))
609 ((zerop (tn-offset x))
616 (if (= (tn-offset fp) esp-offset)
618 (let* ((offset (* (tn-offset y) n-word-bytes))
619 (ea (make-ea :dword :base fp :disp offset)))
622 (:single '((inst fst ea)))
623 (:double '((inst fstd ea)))
625 (:long '((store-long-float ea))))))
629 :disp (frame-byte-offset
637 (:single '((inst fst ea)))
638 (:double '((inst fstd ea)))
640 (:long '((store-long-float ea)))))))))))
641 (define-move-vop ,name :move-arg
642 (,sc descriptor-reg) (,sc)))))
643 (frob move-single-float-arg single-reg single-stack :single)
644 (frob move-double-float-arg double-reg double-stack :double)
646 (frob move-long-float-arg long-reg long-stack :long))
648 ;;;; complex float MOVE-ARG VOP
649 (macrolet ((frob (name sc stack-sc format)
652 (:args (x :scs (,sc) :target y)
654 :load-if (not (sc-is y ,sc))))
656 (:note "complex float argument move")
657 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
660 (unless (location= x y)
661 (let ((x-real (complex-double-reg-real-tn x))
662 (y-real (complex-double-reg-real-tn y)))
663 (cond ((zerop (tn-offset y-real))
664 (copy-fp-reg-to-fr0 x-real))
665 ((zerop (tn-offset x-real))
670 (inst fxch x-real))))
671 (let ((x-imag (complex-double-reg-imag-tn x))
672 (y-imag (complex-double-reg-imag-tn y)))
675 (inst fxch x-imag))))
677 (let ((real-tn (complex-double-reg-real-tn x)))
678 (cond ((zerop (tn-offset real-tn))
682 (ea-for-csf-real-stack y fp))))
685 (ea-for-cdf-real-stack y fp))))
689 (ea-for-clf-real-stack y fp))))))
695 (ea-for-csf-real-stack y fp))))
698 (ea-for-cdf-real-stack y fp))))
702 (ea-for-clf-real-stack y fp)))))
703 (inst fxch real-tn))))
704 (let ((imag-tn (complex-double-reg-imag-tn x)))
708 '((inst fst (ea-for-csf-imag-stack y fp))))
710 '((inst fstd (ea-for-cdf-imag-stack y fp))))
714 (ea-for-clf-imag-stack y fp)))))
715 (inst fxch imag-tn))))))
716 (define-move-vop ,name :move-arg
717 (,sc descriptor-reg) (,sc)))))
718 (frob move-complex-single-float-arg
719 complex-single-reg complex-single-stack :single)
720 (frob move-complex-double-float-arg
721 complex-double-reg complex-double-stack :double)
723 (frob move-complex-long-float-arg
724 complex-long-reg complex-long-stack :long))
726 (define-move-vop move-arg :move-arg
727 (single-reg double-reg #!+long-float long-reg
728 complex-single-reg complex-double-reg #!+long-float complex-long-reg)
734 ;;; dtc: the floating point arithmetic vops
736 ;;; Note: Although these can accept x and y on the stack or pointed to
737 ;;; from a descriptor register, they will work with register loading
738 ;;; without these. Same deal with the result - it need only be a
739 ;;; register. When load-tns are needed they will probably be in ST0
740 ;;; and the code below should be able to correctly handle all cases.
742 ;;; However it seems to produce better code if all arg. and result
743 ;;; options are used; on the P86 there is no extra cost in using a
744 ;;; memory operand to the FP instructions - not so on the PPro.
746 ;;; It may also be useful to handle constant args?
748 ;;; 22-Jul-97: descriptor args lose in some simple cases when
749 ;;; a function result computed in a loop. Then Python insists
750 ;;; on consing the intermediate values! For example
753 ;;; (declare (type (simple-array double-float (*)) a)
756 ;;; (declare (type double-float sum))
758 ;;; (incf sum (* (aref a i)(aref a i))))
761 ;;; So, disabling descriptor args until this can be fixed elsewhere.
763 ((frob (op fop-sti fopr-sti
765 fopd foprd dname dcost
767 #!-long-float (declare (ignore lcost lname))
771 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
773 (y :scs (single-reg single-stack #+nil descriptor-reg)
775 (:temporary (:sc single-reg :offset fr0-offset
776 :from :eval :to :result) fr0)
777 (:results (r :scs (single-reg single-stack)))
778 (:arg-types single-float single-float)
779 (:result-types single-float)
781 (:note "inline float arithmetic")
783 (:save-p :compute-only)
786 ;; Handle a few special cases
788 ;; x, y, and r are the same register.
789 ((and (sc-is x single-reg) (location= x r) (location= y r))
790 (cond ((zerop (tn-offset r))
795 ;; XX the source register will not be valid.
796 (note-next-instruction vop :internal-error)
799 ;; x and r are the same register.
800 ((and (sc-is x single-reg) (location= x r))
801 (cond ((zerop (tn-offset r))
804 ;; ST(0) = ST(0) op ST(y)
807 ;; ST(0) = ST(0) op Mem
808 (inst ,fop (ea-for-sf-stack y)))
810 (inst ,fop (ea-for-sf-desc y)))))
815 (unless (zerop (tn-offset y))
816 (copy-fp-reg-to-fr0 y)))
817 ((single-stack descriptor-reg)
819 (if (sc-is y single-stack)
820 (inst fld (ea-for-sf-stack y))
821 (inst fld (ea-for-sf-desc y)))))
822 ;; ST(i) = ST(i) op ST0
824 (maybe-fp-wait node vop))
825 ;; y and r are the same register.
826 ((and (sc-is y single-reg) (location= y r))
827 (cond ((zerop (tn-offset r))
830 ;; ST(0) = ST(x) op ST(0)
833 ;; ST(0) = Mem op ST(0)
834 (inst ,fopr (ea-for-sf-stack x)))
836 (inst ,fopr (ea-for-sf-desc x)))))
841 (unless (zerop (tn-offset x))
842 (copy-fp-reg-to-fr0 x)))
843 ((single-stack descriptor-reg)
845 (if (sc-is x single-stack)
846 (inst fld (ea-for-sf-stack x))
847 (inst fld (ea-for-sf-desc x)))))
848 ;; ST(i) = ST(0) op ST(i)
850 (maybe-fp-wait node vop))
853 ;; Get the result to ST0.
855 ;; Special handling is needed if x or y are in ST0, and
856 ;; simpler code is generated.
859 ((and (sc-is x single-reg) (zerop (tn-offset x)))
865 (inst ,fop (ea-for-sf-stack y)))
867 (inst ,fop (ea-for-sf-desc y)))))
869 ((and (sc-is y single-reg) (zerop (tn-offset y)))
875 (inst ,fopr (ea-for-sf-stack x)))
877 (inst ,fopr (ea-for-sf-desc x)))))
882 (copy-fp-reg-to-fr0 x))
885 (inst fld (ea-for-sf-stack x)))
888 (inst fld (ea-for-sf-desc x))))
894 (inst ,fop (ea-for-sf-stack y)))
896 (inst ,fop (ea-for-sf-desc y))))))
898 (note-next-instruction vop :internal-error)
900 ;; Finally save the result.
903 (cond ((zerop (tn-offset r))
904 (maybe-fp-wait node))
908 (inst fst (ea-for-sf-stack r))))))))
912 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
914 (y :scs (double-reg double-stack #+nil descriptor-reg)
916 (:temporary (:sc double-reg :offset fr0-offset
917 :from :eval :to :result) fr0)
918 (:results (r :scs (double-reg double-stack)))
919 (:arg-types double-float double-float)
920 (:result-types double-float)
922 (:note "inline float arithmetic")
924 (:save-p :compute-only)
927 ;; Handle a few special cases.
929 ;; x, y, and r are the same register.
930 ((and (sc-is x double-reg) (location= x r) (location= y r))
931 (cond ((zerop (tn-offset r))
936 ;; XX the source register will not be valid.
937 (note-next-instruction vop :internal-error)
940 ;; x and r are the same register.
941 ((and (sc-is x double-reg) (location= x r))
942 (cond ((zerop (tn-offset r))
945 ;; ST(0) = ST(0) op ST(y)
948 ;; ST(0) = ST(0) op Mem
949 (inst ,fopd (ea-for-df-stack y)))
951 (inst ,fopd (ea-for-df-desc y)))))
956 (unless (zerop (tn-offset y))
957 (copy-fp-reg-to-fr0 y)))
958 ((double-stack descriptor-reg)
960 (if (sc-is y double-stack)
961 (inst fldd (ea-for-df-stack y))
962 (inst fldd (ea-for-df-desc y)))))
963 ;; ST(i) = ST(i) op ST0
965 (maybe-fp-wait node vop))
966 ;; y and r are the same register.
967 ((and (sc-is y double-reg) (location= y r))
968 (cond ((zerop (tn-offset r))
971 ;; ST(0) = ST(x) op ST(0)
974 ;; ST(0) = Mem op ST(0)
975 (inst ,foprd (ea-for-df-stack x)))
977 (inst ,foprd (ea-for-df-desc x)))))
982 (unless (zerop (tn-offset x))
983 (copy-fp-reg-to-fr0 x)))
984 ((double-stack descriptor-reg)
986 (if (sc-is x double-stack)
987 (inst fldd (ea-for-df-stack x))
988 (inst fldd (ea-for-df-desc x)))))
989 ;; ST(i) = ST(0) op ST(i)
991 (maybe-fp-wait node vop))
994 ;; Get the result to ST0.
996 ;; Special handling is needed if x or y are in ST0, and
997 ;; simpler code is generated.
1000 ((and (sc-is x double-reg) (zerop (tn-offset x)))
1006 (inst ,fopd (ea-for-df-stack y)))
1008 (inst ,fopd (ea-for-df-desc y)))))
1010 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1016 (inst ,foprd (ea-for-df-stack x)))
1018 (inst ,foprd (ea-for-df-desc x)))))
1023 (copy-fp-reg-to-fr0 x))
1026 (inst fldd (ea-for-df-stack x)))
1029 (inst fldd (ea-for-df-desc x))))
1035 (inst ,fopd (ea-for-df-stack y)))
1037 (inst ,fopd (ea-for-df-desc y))))))
1039 (note-next-instruction vop :internal-error)
1041 ;; Finally save the result.
1044 (cond ((zerop (tn-offset r))
1045 (maybe-fp-wait node))
1049 (inst fstd (ea-for-df-stack r))))))))
1052 (define-vop (,lname)
1054 (:args (x :scs (long-reg) :to :eval)
1055 (y :scs (long-reg) :to :eval))
1056 (:temporary (:sc long-reg :offset fr0-offset
1057 :from :eval :to :result) fr0)
1058 (:results (r :scs (long-reg)))
1059 (:arg-types long-float long-float)
1060 (:result-types long-float)
1061 (:policy :fast-safe)
1062 (:note "inline float arithmetic")
1064 (:save-p :compute-only)
1067 ;; Handle a few special cases.
1069 ;; x, y, and r are the same register.
1070 ((and (location= x r) (location= y r))
1071 (cond ((zerop (tn-offset r))
1076 ;; XX the source register will not be valid.
1077 (note-next-instruction vop :internal-error)
1080 ;; x and r are the same register.
1082 (cond ((zerop (tn-offset r))
1083 ;; ST(0) = ST(0) op ST(y)
1087 (unless (zerop (tn-offset y))
1088 (copy-fp-reg-to-fr0 y))
1089 ;; ST(i) = ST(i) op ST0
1091 (maybe-fp-wait node vop))
1092 ;; y and r are the same register.
1094 (cond ((zerop (tn-offset r))
1095 ;; ST(0) = ST(x) op ST(0)
1099 (unless (zerop (tn-offset x))
1100 (copy-fp-reg-to-fr0 x))
1101 ;; ST(i) = ST(0) op ST(i)
1102 (inst ,fopr-sti r)))
1103 (maybe-fp-wait node vop))
1106 ;; Get the result to ST0.
1108 ;; Special handling is needed if x or y are in ST0, and
1109 ;; simpler code is generated.
1112 ((zerop (tn-offset x))
1116 ((zerop (tn-offset y))
1121 (copy-fp-reg-to-fr0 x)
1125 (note-next-instruction vop :internal-error)
1127 ;; Finally save the result.
1128 (cond ((zerop (tn-offset r))
1129 (maybe-fp-wait node))
1131 (inst fst r))))))))))
1133 (frob + fadd-sti fadd-sti
1134 fadd fadd +/single-float 2
1135 faddd faddd +/double-float 2
1137 (frob - fsub-sti fsubr-sti
1138 fsub fsubr -/single-float 2
1139 fsubd fsubrd -/double-float 2
1141 (frob * fmul-sti fmul-sti
1142 fmul fmul */single-float 3
1143 fmuld fmuld */double-float 3
1145 (frob / fdiv-sti fdivr-sti
1146 fdiv fdivr //single-float 12
1147 fdivd fdivrd //double-float 12
1150 (macrolet ((frob (name inst translate sc type)
1151 `(define-vop (,name)
1152 (:args (x :scs (,sc) :target fr0))
1153 (:results (y :scs (,sc)))
1154 (:translate ,translate)
1155 (:policy :fast-safe)
1157 (:result-types ,type)
1158 (:temporary (:sc double-reg :offset fr0-offset
1159 :from :argument :to :result) fr0)
1161 (:note "inline float arithmetic")
1163 (:save-p :compute-only)
1165 (note-this-location vop :internal-error)
1166 (unless (zerop (tn-offset x))
1167 (inst fxch x) ; x to top of stack
1168 (unless (location= x y)
1169 (inst fst x))) ; Maybe save it.
1170 (inst ,inst) ; Clobber st0.
1171 (unless (zerop (tn-offset y))
1174 (frob abs/single-float fabs abs single-reg single-float)
1175 (frob abs/double-float fabs abs double-reg double-float)
1177 (frob abs/long-float fabs abs long-reg long-float)
1178 (frob %negate/single-float fchs %negate single-reg single-float)
1179 (frob %negate/double-float fchs %negate double-reg double-float)
1181 (frob %negate/long-float fchs %negate long-reg long-float))
1185 (define-vop (=/float)
1187 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1189 (:info target not-p)
1190 (:policy :fast-safe)
1192 (:save-p :compute-only)
1193 (:note "inline float comparison")
1196 (note-this-location vop :internal-error)
1198 ;; x is in ST0; y is in any reg.
1199 ((zerop (tn-offset x))
1201 ;; y is in ST0; x is in another reg.
1202 ((zerop (tn-offset y))
1204 ;; x and y are the same register, not ST0
1209 ;; x and y are different registers, neither ST0.
1214 (inst fnstsw) ; status word to ax
1215 (inst and ah-tn #x45) ; C3 C2 C0
1216 (inst cmp ah-tn #x40)
1217 (inst jmp (if not-p :ne :e) target)))
1219 (define-vop (=/single-float =/float)
1221 (:args (x :scs (single-reg))
1222 (y :scs (single-reg)))
1223 (:arg-types single-float single-float))
1225 (define-vop (=/double-float =/float)
1227 (:args (x :scs (double-reg))
1228 (y :scs (double-reg)))
1229 (:arg-types double-float double-float))
1232 (define-vop (=/long-float =/float)
1234 (:args (x :scs (long-reg))
1235 (y :scs (long-reg)))
1236 (:arg-types long-float long-float))
1238 (define-vop (<single-float)
1240 (:args (x :scs (single-reg single-stack descriptor-reg))
1241 (y :scs (single-reg single-stack descriptor-reg)))
1242 (:arg-types single-float single-float)
1243 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1244 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1246 (:info target not-p)
1247 (:policy :fast-safe)
1248 (:note "inline float comparison")
1251 ;; Handle a few special cases.
1254 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1258 ((single-stack descriptor-reg)
1259 (if (sc-is x single-stack)
1260 (inst fcom (ea-for-sf-stack x))
1261 (inst fcom (ea-for-sf-desc x)))))
1262 (inst fnstsw) ; status word to ax
1263 (inst and ah-tn #x45))
1265 ;; general case when y is not in ST0
1270 (unless (zerop (tn-offset x))
1271 (copy-fp-reg-to-fr0 x)))
1272 ((single-stack descriptor-reg)
1274 (if (sc-is x single-stack)
1275 (inst fld (ea-for-sf-stack x))
1276 (inst fld (ea-for-sf-desc x)))))
1280 ((single-stack descriptor-reg)
1281 (if (sc-is y single-stack)
1282 (inst fcom (ea-for-sf-stack y))
1283 (inst fcom (ea-for-sf-desc y)))))
1284 (inst fnstsw) ; status word to ax
1285 (inst and ah-tn #x45) ; C3 C2 C0
1286 (inst cmp ah-tn #x01)))
1287 (inst jmp (if not-p :ne :e) target)))
1289 (define-vop (<double-float)
1291 (:args (x :scs (double-reg double-stack descriptor-reg))
1292 (y :scs (double-reg double-stack descriptor-reg)))
1293 (:arg-types double-float double-float)
1294 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1295 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1297 (:info target not-p)
1298 (:policy :fast-safe)
1299 (:note "inline float comparison")
1302 ;; Handle a few special cases
1305 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1309 ((double-stack descriptor-reg)
1310 (if (sc-is x double-stack)
1311 (inst fcomd (ea-for-df-stack x))
1312 (inst fcomd (ea-for-df-desc x)))))
1313 (inst fnstsw) ; status word to ax
1314 (inst and ah-tn #x45))
1316 ;; General case when y is not in ST0.
1321 (unless (zerop (tn-offset x))
1322 (copy-fp-reg-to-fr0 x)))
1323 ((double-stack descriptor-reg)
1325 (if (sc-is x double-stack)
1326 (inst fldd (ea-for-df-stack x))
1327 (inst fldd (ea-for-df-desc x)))))
1331 ((double-stack descriptor-reg)
1332 (if (sc-is y double-stack)
1333 (inst fcomd (ea-for-df-stack y))
1334 (inst fcomd (ea-for-df-desc y)))))
1335 (inst fnstsw) ; status word to ax
1336 (inst and ah-tn #x45) ; C3 C2 C0
1337 (inst cmp ah-tn #x01)))
1338 (inst jmp (if not-p :ne :e) target)))
1341 (define-vop (<long-float)
1343 (:args (x :scs (long-reg))
1344 (y :scs (long-reg)))
1345 (:arg-types long-float long-float)
1346 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1348 (:info target not-p)
1349 (:policy :fast-safe)
1350 (:note "inline float comparison")
1354 ;; x is in ST0; y is in any reg.
1355 ((zerop (tn-offset x))
1357 (inst fnstsw) ; status word to ax
1358 (inst and ah-tn #x45) ; C3 C2 C0
1359 (inst cmp ah-tn #x01))
1360 ;; y is in ST0; x is in another reg.
1361 ((zerop (tn-offset y))
1363 (inst fnstsw) ; status word to ax
1364 (inst and ah-tn #x45))
1365 ;; x and y are the same register, not ST0
1366 ;; x and y are different registers, neither ST0.
1371 (inst fnstsw) ; status word to ax
1372 (inst and ah-tn #x45))) ; C3 C2 C0
1373 (inst jmp (if not-p :ne :e) target)))
1375 (define-vop (>single-float)
1377 (:args (x :scs (single-reg single-stack descriptor-reg))
1378 (y :scs (single-reg single-stack descriptor-reg)))
1379 (:arg-types single-float single-float)
1380 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1381 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1383 (:info target not-p)
1384 (:policy :fast-safe)
1385 (:note "inline float comparison")
1388 ;; Handle a few special cases.
1391 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1395 ((single-stack descriptor-reg)
1396 (if (sc-is x single-stack)
1397 (inst fcom (ea-for-sf-stack x))
1398 (inst fcom (ea-for-sf-desc x)))))
1399 (inst fnstsw) ; status word to ax
1400 (inst and ah-tn #x45)
1401 (inst cmp ah-tn #x01))
1403 ;; general case when y is not in ST0
1408 (unless (zerop (tn-offset x))
1409 (copy-fp-reg-to-fr0 x)))
1410 ((single-stack descriptor-reg)
1412 (if (sc-is x single-stack)
1413 (inst fld (ea-for-sf-stack x))
1414 (inst fld (ea-for-sf-desc x)))))
1418 ((single-stack descriptor-reg)
1419 (if (sc-is y single-stack)
1420 (inst fcom (ea-for-sf-stack y))
1421 (inst fcom (ea-for-sf-desc y)))))
1422 (inst fnstsw) ; status word to ax
1423 (inst and ah-tn #x45)))
1424 (inst jmp (if not-p :ne :e) target)))
1426 (define-vop (>double-float)
1428 (:args (x :scs (double-reg double-stack descriptor-reg))
1429 (y :scs (double-reg double-stack descriptor-reg)))
1430 (:arg-types double-float double-float)
1431 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1432 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1434 (:info target not-p)
1435 (:policy :fast-safe)
1436 (:note "inline float comparison")
1439 ;; Handle a few special cases.
1442 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1446 ((double-stack descriptor-reg)
1447 (if (sc-is x double-stack)
1448 (inst fcomd (ea-for-df-stack x))
1449 (inst fcomd (ea-for-df-desc x)))))
1450 (inst fnstsw) ; status word to ax
1451 (inst and ah-tn #x45)
1452 (inst cmp ah-tn #x01))
1454 ;; general case when y is not in ST0
1459 (unless (zerop (tn-offset x))
1460 (copy-fp-reg-to-fr0 x)))
1461 ((double-stack descriptor-reg)
1463 (if (sc-is x double-stack)
1464 (inst fldd (ea-for-df-stack x))
1465 (inst fldd (ea-for-df-desc x)))))
1469 ((double-stack descriptor-reg)
1470 (if (sc-is y double-stack)
1471 (inst fcomd (ea-for-df-stack y))
1472 (inst fcomd (ea-for-df-desc y)))))
1473 (inst fnstsw) ; status word to ax
1474 (inst and ah-tn #x45)))
1475 (inst jmp (if not-p :ne :e) target)))
1478 (define-vop (>long-float)
1480 (:args (x :scs (long-reg))
1481 (y :scs (long-reg)))
1482 (:arg-types long-float long-float)
1483 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1485 (:info target not-p)
1486 (:policy :fast-safe)
1487 (:note "inline float comparison")
1491 ;; y is in ST0; x is in any reg.
1492 ((zerop (tn-offset y))
1494 (inst fnstsw) ; status word to ax
1495 (inst and ah-tn #x45)
1496 (inst cmp ah-tn #x01))
1497 ;; x is in ST0; y is in another reg.
1498 ((zerop (tn-offset x))
1500 (inst fnstsw) ; status word to ax
1501 (inst and ah-tn #x45))
1502 ;; y and x are the same register, not ST0
1503 ;; y and x are different registers, neither ST0.
1508 (inst fnstsw) ; status word to ax
1509 (inst and ah-tn #x45)))
1510 (inst jmp (if not-p :ne :e) target)))
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)
1518 (:info target not-p y)
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))
1540 (inst jmp (if not-p :ne :e) target)))
1542 (define-vop (=0/single-float float-test)
1544 (:args (x :scs (single-reg)))
1545 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1547 (define-vop (=0/double-float float-test)
1549 (:args (x :scs (double-reg)))
1550 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1553 (define-vop (=0/long-float float-test)
1555 (:args (x :scs (long-reg)))
1556 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1559 (define-vop (<0/single-float float-test)
1561 (:args (x :scs (single-reg)))
1562 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1564 (define-vop (<0/double-float float-test)
1566 (:args (x :scs (double-reg)))
1567 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1570 (define-vop (<0/long-float float-test)
1572 (:args (x :scs (long-reg)))
1573 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1576 (define-vop (>0/single-float float-test)
1578 (:args (x :scs (single-reg)))
1579 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1581 (define-vop (>0/double-float float-test)
1583 (:args (x :scs (double-reg)))
1584 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1587 (define-vop (>0/long-float float-test)
1589 (:args (x :scs (long-reg)))
1590 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1594 (deftransform eql ((x y) (long-float long-float))
1595 `(and (= (long-float-low-bits x) (long-float-low-bits y))
1596 (= (long-float-high-bits x) (long-float-high-bits y))
1597 (= (long-float-exp-bits x) (long-float-exp-bits y))))
1601 (macrolet ((frob (name translate to-sc to-type)
1602 `(define-vop (,name)
1603 (:args (x :scs (signed-stack signed-reg) :target temp))
1604 (:temporary (:sc signed-stack) temp)
1605 (:results (y :scs (,to-sc)))
1606 (:arg-types signed-num)
1607 (:result-types ,to-type)
1608 (:policy :fast-safe)
1609 (:note "inline float coercion")
1610 (:translate ,translate)
1612 (:save-p :compute-only)
1617 (with-empty-tn@fp-top(y)
1618 (note-this-location vop :internal-error)
1621 (with-empty-tn@fp-top(y)
1622 (note-this-location vop :internal-error)
1623 (inst fild x))))))))
1624 (frob %single-float/signed %single-float single-reg single-float)
1625 (frob %double-float/signed %double-float double-reg double-float)
1627 (frob %long-float/signed %long-float long-reg long-float))
1629 (macrolet ((frob (name translate to-sc to-type)
1630 `(define-vop (,name)
1631 (:args (x :scs (unsigned-reg)))
1632 (:results (y :scs (,to-sc)))
1633 (:arg-types unsigned-num)
1634 (:result-types ,to-type)
1635 (:policy :fast-safe)
1636 (:note "inline float coercion")
1637 (:translate ,translate)
1639 (:save-p :compute-only)
1643 (with-empty-tn@fp-top(y)
1644 (note-this-location vop :internal-error)
1645 (inst fildl (make-ea :dword :base esp-tn)))
1646 (inst add esp-tn 8)))))
1647 (frob %single-float/unsigned %single-float single-reg single-float)
1648 (frob %double-float/unsigned %double-float double-reg double-float)
1650 (frob %long-float/unsigned %long-float long-reg long-float))
1652 ;;; These should be no-ops but the compiler might want to move some
1654 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1655 `(define-vop (,name)
1656 (:args (x :scs (,from-sc) :target y))
1657 (:results (y :scs (,to-sc)))
1658 (:arg-types ,from-type)
1659 (:result-types ,to-type)
1660 (:policy :fast-safe)
1661 (:note "inline float coercion")
1662 (:translate ,translate)
1664 (:save-p :compute-only)
1666 (note-this-location vop :internal-error)
1667 (unless (location= x y)
1669 ((zerop (tn-offset x))
1670 ;; x is in ST0, y is in another reg. not ST0
1672 ((zerop (tn-offset y))
1673 ;; y is in ST0, x is in another reg. not ST0
1674 (copy-fp-reg-to-fr0 x))
1676 ;; Neither x or y are in ST0, and they are not in
1680 (inst fxch x))))))))
1682 (frob %single-float/double-float %single-float double-reg
1683 double-float single-reg single-float)
1685 (frob %single-float/long-float %single-float long-reg
1686 long-float single-reg single-float)
1687 (frob %double-float/single-float %double-float single-reg single-float
1688 double-reg double-float)
1690 (frob %double-float/long-float %double-float long-reg long-float
1691 double-reg double-float)
1693 (frob %long-float/single-float %long-float single-reg single-float
1694 long-reg long-float)
1696 (frob %long-float/double-float %long-float double-reg double-float
1697 long-reg long-float))
1699 (macrolet ((frob (trans from-sc from-type round-p)
1700 `(define-vop (,(symbolicate trans "/" from-type))
1701 (:args (x :scs (,from-sc)))
1702 (:temporary (:sc signed-stack) stack-temp)
1704 '((:temporary (:sc unsigned-stack) scw)
1705 (:temporary (:sc any-reg) rcw)))
1706 (:results (y :scs (signed-reg)))
1707 (:arg-types ,from-type)
1708 (:result-types signed-num)
1710 (:policy :fast-safe)
1711 (:note "inline float truncate")
1713 (:save-p :compute-only)
1716 '((note-this-location vop :internal-error)
1717 ;; Catch any pending FPE exceptions.
1719 (,(if round-p 'progn 'pseudo-atomic)
1720 ;; Normal mode (for now) is "round to best".
1723 '((inst fnstcw scw) ; save current control word
1724 (move rcw scw) ; into 16-bit register
1725 (inst or rcw (ash #b11 10)) ; CHOP
1726 (move stack-temp rcw)
1727 (inst fldcw stack-temp)))
1732 (inst fist stack-temp)
1733 (inst mov y stack-temp)))
1735 '((inst fldcw scw)))))))))
1736 (frob %unary-truncate single-reg single-float nil)
1737 (frob %unary-truncate double-reg double-float nil)
1739 (frob %unary-truncate long-reg long-float nil)
1740 (frob %unary-round single-reg single-float t)
1741 (frob %unary-round double-reg double-float t)
1743 (frob %unary-round long-reg long-float t))
1745 (macrolet ((frob (trans from-sc from-type round-p)
1746 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1747 (:args (x :scs (,from-sc) :target fr0))
1748 (:temporary (:sc double-reg :offset fr0-offset
1749 :from :argument :to :result) fr0)
1751 '((:temporary (:sc unsigned-stack) stack-temp)
1752 (:temporary (:sc unsigned-stack) scw)
1753 (:temporary (:sc any-reg) rcw)))
1754 (:results (y :scs (unsigned-reg)))
1755 (:arg-types ,from-type)
1756 (:result-types unsigned-num)
1758 (:policy :fast-safe)
1759 (:note "inline float truncate")
1761 (:save-p :compute-only)
1764 '((note-this-location vop :internal-error)
1765 ;; Catch any pending FPE exceptions.
1767 ;; Normal mode (for now) is "round to best".
1768 (unless (zerop (tn-offset x))
1769 (copy-fp-reg-to-fr0 x))
1771 '((inst fnstcw scw) ; save current control word
1772 (move rcw scw) ; into 16-bit register
1773 (inst or rcw (ash #b11 10)) ; CHOP
1774 (move stack-temp rcw)
1775 (inst fldcw stack-temp)))
1777 (inst fistpl (make-ea :dword :base esp-tn))
1779 (inst fld fr0) ; copy fr0 to at least restore stack.
1782 '((inst fldcw scw)))))))
1783 (frob %unary-truncate single-reg single-float nil)
1784 (frob %unary-truncate double-reg double-float nil)
1786 (frob %unary-truncate long-reg long-float nil)
1787 (frob %unary-round single-reg single-float t)
1788 (frob %unary-round double-reg double-float t)
1790 (frob %unary-round long-reg long-float t))
1792 (define-vop (make-single-float)
1793 (:args (bits :scs (signed-reg) :target res
1794 :load-if (not (or (and (sc-is bits signed-stack)
1795 (sc-is res single-reg))
1796 (and (sc-is bits signed-stack)
1797 (sc-is res single-stack)
1798 (location= bits res))))))
1799 (:results (res :scs (single-reg single-stack)))
1800 (:temporary (:sc signed-stack) stack-temp)
1801 (:arg-types signed-num)
1802 (:result-types single-float)
1803 (:translate make-single-float)
1804 (:policy :fast-safe)
1811 (inst mov res bits))
1813 (aver (location= bits res)))))
1817 ;; source must be in memory
1818 (inst mov stack-temp bits)
1819 (with-empty-tn@fp-top(res)
1820 (inst fld stack-temp)))
1822 (with-empty-tn@fp-top(res)
1823 (inst fld bits))))))))
1825 (define-vop (make-double-float)
1826 (:args (hi-bits :scs (signed-reg))
1827 (lo-bits :scs (unsigned-reg)))
1828 (:results (res :scs (double-reg)))
1829 (:temporary (:sc double-stack) temp)
1830 (:arg-types signed-num unsigned-num)
1831 (:result-types double-float)
1832 (:translate make-double-float)
1833 (:policy :fast-safe)
1836 (let ((offset (tn-offset temp)))
1837 (storew hi-bits ebp-tn (frame-word-offset offset))
1838 (storew lo-bits ebp-tn (frame-word-offset (1+ offset)))
1839 (with-empty-tn@fp-top(res)
1840 (inst fldd (make-ea :dword :base ebp-tn
1841 :disp (frame-byte-offset (1+ offset))))))))
1844 (define-vop (make-long-float)
1845 (:args (exp-bits :scs (signed-reg))
1846 (hi-bits :scs (unsigned-reg))
1847 (lo-bits :scs (unsigned-reg)))
1848 (:results (res :scs (long-reg)))
1849 (:temporary (:sc long-stack) temp)
1850 (:arg-types signed-num unsigned-num unsigned-num)
1851 (:result-types long-float)
1852 (:translate make-long-float)
1853 (:policy :fast-safe)
1856 (let ((offset (tn-offset temp)))
1857 (storew exp-bits ebp-tn (frame-word-offset offset))
1858 (storew hi-bits ebp-tn (frame-word-offset (1+ offset)))
1859 (storew lo-bits ebp-tn (frame-word-offset (+ offset 2)))
1860 (with-empty-tn@fp-top(res)
1861 (inst fldl (make-ea :dword :base ebp-tn
1862 :disp (frame-byte-offset (+ offset 2))))))))
1864 (define-vop (single-float-bits)
1865 (:args (float :scs (single-reg descriptor-reg)
1866 :load-if (not (sc-is float single-stack))))
1867 (:results (bits :scs (signed-reg)))
1868 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1869 (:arg-types single-float)
1870 (:result-types signed-num)
1871 (:translate single-float-bits)
1872 (:policy :fast-safe)
1879 (with-tn@fp-top(float)
1880 (inst fst stack-temp)
1881 (inst mov bits stack-temp)))
1883 (inst mov bits float))
1886 bits float single-float-value-slot
1887 other-pointer-lowtag))))
1891 (with-tn@fp-top(float)
1892 (inst fst bits))))))))
1894 (define-vop (double-float-high-bits)
1895 (:args (float :scs (double-reg descriptor-reg)
1896 :load-if (not (sc-is float double-stack))))
1897 (:results (hi-bits :scs (signed-reg)))
1898 (:temporary (:sc double-stack) temp)
1899 (:arg-types double-float)
1900 (:result-types signed-num)
1901 (:translate double-float-high-bits)
1902 (:policy :fast-safe)
1907 (with-tn@fp-top(float)
1908 (let ((where (make-ea :dword :base ebp-tn
1909 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1911 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset temp))))
1913 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1915 (loadw hi-bits float (1+ double-float-value-slot)
1916 other-pointer-lowtag)))))
1918 (define-vop (double-float-low-bits)
1919 (:args (float :scs (double-reg descriptor-reg)
1920 :load-if (not (sc-is float double-stack))))
1921 (:results (lo-bits :scs (unsigned-reg)))
1922 (:temporary (:sc double-stack) temp)
1923 (:arg-types double-float)
1924 (:result-types unsigned-num)
1925 (:translate double-float-low-bits)
1926 (:policy :fast-safe)
1931 (with-tn@fp-top(float)
1932 (let ((where (make-ea :dword :base ebp-tn
1933 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1935 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1937 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset float)))))
1939 (loadw lo-bits float double-float-value-slot
1940 other-pointer-lowtag)))))
1943 (define-vop (long-float-exp-bits)
1944 (:args (float :scs (long-reg descriptor-reg)
1945 :load-if (not (sc-is float long-stack))))
1946 (:results (exp-bits :scs (signed-reg)))
1947 (:temporary (:sc long-stack) temp)
1948 (:arg-types long-float)
1949 (:result-types signed-num)
1950 (:translate long-float-exp-bits)
1951 (:policy :fast-safe)
1956 (with-tn@fp-top(float)
1957 (let ((where (make-ea :dword :base ebp-tn
1958 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1959 (store-long-float where)))
1960 (inst movsx exp-bits
1961 (make-ea :word :base ebp-tn
1962 :disp (frame-byte-offset (tn-offset temp)))))
1964 (inst movsx exp-bits
1965 (make-ea :word :base ebp-tn
1966 :disp (frame-byte-offset (tn-offset temp)))))
1968 (inst movsx exp-bits
1969 (make-ea :word :base float
1970 :disp (- (* (+ 2 long-float-value-slot)
1972 other-pointer-lowtag)))))))
1975 (define-vop (long-float-high-bits)
1976 (:args (float :scs (long-reg descriptor-reg)
1977 :load-if (not (sc-is float long-stack))))
1978 (:results (hi-bits :scs (unsigned-reg)))
1979 (:temporary (:sc long-stack) temp)
1980 (:arg-types long-float)
1981 (:result-types unsigned-num)
1982 (:translate long-float-high-bits)
1983 (:policy :fast-safe)
1988 (with-tn@fp-top(float)
1989 (let ((where (make-ea :dword :base ebp-tn
1990 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1991 (store-long-float where)))
1992 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1994 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1996 (loadw hi-bits float (1+ long-float-value-slot)
1997 other-pointer-lowtag)))))
2000 (define-vop (long-float-low-bits)
2001 (:args (float :scs (long-reg descriptor-reg)
2002 :load-if (not (sc-is float long-stack))))
2003 (:results (lo-bits :scs (unsigned-reg)))
2004 (:temporary (:sc long-stack) temp)
2005 (:arg-types long-float)
2006 (:result-types unsigned-num)
2007 (:translate long-float-low-bits)
2008 (:policy :fast-safe)
2013 (with-tn@fp-top(float)
2014 (let ((where (make-ea :dword :base ebp-tn
2015 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2016 (store-long-float where)))
2017 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset temp) 2))))
2019 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset float) 2))))
2021 (loadw lo-bits float long-float-value-slot
2022 other-pointer-lowtag)))))
2024 ;;;; float mode hackery
2026 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2027 (defknown floating-point-modes () float-modes (flushable))
2028 (defknown ((setf floating-point-modes)) (float-modes)
2031 (def!constant npx-env-size (* 7 n-word-bytes))
2032 (def!constant npx-cw-offset 0)
2033 (def!constant npx-sw-offset 4)
2035 (define-vop (floating-point-modes)
2036 (:results (res :scs (unsigned-reg)))
2037 (:result-types unsigned-num)
2038 (:translate floating-point-modes)
2039 (:policy :fast-safe)
2040 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2043 (inst sub esp-tn npx-env-size) ; Make space on stack.
2044 (inst wait) ; Catch any pending FPE exceptions
2045 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2046 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2047 ;; Move current status to high word.
2048 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2049 ;; Move exception mask to low word.
2050 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2051 (inst add esp-tn npx-env-size) ; Pop stack.
2052 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2055 (define-vop (set-floating-point-modes)
2056 (:args (new :scs (unsigned-reg) :to :result :target res))
2057 (:results (res :scs (unsigned-reg)))
2058 (:arg-types unsigned-num)
2059 (:result-types unsigned-num)
2060 (:translate (setf floating-point-modes))
2061 (:policy :fast-safe)
2062 (:temporary (:sc unsigned-reg :offset eax-offset
2063 :from :eval :to :result) eax)
2065 (inst sub esp-tn npx-env-size) ; Make space on stack.
2066 (inst wait) ; Catch any pending FPE exceptions.
2067 (inst fstenv (make-ea :dword :base esp-tn))
2069 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2070 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2071 (inst shr eax 16) ; position status word
2072 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2073 (inst fldenv (make-ea :dword :base esp-tn))
2074 (inst add esp-tn npx-env-size) ; Pop stack.
2080 ;;; Let's use some of the 80387 special functions.
2082 ;;; These defs will not take effect unless code/irrat.lisp is modified
2083 ;;; to remove the inlined alien routine def.
2085 (macrolet ((frob (func trans op)
2086 `(define-vop (,func)
2087 (:args (x :scs (double-reg) :target fr0))
2088 (:temporary (:sc double-reg :offset fr0-offset
2089 :from :argument :to :result) fr0)
2091 (:results (y :scs (double-reg)))
2092 (:arg-types double-float)
2093 (:result-types double-float)
2095 (:policy :fast-safe)
2096 (:note "inline NPX function")
2098 (:save-p :compute-only)
2101 (note-this-location vop :internal-error)
2102 (unless (zerop (tn-offset x))
2103 (inst fxch x) ; x to top of stack
2104 (unless (location= x y)
2105 (inst fst x))) ; maybe save it
2106 (inst ,op) ; clobber st0
2107 (cond ((zerop (tn-offset y))
2108 (maybe-fp-wait node))
2112 ;; Quick versions of fsin and fcos that require the argument to be
2113 ;; within range 2^63.
2114 (frob fsin-quick %sin-quick fsin)
2115 (frob fcos-quick %cos-quick fcos)
2116 (frob fsqrt %sqrt fsqrt))
2118 ;;; Quick version of ftan that requires the argument to be within
2120 (define-vop (ftan-quick)
2121 (:translate %tan-quick)
2122 (:args (x :scs (double-reg) :target fr0))
2123 (:temporary (:sc double-reg :offset fr0-offset
2124 :from :argument :to :result) fr0)
2125 (:temporary (:sc double-reg :offset fr1-offset
2126 :from :argument :to :result) fr1)
2127 (:results (y :scs (double-reg)))
2128 (:arg-types double-float)
2129 (:result-types double-float)
2130 (:policy :fast-safe)
2131 (:note "inline tan function")
2133 (:save-p :compute-only)
2135 (note-this-location vop :internal-error)
2144 (inst fldd (make-random-tn :kind :normal
2145 :sc (sc-or-lose 'double-reg)
2146 :offset (- (tn-offset x) 2)))))
2157 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2158 ;;; result if the argument is out of range 2^63 and would thus be
2159 ;;; hopelessly inaccurate.
2160 (macrolet ((frob (func trans op)
2161 `(define-vop (,func)
2163 (:args (x :scs (double-reg) :target fr0))
2164 (:temporary (:sc double-reg :offset fr0-offset
2165 :from :argument :to :result) fr0)
2166 (:temporary (:sc unsigned-reg :offset eax-offset
2167 :from :argument :to :result) eax)
2168 (:results (y :scs (double-reg)))
2169 (:arg-types double-float)
2170 (:result-types double-float)
2171 (:policy :fast-safe)
2172 (:note "inline sin/cos function")
2174 (:save-p :compute-only)
2177 (note-this-location vop :internal-error)
2178 (unless (zerop (tn-offset x))
2179 (inst fxch x) ; x to top of stack
2180 (unless (location= x y)
2181 (inst fst x))) ; maybe save it
2183 (inst fnstsw) ; status word to ax
2184 (inst and ah-tn #x04) ; C2
2186 ;; Else x was out of range so reduce it; ST0 is unchanged.
2187 (inst fstp fr0) ; Load 0.0
2190 (unless (zerop (tn-offset y))
2192 (frob fsin %sin fsin)
2193 (frob fcos %cos fcos))
2197 (:args (x :scs (double-reg) :target fr0))
2198 (:temporary (:sc double-reg :offset fr0-offset
2199 :from :argument :to :result) fr0)
2200 (:temporary (:sc double-reg :offset fr1-offset
2201 :from :argument :to :result) fr1)
2202 (:temporary (:sc unsigned-reg :offset eax-offset
2203 :from :argument :to :result) eax)
2204 (:results (y :scs (double-reg)))
2205 (:arg-types double-float)
2206 (:result-types double-float)
2208 (:policy :fast-safe)
2209 (:note "inline tan function")
2211 (:save-p :compute-only)
2214 (note-this-location vop :internal-error)
2223 (inst fldd (make-random-tn :kind :normal
2224 :sc (sc-or-lose 'double-reg)
2225 :offset (- (tn-offset x) 2)))))
2227 (inst fnstsw) ; status word to ax
2228 (inst and ah-tn #x04) ; C2
2230 ;; Else x was out of range so load 0.0
2242 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2243 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2246 (:args (x :scs (double-reg) :target fr0))
2247 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2248 (:temporary (:sc double-reg :offset fr0-offset
2249 :from :argument :to :result) fr0)
2250 (:temporary (:sc double-reg :offset fr1-offset
2251 :from :argument :to :result) fr1)
2252 (:temporary (:sc double-reg :offset fr2-offset
2253 :from :argument :to :result) fr2)
2254 (:results (y :scs (double-reg)))
2255 (:arg-types double-float)
2256 (:result-types double-float)
2257 (:policy :fast-safe)
2258 (:note "inline exp function")
2260 (:save-p :compute-only)
2263 (note-this-location vop :internal-error)
2264 (unless (zerop (tn-offset x))
2265 (inst fxch x) ; x to top of stack
2266 (unless (location= x y)
2267 (inst fst x))) ; maybe save it
2268 ;; Check for Inf or NaN
2272 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2273 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2274 (inst and ah-tn #x02) ; Test sign of Inf.
2275 (inst jmp :z DONE) ; +Inf gives +Inf.
2276 (inst fstp fr0) ; -Inf gives 0
2278 (inst jmp-short DONE)
2283 ;; Now fr0=x log2(e)
2287 (inst fsubp-sti fr1)
2290 (inst faddp-sti fr1)
2294 (unless (zerop (tn-offset y))
2297 ;;; Expm1 = exp(x) - 1.
2298 ;;; Handles the following special cases:
2299 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2300 (define-vop (fexpm1)
2302 (:args (x :scs (double-reg) :target fr0))
2303 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2304 (:temporary (:sc double-reg :offset fr0-offset
2305 :from :argument :to :result) fr0)
2306 (:temporary (:sc double-reg :offset fr1-offset
2307 :from :argument :to :result) fr1)
2308 (:temporary (:sc double-reg :offset fr2-offset
2309 :from :argument :to :result) fr2)
2310 (:results (y :scs (double-reg)))
2311 (:arg-types double-float)
2312 (:result-types double-float)
2313 (:policy :fast-safe)
2314 (:note "inline expm1 function")
2316 (:save-p :compute-only)
2319 (note-this-location vop :internal-error)
2320 (unless (zerop (tn-offset x))
2321 (inst fxch x) ; x to top of stack
2322 (unless (location= x y)
2323 (inst fst x))) ; maybe save it
2324 ;; Check for Inf or NaN
2328 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2329 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2330 (inst and ah-tn #x02) ; Test sign of Inf.
2331 (inst jmp :z DONE) ; +Inf gives +Inf.
2332 (inst fstp fr0) ; -Inf gives -1.0
2335 (inst jmp-short DONE)
2337 ;; Free two stack slots leaving the argument on top.
2341 (inst fmul fr1) ; Now fr0 = x log2(e)
2356 (unless (zerop (tn-offset y))
2361 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2362 (:temporary (:sc double-reg :offset fr0-offset
2363 :from :argument :to :result) fr0)
2364 (:temporary (:sc double-reg :offset fr1-offset
2365 :from :argument :to :result) fr1)
2366 (:results (y :scs (double-reg)))
2367 (:arg-types double-float)
2368 (:result-types double-float)
2369 (:policy :fast-safe)
2370 (:note "inline log function")
2372 (:save-p :compute-only)
2374 (note-this-location vop :internal-error)
2389 ;; x is in a FP reg, not fr0 or fr1
2393 (inst fldd (make-random-tn :kind :normal
2394 :sc (sc-or-lose 'double-reg)
2395 :offset (1- (tn-offset x))))))
2397 ((double-stack descriptor-reg)
2401 (if (sc-is x double-stack)
2402 (inst fldd (ea-for-df-stack x))
2403 (inst fldd (ea-for-df-desc x)))
2408 (t (inst fstd y)))))
2410 (define-vop (flog10)
2412 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2413 (:temporary (:sc double-reg :offset fr0-offset
2414 :from :argument :to :result) fr0)
2415 (:temporary (:sc double-reg :offset fr1-offset
2416 :from :argument :to :result) fr1)
2417 (:results (y :scs (double-reg)))
2418 (:arg-types double-float)
2419 (:result-types double-float)
2420 (:policy :fast-safe)
2421 (:note "inline log10 function")
2423 (:save-p :compute-only)
2425 (note-this-location vop :internal-error)
2440 ;; x is in a FP reg, not fr0 or fr1
2444 (inst fldd (make-random-tn :kind :normal
2445 :sc (sc-or-lose 'double-reg)
2446 :offset (1- (tn-offset x))))))
2448 ((double-stack descriptor-reg)
2452 (if (sc-is x double-stack)
2453 (inst fldd (ea-for-df-stack x))
2454 (inst fldd (ea-for-df-desc x)))
2459 (t (inst fstd y)))))
2463 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2464 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2465 (:temporary (:sc double-reg :offset fr0-offset
2466 :from (:argument 0) :to :result) fr0)
2467 (:temporary (:sc double-reg :offset fr1-offset
2468 :from (:argument 1) :to :result) fr1)
2469 (:temporary (:sc double-reg :offset fr2-offset
2470 :from :load :to :result) fr2)
2471 (:results (r :scs (double-reg)))
2472 (:arg-types double-float double-float)
2473 (:result-types double-float)
2474 (:policy :fast-safe)
2475 (:note "inline pow function")
2477 (:save-p :compute-only)
2479 (note-this-location vop :internal-error)
2480 ;; Setup x in fr0 and y in fr1
2482 ;; x in fr0; y in fr1
2483 ((and (sc-is x double-reg) (zerop (tn-offset x))
2484 (sc-is y double-reg) (= 1 (tn-offset y))))
2485 ;; y in fr1; x not in fr0
2486 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2490 (copy-fp-reg-to-fr0 x))
2493 (inst fldd (ea-for-df-stack x)))
2496 (inst fldd (ea-for-df-desc x)))))
2497 ;; x in fr0; y not in fr1
2498 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2500 ;; Now load y to fr0
2503 (copy-fp-reg-to-fr0 y))
2506 (inst fldd (ea-for-df-stack y)))
2509 (inst fldd (ea-for-df-desc y))))
2511 ;; x in fr1; y not in fr1
2512 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2516 (copy-fp-reg-to-fr0 y))
2519 (inst fldd (ea-for-df-stack y)))
2522 (inst fldd (ea-for-df-desc y))))
2525 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2527 ;; Now load x to fr0
2530 (copy-fp-reg-to-fr0 x))
2533 (inst fldd (ea-for-df-stack x)))
2536 (inst fldd (ea-for-df-desc x)))))
2537 ;; Neither x or y are in either fr0 or fr1
2544 (inst fldd (make-random-tn :kind :normal
2545 :sc (sc-or-lose 'double-reg)
2546 :offset (- (tn-offset y) 2))))
2548 (inst fldd (ea-for-df-stack y)))
2550 (inst fldd (ea-for-df-desc y))))
2554 (inst fldd (make-random-tn :kind :normal
2555 :sc (sc-or-lose 'double-reg)
2556 :offset (1- (tn-offset x)))))
2558 (inst fldd (ea-for-df-stack x)))
2560 (inst fldd (ea-for-df-desc x))))))
2562 ;; Now have x at fr0; and y at fr1
2564 ;; Now fr0=y log2(x)
2568 (inst fsubp-sti fr1)
2571 (inst faddp-sti fr1)
2576 (t (inst fstd r)))))
2578 (define-vop (fscalen)
2579 (:translate %scalbn)
2580 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2581 (y :scs (signed-stack signed-reg) :target temp))
2582 (:temporary (:sc double-reg :offset fr0-offset
2583 :from (:argument 0) :to :result) fr0)
2584 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2585 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2586 (:results (r :scs (double-reg)))
2587 (:arg-types double-float signed-num)
2588 (:result-types double-float)
2589 (:policy :fast-safe)
2590 (:note "inline scalbn function")
2592 ;; Setup x in fr0 and y in fr1
2623 (inst fld (make-random-tn :kind :normal
2624 :sc (sc-or-lose 'double-reg)
2625 :offset (1- (tn-offset x)))))))
2626 ((double-stack descriptor-reg)
2635 (if (sc-is x double-stack)
2636 (inst fldd (ea-for-df-stack x))
2637 (inst fldd (ea-for-df-desc x)))))
2639 (unless (zerop (tn-offset r))
2642 (define-vop (fscale)
2644 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2645 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2646 (:temporary (:sc double-reg :offset fr0-offset
2647 :from (:argument 0) :to :result) fr0)
2648 (:temporary (:sc double-reg :offset fr1-offset
2649 :from (:argument 1) :to :result) fr1)
2650 (:results (r :scs (double-reg)))
2651 (:arg-types double-float double-float)
2652 (:result-types double-float)
2653 (:policy :fast-safe)
2654 (:note "inline scalb function")
2656 (:save-p :compute-only)
2658 (note-this-location vop :internal-error)
2659 ;; Setup x in fr0 and y in fr1
2661 ;; x in fr0; y in fr1
2662 ((and (sc-is x double-reg) (zerop (tn-offset x))
2663 (sc-is y double-reg) (= 1 (tn-offset y))))
2664 ;; y in fr1; x not in fr0
2665 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2669 (copy-fp-reg-to-fr0 x))
2672 (inst fldd (ea-for-df-stack x)))
2675 (inst fldd (ea-for-df-desc x)))))
2676 ;; x in fr0; y not in fr1
2677 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2679 ;; Now load y to fr0
2682 (copy-fp-reg-to-fr0 y))
2685 (inst fldd (ea-for-df-stack y)))
2688 (inst fldd (ea-for-df-desc y))))
2690 ;; x in fr1; y not in fr1
2691 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2695 (copy-fp-reg-to-fr0 y))
2698 (inst fldd (ea-for-df-stack y)))
2701 (inst fldd (ea-for-df-desc y))))
2704 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2706 ;; Now load x to fr0
2709 (copy-fp-reg-to-fr0 x))
2712 (inst fldd (ea-for-df-stack x)))
2715 (inst fldd (ea-for-df-desc x)))))
2716 ;; Neither x or y are in either fr0 or fr1
2723 (inst fldd (make-random-tn :kind :normal
2724 :sc (sc-or-lose 'double-reg)
2725 :offset (- (tn-offset y) 2))))
2727 (inst fldd (ea-for-df-stack y)))
2729 (inst fldd (ea-for-df-desc y))))
2733 (inst fldd (make-random-tn :kind :normal
2734 :sc (sc-or-lose 'double-reg)
2735 :offset (1- (tn-offset x)))))
2737 (inst fldd (ea-for-df-stack x)))
2739 (inst fldd (ea-for-df-desc x))))))
2741 ;; Now have x at fr0; and y at fr1
2743 (unless (zerop (tn-offset r))
2746 (define-vop (flog1p)
2748 (:args (x :scs (double-reg) :to :result))
2749 (:temporary (:sc double-reg :offset fr0-offset
2750 :from :argument :to :result) fr0)
2751 (:temporary (:sc double-reg :offset fr1-offset
2752 :from :argument :to :result) fr1)
2753 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2754 (:results (y :scs (double-reg)))
2755 (:arg-types double-float)
2756 (:result-types double-float)
2757 (:policy :fast-safe)
2758 (:note "inline log1p function")
2761 ;; x is in a FP reg, not fr0, fr1.
2764 (inst fldd (make-random-tn :kind :normal
2765 :sc (sc-or-lose 'double-reg)
2766 :offset (- (tn-offset x) 2)))
2768 (inst push #x3e947ae1) ; Constant 0.29
2770 (inst fld (make-ea :dword :base esp-tn))
2773 (inst fnstsw) ; status word to ax
2774 (inst and ah-tn #x45)
2775 (inst jmp :z WITHIN-RANGE)
2776 ;; Out of range for fyl2xp1.
2778 (inst faddd (make-random-tn :kind :normal
2779 :sc (sc-or-lose 'double-reg)
2780 :offset (- (tn-offset x) 1)))
2788 (inst fldd (make-random-tn :kind :normal
2789 :sc (sc-or-lose 'double-reg)
2790 :offset (- (tn-offset x) 1)))
2796 (t (inst fstd y)))))
2798 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2799 ;;; instruction and a range check can be avoided.
2800 (define-vop (flog1p-pentium)
2802 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2803 (:temporary (:sc double-reg :offset fr0-offset
2804 :from :argument :to :result) fr0)
2805 (:temporary (:sc double-reg :offset fr1-offset
2806 :from :argument :to :result) fr1)
2807 (:results (y :scs (double-reg)))
2808 (:arg-types double-float)
2809 (:result-types double-float)
2810 (:policy :fast-safe)
2811 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2812 (:note "inline log1p with limited x range function")
2814 (:save-p :compute-only)
2816 (note-this-location vop :internal-error)
2831 ;; x is in a FP reg, not fr0 or fr1
2835 (inst fldd (make-random-tn :kind :normal
2836 :sc (sc-or-lose 'double-reg)
2837 :offset (1- (tn-offset x)))))))
2838 ((double-stack descriptor-reg)
2842 (if (sc-is x double-stack)
2843 (inst fldd (ea-for-df-stack x))
2844 (inst fldd (ea-for-df-desc x)))))
2849 (t (inst fstd y)))))
2853 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2854 (:temporary (:sc double-reg :offset fr0-offset
2855 :from :argument :to :result) fr0)
2856 (:temporary (:sc double-reg :offset fr1-offset
2857 :from :argument :to :result) fr1)
2858 (:results (y :scs (double-reg)))
2859 (:arg-types double-float)
2860 (:result-types double-float)
2861 (:policy :fast-safe)
2862 (:note "inline logb function")
2864 (:save-p :compute-only)
2866 (note-this-location vop :internal-error)
2877 ;; x is in a FP reg, not fr0 or fr1
2880 (inst fldd (make-random-tn :kind :normal
2881 :sc (sc-or-lose 'double-reg)
2882 :offset (- (tn-offset x) 2))))))
2883 ((double-stack descriptor-reg)
2886 (if (sc-is x double-stack)
2887 (inst fldd (ea-for-df-stack x))
2888 (inst fldd (ea-for-df-desc x)))))
2899 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2900 (:temporary (:sc double-reg :offset fr0-offset
2901 :from (:argument 0) :to :result) fr0)
2902 (:temporary (:sc double-reg :offset fr1-offset
2903 :from (:argument 0) :to :result) fr1)
2904 (:results (r :scs (double-reg)))
2905 (:arg-types double-float)
2906 (:result-types double-float)
2907 (:policy :fast-safe)
2908 (:note "inline atan function")
2910 (:save-p :compute-only)
2912 (note-this-location vop :internal-error)
2913 ;; Setup x in fr1 and 1.0 in fr0
2916 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2919 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2921 ;; x not in fr0 or fr1
2928 (inst fldd (make-random-tn :kind :normal
2929 :sc (sc-or-lose 'double-reg)
2930 :offset (- (tn-offset x) 2))))
2932 (inst fldd (ea-for-df-stack x)))
2934 (inst fldd (ea-for-df-desc x))))))
2936 ;; Now have x at fr1; and 1.0 at fr0
2941 (t (inst fstd r)))))
2943 (define-vop (fatan2)
2945 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2946 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2947 (:temporary (:sc double-reg :offset fr0-offset
2948 :from (:argument 1) :to :result) fr0)
2949 (:temporary (:sc double-reg :offset fr1-offset
2950 :from (:argument 0) :to :result) fr1)
2951 (:results (r :scs (double-reg)))
2952 (:arg-types double-float double-float)
2953 (:result-types double-float)
2954 (:policy :fast-safe)
2955 (:note "inline atan2 function")
2957 (:save-p :compute-only)
2959 (note-this-location vop :internal-error)
2960 ;; Setup x in fr1 and y in fr0
2962 ;; y in fr0; x in fr1
2963 ((and (sc-is y double-reg) (zerop (tn-offset y))
2964 (sc-is x double-reg) (= 1 (tn-offset x))))
2965 ;; x in fr1; y not in fr0
2966 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2970 (copy-fp-reg-to-fr0 y))
2973 (inst fldd (ea-for-df-stack y)))
2976 (inst fldd (ea-for-df-desc y)))))
2977 ((and (sc-is x double-reg) (zerop (tn-offset x))
2978 (sc-is y double-reg) (zerop (tn-offset x)))
2981 ;; y in fr0; x not in fr1
2982 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2984 ;; Now load x to fr0
2987 (copy-fp-reg-to-fr0 x))
2990 (inst fldd (ea-for-df-stack x)))
2993 (inst fldd (ea-for-df-desc x))))
2995 ;; y in fr1; x not in fr1
2996 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3000 (copy-fp-reg-to-fr0 x))
3003 (inst fldd (ea-for-df-stack x)))
3006 (inst fldd (ea-for-df-desc x))))
3009 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3011 ;; Now load y to fr0
3014 (copy-fp-reg-to-fr0 y))
3017 (inst fldd (ea-for-df-stack y)))
3020 (inst fldd (ea-for-df-desc y)))))
3021 ;; Neither y or x are in either fr0 or fr1
3028 (inst fldd (make-random-tn :kind :normal
3029 :sc (sc-or-lose 'double-reg)
3030 :offset (- (tn-offset x) 2))))
3032 (inst fldd (ea-for-df-stack x)))
3034 (inst fldd (ea-for-df-desc x))))
3038 (inst fldd (make-random-tn :kind :normal
3039 :sc (sc-or-lose 'double-reg)
3040 :offset (1- (tn-offset y)))))
3042 (inst fldd (ea-for-df-stack y)))
3044 (inst fldd (ea-for-df-desc y))))))
3046 ;; Now have y at fr0; and x at fr1
3051 (t (inst fstd r)))))
3052 ) ; PROGN #!-LONG-FLOAT
3057 ;;; Lets use some of the 80387 special functions.
3059 ;;; These defs will not take effect unless code/irrat.lisp is modified
3060 ;;; to remove the inlined alien routine def.
3062 (macrolet ((frob (func trans op)
3063 `(define-vop (,func)
3064 (:args (x :scs (long-reg) :target fr0))
3065 (:temporary (:sc long-reg :offset fr0-offset
3066 :from :argument :to :result) fr0)
3068 (:results (y :scs (long-reg)))
3069 (:arg-types long-float)
3070 (:result-types long-float)
3072 (:policy :fast-safe)
3073 (:note "inline NPX function")
3075 (:save-p :compute-only)
3078 (note-this-location vop :internal-error)
3079 (unless (zerop (tn-offset x))
3080 (inst fxch x) ; x to top of stack
3081 (unless (location= x y)
3082 (inst fst x))) ; maybe save it
3083 (inst ,op) ; clobber st0
3084 (cond ((zerop (tn-offset y))
3085 (maybe-fp-wait node))
3089 ;; Quick versions of FSIN and FCOS that require the argument to be
3090 ;; within range 2^63.
3091 (frob fsin-quick %sin-quick fsin)
3092 (frob fcos-quick %cos-quick fcos)
3093 (frob fsqrt %sqrt fsqrt))
3095 ;;; Quick version of ftan that requires the argument to be within
3097 (define-vop (ftan-quick)
3098 (:translate %tan-quick)
3099 (:args (x :scs (long-reg) :target fr0))
3100 (:temporary (:sc long-reg :offset fr0-offset
3101 :from :argument :to :result) fr0)
3102 (:temporary (:sc long-reg :offset fr1-offset
3103 :from :argument :to :result) fr1)
3104 (:results (y :scs (long-reg)))
3105 (:arg-types long-float)
3106 (:result-types long-float)
3107 (:policy :fast-safe)
3108 (:note "inline tan function")
3110 (:save-p :compute-only)
3112 (note-this-location vop :internal-error)
3121 (inst fldd (make-random-tn :kind :normal
3122 :sc (sc-or-lose 'double-reg)
3123 :offset (- (tn-offset x) 2)))))
3134 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3135 ;;; the argument is out of range 2^63 and would thus be hopelessly
3137 (macrolet ((frob (func trans op)
3138 `(define-vop (,func)
3140 (:args (x :scs (long-reg) :target fr0))
3141 (:temporary (:sc long-reg :offset fr0-offset
3142 :from :argument :to :result) fr0)
3143 (:temporary (:sc unsigned-reg :offset eax-offset
3144 :from :argument :to :result) eax)
3145 (:results (y :scs (long-reg)))
3146 (:arg-types long-float)
3147 (:result-types long-float)
3148 (:policy :fast-safe)
3149 (:note "inline sin/cos function")
3151 (:save-p :compute-only)
3154 (note-this-location vop :internal-error)
3155 (unless (zerop (tn-offset x))
3156 (inst fxch x) ; x to top of stack
3157 (unless (location= x y)
3158 (inst fst x))) ; maybe save it
3160 (inst fnstsw) ; status word to ax
3161 (inst and ah-tn #x04) ; C2
3163 ;; Else x was out of range so reduce it; ST0 is unchanged.
3164 (inst fstp fr0) ; Load 0.0
3167 (unless (zerop (tn-offset y))
3169 (frob fsin %sin fsin)
3170 (frob fcos %cos fcos))
3174 (:args (x :scs (long-reg) :target fr0))
3175 (:temporary (:sc long-reg :offset fr0-offset
3176 :from :argument :to :result) fr0)
3177 (:temporary (:sc long-reg :offset fr1-offset
3178 :from :argument :to :result) fr1)
3179 (:temporary (:sc unsigned-reg :offset eax-offset
3180 :from :argument :to :result) eax)
3181 (:results (y :scs (long-reg)))
3182 (:arg-types long-float)
3183 (:result-types long-float)
3185 (:policy :fast-safe)
3186 (:note "inline tan function")
3188 (:save-p :compute-only)
3191 (note-this-location vop :internal-error)
3200 (inst fldd (make-random-tn :kind :normal
3201 :sc (sc-or-lose 'double-reg)
3202 :offset (- (tn-offset x) 2)))))
3204 (inst fnstsw) ; status word to ax
3205 (inst and ah-tn #x04) ; C2
3207 ;; Else x was out of range so reduce it; ST0 is unchanged.
3208 (inst fldz) ; Load 0.0
3220 ;;; Modified exp that handles the following special cases:
3221 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3224 (:args (x :scs (long-reg) :target fr0))
3225 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3226 (:temporary (:sc long-reg :offset fr0-offset
3227 :from :argument :to :result) fr0)
3228 (:temporary (:sc long-reg :offset fr1-offset
3229 :from :argument :to :result) fr1)
3230 (:temporary (:sc long-reg :offset fr2-offset
3231 :from :argument :to :result) fr2)
3232 (:results (y :scs (long-reg)))
3233 (:arg-types long-float)
3234 (:result-types long-float)
3235 (:policy :fast-safe)
3236 (:note "inline exp function")
3238 (:save-p :compute-only)
3241 (note-this-location vop :internal-error)
3242 (unless (zerop (tn-offset x))
3243 (inst fxch x) ; x to top of stack
3244 (unless (location= x y)
3245 (inst fst x))) ; maybe save it
3246 ;; Check for Inf or NaN
3250 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3251 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3252 (inst and ah-tn #x02) ; Test sign of Inf.
3253 (inst jmp :z DONE) ; +Inf gives +Inf.
3254 (inst fstp fr0) ; -Inf gives 0
3256 (inst jmp-short DONE)
3261 ;; Now fr0=x log2(e)
3265 (inst fsubp-sti fr1)
3268 (inst faddp-sti fr1)
3272 (unless (zerop (tn-offset y))
3275 ;;; Expm1 = exp(x) - 1.
3276 ;;; Handles the following special cases:
3277 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3278 (define-vop (fexpm1)
3280 (:args (x :scs (long-reg) :target fr0))
3281 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3282 (:temporary (:sc long-reg :offset fr0-offset
3283 :from :argument :to :result) fr0)
3284 (:temporary (:sc long-reg :offset fr1-offset
3285 :from :argument :to :result) fr1)
3286 (:temporary (:sc long-reg :offset fr2-offset
3287 :from :argument :to :result) fr2)
3288 (:results (y :scs (long-reg)))
3289 (:arg-types long-float)
3290 (:result-types long-float)
3291 (:policy :fast-safe)
3292 (:note "inline expm1 function")
3294 (:save-p :compute-only)
3297 (note-this-location vop :internal-error)
3298 (unless (zerop (tn-offset x))
3299 (inst fxch x) ; x to top of stack
3300 (unless (location= x y)
3301 (inst fst x))) ; maybe save it
3302 ;; Check for Inf or NaN
3306 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3307 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3308 (inst and ah-tn #x02) ; Test sign of Inf.
3309 (inst jmp :z DONE) ; +Inf gives +Inf.
3310 (inst fstp fr0) ; -Inf gives -1.0
3313 (inst jmp-short DONE)
3315 ;; Free two stack slots leaving the argument on top.
3319 (inst fmul fr1) ; Now fr0 = x log2(e)
3334 (unless (zerop (tn-offset y))
3339 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3340 (:temporary (:sc long-reg :offset fr0-offset
3341 :from :argument :to :result) fr0)
3342 (:temporary (:sc long-reg :offset fr1-offset
3343 :from :argument :to :result) fr1)
3344 (:results (y :scs (long-reg)))
3345 (:arg-types long-float)
3346 (:result-types long-float)
3347 (:policy :fast-safe)
3348 (:note "inline log function")
3350 (:save-p :compute-only)
3352 (note-this-location vop :internal-error)
3367 ;; x is in a FP reg, not fr0 or fr1
3371 (inst fldd (make-random-tn :kind :normal
3372 :sc (sc-or-lose 'double-reg)
3373 :offset (1- (tn-offset x))))))
3375 ((long-stack descriptor-reg)
3379 (if (sc-is x long-stack)
3380 (inst fldl (ea-for-lf-stack x))
3381 (inst fldl (ea-for-lf-desc x)))
3386 (t (inst fstd y)))))
3388 (define-vop (flog10)
3390 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3391 (:temporary (:sc long-reg :offset fr0-offset
3392 :from :argument :to :result) fr0)
3393 (:temporary (:sc long-reg :offset fr1-offset
3394 :from :argument :to :result) fr1)
3395 (:results (y :scs (long-reg)))
3396 (:arg-types long-float)
3397 (:result-types long-float)
3398 (:policy :fast-safe)
3399 (:note "inline log10 function")
3401 (:save-p :compute-only)
3403 (note-this-location vop :internal-error)
3418 ;; x is in a FP reg, not fr0 or fr1
3422 (inst fldd (make-random-tn :kind :normal
3423 :sc (sc-or-lose 'double-reg)
3424 :offset (1- (tn-offset x))))))
3426 ((long-stack descriptor-reg)
3430 (if (sc-is x long-stack)
3431 (inst fldl (ea-for-lf-stack x))
3432 (inst fldl (ea-for-lf-desc x)))
3437 (t (inst fstd y)))))
3441 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3442 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3443 (:temporary (:sc long-reg :offset fr0-offset
3444 :from (:argument 0) :to :result) fr0)
3445 (:temporary (:sc long-reg :offset fr1-offset
3446 :from (:argument 1) :to :result) fr1)
3447 (:temporary (:sc long-reg :offset fr2-offset
3448 :from :load :to :result) fr2)
3449 (:results (r :scs (long-reg)))
3450 (:arg-types long-float long-float)
3451 (:result-types long-float)
3452 (:policy :fast-safe)
3453 (:note "inline pow function")
3455 (:save-p :compute-only)
3457 (note-this-location vop :internal-error)
3458 ;; Setup x in fr0 and y in fr1
3460 ;; x in fr0; y in fr1
3461 ((and (sc-is x long-reg) (zerop (tn-offset x))
3462 (sc-is y long-reg) (= 1 (tn-offset y))))
3463 ;; y in fr1; x not in fr0
3464 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3468 (copy-fp-reg-to-fr0 x))
3471 (inst fldl (ea-for-lf-stack x)))
3474 (inst fldl (ea-for-lf-desc x)))))
3475 ;; x in fr0; y not in fr1
3476 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3478 ;; Now load y to fr0
3481 (copy-fp-reg-to-fr0 y))
3484 (inst fldl (ea-for-lf-stack y)))
3487 (inst fldl (ea-for-lf-desc y))))
3489 ;; x in fr1; y not in fr1
3490 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3494 (copy-fp-reg-to-fr0 y))
3497 (inst fldl (ea-for-lf-stack y)))
3500 (inst fldl (ea-for-lf-desc y))))
3503 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3505 ;; Now load x to fr0
3508 (copy-fp-reg-to-fr0 x))
3511 (inst fldl (ea-for-lf-stack x)))
3514 (inst fldl (ea-for-lf-desc x)))))
3515 ;; Neither x or y are in either fr0 or fr1
3522 (inst fldd (make-random-tn :kind :normal
3523 :sc (sc-or-lose 'double-reg)
3524 :offset (- (tn-offset y) 2))))
3526 (inst fldl (ea-for-lf-stack y)))
3528 (inst fldl (ea-for-lf-desc y))))
3532 (inst fldd (make-random-tn :kind :normal
3533 :sc (sc-or-lose 'double-reg)
3534 :offset (1- (tn-offset x)))))
3536 (inst fldl (ea-for-lf-stack x)))
3538 (inst fldl (ea-for-lf-desc x))))))
3540 ;; Now have x at fr0; and y at fr1
3542 ;; Now fr0=y log2(x)
3546 (inst fsubp-sti fr1)
3549 (inst faddp-sti fr1)
3554 (t (inst fstd r)))))
3556 (define-vop (fscalen)
3557 (:translate %scalbn)
3558 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3559 (y :scs (signed-stack signed-reg) :target temp))
3560 (:temporary (:sc long-reg :offset fr0-offset
3561 :from (:argument 0) :to :result) fr0)
3562 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3563 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3564 (:results (r :scs (long-reg)))
3565 (:arg-types long-float signed-num)
3566 (:result-types long-float)
3567 (:policy :fast-safe)
3568 (:note "inline scalbn function")
3570 ;; Setup x in fr0 and y in fr1
3601 (inst fld (make-random-tn :kind :normal
3602 :sc (sc-or-lose 'double-reg)
3603 :offset (1- (tn-offset x)))))))
3604 ((long-stack descriptor-reg)
3613 (if (sc-is x long-stack)
3614 (inst fldl (ea-for-lf-stack x))
3615 (inst fldl (ea-for-lf-desc x)))))
3617 (unless (zerop (tn-offset r))
3620 (define-vop (fscale)
3622 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3623 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3624 (:temporary (:sc long-reg :offset fr0-offset
3625 :from (:argument 0) :to :result) fr0)
3626 (:temporary (:sc long-reg :offset fr1-offset
3627 :from (:argument 1) :to :result) fr1)
3628 (:results (r :scs (long-reg)))
3629 (:arg-types long-float long-float)
3630 (:result-types long-float)
3631 (:policy :fast-safe)
3632 (:note "inline scalb function")
3634 (:save-p :compute-only)
3636 (note-this-location vop :internal-error)
3637 ;; Setup x in fr0 and y in fr1
3639 ;; x in fr0; y in fr1
3640 ((and (sc-is x long-reg) (zerop (tn-offset x))
3641 (sc-is y long-reg) (= 1 (tn-offset y))))
3642 ;; y in fr1; x not in fr0
3643 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3647 (copy-fp-reg-to-fr0 x))
3650 (inst fldl (ea-for-lf-stack x)))
3653 (inst fldl (ea-for-lf-desc x)))))
3654 ;; x in fr0; y not in fr1
3655 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3657 ;; Now load y to fr0
3660 (copy-fp-reg-to-fr0 y))
3663 (inst fldl (ea-for-lf-stack y)))
3666 (inst fldl (ea-for-lf-desc y))))
3668 ;; x in fr1; y not in fr1
3669 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3673 (copy-fp-reg-to-fr0 y))
3676 (inst fldl (ea-for-lf-stack y)))
3679 (inst fldl (ea-for-lf-desc y))))
3682 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3684 ;; Now load x to fr0
3687 (copy-fp-reg-to-fr0 x))
3690 (inst fldl (ea-for-lf-stack x)))
3693 (inst fldl (ea-for-lf-desc x)))))
3694 ;; Neither x or y are in either fr0 or fr1
3701 (inst fldd (make-random-tn :kind :normal
3702 :sc (sc-or-lose 'double-reg)
3703 :offset (- (tn-offset y) 2))))
3705 (inst fldl (ea-for-lf-stack y)))
3707 (inst fldl (ea-for-lf-desc y))))
3711 (inst fldd (make-random-tn :kind :normal
3712 :sc (sc-or-lose 'double-reg)
3713 :offset (1- (tn-offset x)))))
3715 (inst fldl (ea-for-lf-stack x)))
3717 (inst fldl (ea-for-lf-desc x))))))
3719 ;; Now have x at fr0; and y at fr1
3721 (unless (zerop (tn-offset r))
3724 (define-vop (flog1p)
3726 (:args (x :scs (long-reg) :to :result))
3727 (:temporary (:sc long-reg :offset fr0-offset
3728 :from :argument :to :result) fr0)
3729 (:temporary (:sc long-reg :offset fr1-offset
3730 :from :argument :to :result) fr1)
3731 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3732 (:results (y :scs (long-reg)))
3733 (:arg-types long-float)
3734 (:result-types long-float)
3735 (:policy :fast-safe)
3736 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3737 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3738 ;; an enormous PROGN above. Still, it would be probably be good to
3739 ;; add some code to warn about redefining VOPs.
3740 (:note "inline log1p function")
3743 ;; x is in a FP reg, not fr0, fr1.
3746 (inst fldd (make-random-tn :kind :normal
3747 :sc (sc-or-lose 'double-reg)
3748 :offset (- (tn-offset x) 2)))
3750 (inst push #x3e947ae1) ; Constant 0.29
3752 (inst fld (make-ea :dword :base esp-tn))
3755 (inst fnstsw) ; status word to ax
3756 (inst and ah-tn #x45)
3757 (inst jmp :z WITHIN-RANGE)
3758 ;; Out of range for fyl2xp1.
3760 (inst faddd (make-random-tn :kind :normal
3761 :sc (sc-or-lose 'double-reg)
3762 :offset (- (tn-offset x) 1)))
3770 (inst fldd (make-random-tn :kind :normal
3771 :sc (sc-or-lose 'double-reg)
3772 :offset (- (tn-offset x) 1)))
3778 (t (inst fstd y)))))
3780 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3781 ;;; instruction and a range check can be avoided.
3782 (define-vop (flog1p-pentium)
3784 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3785 (:temporary (:sc long-reg :offset fr0-offset
3786 :from :argument :to :result) fr0)
3787 (:temporary (:sc long-reg :offset fr1-offset
3788 :from :argument :to :result) fr1)
3789 (:results (y :scs (long-reg)))
3790 (:arg-types long-float)
3791 (:result-types long-float)
3792 (:policy :fast-safe)
3793 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3794 (:note "inline log1p function")
3810 ;; x is in a FP reg, not fr0 or fr1
3814 (inst fldd (make-random-tn :kind :normal
3815 :sc (sc-or-lose 'double-reg)
3816 :offset (1- (tn-offset x)))))))
3817 ((long-stack descriptor-reg)
3821 (if (sc-is x long-stack)
3822 (inst fldl (ea-for-lf-stack x))
3823 (inst fldl (ea-for-lf-desc x)))))
3828 (t (inst fstd y)))))
3832 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3833 (:temporary (:sc long-reg :offset fr0-offset
3834 :from :argument :to :result) fr0)
3835 (:temporary (:sc long-reg :offset fr1-offset
3836 :from :argument :to :result) fr1)
3837 (:results (y :scs (long-reg)))
3838 (:arg-types long-float)
3839 (:result-types long-float)
3840 (:policy :fast-safe)
3841 (:note "inline logb function")
3843 (:save-p :compute-only)
3845 (note-this-location vop :internal-error)
3856 ;; x is in a FP reg, not fr0 or fr1
3859 (inst fldd (make-random-tn :kind :normal
3860 :sc (sc-or-lose 'double-reg)
3861 :offset (- (tn-offset x) 2))))))
3862 ((long-stack descriptor-reg)
3865 (if (sc-is x long-stack)
3866 (inst fldl (ea-for-lf-stack x))
3867 (inst fldl (ea-for-lf-desc x)))))
3878 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3879 (:temporary (:sc long-reg :offset fr0-offset
3880 :from (:argument 0) :to :result) fr0)
3881 (:temporary (:sc long-reg :offset fr1-offset
3882 :from (:argument 0) :to :result) fr1)
3883 (:results (r :scs (long-reg)))
3884 (:arg-types long-float)
3885 (:result-types long-float)
3886 (:policy :fast-safe)
3887 (:note "inline atan function")
3889 (:save-p :compute-only)
3891 (note-this-location vop :internal-error)
3892 ;; Setup x in fr1 and 1.0 in fr0
3895 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3898 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3900 ;; x not in fr0 or fr1
3907 (inst fldd (make-random-tn :kind :normal
3908 :sc (sc-or-lose 'double-reg)
3909 :offset (- (tn-offset x) 2))))
3911 (inst fldl (ea-for-lf-stack x)))
3913 (inst fldl (ea-for-lf-desc x))))))
3915 ;; Now have x at fr1; and 1.0 at fr0
3920 (t (inst fstd r)))))
3922 (define-vop (fatan2)
3924 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3925 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3926 (:temporary (:sc long-reg :offset fr0-offset
3927 :from (:argument 1) :to :result) fr0)
3928 (:temporary (:sc long-reg :offset fr1-offset
3929 :from (:argument 0) :to :result) fr1)
3930 (:results (r :scs (long-reg)))
3931 (:arg-types long-float long-float)
3932 (:result-types long-float)
3933 (:policy :fast-safe)
3934 (:note "inline atan2 function")
3936 (:save-p :compute-only)
3938 (note-this-location vop :internal-error)
3939 ;; Setup x in fr1 and y in fr0
3941 ;; y in fr0; x in fr1
3942 ((and (sc-is y long-reg) (zerop (tn-offset y))
3943 (sc-is x long-reg) (= 1 (tn-offset x))))
3944 ;; x in fr1; y not in fr0
3945 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3949 (copy-fp-reg-to-fr0 y))
3952 (inst fldl (ea-for-lf-stack y)))
3955 (inst fldl (ea-for-lf-desc y)))))
3956 ;; y in fr0; x not in fr1
3957 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3959 ;; Now load x to fr0
3962 (copy-fp-reg-to-fr0 x))
3965 (inst fldl (ea-for-lf-stack x)))
3968 (inst fldl (ea-for-lf-desc x))))
3970 ;; y in fr1; x not in fr1
3971 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3975 (copy-fp-reg-to-fr0 x))
3978 (inst fldl (ea-for-lf-stack x)))
3981 (inst fldl (ea-for-lf-desc x))))
3984 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3986 ;; Now load y to fr0
3989 (copy-fp-reg-to-fr0 y))
3992 (inst fldl (ea-for-lf-stack y)))
3995 (inst fldl (ea-for-lf-desc y)))))
3996 ;; Neither y or x are in either fr0 or fr1
4003 (inst fldd (make-random-tn :kind :normal
4004 :sc (sc-or-lose 'double-reg)
4005 :offset (- (tn-offset x) 2))))
4007 (inst fldl (ea-for-lf-stack x)))
4009 (inst fldl (ea-for-lf-desc x))))
4013 (inst fldd (make-random-tn :kind :normal
4014 :sc (sc-or-lose 'double-reg)
4015 :offset (1- (tn-offset y)))))
4017 (inst fldl (ea-for-lf-stack y)))
4019 (inst fldl (ea-for-lf-desc y))))))
4021 ;; Now have y at fr0; and x at fr1
4026 (t (inst fstd r)))))
4028 ) ; PROGN #!+LONG-FLOAT
4030 ;;;; complex float VOPs
4032 (define-vop (make-complex-single-float)
4033 (:translate complex)
4034 (:args (real :scs (single-reg) :to :result :target r
4035 :load-if (not (location= real r)))
4036 (imag :scs (single-reg) :to :save))
4037 (:arg-types single-float single-float)
4038 (:results (r :scs (complex-single-reg) :from (:argument 0)
4039 :load-if (not (sc-is r complex-single-stack))))
4040 (:result-types complex-single-float)
4041 (:note "inline complex single-float creation")
4042 (:policy :fast-safe)
4046 (let ((r-real (complex-double-reg-real-tn r)))
4047 (unless (location= real r-real)
4048 (cond ((zerop (tn-offset r-real))
4049 (copy-fp-reg-to-fr0 real))
4050 ((zerop (tn-offset real))
4055 (inst fxch real)))))
4056 (let ((r-imag (complex-double-reg-imag-tn r)))
4057 (unless (location= imag r-imag)
4058 (cond ((zerop (tn-offset imag))
4063 (inst fxch imag))))))
4064 (complex-single-stack
4065 (unless (location= real r)
4066 (cond ((zerop (tn-offset real))
4067 (inst fst (ea-for-csf-real-stack r)))
4070 (inst fst (ea-for-csf-real-stack r))
4073 (inst fst (ea-for-csf-imag-stack r))
4074 (inst fxch imag)))))
4076 (define-vop (make-complex-double-float)
4077 (:translate complex)
4078 (:args (real :scs (double-reg) :target r
4079 :load-if (not (location= real r)))
4080 (imag :scs (double-reg) :to :save))
4081 (:arg-types double-float double-float)
4082 (:results (r :scs (complex-double-reg) :from (:argument 0)
4083 :load-if (not (sc-is r complex-double-stack))))
4084 (:result-types complex-double-float)
4085 (:note "inline complex double-float creation")
4086 (:policy :fast-safe)
4090 (let ((r-real (complex-double-reg-real-tn r)))
4091 (unless (location= real r-real)
4092 (cond ((zerop (tn-offset r-real))
4093 (copy-fp-reg-to-fr0 real))
4094 ((zerop (tn-offset real))
4099 (inst fxch real)))))
4100 (let ((r-imag (complex-double-reg-imag-tn r)))
4101 (unless (location= imag r-imag)
4102 (cond ((zerop (tn-offset imag))
4107 (inst fxch imag))))))
4108 (complex-double-stack
4109 (unless (location= real r)
4110 (cond ((zerop (tn-offset real))
4111 (inst fstd (ea-for-cdf-real-stack r)))
4114 (inst fstd (ea-for-cdf-real-stack r))
4117 (inst fstd (ea-for-cdf-imag-stack r))
4118 (inst fxch imag)))))
4121 (define-vop (make-complex-long-float)
4122 (:translate complex)
4123 (:args (real :scs (long-reg) :target r
4124 :load-if (not (location= real r)))
4125 (imag :scs (long-reg) :to :save))
4126 (:arg-types long-float long-float)
4127 (:results (r :scs (complex-long-reg) :from (:argument 0)
4128 :load-if (not (sc-is r complex-long-stack))))
4129 (:result-types complex-long-float)
4130 (:note "inline complex long-float creation")
4131 (:policy :fast-safe)
4135 (let ((r-real (complex-double-reg-real-tn r)))
4136 (unless (location= real r-real)
4137 (cond ((zerop (tn-offset r-real))
4138 (copy-fp-reg-to-fr0 real))
4139 ((zerop (tn-offset real))
4144 (inst fxch real)))))
4145 (let ((r-imag (complex-double-reg-imag-tn r)))
4146 (unless (location= imag r-imag)
4147 (cond ((zerop (tn-offset imag))
4152 (inst fxch imag))))))
4154 (unless (location= real r)
4155 (cond ((zerop (tn-offset real))
4156 (store-long-float (ea-for-clf-real-stack r)))
4159 (store-long-float (ea-for-clf-real-stack r))
4162 (store-long-float (ea-for-clf-imag-stack r))
4163 (inst fxch imag)))))
4166 (define-vop (complex-float-value)
4167 (:args (x :target r))
4169 (:variant-vars offset)
4170 (:policy :fast-safe)
4172 (cond ((sc-is x complex-single-reg complex-double-reg
4173 #!+long-float complex-long-reg)
4175 (make-random-tn :kind :normal
4176 :sc (sc-or-lose 'double-reg)
4177 :offset (+ offset (tn-offset x)))))
4178 (unless (location= value-tn r)
4179 (cond ((zerop (tn-offset r))
4180 (copy-fp-reg-to-fr0 value-tn))
4181 ((zerop (tn-offset value-tn))
4184 (inst fxch value-tn)
4186 (inst fxch value-tn))))))
4187 ((sc-is r single-reg)
4188 (let ((ea (sc-case x
4189 (complex-single-stack
4191 (0 (ea-for-csf-real-stack x))
4192 (1 (ea-for-csf-imag-stack x))))
4195 (0 (ea-for-csf-real-desc x))
4196 (1 (ea-for-csf-imag-desc x)))))))
4197 (with-empty-tn@fp-top(r)
4199 ((sc-is r double-reg)
4200 (let ((ea (sc-case x
4201 (complex-double-stack
4203 (0 (ea-for-cdf-real-stack x))
4204 (1 (ea-for-cdf-imag-stack x))))
4207 (0 (ea-for-cdf-real-desc x))
4208 (1 (ea-for-cdf-imag-desc x)))))))
4209 (with-empty-tn@fp-top(r)
4213 (let ((ea (sc-case x
4216 (0 (ea-for-clf-real-stack x))
4217 (1 (ea-for-clf-imag-stack x))))
4220 (0 (ea-for-clf-real-desc x))
4221 (1 (ea-for-clf-imag-desc x)))))))
4222 (with-empty-tn@fp-top(r)
4224 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4226 (define-vop (realpart/complex-single-float complex-float-value)
4227 (:translate realpart)
4228 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4230 (:arg-types complex-single-float)
4231 (:results (r :scs (single-reg)))
4232 (:result-types single-float)
4233 (:note "complex float realpart")
4236 (define-vop (realpart/complex-double-float complex-float-value)
4237 (:translate realpart)
4238 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4240 (:arg-types complex-double-float)
4241 (:results (r :scs (double-reg)))
4242 (:result-types double-float)
4243 (:note "complex float realpart")
4247 (define-vop (realpart/complex-long-float complex-float-value)
4248 (:translate realpart)
4249 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4251 (:arg-types complex-long-float)
4252 (:results (r :scs (long-reg)))
4253 (:result-types long-float)
4254 (:note "complex float realpart")
4257 (define-vop (imagpart/complex-single-float complex-float-value)
4258 (:translate imagpart)
4259 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4261 (:arg-types complex-single-float)
4262 (:results (r :scs (single-reg)))
4263 (:result-types single-float)
4264 (:note "complex float imagpart")
4267 (define-vop (imagpart/complex-double-float complex-float-value)
4268 (:translate imagpart)
4269 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4271 (:arg-types complex-double-float)
4272 (:results (r :scs (double-reg)))
4273 (:result-types double-float)
4274 (:note "complex float imagpart")
4278 (define-vop (imagpart/complex-long-float complex-float-value)
4279 (:translate imagpart)
4280 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4282 (:arg-types complex-long-float)
4283 (:results (r :scs (long-reg)))
4284 (:result-types long-float)
4285 (:note "complex float imagpart")
4288 ;;; hack dummy VOPs to bias the representation selection of their
4289 ;;; arguments towards a FP register, which can help avoid consing at
4290 ;;; inappropriate locations
4291 (defknown double-float-reg-bias (double-float) (values))
4292 (define-vop (double-float-reg-bias)
4293 (:translate double-float-reg-bias)
4294 (:args (x :scs (double-reg double-stack) :load-if nil))
4295 (:arg-types double-float)
4296 (:policy :fast-safe)
4297 (:note "inline dummy FP register bias")
4300 (defknown single-float-reg-bias (single-float) (values))
4301 (define-vop (single-float-reg-bias)
4302 (:translate single-float-reg-bias)
4303 (:args (x :scs (single-reg single-stack) :load-if nil))
4304 (:arg-types single-float)
4305 (:policy :fast-safe)
4306 (:note "inline dummy FP register bias")