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 (- (* (+ (tn-offset ,tn)
46 (ecase ,kind (:single 1) (:double 2) (:long 3)))
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 (- (* (+ (tn-offset ,tn)
87 (ecase ,slot (:real 1) (:imag 2))))
89 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
90 (ea-for-cxf-stack tn :single :real base))
91 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
92 (ea-for-cxf-stack tn :single :imag base))
93 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
94 (ea-for-cxf-stack tn :double :real base))
95 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
96 (ea-for-cxf-stack tn :double :imag base))
98 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
99 (ea-for-cxf-stack tn :long :real base))
101 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
102 (ea-for-cxf-stack tn :long :imag base)))
104 ;;; Abstract out the copying of a FP register to the FP stack top, and
105 ;;; provide two alternatives for its implementation. Note: it's not
106 ;;; necessary to distinguish between a single or double register move
109 ;;; Using a Pop then load.
110 (defun copy-fp-reg-to-fr0 (reg)
111 (aver (not (zerop (tn-offset reg))))
113 (inst fld (make-random-tn :kind :normal
114 :sc (sc-or-lose 'double-reg)
115 :offset (1- (tn-offset reg)))))
116 ;;; Using Fxch then Fst to restore the original reg contents.
118 (defun copy-fp-reg-to-fr0 (reg)
119 (aver (not (zerop (tn-offset reg))))
123 ;;; The x86 can't store a long-float to memory without popping the
124 ;;; stack and marking a register as empty, so it is necessary to
125 ;;; restore the register from memory.
127 (defun store-long-float (ea)
133 ;;; X is source, Y is destination.
134 (define-move-fun (load-single 2) (vop x y)
135 ((single-stack) (single-reg))
136 (with-empty-tn@fp-top(y)
137 (inst fld (ea-for-sf-stack x))))
139 (define-move-fun (store-single 2) (vop x y)
140 ((single-reg) (single-stack))
141 (cond ((zerop (tn-offset x))
142 (inst fst (ea-for-sf-stack y)))
145 (inst fst (ea-for-sf-stack y))
146 ;; This may not be necessary as ST0 is likely invalid now.
149 (define-move-fun (load-double 2) (vop x y)
150 ((double-stack) (double-reg))
151 (with-empty-tn@fp-top(y)
152 (inst fldd (ea-for-df-stack x))))
154 (define-move-fun (store-double 2) (vop x y)
155 ((double-reg) (double-stack))
156 (cond ((zerop (tn-offset x))
157 (inst fstd (ea-for-df-stack y)))
160 (inst fstd (ea-for-df-stack y))
161 ;; This may not be necessary as ST0 is likely invalid now.
165 (define-move-fun (load-long 2) (vop x y)
166 ((long-stack) (long-reg))
167 (with-empty-tn@fp-top(y)
168 (inst fldl (ea-for-lf-stack x))))
171 (define-move-fun (store-long 2) (vop x y)
172 ((long-reg) (long-stack))
173 (cond ((zerop (tn-offset x))
174 (store-long-float (ea-for-lf-stack y)))
177 (store-long-float (ea-for-lf-stack y))
178 ;; This may not be necessary as ST0 is likely invalid now.
181 ;;; The i387 has instructions to load some useful constants. This
182 ;;; doesn't save much time but might cut down on memory access and
183 ;;; reduce the size of the constant vector (CV). Intel claims they are
184 ;;; stored in a more precise form on chip. Anyhow, might as well use
185 ;;; the feature. It can be turned off by hacking the
186 ;;; "immediate-constant-sc" in vm.lisp.
187 (eval-when (:compile-toplevel :execute)
188 (setf *read-default-float-format*
189 #!+long-float 'long-float #!-long-float 'double-float))
190 (define-move-fun (load-fp-constant 2) (vop x y)
191 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
192 (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
193 (with-empty-tn@fp-top(y)
198 ((= value (coerce pi *read-default-float-format*))
200 ((= value (log 10e0 2e0))
202 ((= value (log 2.718281828459045235360287471352662e0 2e0))
204 ((= value (log 2e0 10e0))
206 ((= value (log 2e0 2.718281828459045235360287471352662e0))
208 (t (warn "ignoring bogus i387 constant ~A" value))))))
209 (eval-when (:compile-toplevel :execute)
210 (setf *read-default-float-format* 'single-float))
212 ;;;; complex float move functions
214 (defun complex-single-reg-real-tn (x)
215 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
216 :offset (tn-offset x)))
217 (defun complex-single-reg-imag-tn (x)
218 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
219 :offset (1+ (tn-offset x))))
221 (defun complex-double-reg-real-tn (x)
222 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
223 :offset (tn-offset x)))
224 (defun complex-double-reg-imag-tn (x)
225 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
226 :offset (1+ (tn-offset x))))
229 (defun complex-long-reg-real-tn (x)
230 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
231 :offset (tn-offset x)))
233 (defun complex-long-reg-imag-tn (x)
234 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
235 :offset (1+ (tn-offset x))))
237 ;;; X is source, Y is destination.
238 (define-move-fun (load-complex-single 2) (vop x y)
239 ((complex-single-stack) (complex-single-reg))
240 (let ((real-tn (complex-single-reg-real-tn y)))
241 (with-empty-tn@fp-top (real-tn)
242 (inst fld (ea-for-csf-real-stack x))))
243 (let ((imag-tn (complex-single-reg-imag-tn y)))
244 (with-empty-tn@fp-top (imag-tn)
245 (inst fld (ea-for-csf-imag-stack x)))))
247 (define-move-fun (store-complex-single 2) (vop x y)
248 ((complex-single-reg) (complex-single-stack))
249 (let ((real-tn (complex-single-reg-real-tn x)))
250 (cond ((zerop (tn-offset real-tn))
251 (inst fst (ea-for-csf-real-stack y)))
254 (inst fst (ea-for-csf-real-stack y))
255 (inst fxch real-tn))))
256 (let ((imag-tn (complex-single-reg-imag-tn x)))
258 (inst fst (ea-for-csf-imag-stack y))
259 (inst fxch imag-tn)))
261 (define-move-fun (load-complex-double 2) (vop x y)
262 ((complex-double-stack) (complex-double-reg))
263 (let ((real-tn (complex-double-reg-real-tn y)))
264 (with-empty-tn@fp-top(real-tn)
265 (inst fldd (ea-for-cdf-real-stack x))))
266 (let ((imag-tn (complex-double-reg-imag-tn y)))
267 (with-empty-tn@fp-top(imag-tn)
268 (inst fldd (ea-for-cdf-imag-stack x)))))
270 (define-move-fun (store-complex-double 2) (vop x y)
271 ((complex-double-reg) (complex-double-stack))
272 (let ((real-tn (complex-double-reg-real-tn x)))
273 (cond ((zerop (tn-offset real-tn))
274 (inst fstd (ea-for-cdf-real-stack y)))
277 (inst fstd (ea-for-cdf-real-stack y))
278 (inst fxch real-tn))))
279 (let ((imag-tn (complex-double-reg-imag-tn x)))
281 (inst fstd (ea-for-cdf-imag-stack y))
282 (inst fxch imag-tn)))
285 (define-move-fun (load-complex-long 2) (vop x y)
286 ((complex-long-stack) (complex-long-reg))
287 (let ((real-tn (complex-long-reg-real-tn y)))
288 (with-empty-tn@fp-top(real-tn)
289 (inst fldl (ea-for-clf-real-stack x))))
290 (let ((imag-tn (complex-long-reg-imag-tn y)))
291 (with-empty-tn@fp-top(imag-tn)
292 (inst fldl (ea-for-clf-imag-stack x)))))
295 (define-move-fun (store-complex-long 2) (vop x y)
296 ((complex-long-reg) (complex-long-stack))
297 (let ((real-tn (complex-long-reg-real-tn x)))
298 (cond ((zerop (tn-offset real-tn))
299 (store-long-float (ea-for-clf-real-stack y)))
302 (store-long-float (ea-for-clf-real-stack y))
303 (inst fxch real-tn))))
304 (let ((imag-tn (complex-long-reg-imag-tn x)))
306 (store-long-float (ea-for-clf-imag-stack y))
307 (inst fxch imag-tn)))
312 ;;; float register to register moves
313 (define-vop (float-move)
318 (unless (location= x y)
319 (cond ((zerop (tn-offset y))
320 (copy-fp-reg-to-fr0 x))
321 ((zerop (tn-offset x))
328 (define-vop (single-move float-move)
329 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
330 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
331 (define-move-vop single-move :move (single-reg) (single-reg))
333 (define-vop (double-move float-move)
334 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
335 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
336 (define-move-vop double-move :move (double-reg) (double-reg))
339 (define-vop (long-move float-move)
340 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
341 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
343 (define-move-vop long-move :move (long-reg) (long-reg))
345 ;;; complex float register to register moves
346 (define-vop (complex-float-move)
347 (:args (x :target y :load-if (not (location= x y))))
348 (:results (y :load-if (not (location= x y))))
349 (:note "complex float move")
351 (unless (location= x y)
352 ;; Note the complex-float-regs are aligned to every second
353 ;; float register so there is not need to worry about overlap.
354 (let ((x-real (complex-double-reg-real-tn x))
355 (y-real (complex-double-reg-real-tn y)))
356 (cond ((zerop (tn-offset y-real))
357 (copy-fp-reg-to-fr0 x-real))
358 ((zerop (tn-offset x-real))
363 (inst fxch x-real))))
364 (let ((x-imag (complex-double-reg-imag-tn x))
365 (y-imag (complex-double-reg-imag-tn y)))
368 (inst fxch x-imag)))))
370 (define-vop (complex-single-move complex-float-move)
371 (:args (x :scs (complex-single-reg) :target y
372 :load-if (not (location= x y))))
373 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
374 (define-move-vop complex-single-move :move
375 (complex-single-reg) (complex-single-reg))
377 (define-vop (complex-double-move complex-float-move)
378 (:args (x :scs (complex-double-reg)
379 :target y :load-if (not (location= x y))))
380 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
381 (define-move-vop complex-double-move :move
382 (complex-double-reg) (complex-double-reg))
385 (define-vop (complex-long-move complex-float-move)
386 (:args (x :scs (complex-long-reg)
387 :target y :load-if (not (location= x y))))
388 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
390 (define-move-vop complex-long-move :move
391 (complex-long-reg) (complex-long-reg))
393 ;;; Move from float to a descriptor reg. allocating a new float
394 ;;; object in the process.
395 (define-vop (move-from-single)
396 (:args (x :scs (single-reg) :to :save))
397 (:results (y :scs (descriptor-reg)))
399 (:note "float to pointer coercion")
401 (with-fixed-allocation (y
403 single-float-size node)
405 (inst fst (ea-for-sf-desc y))))))
406 (define-move-vop move-from-single :move
407 (single-reg) (descriptor-reg))
409 (define-vop (move-from-double)
410 (:args (x :scs (double-reg) :to :save))
411 (:results (y :scs (descriptor-reg)))
413 (:note "float to pointer coercion")
415 (with-fixed-allocation (y
420 (inst fstd (ea-for-df-desc y))))))
421 (define-move-vop move-from-double :move
422 (double-reg) (descriptor-reg))
425 (define-vop (move-from-long)
426 (:args (x :scs (long-reg) :to :save))
427 (:results (y :scs (descriptor-reg)))
429 (:note "float to pointer coercion")
431 (with-fixed-allocation (y
436 (store-long-float (ea-for-lf-desc y))))))
438 (define-move-vop move-from-long :move
439 (long-reg) (descriptor-reg))
441 (define-vop (move-from-fp-constant)
442 (:args (x :scs (fp-constant)))
443 (:results (y :scs (descriptor-reg)))
445 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
446 (0f0 (load-symbol-value y *fp-constant-0f0*))
447 (1f0 (load-symbol-value y *fp-constant-1f0*))
448 (0d0 (load-symbol-value y *fp-constant-0d0*))
449 (1d0 (load-symbol-value y *fp-constant-1d0*))
451 (0l0 (load-symbol-value y *fp-constant-0l0*))
453 (1l0 (load-symbol-value y *fp-constant-1l0*))
455 (#.pi (load-symbol-value y *fp-constant-pi*))
457 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
459 (#.(log 2.718281828459045235360287471352662L0 2l0)
460 (load-symbol-value y *fp-constant-l2e*))
462 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
464 (#.(log 2l0 2.718281828459045235360287471352662L0)
465 (load-symbol-value y *fp-constant-ln2*)))))
466 (define-move-vop move-from-fp-constant :move
467 (fp-constant) (descriptor-reg))
469 ;;; Move from a descriptor to a float register.
470 (define-vop (move-to-single)
471 (:args (x :scs (descriptor-reg)))
472 (:results (y :scs (single-reg)))
473 (:note "pointer to float coercion")
475 (with-empty-tn@fp-top(y)
476 (inst fld (ea-for-sf-desc x)))))
477 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
479 (define-vop (move-to-double)
480 (:args (x :scs (descriptor-reg)))
481 (:results (y :scs (double-reg)))
482 (:note "pointer to float coercion")
484 (with-empty-tn@fp-top(y)
485 (inst fldd (ea-for-df-desc x)))))
486 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
489 (define-vop (move-to-long)
490 (:args (x :scs (descriptor-reg)))
491 (:results (y :scs (long-reg)))
492 (:note "pointer to float coercion")
494 (with-empty-tn@fp-top(y)
495 (inst fldl (ea-for-lf-desc x)))))
497 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
499 ;;; Move from complex float to a descriptor reg. allocating a new
500 ;;; complex float object in the process.
501 (define-vop (move-from-complex-single)
502 (:args (x :scs (complex-single-reg) :to :save))
503 (:results (y :scs (descriptor-reg)))
505 (:note "complex float to pointer coercion")
507 (with-fixed-allocation (y
508 complex-single-float-widetag
509 complex-single-float-size
511 (let ((real-tn (complex-single-reg-real-tn x)))
512 (with-tn@fp-top(real-tn)
513 (inst fst (ea-for-csf-real-desc y))))
514 (let ((imag-tn (complex-single-reg-imag-tn x)))
515 (with-tn@fp-top(imag-tn)
516 (inst fst (ea-for-csf-imag-desc y)))))))
517 (define-move-vop move-from-complex-single :move
518 (complex-single-reg) (descriptor-reg))
520 (define-vop (move-from-complex-double)
521 (:args (x :scs (complex-double-reg) :to :save))
522 (:results (y :scs (descriptor-reg)))
524 (:note "complex float to pointer coercion")
526 (with-fixed-allocation (y
527 complex-double-float-widetag
528 complex-double-float-size
530 (let ((real-tn (complex-double-reg-real-tn x)))
531 (with-tn@fp-top(real-tn)
532 (inst fstd (ea-for-cdf-real-desc y))))
533 (let ((imag-tn (complex-double-reg-imag-tn x)))
534 (with-tn@fp-top(imag-tn)
535 (inst fstd (ea-for-cdf-imag-desc y)))))))
536 (define-move-vop move-from-complex-double :move
537 (complex-double-reg) (descriptor-reg))
540 (define-vop (move-from-complex-long)
541 (:args (x :scs (complex-long-reg) :to :save))
542 (:results (y :scs (descriptor-reg)))
544 (:note "complex float to pointer coercion")
546 (with-fixed-allocation (y
547 complex-long-float-widetag
548 complex-long-float-size
550 (let ((real-tn (complex-long-reg-real-tn x)))
551 (with-tn@fp-top(real-tn)
552 (store-long-float (ea-for-clf-real-desc y))))
553 (let ((imag-tn (complex-long-reg-imag-tn x)))
554 (with-tn@fp-top(imag-tn)
555 (store-long-float (ea-for-clf-imag-desc y)))))))
557 (define-move-vop move-from-complex-long :move
558 (complex-long-reg) (descriptor-reg))
560 ;;; Move from a descriptor to a complex float register.
561 (macrolet ((frob (name sc format)
564 (:args (x :scs (descriptor-reg)))
565 (:results (y :scs (,sc)))
566 (:note "pointer to complex float coercion")
568 (let ((real-tn (complex-double-reg-real-tn y)))
569 (with-empty-tn@fp-top(real-tn)
571 (:single '((inst fld (ea-for-csf-real-desc x))))
572 (:double '((inst fldd (ea-for-cdf-real-desc x))))
574 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
575 (let ((imag-tn (complex-double-reg-imag-tn y)))
576 (with-empty-tn@fp-top(imag-tn)
578 (:single '((inst fld (ea-for-csf-imag-desc x))))
579 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
581 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
582 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
583 (frob move-to-complex-single complex-single-reg :single)
584 (frob move-to-complex-double complex-double-reg :double)
586 (frob move-to-complex-double complex-long-reg :long))
588 ;;;; the move argument vops
590 ;;;; Note these are also used to stuff fp numbers onto the c-call
591 ;;;; stack so the order is different than the lisp-stack.
593 ;;; the general MOVE-ARG VOP
594 (macrolet ((frob (name sc stack-sc format)
597 (:args (x :scs (,sc) :target y)
599 :load-if (not (sc-is y ,sc))))
601 (:note "float argument move")
602 (:generator ,(case format (:single 2) (:double 3) (:long 4))
605 (unless (location= x y)
606 (cond ((zerop (tn-offset y))
607 (copy-fp-reg-to-fr0 x))
608 ((zerop (tn-offset x))
615 (if (= (tn-offset fp) esp-offset)
616 (let* ((offset (* (tn-offset y) n-word-bytes))
617 (ea (make-ea :dword :base fp :disp offset)))
620 (:single '((inst fst ea)))
621 (:double '((inst fstd ea)))
623 (:long '((store-long-float ea))))))
626 :disp (- (* (+ (tn-offset y)
634 (:single '((inst fst ea)))
635 (:double '((inst fstd ea)))
637 (:long '((store-long-float ea)))))))))))
638 (define-move-vop ,name :move-arg
639 (,sc descriptor-reg) (,sc)))))
640 (frob move-single-float-arg single-reg single-stack :single)
641 (frob move-double-float-arg double-reg double-stack :double)
643 (frob move-long-float-arg long-reg long-stack :long))
645 ;;;; complex float MOVE-ARG VOP
646 (macrolet ((frob (name sc stack-sc format)
649 (:args (x :scs (,sc) :target y)
651 :load-if (not (sc-is y ,sc))))
653 (:note "complex float argument move")
654 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
657 (unless (location= x y)
658 (let ((x-real (complex-double-reg-real-tn x))
659 (y-real (complex-double-reg-real-tn y)))
660 (cond ((zerop (tn-offset y-real))
661 (copy-fp-reg-to-fr0 x-real))
662 ((zerop (tn-offset x-real))
667 (inst fxch x-real))))
668 (let ((x-imag (complex-double-reg-imag-tn x))
669 (y-imag (complex-double-reg-imag-tn y)))
672 (inst fxch x-imag))))
674 (let ((real-tn (complex-double-reg-real-tn x)))
675 (cond ((zerop (tn-offset real-tn))
679 (ea-for-csf-real-stack y fp))))
682 (ea-for-cdf-real-stack y fp))))
686 (ea-for-clf-real-stack y fp))))))
692 (ea-for-csf-real-stack y fp))))
695 (ea-for-cdf-real-stack y fp))))
699 (ea-for-clf-real-stack y fp)))))
700 (inst fxch real-tn))))
701 (let ((imag-tn (complex-double-reg-imag-tn x)))
705 '((inst fst (ea-for-csf-imag-stack y fp))))
707 '((inst fstd (ea-for-cdf-imag-stack y fp))))
711 (ea-for-clf-imag-stack y fp)))))
712 (inst fxch imag-tn))))))
713 (define-move-vop ,name :move-arg
714 (,sc descriptor-reg) (,sc)))))
715 (frob move-complex-single-float-arg
716 complex-single-reg complex-single-stack :single)
717 (frob move-complex-double-float-arg
718 complex-double-reg complex-double-stack :double)
720 (frob move-complex-long-float-arg
721 complex-long-reg complex-long-stack :long))
723 (define-move-vop move-arg :move-arg
724 (single-reg double-reg #!+long-float long-reg
725 complex-single-reg complex-double-reg #!+long-float complex-long-reg)
731 ;;; dtc: the floating point arithmetic vops
733 ;;; Note: Although these can accept x and y on the stack or pointed to
734 ;;; from a descriptor register, they will work with register loading
735 ;;; without these. Same deal with the result - it need only be a
736 ;;; register. When load-tns are needed they will probably be in ST0
737 ;;; and the code below should be able to correctly handle all cases.
739 ;;; However it seems to produce better code if all arg. and result
740 ;;; options are used; on the P86 there is no extra cost in using a
741 ;;; memory operand to the FP instructions - not so on the PPro.
743 ;;; It may also be useful to handle constant args?
745 ;;; 22-Jul-97: descriptor args lose in some simple cases when
746 ;;; a function result computed in a loop. Then Python insists
747 ;;; on consing the intermediate values! For example
750 ;;; (declare (type (simple-array double-float (*)) a)
753 ;;; (declare (type double-float sum))
755 ;;; (incf sum (* (aref a i)(aref a i))))
758 ;;; So, disabling descriptor args until this can be fixed elsewhere.
760 ((frob (op fop-sti fopr-sti
762 fopd foprd dname dcost
764 #!-long-float (declare (ignore lcost lname))
768 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
770 (y :scs (single-reg single-stack #+nil descriptor-reg)
772 (:temporary (:sc single-reg :offset fr0-offset
773 :from :eval :to :result) fr0)
774 (:results (r :scs (single-reg single-stack)))
775 (:arg-types single-float single-float)
776 (:result-types single-float)
778 (:note "inline float arithmetic")
780 (:save-p :compute-only)
783 ;; Handle a few special cases
785 ;; x, y, and r are the same register.
786 ((and (sc-is x single-reg) (location= x r) (location= y r))
787 (cond ((zerop (tn-offset r))
792 ;; XX the source register will not be valid.
793 (note-next-instruction vop :internal-error)
796 ;; x and r are the same register.
797 ((and (sc-is x single-reg) (location= x r))
798 (cond ((zerop (tn-offset r))
801 ;; ST(0) = ST(0) op ST(y)
804 ;; ST(0) = ST(0) op Mem
805 (inst ,fop (ea-for-sf-stack y)))
807 (inst ,fop (ea-for-sf-desc y)))))
812 (unless (zerop (tn-offset y))
813 (copy-fp-reg-to-fr0 y)))
814 ((single-stack descriptor-reg)
816 (if (sc-is y single-stack)
817 (inst fld (ea-for-sf-stack y))
818 (inst fld (ea-for-sf-desc y)))))
819 ;; ST(i) = ST(i) op ST0
821 (maybe-fp-wait node vop))
822 ;; y and r are the same register.
823 ((and (sc-is y single-reg) (location= y r))
824 (cond ((zerop (tn-offset r))
827 ;; ST(0) = ST(x) op ST(0)
830 ;; ST(0) = Mem op ST(0)
831 (inst ,fopr (ea-for-sf-stack x)))
833 (inst ,fopr (ea-for-sf-desc x)))))
838 (unless (zerop (tn-offset x))
839 (copy-fp-reg-to-fr0 x)))
840 ((single-stack descriptor-reg)
842 (if (sc-is x single-stack)
843 (inst fld (ea-for-sf-stack x))
844 (inst fld (ea-for-sf-desc x)))))
845 ;; ST(i) = ST(0) op ST(i)
847 (maybe-fp-wait node vop))
850 ;; Get the result to ST0.
852 ;; Special handling is needed if x or y are in ST0, and
853 ;; simpler code is generated.
856 ((and (sc-is x single-reg) (zerop (tn-offset x)))
862 (inst ,fop (ea-for-sf-stack y)))
864 (inst ,fop (ea-for-sf-desc y)))))
866 ((and (sc-is y single-reg) (zerop (tn-offset y)))
872 (inst ,fopr (ea-for-sf-stack x)))
874 (inst ,fopr (ea-for-sf-desc x)))))
879 (copy-fp-reg-to-fr0 x))
882 (inst fld (ea-for-sf-stack x)))
885 (inst fld (ea-for-sf-desc x))))
891 (inst ,fop (ea-for-sf-stack y)))
893 (inst ,fop (ea-for-sf-desc y))))))
895 (note-next-instruction vop :internal-error)
897 ;; Finally save the result.
900 (cond ((zerop (tn-offset r))
901 (maybe-fp-wait node))
905 (inst fst (ea-for-sf-stack r))))))))
909 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
911 (y :scs (double-reg double-stack #+nil descriptor-reg)
913 (:temporary (:sc double-reg :offset fr0-offset
914 :from :eval :to :result) fr0)
915 (:results (r :scs (double-reg double-stack)))
916 (:arg-types double-float double-float)
917 (:result-types double-float)
919 (:note "inline float arithmetic")
921 (:save-p :compute-only)
924 ;; Handle a few special cases.
926 ;; x, y, and r are the same register.
927 ((and (sc-is x double-reg) (location= x r) (location= y r))
928 (cond ((zerop (tn-offset r))
933 ;; XX the source register will not be valid.
934 (note-next-instruction vop :internal-error)
937 ;; x and r are the same register.
938 ((and (sc-is x double-reg) (location= x r))
939 (cond ((zerop (tn-offset r))
942 ;; ST(0) = ST(0) op ST(y)
945 ;; ST(0) = ST(0) op Mem
946 (inst ,fopd (ea-for-df-stack y)))
948 (inst ,fopd (ea-for-df-desc y)))))
953 (unless (zerop (tn-offset y))
954 (copy-fp-reg-to-fr0 y)))
955 ((double-stack descriptor-reg)
957 (if (sc-is y double-stack)
958 (inst fldd (ea-for-df-stack y))
959 (inst fldd (ea-for-df-desc y)))))
960 ;; ST(i) = ST(i) op ST0
962 (maybe-fp-wait node vop))
963 ;; y and r are the same register.
964 ((and (sc-is y double-reg) (location= y r))
965 (cond ((zerop (tn-offset r))
968 ;; ST(0) = ST(x) op ST(0)
971 ;; ST(0) = Mem op ST(0)
972 (inst ,foprd (ea-for-df-stack x)))
974 (inst ,foprd (ea-for-df-desc x)))))
979 (unless (zerop (tn-offset x))
980 (copy-fp-reg-to-fr0 x)))
981 ((double-stack descriptor-reg)
983 (if (sc-is x double-stack)
984 (inst fldd (ea-for-df-stack x))
985 (inst fldd (ea-for-df-desc x)))))
986 ;; ST(i) = ST(0) op ST(i)
988 (maybe-fp-wait node vop))
991 ;; Get the result to ST0.
993 ;; Special handling is needed if x or y are in ST0, and
994 ;; simpler code is generated.
997 ((and (sc-is x double-reg) (zerop (tn-offset x)))
1003 (inst ,fopd (ea-for-df-stack y)))
1005 (inst ,fopd (ea-for-df-desc y)))))
1007 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1013 (inst ,foprd (ea-for-df-stack x)))
1015 (inst ,foprd (ea-for-df-desc x)))))
1020 (copy-fp-reg-to-fr0 x))
1023 (inst fldd (ea-for-df-stack x)))
1026 (inst fldd (ea-for-df-desc x))))
1032 (inst ,fopd (ea-for-df-stack y)))
1034 (inst ,fopd (ea-for-df-desc y))))))
1036 (note-next-instruction vop :internal-error)
1038 ;; Finally save the result.
1041 (cond ((zerop (tn-offset r))
1042 (maybe-fp-wait node))
1046 (inst fstd (ea-for-df-stack r))))))))
1049 (define-vop (,lname)
1051 (:args (x :scs (long-reg) :to :eval)
1052 (y :scs (long-reg) :to :eval))
1053 (:temporary (:sc long-reg :offset fr0-offset
1054 :from :eval :to :result) fr0)
1055 (:results (r :scs (long-reg)))
1056 (:arg-types long-float long-float)
1057 (:result-types long-float)
1058 (:policy :fast-safe)
1059 (:note "inline float arithmetic")
1061 (:save-p :compute-only)
1064 ;; Handle a few special cases.
1066 ;; x, y, and r are the same register.
1067 ((and (location= x r) (location= y r))
1068 (cond ((zerop (tn-offset r))
1073 ;; XX the source register will not be valid.
1074 (note-next-instruction vop :internal-error)
1077 ;; x and r are the same register.
1079 (cond ((zerop (tn-offset r))
1080 ;; ST(0) = ST(0) op ST(y)
1084 (unless (zerop (tn-offset y))
1085 (copy-fp-reg-to-fr0 y))
1086 ;; ST(i) = ST(i) op ST0
1088 (maybe-fp-wait node vop))
1089 ;; y and r are the same register.
1091 (cond ((zerop (tn-offset r))
1092 ;; ST(0) = ST(x) op ST(0)
1096 (unless (zerop (tn-offset x))
1097 (copy-fp-reg-to-fr0 x))
1098 ;; ST(i) = ST(0) op ST(i)
1099 (inst ,fopr-sti r)))
1100 (maybe-fp-wait node vop))
1103 ;; Get the result to ST0.
1105 ;; Special handling is needed if x or y are in ST0, and
1106 ;; simpler code is generated.
1109 ((zerop (tn-offset x))
1113 ((zerop (tn-offset y))
1118 (copy-fp-reg-to-fr0 x)
1122 (note-next-instruction vop :internal-error)
1124 ;; Finally save the result.
1125 (cond ((zerop (tn-offset r))
1126 (maybe-fp-wait node))
1128 (inst fst r))))))))))
1130 (frob + fadd-sti fadd-sti
1131 fadd fadd +/single-float 2
1132 faddd faddd +/double-float 2
1134 (frob - fsub-sti fsubr-sti
1135 fsub fsubr -/single-float 2
1136 fsubd fsubrd -/double-float 2
1138 (frob * fmul-sti fmul-sti
1139 fmul fmul */single-float 3
1140 fmuld fmuld */double-float 3
1142 (frob / fdiv-sti fdivr-sti
1143 fdiv fdivr //single-float 12
1144 fdivd fdivrd //double-float 12
1147 (macrolet ((frob (name inst translate sc type)
1148 `(define-vop (,name)
1149 (:args (x :scs (,sc) :target fr0))
1150 (:results (y :scs (,sc)))
1151 (:translate ,translate)
1152 (:policy :fast-safe)
1154 (:result-types ,type)
1155 (:temporary (:sc double-reg :offset fr0-offset
1156 :from :argument :to :result) fr0)
1158 (:note "inline float arithmetic")
1160 (:save-p :compute-only)
1162 (note-this-location vop :internal-error)
1163 (unless (zerop (tn-offset x))
1164 (inst fxch x) ; x to top of stack
1165 (unless (location= x y)
1166 (inst fst x))) ; Maybe save it.
1167 (inst ,inst) ; Clobber st0.
1168 (unless (zerop (tn-offset y))
1171 (frob abs/single-float fabs abs single-reg single-float)
1172 (frob abs/double-float fabs abs double-reg double-float)
1174 (frob abs/long-float fabs abs long-reg long-float)
1175 (frob %negate/single-float fchs %negate single-reg single-float)
1176 (frob %negate/double-float fchs %negate double-reg double-float)
1178 (frob %negate/long-float fchs %negate long-reg long-float))
1182 (define-vop (=/float)
1184 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1186 (:info target not-p)
1187 (:policy :fast-safe)
1189 (:save-p :compute-only)
1190 (:note "inline float comparison")
1193 (note-this-location vop :internal-error)
1195 ;; x is in ST0; y is in any reg.
1196 ((zerop (tn-offset x))
1198 ;; y is in ST0; x is in another reg.
1199 ((zerop (tn-offset y))
1201 ;; x and y are the same register, not ST0
1206 ;; x and y are different registers, neither ST0.
1211 (inst fnstsw) ; status word to ax
1212 (inst and ah-tn #x45) ; C3 C2 C0
1213 (inst cmp ah-tn #x40)
1214 (inst jmp (if not-p :ne :e) target)))
1216 (define-vop (=/single-float =/float)
1218 (:args (x :scs (single-reg))
1219 (y :scs (single-reg)))
1220 (:arg-types single-float single-float))
1222 (define-vop (=/double-float =/float)
1224 (:args (x :scs (double-reg))
1225 (y :scs (double-reg)))
1226 (:arg-types double-float double-float))
1229 (define-vop (=/long-float =/float)
1231 (:args (x :scs (long-reg))
1232 (y :scs (long-reg)))
1233 (:arg-types long-float long-float))
1235 (define-vop (<single-float)
1237 (:args (x :scs (single-reg single-stack descriptor-reg))
1238 (y :scs (single-reg single-stack descriptor-reg)))
1239 (:arg-types single-float single-float)
1240 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1241 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1243 (:info target not-p)
1244 (:policy :fast-safe)
1245 (:note "inline float comparison")
1248 ;; Handle a few special cases.
1251 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1255 ((single-stack descriptor-reg)
1256 (if (sc-is x single-stack)
1257 (inst fcom (ea-for-sf-stack x))
1258 (inst fcom (ea-for-sf-desc x)))))
1259 (inst fnstsw) ; status word to ax
1260 (inst and ah-tn #x45))
1262 ;; general case when y is not in ST0
1267 (unless (zerop (tn-offset x))
1268 (copy-fp-reg-to-fr0 x)))
1269 ((single-stack descriptor-reg)
1271 (if (sc-is x single-stack)
1272 (inst fld (ea-for-sf-stack x))
1273 (inst fld (ea-for-sf-desc x)))))
1277 ((single-stack descriptor-reg)
1278 (if (sc-is y single-stack)
1279 (inst fcom (ea-for-sf-stack y))
1280 (inst fcom (ea-for-sf-desc y)))))
1281 (inst fnstsw) ; status word to ax
1282 (inst and ah-tn #x45) ; C3 C2 C0
1283 (inst cmp ah-tn #x01)))
1284 (inst jmp (if not-p :ne :e) target)))
1286 (define-vop (<double-float)
1288 (:args (x :scs (double-reg double-stack descriptor-reg))
1289 (y :scs (double-reg double-stack descriptor-reg)))
1290 (:arg-types double-float double-float)
1291 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1292 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1294 (:info target not-p)
1295 (:policy :fast-safe)
1296 (:note "inline float comparison")
1299 ;; Handle a few special cases
1302 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1306 ((double-stack descriptor-reg)
1307 (if (sc-is x double-stack)
1308 (inst fcomd (ea-for-df-stack x))
1309 (inst fcomd (ea-for-df-desc x)))))
1310 (inst fnstsw) ; status word to ax
1311 (inst and ah-tn #x45))
1313 ;; General case when y is not in ST0.
1318 (unless (zerop (tn-offset x))
1319 (copy-fp-reg-to-fr0 x)))
1320 ((double-stack descriptor-reg)
1322 (if (sc-is x double-stack)
1323 (inst fldd (ea-for-df-stack x))
1324 (inst fldd (ea-for-df-desc x)))))
1328 ((double-stack descriptor-reg)
1329 (if (sc-is y double-stack)
1330 (inst fcomd (ea-for-df-stack y))
1331 (inst fcomd (ea-for-df-desc y)))))
1332 (inst fnstsw) ; status word to ax
1333 (inst and ah-tn #x45) ; C3 C2 C0
1334 (inst cmp ah-tn #x01)))
1335 (inst jmp (if not-p :ne :e) target)))
1338 (define-vop (<long-float)
1340 (:args (x :scs (long-reg))
1341 (y :scs (long-reg)))
1342 (:arg-types long-float long-float)
1343 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1345 (:info target not-p)
1346 (:policy :fast-safe)
1347 (:note "inline float comparison")
1351 ;; x is in ST0; y is in any reg.
1352 ((zerop (tn-offset x))
1354 (inst fnstsw) ; status word to ax
1355 (inst and ah-tn #x45) ; C3 C2 C0
1356 (inst cmp ah-tn #x01))
1357 ;; y is in ST0; x is in another reg.
1358 ((zerop (tn-offset y))
1360 (inst fnstsw) ; status word to ax
1361 (inst and ah-tn #x45))
1362 ;; x and y are the same register, not ST0
1363 ;; x and y are different registers, neither ST0.
1368 (inst fnstsw) ; status word to ax
1369 (inst and ah-tn #x45))) ; C3 C2 C0
1370 (inst jmp (if not-p :ne :e) target)))
1372 (define-vop (>single-float)
1374 (:args (x :scs (single-reg single-stack descriptor-reg))
1375 (y :scs (single-reg single-stack descriptor-reg)))
1376 (:arg-types single-float single-float)
1377 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1378 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1380 (:info target not-p)
1381 (:policy :fast-safe)
1382 (:note "inline float comparison")
1385 ;; Handle a few special cases.
1388 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1392 ((single-stack descriptor-reg)
1393 (if (sc-is x single-stack)
1394 (inst fcom (ea-for-sf-stack x))
1395 (inst fcom (ea-for-sf-desc x)))))
1396 (inst fnstsw) ; status word to ax
1397 (inst and ah-tn #x45)
1398 (inst cmp ah-tn #x01))
1400 ;; general case when y is not in ST0
1405 (unless (zerop (tn-offset x))
1406 (copy-fp-reg-to-fr0 x)))
1407 ((single-stack descriptor-reg)
1409 (if (sc-is x single-stack)
1410 (inst fld (ea-for-sf-stack x))
1411 (inst fld (ea-for-sf-desc x)))))
1415 ((single-stack descriptor-reg)
1416 (if (sc-is y single-stack)
1417 (inst fcom (ea-for-sf-stack y))
1418 (inst fcom (ea-for-sf-desc y)))))
1419 (inst fnstsw) ; status word to ax
1420 (inst and ah-tn #x45)))
1421 (inst jmp (if not-p :ne :e) target)))
1423 (define-vop (>double-float)
1425 (:args (x :scs (double-reg double-stack descriptor-reg))
1426 (y :scs (double-reg double-stack descriptor-reg)))
1427 (:arg-types double-float double-float)
1428 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1429 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1431 (:info target not-p)
1432 (:policy :fast-safe)
1433 (:note "inline float comparison")
1436 ;; Handle a few special cases.
1439 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1443 ((double-stack descriptor-reg)
1444 (if (sc-is x double-stack)
1445 (inst fcomd (ea-for-df-stack x))
1446 (inst fcomd (ea-for-df-desc x)))))
1447 (inst fnstsw) ; status word to ax
1448 (inst and ah-tn #x45)
1449 (inst cmp ah-tn #x01))
1451 ;; general case when y is not in ST0
1456 (unless (zerop (tn-offset x))
1457 (copy-fp-reg-to-fr0 x)))
1458 ((double-stack descriptor-reg)
1460 (if (sc-is x double-stack)
1461 (inst fldd (ea-for-df-stack x))
1462 (inst fldd (ea-for-df-desc x)))))
1466 ((double-stack descriptor-reg)
1467 (if (sc-is y double-stack)
1468 (inst fcomd (ea-for-df-stack y))
1469 (inst fcomd (ea-for-df-desc y)))))
1470 (inst fnstsw) ; status word to ax
1471 (inst and ah-tn #x45)))
1472 (inst jmp (if not-p :ne :e) target)))
1475 (define-vop (>long-float)
1477 (:args (x :scs (long-reg))
1478 (y :scs (long-reg)))
1479 (:arg-types long-float long-float)
1480 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1482 (:info target not-p)
1483 (:policy :fast-safe)
1484 (:note "inline float comparison")
1488 ;; y is in ST0; x is in any reg.
1489 ((zerop (tn-offset y))
1491 (inst fnstsw) ; status word to ax
1492 (inst and ah-tn #x45)
1493 (inst cmp ah-tn #x01))
1494 ;; x is in ST0; y is in another reg.
1495 ((zerop (tn-offset x))
1497 (inst fnstsw) ; status word to ax
1498 (inst and ah-tn #x45))
1499 ;; y and x are the same register, not ST0
1500 ;; y and x are different registers, neither ST0.
1505 (inst fnstsw) ; status word to ax
1506 (inst and ah-tn #x45)))
1507 (inst jmp (if not-p :ne :e) target)))
1509 ;;; Comparisons with 0 can use the FTST instruction.
1511 (define-vop (float-test)
1513 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1515 (:info target not-p y)
1516 (:variant-vars code)
1517 (:policy :fast-safe)
1519 (:save-p :compute-only)
1520 (:note "inline float comparison")
1523 (note-this-location vop :internal-error)
1526 ((zerop (tn-offset x))
1533 (inst fnstsw) ; status word to ax
1534 (inst and ah-tn #x45) ; C3 C2 C0
1535 (unless (zerop code)
1536 (inst cmp ah-tn code))
1537 (inst jmp (if not-p :ne :e) target)))
1539 (define-vop (=0/single-float float-test)
1541 (:args (x :scs (single-reg)))
1542 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1544 (define-vop (=0/double-float float-test)
1546 (:args (x :scs (double-reg)))
1547 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1550 (define-vop (=0/long-float float-test)
1552 (:args (x :scs (long-reg)))
1553 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1556 (define-vop (<0/single-float float-test)
1558 (:args (x :scs (single-reg)))
1559 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1561 (define-vop (<0/double-float float-test)
1563 (:args (x :scs (double-reg)))
1564 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1567 (define-vop (<0/long-float float-test)
1569 (:args (x :scs (long-reg)))
1570 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1573 (define-vop (>0/single-float float-test)
1575 (:args (x :scs (single-reg)))
1576 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1578 (define-vop (>0/double-float float-test)
1580 (:args (x :scs (double-reg)))
1581 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1584 (define-vop (>0/long-float float-test)
1586 (:args (x :scs (long-reg)))
1587 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1591 (deftransform eql ((x y) (long-float long-float))
1592 `(and (= (long-float-low-bits x) (long-float-low-bits y))
1593 (= (long-float-high-bits x) (long-float-high-bits y))
1594 (= (long-float-exp-bits x) (long-float-exp-bits y))))
1598 (macrolet ((frob (name translate to-sc to-type)
1599 `(define-vop (,name)
1600 (:args (x :scs (signed-stack signed-reg) :target temp))
1601 (:temporary (:sc signed-stack) temp)
1602 (:results (y :scs (,to-sc)))
1603 (:arg-types signed-num)
1604 (:result-types ,to-type)
1605 (:policy :fast-safe)
1606 (:note "inline float coercion")
1607 (:translate ,translate)
1609 (:save-p :compute-only)
1614 (with-empty-tn@fp-top(y)
1615 (note-this-location vop :internal-error)
1618 (with-empty-tn@fp-top(y)
1619 (note-this-location vop :internal-error)
1620 (inst fild x))))))))
1621 (frob %single-float/signed %single-float single-reg single-float)
1622 (frob %double-float/signed %double-float double-reg double-float)
1624 (frob %long-float/signed %long-float long-reg long-float))
1626 (macrolet ((frob (name translate to-sc to-type)
1627 `(define-vop (,name)
1628 (:args (x :scs (unsigned-reg)))
1629 (:results (y :scs (,to-sc)))
1630 (:arg-types unsigned-num)
1631 (:result-types ,to-type)
1632 (:policy :fast-safe)
1633 (:note "inline float coercion")
1634 (:translate ,translate)
1636 (:save-p :compute-only)
1640 (with-empty-tn@fp-top(y)
1641 (note-this-location vop :internal-error)
1642 (inst fildl (make-ea :dword :base esp-tn)))
1643 (inst add esp-tn 8)))))
1644 (frob %single-float/unsigned %single-float single-reg single-float)
1645 (frob %double-float/unsigned %double-float double-reg double-float)
1647 (frob %long-float/unsigned %long-float long-reg long-float))
1649 ;;; These should be no-ops but the compiler might want to move some
1651 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1652 `(define-vop (,name)
1653 (:args (x :scs (,from-sc) :target y))
1654 (:results (y :scs (,to-sc)))
1655 (:arg-types ,from-type)
1656 (:result-types ,to-type)
1657 (:policy :fast-safe)
1658 (:note "inline float coercion")
1659 (:translate ,translate)
1661 (:save-p :compute-only)
1663 (note-this-location vop :internal-error)
1664 (unless (location= x y)
1666 ((zerop (tn-offset x))
1667 ;; x is in ST0, y is in another reg. not ST0
1669 ((zerop (tn-offset y))
1670 ;; y is in ST0, x is in another reg. not ST0
1671 (copy-fp-reg-to-fr0 x))
1673 ;; Neither x or y are in ST0, and they are not in
1677 (inst fxch x))))))))
1679 (frob %single-float/double-float %single-float double-reg
1680 double-float single-reg single-float)
1682 (frob %single-float/long-float %single-float long-reg
1683 long-float single-reg single-float)
1684 (frob %double-float/single-float %double-float single-reg single-float
1685 double-reg double-float)
1687 (frob %double-float/long-float %double-float long-reg long-float
1688 double-reg double-float)
1690 (frob %long-float/single-float %long-float single-reg single-float
1691 long-reg long-float)
1693 (frob %long-float/double-float %long-float double-reg double-float
1694 long-reg long-float))
1696 (macrolet ((frob (trans from-sc from-type round-p)
1697 `(define-vop (,(symbolicate trans "/" from-type))
1698 (:args (x :scs (,from-sc)))
1699 (:temporary (:sc signed-stack) stack-temp)
1701 '((:temporary (:sc unsigned-stack) scw)
1702 (:temporary (:sc any-reg) rcw)))
1703 (:results (y :scs (signed-reg)))
1704 (:arg-types ,from-type)
1705 (:result-types signed-num)
1707 (:policy :fast-safe)
1708 (:note "inline float truncate")
1710 (:save-p :compute-only)
1713 '((note-this-location vop :internal-error)
1714 ;; Catch any pending FPE exceptions.
1716 (,(if round-p 'progn 'pseudo-atomic)
1717 ;; Normal mode (for now) is "round to best".
1720 '((inst fnstcw scw) ; save current control word
1721 (move rcw scw) ; into 16-bit register
1722 (inst or rcw (ash #b11 10)) ; CHOP
1723 (move stack-temp rcw)
1724 (inst fldcw stack-temp)))
1729 (inst fist stack-temp)
1730 (inst mov y stack-temp)))
1732 '((inst fldcw scw)))))))))
1733 (frob %unary-truncate single-reg single-float nil)
1734 (frob %unary-truncate double-reg double-float nil)
1736 (frob %unary-truncate long-reg long-float nil)
1737 (frob %unary-round single-reg single-float t)
1738 (frob %unary-round double-reg double-float t)
1740 (frob %unary-round long-reg long-float t))
1742 (macrolet ((frob (trans from-sc from-type round-p)
1743 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1744 (:args (x :scs (,from-sc) :target fr0))
1745 (:temporary (:sc double-reg :offset fr0-offset
1746 :from :argument :to :result) fr0)
1748 '((:temporary (:sc unsigned-stack) stack-temp)
1749 (:temporary (:sc unsigned-stack) scw)
1750 (:temporary (:sc any-reg) rcw)))
1751 (:results (y :scs (unsigned-reg)))
1752 (:arg-types ,from-type)
1753 (:result-types unsigned-num)
1755 (:policy :fast-safe)
1756 (:note "inline float truncate")
1758 (:save-p :compute-only)
1761 '((note-this-location vop :internal-error)
1762 ;; Catch any pending FPE exceptions.
1764 ;; Normal mode (for now) is "round to best".
1765 (unless (zerop (tn-offset x))
1766 (copy-fp-reg-to-fr0 x))
1768 '((inst fnstcw scw) ; save current control word
1769 (move rcw scw) ; into 16-bit register
1770 (inst or rcw (ash #b11 10)) ; CHOP
1771 (move stack-temp rcw)
1772 (inst fldcw stack-temp)))
1774 (inst fistpl (make-ea :dword :base esp-tn))
1776 (inst fld fr0) ; copy fr0 to at least restore stack.
1779 '((inst fldcw scw)))))))
1780 (frob %unary-truncate single-reg single-float nil)
1781 (frob %unary-truncate double-reg double-float nil)
1783 (frob %unary-truncate long-reg long-float nil)
1784 (frob %unary-round single-reg single-float t)
1785 (frob %unary-round double-reg double-float t)
1787 (frob %unary-round long-reg long-float t))
1789 (define-vop (make-single-float)
1790 (:args (bits :scs (signed-reg) :target res
1791 :load-if (not (or (and (sc-is bits signed-stack)
1792 (sc-is res single-reg))
1793 (and (sc-is bits signed-stack)
1794 (sc-is res single-stack)
1795 (location= bits res))))))
1796 (:results (res :scs (single-reg single-stack)))
1797 (:temporary (:sc signed-stack) stack-temp)
1798 (:arg-types signed-num)
1799 (:result-types single-float)
1800 (:translate make-single-float)
1801 (:policy :fast-safe)
1808 (inst mov res bits))
1810 (aver (location= bits res)))))
1814 ;; source must be in memory
1815 (inst mov stack-temp bits)
1816 (with-empty-tn@fp-top(res)
1817 (inst fld stack-temp)))
1819 (with-empty-tn@fp-top(res)
1820 (inst fld bits))))))))
1822 (define-vop (make-double-float)
1823 (:args (hi-bits :scs (signed-reg))
1824 (lo-bits :scs (unsigned-reg)))
1825 (:results (res :scs (double-reg)))
1826 (:temporary (:sc double-stack) temp)
1827 (:arg-types signed-num unsigned-num)
1828 (:result-types double-float)
1829 (:translate make-double-float)
1830 (:policy :fast-safe)
1833 (let ((offset (1+ (tn-offset temp))))
1834 (storew hi-bits ebp-tn (- offset))
1835 (storew lo-bits ebp-tn (- (1+ offset)))
1836 (with-empty-tn@fp-top(res)
1837 (inst fldd (make-ea :dword :base ebp-tn
1838 :disp (- (* (1+ offset) n-word-bytes))))))))
1841 (define-vop (make-long-float)
1842 (:args (exp-bits :scs (signed-reg))
1843 (hi-bits :scs (unsigned-reg))
1844 (lo-bits :scs (unsigned-reg)))
1845 (:results (res :scs (long-reg)))
1846 (:temporary (:sc long-stack) temp)
1847 (:arg-types signed-num unsigned-num unsigned-num)
1848 (:result-types long-float)
1849 (:translate make-long-float)
1850 (:policy :fast-safe)
1853 (let ((offset (1+ (tn-offset temp))))
1854 (storew exp-bits ebp-tn (- offset))
1855 (storew hi-bits ebp-tn (- (1+ offset)))
1856 (storew lo-bits ebp-tn (- (+ offset 2)))
1857 (with-empty-tn@fp-top(res)
1858 (inst fldl (make-ea :dword :base ebp-tn
1859 :disp (- (* (+ offset 2) n-word-bytes))))))))
1861 (define-vop (single-float-bits)
1862 (:args (float :scs (single-reg descriptor-reg)
1863 :load-if (not (sc-is float single-stack))))
1864 (:results (bits :scs (signed-reg)))
1865 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1866 (:arg-types single-float)
1867 (:result-types signed-num)
1868 (:translate single-float-bits)
1869 (:policy :fast-safe)
1876 (with-tn@fp-top(float)
1877 (inst fst stack-temp)
1878 (inst mov bits stack-temp)))
1880 (inst mov bits float))
1883 bits float single-float-value-slot
1884 other-pointer-lowtag))))
1888 (with-tn@fp-top(float)
1889 (inst fst bits))))))))
1891 (define-vop (double-float-high-bits)
1892 (:args (float :scs (double-reg descriptor-reg)
1893 :load-if (not (sc-is float double-stack))))
1894 (:results (hi-bits :scs (signed-reg)))
1895 (:temporary (:sc double-stack) temp)
1896 (:arg-types double-float)
1897 (:result-types signed-num)
1898 (:translate double-float-high-bits)
1899 (:policy :fast-safe)
1904 (with-tn@fp-top(float)
1905 (let ((where (make-ea :dword :base ebp-tn
1906 :disp (- (* (+ 2 (tn-offset temp))
1909 (loadw hi-bits ebp-tn (- (1+ (tn-offset temp)))))
1911 (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
1913 (loadw hi-bits float (1+ double-float-value-slot)
1914 other-pointer-lowtag)))))
1916 (define-vop (double-float-low-bits)
1917 (:args (float :scs (double-reg descriptor-reg)
1918 :load-if (not (sc-is float double-stack))))
1919 (:results (lo-bits :scs (unsigned-reg)))
1920 (:temporary (:sc double-stack) temp)
1921 (:arg-types double-float)
1922 (:result-types unsigned-num)
1923 (:translate double-float-low-bits)
1924 (:policy :fast-safe)
1929 (with-tn@fp-top(float)
1930 (let ((where (make-ea :dword :base ebp-tn
1931 :disp (- (* (+ 2 (tn-offset temp))
1934 (loadw lo-bits ebp-tn (- (+ 2 (tn-offset temp)))))
1936 (loadw lo-bits ebp-tn (- (+ 2 (tn-offset float)))))
1938 (loadw lo-bits float double-float-value-slot
1939 other-pointer-lowtag)))))
1942 (define-vop (long-float-exp-bits)
1943 (:args (float :scs (long-reg descriptor-reg)
1944 :load-if (not (sc-is float long-stack))))
1945 (:results (exp-bits :scs (signed-reg)))
1946 (:temporary (:sc long-stack) temp)
1947 (:arg-types long-float)
1948 (:result-types signed-num)
1949 (:translate long-float-exp-bits)
1950 (:policy :fast-safe)
1955 (with-tn@fp-top(float)
1956 (let ((where (make-ea :dword :base ebp-tn
1957 :disp (- (* (+ 3 (tn-offset temp))
1959 (store-long-float where)))
1960 (inst movsx exp-bits
1961 (make-ea :word :base ebp-tn
1962 :disp (* (- (1+ (tn-offset temp))) n-word-bytes))))
1964 (inst movsx exp-bits
1965 (make-ea :word :base ebp-tn
1966 :disp (* (- (1+ (tn-offset float))) n-word-bytes))))
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 (- (* (+ 3 (tn-offset temp))
1992 (store-long-float where)))
1993 (loadw hi-bits ebp-tn (- (+ (tn-offset temp) 2))))
1995 (loadw hi-bits ebp-tn (- (+ (tn-offset float) 2))))
1997 (loadw hi-bits float (1+ long-float-value-slot)
1998 other-pointer-lowtag)))))
2001 (define-vop (long-float-low-bits)
2002 (:args (float :scs (long-reg descriptor-reg)
2003 :load-if (not (sc-is float long-stack))))
2004 (:results (lo-bits :scs (unsigned-reg)))
2005 (:temporary (:sc long-stack) temp)
2006 (:arg-types long-float)
2007 (:result-types unsigned-num)
2008 (:translate long-float-low-bits)
2009 (:policy :fast-safe)
2014 (with-tn@fp-top(float)
2015 (let ((where (make-ea :dword :base ebp-tn
2016 :disp (- (* (+ 3 (tn-offset temp))
2018 (store-long-float where)))
2019 (loadw lo-bits ebp-tn (- (+ (tn-offset temp) 3))))
2021 (loadw lo-bits ebp-tn (- (+ (tn-offset float) 3))))
2023 (loadw lo-bits float long-float-value-slot
2024 other-pointer-lowtag)))))
2026 ;;;; float mode hackery
2028 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2029 (defknown floating-point-modes () float-modes (flushable))
2030 (defknown ((setf floating-point-modes)) (float-modes)
2033 (def!constant npx-env-size (* 7 n-word-bytes))
2034 (def!constant npx-cw-offset 0)
2035 (def!constant npx-sw-offset 4)
2037 (define-vop (floating-point-modes)
2038 (:results (res :scs (unsigned-reg)))
2039 (:result-types unsigned-num)
2040 (:translate floating-point-modes)
2041 (:policy :fast-safe)
2042 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2045 (inst sub esp-tn npx-env-size) ; Make space on stack.
2046 (inst wait) ; Catch any pending FPE exceptions
2047 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2048 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2049 ;; Move current status to high word.
2050 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2051 ;; Move exception mask to low word.
2052 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2053 (inst add esp-tn npx-env-size) ; Pop stack.
2054 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2057 (define-vop (set-floating-point-modes)
2058 (:args (new :scs (unsigned-reg) :to :result :target res))
2059 (:results (res :scs (unsigned-reg)))
2060 (:arg-types unsigned-num)
2061 (:result-types unsigned-num)
2062 (:translate (setf floating-point-modes))
2063 (:policy :fast-safe)
2064 (:temporary (:sc unsigned-reg :offset eax-offset
2065 :from :eval :to :result) eax)
2067 (inst sub esp-tn npx-env-size) ; Make space on stack.
2068 (inst wait) ; Catch any pending FPE exceptions.
2069 (inst fstenv (make-ea :dword :base esp-tn))
2071 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2072 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2073 (inst shr eax 16) ; position status word
2074 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2075 (inst fldenv (make-ea :dword :base esp-tn))
2076 (inst add esp-tn npx-env-size) ; Pop stack.
2082 ;;; Let's use some of the 80387 special functions.
2084 ;;; These defs will not take effect unless code/irrat.lisp is modified
2085 ;;; to remove the inlined alien routine def.
2087 (macrolet ((frob (func trans op)
2088 `(define-vop (,func)
2089 (:args (x :scs (double-reg) :target fr0))
2090 (:temporary (:sc double-reg :offset fr0-offset
2091 :from :argument :to :result) fr0)
2093 (:results (y :scs (double-reg)))
2094 (:arg-types double-float)
2095 (:result-types double-float)
2097 (:policy :fast-safe)
2098 (:note "inline NPX function")
2100 (:save-p :compute-only)
2103 (note-this-location vop :internal-error)
2104 (unless (zerop (tn-offset x))
2105 (inst fxch x) ; x to top of stack
2106 (unless (location= x y)
2107 (inst fst x))) ; maybe save it
2108 (inst ,op) ; clobber st0
2109 (cond ((zerop (tn-offset y))
2110 (maybe-fp-wait node))
2114 ;; Quick versions of fsin and fcos that require the argument to be
2115 ;; within range 2^63.
2116 (frob fsin-quick %sin-quick fsin)
2117 (frob fcos-quick %cos-quick fcos)
2118 (frob fsqrt %sqrt fsqrt))
2120 ;;; Quick version of ftan that requires the argument to be within
2122 (define-vop (ftan-quick)
2123 (:translate %tan-quick)
2124 (:args (x :scs (double-reg) :target fr0))
2125 (:temporary (:sc double-reg :offset fr0-offset
2126 :from :argument :to :result) fr0)
2127 (:temporary (:sc double-reg :offset fr1-offset
2128 :from :argument :to :result) fr1)
2129 (:results (y :scs (double-reg)))
2130 (:arg-types double-float)
2131 (:result-types double-float)
2132 (:policy :fast-safe)
2133 (:note "inline tan function")
2135 (:save-p :compute-only)
2137 (note-this-location vop :internal-error)
2146 (inst fldd (make-random-tn :kind :normal
2147 :sc (sc-or-lose 'double-reg)
2148 :offset (- (tn-offset x) 2)))))
2159 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2160 ;;; result if the argument is out of range 2^63 and would thus be
2161 ;;; hopelessly inaccurate.
2162 (macrolet ((frob (func trans op)
2163 `(define-vop (,func)
2165 (:args (x :scs (double-reg) :target fr0))
2166 (:temporary (:sc double-reg :offset fr0-offset
2167 :from :argument :to :result) fr0)
2168 (:temporary (:sc unsigned-reg :offset eax-offset
2169 :from :argument :to :result) eax)
2170 (:results (y :scs (double-reg)))
2171 (:arg-types double-float)
2172 (:result-types double-float)
2173 (:policy :fast-safe)
2174 (:note "inline sin/cos function")
2176 (:save-p :compute-only)
2179 (note-this-location vop :internal-error)
2180 (unless (zerop (tn-offset x))
2181 (inst fxch x) ; x to top of stack
2182 (unless (location= x y)
2183 (inst fst x))) ; maybe save it
2185 (inst fnstsw) ; status word to ax
2186 (inst and ah-tn #x04) ; C2
2188 ;; Else x was out of range so reduce it; ST0 is unchanged.
2189 (inst fstp fr0) ; Load 0.0
2192 (unless (zerop (tn-offset y))
2194 (frob fsin %sin fsin)
2195 (frob fcos %cos fcos))
2199 (:args (x :scs (double-reg) :target fr0))
2200 (:temporary (:sc double-reg :offset fr0-offset
2201 :from :argument :to :result) fr0)
2202 (:temporary (:sc double-reg :offset fr1-offset
2203 :from :argument :to :result) fr1)
2204 (:temporary (:sc unsigned-reg :offset eax-offset
2205 :from :argument :to :result) eax)
2206 (:results (y :scs (double-reg)))
2207 (:arg-types double-float)
2208 (:result-types double-float)
2210 (:policy :fast-safe)
2211 (:note "inline tan function")
2213 (:save-p :compute-only)
2216 (note-this-location vop :internal-error)
2225 (inst fldd (make-random-tn :kind :normal
2226 :sc (sc-or-lose 'double-reg)
2227 :offset (- (tn-offset x) 2)))))
2229 (inst fnstsw) ; status word to ax
2230 (inst and ah-tn #x04) ; C2
2232 ;; Else x was out of range so load 0.0
2244 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2245 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2248 (:args (x :scs (double-reg) :target fr0))
2249 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2250 (:temporary (:sc double-reg :offset fr0-offset
2251 :from :argument :to :result) fr0)
2252 (:temporary (:sc double-reg :offset fr1-offset
2253 :from :argument :to :result) fr1)
2254 (:temporary (:sc double-reg :offset fr2-offset
2255 :from :argument :to :result) fr2)
2256 (:results (y :scs (double-reg)))
2257 (:arg-types double-float)
2258 (:result-types double-float)
2259 (:policy :fast-safe)
2260 (:note "inline exp function")
2262 (:save-p :compute-only)
2265 (note-this-location vop :internal-error)
2266 (unless (zerop (tn-offset x))
2267 (inst fxch x) ; x to top of stack
2268 (unless (location= x y)
2269 (inst fst x))) ; maybe save it
2270 ;; Check for Inf or NaN
2274 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2275 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2276 (inst and ah-tn #x02) ; Test sign of Inf.
2277 (inst jmp :z DONE) ; +Inf gives +Inf.
2278 (inst fstp fr0) ; -Inf gives 0
2280 (inst jmp-short DONE)
2285 ;; Now fr0=x log2(e)
2289 (inst fsubp-sti fr1)
2292 (inst faddp-sti fr1)
2296 (unless (zerop (tn-offset y))
2299 ;;; Expm1 = exp(x) - 1.
2300 ;;; Handles the following special cases:
2301 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2302 (define-vop (fexpm1)
2304 (:args (x :scs (double-reg) :target fr0))
2305 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2306 (:temporary (:sc double-reg :offset fr0-offset
2307 :from :argument :to :result) fr0)
2308 (:temporary (:sc double-reg :offset fr1-offset
2309 :from :argument :to :result) fr1)
2310 (:temporary (:sc double-reg :offset fr2-offset
2311 :from :argument :to :result) fr2)
2312 (:results (y :scs (double-reg)))
2313 (:arg-types double-float)
2314 (:result-types double-float)
2315 (:policy :fast-safe)
2316 (:note "inline expm1 function")
2318 (:save-p :compute-only)
2321 (note-this-location vop :internal-error)
2322 (unless (zerop (tn-offset x))
2323 (inst fxch x) ; x to top of stack
2324 (unless (location= x y)
2325 (inst fst x))) ; maybe save it
2326 ;; Check for Inf or NaN
2330 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2331 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2332 (inst and ah-tn #x02) ; Test sign of Inf.
2333 (inst jmp :z DONE) ; +Inf gives +Inf.
2334 (inst fstp fr0) ; -Inf gives -1.0
2337 (inst jmp-short DONE)
2339 ;; Free two stack slots leaving the argument on top.
2343 (inst fmul fr1) ; Now fr0 = x log2(e)
2358 (unless (zerop (tn-offset y))
2363 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2364 (:temporary (:sc double-reg :offset fr0-offset
2365 :from :argument :to :result) fr0)
2366 (:temporary (:sc double-reg :offset fr1-offset
2367 :from :argument :to :result) fr1)
2368 (:results (y :scs (double-reg)))
2369 (:arg-types double-float)
2370 (:result-types double-float)
2371 (:policy :fast-safe)
2372 (:note "inline log function")
2374 (:save-p :compute-only)
2376 (note-this-location vop :internal-error)
2391 ;; x is in a FP reg, not fr0 or fr1
2395 (inst fldd (make-random-tn :kind :normal
2396 :sc (sc-or-lose 'double-reg)
2397 :offset (1- (tn-offset x))))))
2399 ((double-stack descriptor-reg)
2403 (if (sc-is x double-stack)
2404 (inst fldd (ea-for-df-stack x))
2405 (inst fldd (ea-for-df-desc x)))
2410 (t (inst fstd y)))))
2412 (define-vop (flog10)
2414 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2415 (:temporary (:sc double-reg :offset fr0-offset
2416 :from :argument :to :result) fr0)
2417 (:temporary (:sc double-reg :offset fr1-offset
2418 :from :argument :to :result) fr1)
2419 (:results (y :scs (double-reg)))
2420 (:arg-types double-float)
2421 (:result-types double-float)
2422 (:policy :fast-safe)
2423 (:note "inline log10 function")
2425 (:save-p :compute-only)
2427 (note-this-location vop :internal-error)
2442 ;; x is in a FP reg, not fr0 or fr1
2446 (inst fldd (make-random-tn :kind :normal
2447 :sc (sc-or-lose 'double-reg)
2448 :offset (1- (tn-offset x))))))
2450 ((double-stack descriptor-reg)
2454 (if (sc-is x double-stack)
2455 (inst fldd (ea-for-df-stack x))
2456 (inst fldd (ea-for-df-desc x)))
2461 (t (inst fstd y)))))
2465 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2466 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2467 (:temporary (:sc double-reg :offset fr0-offset
2468 :from (:argument 0) :to :result) fr0)
2469 (:temporary (:sc double-reg :offset fr1-offset
2470 :from (:argument 1) :to :result) fr1)
2471 (:temporary (:sc double-reg :offset fr2-offset
2472 :from :load :to :result) fr2)
2473 (:results (r :scs (double-reg)))
2474 (:arg-types double-float double-float)
2475 (:result-types double-float)
2476 (:policy :fast-safe)
2477 (:note "inline pow function")
2479 (:save-p :compute-only)
2481 (note-this-location vop :internal-error)
2482 ;; Setup x in fr0 and y in fr1
2484 ;; x in fr0; y in fr1
2485 ((and (sc-is x double-reg) (zerop (tn-offset x))
2486 (sc-is y double-reg) (= 1 (tn-offset y))))
2487 ;; y in fr1; x not in fr0
2488 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2492 (copy-fp-reg-to-fr0 x))
2495 (inst fldd (ea-for-df-stack x)))
2498 (inst fldd (ea-for-df-desc x)))))
2499 ;; x in fr0; y not in fr1
2500 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2502 ;; Now load y to fr0
2505 (copy-fp-reg-to-fr0 y))
2508 (inst fldd (ea-for-df-stack y)))
2511 (inst fldd (ea-for-df-desc y))))
2513 ;; x in fr1; y not in fr1
2514 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2518 (copy-fp-reg-to-fr0 y))
2521 (inst fldd (ea-for-df-stack y)))
2524 (inst fldd (ea-for-df-desc y))))
2527 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2529 ;; Now load x to fr0
2532 (copy-fp-reg-to-fr0 x))
2535 (inst fldd (ea-for-df-stack x)))
2538 (inst fldd (ea-for-df-desc x)))))
2539 ;; Neither x or y are in either fr0 or fr1
2546 (inst fldd (make-random-tn :kind :normal
2547 :sc (sc-or-lose 'double-reg)
2548 :offset (- (tn-offset y) 2))))
2550 (inst fldd (ea-for-df-stack y)))
2552 (inst fldd (ea-for-df-desc y))))
2556 (inst fldd (make-random-tn :kind :normal
2557 :sc (sc-or-lose 'double-reg)
2558 :offset (1- (tn-offset x)))))
2560 (inst fldd (ea-for-df-stack x)))
2562 (inst fldd (ea-for-df-desc x))))))
2564 ;; Now have x at fr0; and y at fr1
2566 ;; Now fr0=y log2(x)
2570 (inst fsubp-sti fr1)
2573 (inst faddp-sti fr1)
2578 (t (inst fstd r)))))
2580 (define-vop (fscalen)
2581 (:translate %scalbn)
2582 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2583 (y :scs (signed-stack signed-reg) :target temp))
2584 (:temporary (:sc double-reg :offset fr0-offset
2585 :from (:argument 0) :to :result) fr0)
2586 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2587 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2588 (:results (r :scs (double-reg)))
2589 (:arg-types double-float signed-num)
2590 (:result-types double-float)
2591 (:policy :fast-safe)
2592 (:note "inline scalbn function")
2594 ;; Setup x in fr0 and y in fr1
2625 (inst fld (make-random-tn :kind :normal
2626 :sc (sc-or-lose 'double-reg)
2627 :offset (1- (tn-offset x)))))))
2628 ((double-stack descriptor-reg)
2637 (if (sc-is x double-stack)
2638 (inst fldd (ea-for-df-stack x))
2639 (inst fldd (ea-for-df-desc x)))))
2641 (unless (zerop (tn-offset r))
2644 (define-vop (fscale)
2646 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2647 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2648 (:temporary (:sc double-reg :offset fr0-offset
2649 :from (:argument 0) :to :result) fr0)
2650 (:temporary (:sc double-reg :offset fr1-offset
2651 :from (:argument 1) :to :result) fr1)
2652 (:results (r :scs (double-reg)))
2653 (:arg-types double-float double-float)
2654 (:result-types double-float)
2655 (:policy :fast-safe)
2656 (:note "inline scalb function")
2658 (:save-p :compute-only)
2660 (note-this-location vop :internal-error)
2661 ;; Setup x in fr0 and y in fr1
2663 ;; x in fr0; y in fr1
2664 ((and (sc-is x double-reg) (zerop (tn-offset x))
2665 (sc-is y double-reg) (= 1 (tn-offset y))))
2666 ;; y in fr1; x not in fr0
2667 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2671 (copy-fp-reg-to-fr0 x))
2674 (inst fldd (ea-for-df-stack x)))
2677 (inst fldd (ea-for-df-desc x)))))
2678 ;; x in fr0; y not in fr1
2679 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2681 ;; Now load y to fr0
2684 (copy-fp-reg-to-fr0 y))
2687 (inst fldd (ea-for-df-stack y)))
2690 (inst fldd (ea-for-df-desc y))))
2692 ;; x in fr1; y not in fr1
2693 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2697 (copy-fp-reg-to-fr0 y))
2700 (inst fldd (ea-for-df-stack y)))
2703 (inst fldd (ea-for-df-desc y))))
2706 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2708 ;; Now load x to fr0
2711 (copy-fp-reg-to-fr0 x))
2714 (inst fldd (ea-for-df-stack x)))
2717 (inst fldd (ea-for-df-desc x)))))
2718 ;; Neither x or y are in either fr0 or fr1
2725 (inst fldd (make-random-tn :kind :normal
2726 :sc (sc-or-lose 'double-reg)
2727 :offset (- (tn-offset y) 2))))
2729 (inst fldd (ea-for-df-stack y)))
2731 (inst fldd (ea-for-df-desc y))))
2735 (inst fldd (make-random-tn :kind :normal
2736 :sc (sc-or-lose 'double-reg)
2737 :offset (1- (tn-offset x)))))
2739 (inst fldd (ea-for-df-stack x)))
2741 (inst fldd (ea-for-df-desc x))))))
2743 ;; Now have x at fr0; and y at fr1
2745 (unless (zerop (tn-offset r))
2748 (define-vop (flog1p)
2750 (:args (x :scs (double-reg) :to :result))
2751 (:temporary (:sc double-reg :offset fr0-offset
2752 :from :argument :to :result) fr0)
2753 (:temporary (:sc double-reg :offset fr1-offset
2754 :from :argument :to :result) fr1)
2755 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2756 (:results (y :scs (double-reg)))
2757 (:arg-types double-float)
2758 (:result-types double-float)
2759 (:policy :fast-safe)
2760 (:note "inline log1p function")
2763 ;; x is in a FP reg, not fr0, fr1.
2766 (inst fldd (make-random-tn :kind :normal
2767 :sc (sc-or-lose 'double-reg)
2768 :offset (- (tn-offset x) 2)))
2770 (inst push #x3e947ae1) ; Constant 0.29
2772 (inst fld (make-ea :dword :base esp-tn))
2775 (inst fnstsw) ; status word to ax
2776 (inst and ah-tn #x45)
2777 (inst jmp :z WITHIN-RANGE)
2778 ;; Out of range for fyl2xp1.
2780 (inst faddd (make-random-tn :kind :normal
2781 :sc (sc-or-lose 'double-reg)
2782 :offset (- (tn-offset x) 1)))
2790 (inst fldd (make-random-tn :kind :normal
2791 :sc (sc-or-lose 'double-reg)
2792 :offset (- (tn-offset x) 1)))
2798 (t (inst fstd y)))))
2800 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2801 ;;; instruction and a range check can be avoided.
2802 (define-vop (flog1p-pentium)
2804 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2805 (:temporary (:sc double-reg :offset fr0-offset
2806 :from :argument :to :result) fr0)
2807 (:temporary (:sc double-reg :offset fr1-offset
2808 :from :argument :to :result) fr1)
2809 (:results (y :scs (double-reg)))
2810 (:arg-types double-float)
2811 (:result-types double-float)
2812 (:policy :fast-safe)
2813 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2814 (:note "inline log1p with limited x range function")
2816 (:save-p :compute-only)
2818 (note-this-location vop :internal-error)
2833 ;; x is in a FP reg, not fr0 or fr1
2837 (inst fldd (make-random-tn :kind :normal
2838 :sc (sc-or-lose 'double-reg)
2839 :offset (1- (tn-offset x)))))))
2840 ((double-stack descriptor-reg)
2844 (if (sc-is x double-stack)
2845 (inst fldd (ea-for-df-stack x))
2846 (inst fldd (ea-for-df-desc x)))))
2851 (t (inst fstd y)))))
2855 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2856 (:temporary (:sc double-reg :offset fr0-offset
2857 :from :argument :to :result) fr0)
2858 (:temporary (:sc double-reg :offset fr1-offset
2859 :from :argument :to :result) fr1)
2860 (:results (y :scs (double-reg)))
2861 (:arg-types double-float)
2862 (:result-types double-float)
2863 (:policy :fast-safe)
2864 (:note "inline logb function")
2866 (:save-p :compute-only)
2868 (note-this-location vop :internal-error)
2879 ;; x is in a FP reg, not fr0 or fr1
2882 (inst fldd (make-random-tn :kind :normal
2883 :sc (sc-or-lose 'double-reg)
2884 :offset (- (tn-offset x) 2))))))
2885 ((double-stack descriptor-reg)
2888 (if (sc-is x double-stack)
2889 (inst fldd (ea-for-df-stack x))
2890 (inst fldd (ea-for-df-desc x)))))
2901 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2902 (:temporary (:sc double-reg :offset fr0-offset
2903 :from (:argument 0) :to :result) fr0)
2904 (:temporary (:sc double-reg :offset fr1-offset
2905 :from (:argument 0) :to :result) fr1)
2906 (:results (r :scs (double-reg)))
2907 (:arg-types double-float)
2908 (:result-types double-float)
2909 (:policy :fast-safe)
2910 (:note "inline atan function")
2912 (:save-p :compute-only)
2914 (note-this-location vop :internal-error)
2915 ;; Setup x in fr1 and 1.0 in fr0
2918 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2921 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2923 ;; x not in fr0 or fr1
2930 (inst fldd (make-random-tn :kind :normal
2931 :sc (sc-or-lose 'double-reg)
2932 :offset (- (tn-offset x) 2))))
2934 (inst fldd (ea-for-df-stack x)))
2936 (inst fldd (ea-for-df-desc x))))))
2938 ;; Now have x at fr1; and 1.0 at fr0
2943 (t (inst fstd r)))))
2945 (define-vop (fatan2)
2947 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2948 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2949 (:temporary (:sc double-reg :offset fr0-offset
2950 :from (:argument 1) :to :result) fr0)
2951 (:temporary (:sc double-reg :offset fr1-offset
2952 :from (:argument 0) :to :result) fr1)
2953 (:results (r :scs (double-reg)))
2954 (:arg-types double-float double-float)
2955 (:result-types double-float)
2956 (:policy :fast-safe)
2957 (:note "inline atan2 function")
2959 (:save-p :compute-only)
2961 (note-this-location vop :internal-error)
2962 ;; Setup x in fr1 and y in fr0
2964 ;; y in fr0; x in fr1
2965 ((and (sc-is y double-reg) (zerop (tn-offset y))
2966 (sc-is x double-reg) (= 1 (tn-offset x))))
2967 ;; x in fr1; y not in fr0
2968 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2972 (copy-fp-reg-to-fr0 y))
2975 (inst fldd (ea-for-df-stack y)))
2978 (inst fldd (ea-for-df-desc y)))))
2979 ((and (sc-is x double-reg) (zerop (tn-offset x))
2980 (sc-is y double-reg) (zerop (tn-offset x)))
2983 ;; y in fr0; x not in fr1
2984 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2986 ;; Now load x to fr0
2989 (copy-fp-reg-to-fr0 x))
2992 (inst fldd (ea-for-df-stack x)))
2995 (inst fldd (ea-for-df-desc x))))
2997 ;; y in fr1; x not in fr1
2998 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3002 (copy-fp-reg-to-fr0 x))
3005 (inst fldd (ea-for-df-stack x)))
3008 (inst fldd (ea-for-df-desc x))))
3011 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3013 ;; Now load y to fr0
3016 (copy-fp-reg-to-fr0 y))
3019 (inst fldd (ea-for-df-stack y)))
3022 (inst fldd (ea-for-df-desc y)))))
3023 ;; Neither y or x are in either fr0 or fr1
3030 (inst fldd (make-random-tn :kind :normal
3031 :sc (sc-or-lose 'double-reg)
3032 :offset (- (tn-offset x) 2))))
3034 (inst fldd (ea-for-df-stack x)))
3036 (inst fldd (ea-for-df-desc x))))
3040 (inst fldd (make-random-tn :kind :normal
3041 :sc (sc-or-lose 'double-reg)
3042 :offset (1- (tn-offset y)))))
3044 (inst fldd (ea-for-df-stack y)))
3046 (inst fldd (ea-for-df-desc y))))))
3048 ;; Now have y at fr0; and x at fr1
3053 (t (inst fstd r)))))
3054 ) ; PROGN #!-LONG-FLOAT
3059 ;;; Lets use some of the 80387 special functions.
3061 ;;; These defs will not take effect unless code/irrat.lisp is modified
3062 ;;; to remove the inlined alien routine def.
3064 (macrolet ((frob (func trans op)
3065 `(define-vop (,func)
3066 (:args (x :scs (long-reg) :target fr0))
3067 (:temporary (:sc long-reg :offset fr0-offset
3068 :from :argument :to :result) fr0)
3070 (:results (y :scs (long-reg)))
3071 (:arg-types long-float)
3072 (:result-types long-float)
3074 (:policy :fast-safe)
3075 (:note "inline NPX function")
3077 (:save-p :compute-only)
3080 (note-this-location vop :internal-error)
3081 (unless (zerop (tn-offset x))
3082 (inst fxch x) ; x to top of stack
3083 (unless (location= x y)
3084 (inst fst x))) ; maybe save it
3085 (inst ,op) ; clobber st0
3086 (cond ((zerop (tn-offset y))
3087 (maybe-fp-wait node))
3091 ;; Quick versions of FSIN and FCOS that require the argument to be
3092 ;; within range 2^63.
3093 (frob fsin-quick %sin-quick fsin)
3094 (frob fcos-quick %cos-quick fcos)
3095 (frob fsqrt %sqrt fsqrt))
3097 ;;; Quick version of ftan that requires the argument to be within
3099 (define-vop (ftan-quick)
3100 (:translate %tan-quick)
3101 (:args (x :scs (long-reg) :target fr0))
3102 (:temporary (:sc long-reg :offset fr0-offset
3103 :from :argument :to :result) fr0)
3104 (:temporary (:sc long-reg :offset fr1-offset
3105 :from :argument :to :result) fr1)
3106 (:results (y :scs (long-reg)))
3107 (:arg-types long-float)
3108 (:result-types long-float)
3109 (:policy :fast-safe)
3110 (:note "inline tan function")
3112 (:save-p :compute-only)
3114 (note-this-location vop :internal-error)
3123 (inst fldd (make-random-tn :kind :normal
3124 :sc (sc-or-lose 'double-reg)
3125 :offset (- (tn-offset x) 2)))))
3136 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3137 ;;; the argument is out of range 2^63 and would thus be hopelessly
3139 (macrolet ((frob (func trans op)
3140 `(define-vop (,func)
3142 (:args (x :scs (long-reg) :target fr0))
3143 (:temporary (:sc long-reg :offset fr0-offset
3144 :from :argument :to :result) fr0)
3145 (:temporary (:sc unsigned-reg :offset eax-offset
3146 :from :argument :to :result) eax)
3147 (:results (y :scs (long-reg)))
3148 (:arg-types long-float)
3149 (:result-types long-float)
3150 (:policy :fast-safe)
3151 (:note "inline sin/cos function")
3153 (:save-p :compute-only)
3156 (note-this-location vop :internal-error)
3157 (unless (zerop (tn-offset x))
3158 (inst fxch x) ; x to top of stack
3159 (unless (location= x y)
3160 (inst fst x))) ; maybe save it
3162 (inst fnstsw) ; status word to ax
3163 (inst and ah-tn #x04) ; C2
3165 ;; Else x was out of range so reduce it; ST0 is unchanged.
3166 (inst fstp fr0) ; Load 0.0
3169 (unless (zerop (tn-offset y))
3171 (frob fsin %sin fsin)
3172 (frob fcos %cos fcos))
3176 (:args (x :scs (long-reg) :target fr0))
3177 (:temporary (:sc long-reg :offset fr0-offset
3178 :from :argument :to :result) fr0)
3179 (:temporary (:sc long-reg :offset fr1-offset
3180 :from :argument :to :result) fr1)
3181 (:temporary (:sc unsigned-reg :offset eax-offset
3182 :from :argument :to :result) eax)
3183 (:results (y :scs (long-reg)))
3184 (:arg-types long-float)
3185 (:result-types long-float)
3187 (:policy :fast-safe)
3188 (:note "inline tan function")
3190 (:save-p :compute-only)
3193 (note-this-location vop :internal-error)
3202 (inst fldd (make-random-tn :kind :normal
3203 :sc (sc-or-lose 'double-reg)
3204 :offset (- (tn-offset x) 2)))))
3206 (inst fnstsw) ; status word to ax
3207 (inst and ah-tn #x04) ; C2
3209 ;; Else x was out of range so reduce it; ST0 is unchanged.
3210 (inst fldz) ; Load 0.0
3222 ;;; Modified exp that handles the following special cases:
3223 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3226 (:args (x :scs (long-reg) :target fr0))
3227 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3228 (:temporary (:sc long-reg :offset fr0-offset
3229 :from :argument :to :result) fr0)
3230 (:temporary (:sc long-reg :offset fr1-offset
3231 :from :argument :to :result) fr1)
3232 (:temporary (:sc long-reg :offset fr2-offset
3233 :from :argument :to :result) fr2)
3234 (:results (y :scs (long-reg)))
3235 (:arg-types long-float)
3236 (:result-types long-float)
3237 (:policy :fast-safe)
3238 (:note "inline exp function")
3240 (:save-p :compute-only)
3243 (note-this-location vop :internal-error)
3244 (unless (zerop (tn-offset x))
3245 (inst fxch x) ; x to top of stack
3246 (unless (location= x y)
3247 (inst fst x))) ; maybe save it
3248 ;; Check for Inf or NaN
3252 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3253 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3254 (inst and ah-tn #x02) ; Test sign of Inf.
3255 (inst jmp :z DONE) ; +Inf gives +Inf.
3256 (inst fstp fr0) ; -Inf gives 0
3258 (inst jmp-short DONE)
3263 ;; Now fr0=x log2(e)
3267 (inst fsubp-sti fr1)
3270 (inst faddp-sti fr1)
3274 (unless (zerop (tn-offset y))
3277 ;;; Expm1 = exp(x) - 1.
3278 ;;; Handles the following special cases:
3279 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3280 (define-vop (fexpm1)
3282 (:args (x :scs (long-reg) :target fr0))
3283 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3284 (:temporary (:sc long-reg :offset fr0-offset
3285 :from :argument :to :result) fr0)
3286 (:temporary (:sc long-reg :offset fr1-offset
3287 :from :argument :to :result) fr1)
3288 (:temporary (:sc long-reg :offset fr2-offset
3289 :from :argument :to :result) fr2)
3290 (:results (y :scs (long-reg)))
3291 (:arg-types long-float)
3292 (:result-types long-float)
3293 (:policy :fast-safe)
3294 (:note "inline expm1 function")
3296 (:save-p :compute-only)
3299 (note-this-location vop :internal-error)
3300 (unless (zerop (tn-offset x))
3301 (inst fxch x) ; x to top of stack
3302 (unless (location= x y)
3303 (inst fst x))) ; maybe save it
3304 ;; Check for Inf or NaN
3308 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3309 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3310 (inst and ah-tn #x02) ; Test sign of Inf.
3311 (inst jmp :z DONE) ; +Inf gives +Inf.
3312 (inst fstp fr0) ; -Inf gives -1.0
3315 (inst jmp-short DONE)
3317 ;; Free two stack slots leaving the argument on top.
3321 (inst fmul fr1) ; Now fr0 = x log2(e)
3336 (unless (zerop (tn-offset y))
3341 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3342 (:temporary (:sc long-reg :offset fr0-offset
3343 :from :argument :to :result) fr0)
3344 (:temporary (:sc long-reg :offset fr1-offset
3345 :from :argument :to :result) fr1)
3346 (:results (y :scs (long-reg)))
3347 (:arg-types long-float)
3348 (:result-types long-float)
3349 (:policy :fast-safe)
3350 (:note "inline log function")
3352 (:save-p :compute-only)
3354 (note-this-location vop :internal-error)
3369 ;; x is in a FP reg, not fr0 or fr1
3373 (inst fldd (make-random-tn :kind :normal
3374 :sc (sc-or-lose 'double-reg)
3375 :offset (1- (tn-offset x))))))
3377 ((long-stack descriptor-reg)
3381 (if (sc-is x long-stack)
3382 (inst fldl (ea-for-lf-stack x))
3383 (inst fldl (ea-for-lf-desc x)))
3388 (t (inst fstd y)))))
3390 (define-vop (flog10)
3392 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3393 (:temporary (:sc long-reg :offset fr0-offset
3394 :from :argument :to :result) fr0)
3395 (:temporary (:sc long-reg :offset fr1-offset
3396 :from :argument :to :result) fr1)
3397 (:results (y :scs (long-reg)))
3398 (:arg-types long-float)
3399 (:result-types long-float)
3400 (:policy :fast-safe)
3401 (:note "inline log10 function")
3403 (:save-p :compute-only)
3405 (note-this-location vop :internal-error)
3420 ;; x is in a FP reg, not fr0 or fr1
3424 (inst fldd (make-random-tn :kind :normal
3425 :sc (sc-or-lose 'double-reg)
3426 :offset (1- (tn-offset x))))))
3428 ((long-stack descriptor-reg)
3432 (if (sc-is x long-stack)
3433 (inst fldl (ea-for-lf-stack x))
3434 (inst fldl (ea-for-lf-desc x)))
3439 (t (inst fstd y)))))
3443 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3444 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3445 (:temporary (:sc long-reg :offset fr0-offset
3446 :from (:argument 0) :to :result) fr0)
3447 (:temporary (:sc long-reg :offset fr1-offset
3448 :from (:argument 1) :to :result) fr1)
3449 (:temporary (:sc long-reg :offset fr2-offset
3450 :from :load :to :result) fr2)
3451 (:results (r :scs (long-reg)))
3452 (:arg-types long-float long-float)
3453 (:result-types long-float)
3454 (:policy :fast-safe)
3455 (:note "inline pow function")
3457 (:save-p :compute-only)
3459 (note-this-location vop :internal-error)
3460 ;; Setup x in fr0 and y in fr1
3462 ;; x in fr0; y in fr1
3463 ((and (sc-is x long-reg) (zerop (tn-offset x))
3464 (sc-is y long-reg) (= 1 (tn-offset y))))
3465 ;; y in fr1; x not in fr0
3466 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3470 (copy-fp-reg-to-fr0 x))
3473 (inst fldl (ea-for-lf-stack x)))
3476 (inst fldl (ea-for-lf-desc x)))))
3477 ;; x in fr0; y not in fr1
3478 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3480 ;; Now load y to fr0
3483 (copy-fp-reg-to-fr0 y))
3486 (inst fldl (ea-for-lf-stack y)))
3489 (inst fldl (ea-for-lf-desc y))))
3491 ;; x in fr1; y not in fr1
3492 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3496 (copy-fp-reg-to-fr0 y))
3499 (inst fldl (ea-for-lf-stack y)))
3502 (inst fldl (ea-for-lf-desc y))))
3505 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3507 ;; Now load x to fr0
3510 (copy-fp-reg-to-fr0 x))
3513 (inst fldl (ea-for-lf-stack x)))
3516 (inst fldl (ea-for-lf-desc x)))))
3517 ;; Neither x or y are in either fr0 or fr1
3524 (inst fldd (make-random-tn :kind :normal
3525 :sc (sc-or-lose 'double-reg)
3526 :offset (- (tn-offset y) 2))))
3528 (inst fldl (ea-for-lf-stack y)))
3530 (inst fldl (ea-for-lf-desc y))))
3534 (inst fldd (make-random-tn :kind :normal
3535 :sc (sc-or-lose 'double-reg)
3536 :offset (1- (tn-offset x)))))
3538 (inst fldl (ea-for-lf-stack x)))
3540 (inst fldl (ea-for-lf-desc x))))))
3542 ;; Now have x at fr0; and y at fr1
3544 ;; Now fr0=y log2(x)
3548 (inst fsubp-sti fr1)
3551 (inst faddp-sti fr1)
3556 (t (inst fstd r)))))
3558 (define-vop (fscalen)
3559 (:translate %scalbn)
3560 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3561 (y :scs (signed-stack signed-reg) :target temp))
3562 (:temporary (:sc long-reg :offset fr0-offset
3563 :from (:argument 0) :to :result) fr0)
3564 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3565 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3566 (:results (r :scs (long-reg)))
3567 (:arg-types long-float signed-num)
3568 (:result-types long-float)
3569 (:policy :fast-safe)
3570 (:note "inline scalbn function")
3572 ;; Setup x in fr0 and y in fr1
3603 (inst fld (make-random-tn :kind :normal
3604 :sc (sc-or-lose 'double-reg)
3605 :offset (1- (tn-offset x)))))))
3606 ((long-stack descriptor-reg)
3615 (if (sc-is x long-stack)
3616 (inst fldl (ea-for-lf-stack x))
3617 (inst fldl (ea-for-lf-desc x)))))
3619 (unless (zerop (tn-offset r))
3622 (define-vop (fscale)
3624 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3625 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3626 (:temporary (:sc long-reg :offset fr0-offset
3627 :from (:argument 0) :to :result) fr0)
3628 (:temporary (:sc long-reg :offset fr1-offset
3629 :from (:argument 1) :to :result) fr1)
3630 (:results (r :scs (long-reg)))
3631 (:arg-types long-float long-float)
3632 (:result-types long-float)
3633 (:policy :fast-safe)
3634 (:note "inline scalb function")
3636 (:save-p :compute-only)
3638 (note-this-location vop :internal-error)
3639 ;; Setup x in fr0 and y in fr1
3641 ;; x in fr0; y in fr1
3642 ((and (sc-is x long-reg) (zerop (tn-offset x))
3643 (sc-is y long-reg) (= 1 (tn-offset y))))
3644 ;; y in fr1; x not in fr0
3645 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3649 (copy-fp-reg-to-fr0 x))
3652 (inst fldl (ea-for-lf-stack x)))
3655 (inst fldl (ea-for-lf-desc x)))))
3656 ;; x in fr0; y not in fr1
3657 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3659 ;; Now load y to fr0
3662 (copy-fp-reg-to-fr0 y))
3665 (inst fldl (ea-for-lf-stack y)))
3668 (inst fldl (ea-for-lf-desc y))))
3670 ;; x in fr1; y not in fr1
3671 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3675 (copy-fp-reg-to-fr0 y))
3678 (inst fldl (ea-for-lf-stack y)))
3681 (inst fldl (ea-for-lf-desc y))))
3684 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3686 ;; Now load x to fr0
3689 (copy-fp-reg-to-fr0 x))
3692 (inst fldl (ea-for-lf-stack x)))
3695 (inst fldl (ea-for-lf-desc x)))))
3696 ;; Neither x or y are in either fr0 or fr1
3703 (inst fldd (make-random-tn :kind :normal
3704 :sc (sc-or-lose 'double-reg)
3705 :offset (- (tn-offset y) 2))))
3707 (inst fldl (ea-for-lf-stack y)))
3709 (inst fldl (ea-for-lf-desc y))))
3713 (inst fldd (make-random-tn :kind :normal
3714 :sc (sc-or-lose 'double-reg)
3715 :offset (1- (tn-offset x)))))
3717 (inst fldl (ea-for-lf-stack x)))
3719 (inst fldl (ea-for-lf-desc x))))))
3721 ;; Now have x at fr0; and y at fr1
3723 (unless (zerop (tn-offset r))
3726 (define-vop (flog1p)
3728 (:args (x :scs (long-reg) :to :result))
3729 (:temporary (:sc long-reg :offset fr0-offset
3730 :from :argument :to :result) fr0)
3731 (:temporary (:sc long-reg :offset fr1-offset
3732 :from :argument :to :result) fr1)
3733 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3734 (:results (y :scs (long-reg)))
3735 (:arg-types long-float)
3736 (:result-types long-float)
3737 (:policy :fast-safe)
3738 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3739 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3740 ;; an enormous PROGN above. Still, it would be probably be good to
3741 ;; add some code to warn about redefining VOPs.
3742 (:note "inline log1p function")
3745 ;; x is in a FP reg, not fr0, fr1.
3748 (inst fldd (make-random-tn :kind :normal
3749 :sc (sc-or-lose 'double-reg)
3750 :offset (- (tn-offset x) 2)))
3752 (inst push #x3e947ae1) ; Constant 0.29
3754 (inst fld (make-ea :dword :base esp-tn))
3757 (inst fnstsw) ; status word to ax
3758 (inst and ah-tn #x45)
3759 (inst jmp :z WITHIN-RANGE)
3760 ;; Out of range for fyl2xp1.
3762 (inst faddd (make-random-tn :kind :normal
3763 :sc (sc-or-lose 'double-reg)
3764 :offset (- (tn-offset x) 1)))
3772 (inst fldd (make-random-tn :kind :normal
3773 :sc (sc-or-lose 'double-reg)
3774 :offset (- (tn-offset x) 1)))
3780 (t (inst fstd y)))))
3782 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3783 ;;; instruction and a range check can be avoided.
3784 (define-vop (flog1p-pentium)
3786 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3787 (:temporary (:sc long-reg :offset fr0-offset
3788 :from :argument :to :result) fr0)
3789 (:temporary (:sc long-reg :offset fr1-offset
3790 :from :argument :to :result) fr1)
3791 (:results (y :scs (long-reg)))
3792 (:arg-types long-float)
3793 (:result-types long-float)
3794 (:policy :fast-safe)
3795 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3796 (:note "inline log1p function")
3812 ;; x is in a FP reg, not fr0 or fr1
3816 (inst fldd (make-random-tn :kind :normal
3817 :sc (sc-or-lose 'double-reg)
3818 :offset (1- (tn-offset x)))))))
3819 ((long-stack descriptor-reg)
3823 (if (sc-is x long-stack)
3824 (inst fldl (ea-for-lf-stack x))
3825 (inst fldl (ea-for-lf-desc x)))))
3830 (t (inst fstd y)))))
3834 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3835 (:temporary (:sc long-reg :offset fr0-offset
3836 :from :argument :to :result) fr0)
3837 (:temporary (:sc long-reg :offset fr1-offset
3838 :from :argument :to :result) fr1)
3839 (:results (y :scs (long-reg)))
3840 (:arg-types long-float)
3841 (:result-types long-float)
3842 (:policy :fast-safe)
3843 (:note "inline logb function")
3845 (:save-p :compute-only)
3847 (note-this-location vop :internal-error)
3858 ;; x is in a FP reg, not fr0 or fr1
3861 (inst fldd (make-random-tn :kind :normal
3862 :sc (sc-or-lose 'double-reg)
3863 :offset (- (tn-offset x) 2))))))
3864 ((long-stack descriptor-reg)
3867 (if (sc-is x long-stack)
3868 (inst fldl (ea-for-lf-stack x))
3869 (inst fldl (ea-for-lf-desc x)))))
3880 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3881 (:temporary (:sc long-reg :offset fr0-offset
3882 :from (:argument 0) :to :result) fr0)
3883 (:temporary (:sc long-reg :offset fr1-offset
3884 :from (:argument 0) :to :result) fr1)
3885 (:results (r :scs (long-reg)))
3886 (:arg-types long-float)
3887 (:result-types long-float)
3888 (:policy :fast-safe)
3889 (:note "inline atan function")
3891 (:save-p :compute-only)
3893 (note-this-location vop :internal-error)
3894 ;; Setup x in fr1 and 1.0 in fr0
3897 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3900 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3902 ;; x not in fr0 or fr1
3909 (inst fldd (make-random-tn :kind :normal
3910 :sc (sc-or-lose 'double-reg)
3911 :offset (- (tn-offset x) 2))))
3913 (inst fldl (ea-for-lf-stack x)))
3915 (inst fldl (ea-for-lf-desc x))))))
3917 ;; Now have x at fr1; and 1.0 at fr0
3922 (t (inst fstd r)))))
3924 (define-vop (fatan2)
3926 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3927 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3928 (:temporary (:sc long-reg :offset fr0-offset
3929 :from (:argument 1) :to :result) fr0)
3930 (:temporary (:sc long-reg :offset fr1-offset
3931 :from (:argument 0) :to :result) fr1)
3932 (:results (r :scs (long-reg)))
3933 (:arg-types long-float long-float)
3934 (:result-types long-float)
3935 (:policy :fast-safe)
3936 (:note "inline atan2 function")
3938 (:save-p :compute-only)
3940 (note-this-location vop :internal-error)
3941 ;; Setup x in fr1 and y in fr0
3943 ;; y in fr0; x in fr1
3944 ((and (sc-is y long-reg) (zerop (tn-offset y))
3945 (sc-is x long-reg) (= 1 (tn-offset x))))
3946 ;; x in fr1; y not in fr0
3947 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3951 (copy-fp-reg-to-fr0 y))
3954 (inst fldl (ea-for-lf-stack y)))
3957 (inst fldl (ea-for-lf-desc y)))))
3958 ;; y in fr0; x not in fr1
3959 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3961 ;; Now load x to fr0
3964 (copy-fp-reg-to-fr0 x))
3967 (inst fldl (ea-for-lf-stack x)))
3970 (inst fldl (ea-for-lf-desc x))))
3972 ;; y in fr1; x not in fr1
3973 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3977 (copy-fp-reg-to-fr0 x))
3980 (inst fldl (ea-for-lf-stack x)))
3983 (inst fldl (ea-for-lf-desc x))))
3986 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3988 ;; Now load y to fr0
3991 (copy-fp-reg-to-fr0 y))
3994 (inst fldl (ea-for-lf-stack y)))
3997 (inst fldl (ea-for-lf-desc y)))))
3998 ;; Neither y or x are in either fr0 or fr1
4005 (inst fldd (make-random-tn :kind :normal
4006 :sc (sc-or-lose 'double-reg)
4007 :offset (- (tn-offset x) 2))))
4009 (inst fldl (ea-for-lf-stack x)))
4011 (inst fldl (ea-for-lf-desc x))))
4015 (inst fldd (make-random-tn :kind :normal
4016 :sc (sc-or-lose 'double-reg)
4017 :offset (1- (tn-offset y)))))
4019 (inst fldl (ea-for-lf-stack y)))
4021 (inst fldl (ea-for-lf-desc y))))))
4023 ;; Now have y at fr0; and x at fr1
4028 (t (inst fstd r)))))
4030 ) ; PROGN #!+LONG-FLOAT
4032 ;;;; complex float VOPs
4034 (define-vop (make-complex-single-float)
4035 (:translate complex)
4036 (:args (real :scs (single-reg) :to :result :target r
4037 :load-if (not (location= real r)))
4038 (imag :scs (single-reg) :to :save))
4039 (:arg-types single-float single-float)
4040 (:results (r :scs (complex-single-reg) :from (:argument 0)
4041 :load-if (not (sc-is r complex-single-stack))))
4042 (:result-types complex-single-float)
4043 (:note "inline complex single-float creation")
4044 (:policy :fast-safe)
4048 (let ((r-real (complex-double-reg-real-tn r)))
4049 (unless (location= real r-real)
4050 (cond ((zerop (tn-offset r-real))
4051 (copy-fp-reg-to-fr0 real))
4052 ((zerop (tn-offset real))
4057 (inst fxch real)))))
4058 (let ((r-imag (complex-double-reg-imag-tn r)))
4059 (unless (location= imag r-imag)
4060 (cond ((zerop (tn-offset imag))
4065 (inst fxch imag))))))
4066 (complex-single-stack
4067 (unless (location= real r)
4068 (cond ((zerop (tn-offset real))
4069 (inst fst (ea-for-csf-real-stack r)))
4072 (inst fst (ea-for-csf-real-stack r))
4075 (inst fst (ea-for-csf-imag-stack r))
4076 (inst fxch imag)))))
4078 (define-vop (make-complex-double-float)
4079 (:translate complex)
4080 (:args (real :scs (double-reg) :target r
4081 :load-if (not (location= real r)))
4082 (imag :scs (double-reg) :to :save))
4083 (:arg-types double-float double-float)
4084 (:results (r :scs (complex-double-reg) :from (:argument 0)
4085 :load-if (not (sc-is r complex-double-stack))))
4086 (:result-types complex-double-float)
4087 (:note "inline complex double-float creation")
4088 (:policy :fast-safe)
4092 (let ((r-real (complex-double-reg-real-tn r)))
4093 (unless (location= real r-real)
4094 (cond ((zerop (tn-offset r-real))
4095 (copy-fp-reg-to-fr0 real))
4096 ((zerop (tn-offset real))
4101 (inst fxch real)))))
4102 (let ((r-imag (complex-double-reg-imag-tn r)))
4103 (unless (location= imag r-imag)
4104 (cond ((zerop (tn-offset imag))
4109 (inst fxch imag))))))
4110 (complex-double-stack
4111 (unless (location= real r)
4112 (cond ((zerop (tn-offset real))
4113 (inst fstd (ea-for-cdf-real-stack r)))
4116 (inst fstd (ea-for-cdf-real-stack r))
4119 (inst fstd (ea-for-cdf-imag-stack r))
4120 (inst fxch imag)))))
4123 (define-vop (make-complex-long-float)
4124 (:translate complex)
4125 (:args (real :scs (long-reg) :target r
4126 :load-if (not (location= real r)))
4127 (imag :scs (long-reg) :to :save))
4128 (:arg-types long-float long-float)
4129 (:results (r :scs (complex-long-reg) :from (:argument 0)
4130 :load-if (not (sc-is r complex-long-stack))))
4131 (:result-types complex-long-float)
4132 (:note "inline complex long-float creation")
4133 (:policy :fast-safe)
4137 (let ((r-real (complex-double-reg-real-tn r)))
4138 (unless (location= real r-real)
4139 (cond ((zerop (tn-offset r-real))
4140 (copy-fp-reg-to-fr0 real))
4141 ((zerop (tn-offset real))
4146 (inst fxch real)))))
4147 (let ((r-imag (complex-double-reg-imag-tn r)))
4148 (unless (location= imag r-imag)
4149 (cond ((zerop (tn-offset imag))
4154 (inst fxch imag))))))
4156 (unless (location= real r)
4157 (cond ((zerop (tn-offset real))
4158 (store-long-float (ea-for-clf-real-stack r)))
4161 (store-long-float (ea-for-clf-real-stack r))
4164 (store-long-float (ea-for-clf-imag-stack r))
4165 (inst fxch imag)))))
4168 (define-vop (complex-float-value)
4169 (:args (x :target r))
4171 (:variant-vars offset)
4172 (:policy :fast-safe)
4174 (cond ((sc-is x complex-single-reg complex-double-reg
4175 #!+long-float complex-long-reg)
4177 (make-random-tn :kind :normal
4178 :sc (sc-or-lose 'double-reg)
4179 :offset (+ offset (tn-offset x)))))
4180 (unless (location= value-tn r)
4181 (cond ((zerop (tn-offset r))
4182 (copy-fp-reg-to-fr0 value-tn))
4183 ((zerop (tn-offset value-tn))
4186 (inst fxch value-tn)
4188 (inst fxch value-tn))))))
4189 ((sc-is r single-reg)
4190 (let ((ea (sc-case x
4191 (complex-single-stack
4193 (0 (ea-for-csf-real-stack x))
4194 (1 (ea-for-csf-imag-stack x))))
4197 (0 (ea-for-csf-real-desc x))
4198 (1 (ea-for-csf-imag-desc x)))))))
4199 (with-empty-tn@fp-top(r)
4201 ((sc-is r double-reg)
4202 (let ((ea (sc-case x
4203 (complex-double-stack
4205 (0 (ea-for-cdf-real-stack x))
4206 (1 (ea-for-cdf-imag-stack x))))
4209 (0 (ea-for-cdf-real-desc x))
4210 (1 (ea-for-cdf-imag-desc x)))))))
4211 (with-empty-tn@fp-top(r)
4215 (let ((ea (sc-case x
4218 (0 (ea-for-clf-real-stack x))
4219 (1 (ea-for-clf-imag-stack x))))
4222 (0 (ea-for-clf-real-desc x))
4223 (1 (ea-for-clf-imag-desc x)))))))
4224 (with-empty-tn@fp-top(r)
4226 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4228 (define-vop (realpart/complex-single-float complex-float-value)
4229 (:translate realpart)
4230 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4232 (:arg-types complex-single-float)
4233 (:results (r :scs (single-reg)))
4234 (:result-types single-float)
4235 (:note "complex float realpart")
4238 (define-vop (realpart/complex-double-float complex-float-value)
4239 (:translate realpart)
4240 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4242 (:arg-types complex-double-float)
4243 (:results (r :scs (double-reg)))
4244 (:result-types double-float)
4245 (:note "complex float realpart")
4249 (define-vop (realpart/complex-long-float complex-float-value)
4250 (:translate realpart)
4251 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4253 (:arg-types complex-long-float)
4254 (:results (r :scs (long-reg)))
4255 (:result-types long-float)
4256 (:note "complex float realpart")
4259 (define-vop (imagpart/complex-single-float complex-float-value)
4260 (:translate imagpart)
4261 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4263 (:arg-types complex-single-float)
4264 (:results (r :scs (single-reg)))
4265 (:result-types single-float)
4266 (:note "complex float imagpart")
4269 (define-vop (imagpart/complex-double-float complex-float-value)
4270 (:translate imagpart)
4271 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4273 (:arg-types complex-double-float)
4274 (:results (r :scs (double-reg)))
4275 (:result-types double-float)
4276 (:note "complex float imagpart")
4280 (define-vop (imagpart/complex-long-float complex-float-value)
4281 (:translate imagpart)
4282 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4284 (:arg-types complex-long-float)
4285 (:results (r :scs (long-reg)))
4286 (:result-types long-float)
4287 (:note "complex float imagpart")
4290 ;;; hack dummy VOPs to bias the representation selection of their
4291 ;;; arguments towards a FP register, which can help avoid consing at
4292 ;;; inappropriate locations
4293 (defknown double-float-reg-bias (double-float) (values))
4294 (define-vop (double-float-reg-bias)
4295 (:translate double-float-reg-bias)
4296 (:args (x :scs (double-reg double-stack) :load-if nil))
4297 (:arg-types double-float)
4298 (:policy :fast-safe)
4299 (:note "inline dummy FP register bias")
4302 (defknown single-float-reg-bias (single-float) (values))
4303 (define-vop (single-float-reg-bias)
4304 (:translate single-float-reg-bias)
4305 (:args (x :scs (single-reg single-stack) :load-if nil))
4306 (:arg-types single-float)
4307 (:policy :fast-safe)
4308 (:note "inline dummy FP register bias")