1 ;;;; floating point support for the x86
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 (macrolet ((ea-for-xf-desc (tn slot)
15 `(make-ea-for-object-slot ,tn ,slot other-pointer-lowtag)))
16 (defun ea-for-sf-desc (tn)
17 (ea-for-xf-desc tn single-float-value-slot))
18 (defun ea-for-df-desc (tn)
19 (ea-for-xf-desc tn double-float-value-slot))
21 (defun ea-for-lf-desc (tn)
22 (ea-for-xf-desc tn long-float-value-slot))
24 (defun ea-for-csf-real-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-real-slot))
26 (defun ea-for-csf-imag-desc (tn)
27 (ea-for-xf-desc tn complex-single-float-imag-slot))
28 (defun ea-for-cdf-real-desc (tn)
29 (ea-for-xf-desc tn complex-double-float-real-slot))
30 (defun ea-for-cdf-imag-desc (tn)
31 (ea-for-xf-desc tn complex-double-float-imag-slot))
33 (defun ea-for-clf-real-desc (tn)
34 (ea-for-xf-desc tn complex-long-float-real-slot))
36 (defun ea-for-clf-imag-desc (tn)
37 (ea-for-xf-desc tn complex-long-float-imag-slot)))
39 (macrolet ((ea-for-xf-stack (tn kind)
42 :disp (frame-byte-offset
44 (ecase ,kind (:single 0) (:double 1) (:long 2)))))))
45 (defun ea-for-sf-stack (tn)
46 (ea-for-xf-stack tn :single))
47 (defun ea-for-df-stack (tn)
48 (ea-for-xf-stack tn :double))
50 (defun ea-for-lf-stack (tn)
51 (ea-for-xf-stack tn :long)))
53 ;;; Telling the FPU to wait is required in order to make signals occur
54 ;;; at the expected place, but naturally slows things down.
56 ;;; NODE is the node whose compilation policy controls the decision
57 ;;; whether to just blast through carelessly or carefully emit wait
58 ;;; instructions and whatnot.
60 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
61 ;;; #'NOTE-NEXT-INSTRUCTION.
63 ;;; Until 2004-03-15, the implementation of this was buggy; it
64 ;;; unconditionally emitted the WAIT instruction. It turns out that
65 ;;; this is the right thing to do anyway; omitting them can lead to
66 ;;; system corruption on conforming code. -- CSR
67 (defun maybe-fp-wait (node &optional note-next-instruction)
68 (declare (ignore node))
70 (when (policy node (or (= debug 3) (> safety speed))))
71 (when note-next-instruction
72 (note-next-instruction note-next-instruction :internal-error))
75 ;;; complex float stack EAs
76 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
79 :disp (frame-byte-offset
86 (ecase ,slot (:real 1) (:imag 2))))))))
87 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
88 (ea-for-cxf-stack tn :single :real base))
89 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
90 (ea-for-cxf-stack tn :single :imag base))
91 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
92 (ea-for-cxf-stack tn :double :real base))
93 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
94 (ea-for-cxf-stack tn :double :imag base))
96 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
97 (ea-for-cxf-stack tn :long :real base))
99 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
100 (ea-for-cxf-stack tn :long :imag base)))
102 ;;; Abstract out the copying of a FP register to the FP stack top, and
103 ;;; provide two alternatives for its implementation. Note: it's not
104 ;;; necessary to distinguish between a single or double register move
107 ;;; Using a Pop then load.
108 (defun copy-fp-reg-to-fr0 (reg)
109 (aver (not (zerop (tn-offset reg))))
111 (inst fld (make-random-tn :kind :normal
112 :sc (sc-or-lose 'double-reg)
113 :offset (1- (tn-offset reg)))))
114 ;;; Using Fxch then Fst to restore the original reg contents.
116 (defun copy-fp-reg-to-fr0 (reg)
117 (aver (not (zerop (tn-offset reg))))
121 ;;; The x86 can't store a long-float to memory without popping the
122 ;;; stack and marking a register as empty, so it is necessary to
123 ;;; restore the register from memory.
125 (defun store-long-float (ea)
131 ;;; X is source, Y is destination.
132 (define-move-fun (load-single 2) (vop x y)
133 ((single-stack) (single-reg))
134 (with-empty-tn@fp-top(y)
135 (inst fld (ea-for-sf-stack x))))
137 (define-move-fun (store-single 2) (vop x y)
138 ((single-reg) (single-stack))
139 (cond ((zerop (tn-offset x))
140 (inst fst (ea-for-sf-stack y)))
143 (inst fst (ea-for-sf-stack y))
144 ;; This may not be necessary as ST0 is likely invalid now.
147 (define-move-fun (load-double 2) (vop x y)
148 ((double-stack) (double-reg))
149 (with-empty-tn@fp-top(y)
150 (inst fldd (ea-for-df-stack x))))
152 (define-move-fun (store-double 2) (vop x y)
153 ((double-reg) (double-stack))
154 (cond ((zerop (tn-offset x))
155 (inst fstd (ea-for-df-stack y)))
158 (inst fstd (ea-for-df-stack y))
159 ;; This may not be necessary as ST0 is likely invalid now.
163 (define-move-fun (load-long 2) (vop x y)
164 ((long-stack) (long-reg))
165 (with-empty-tn@fp-top(y)
166 (inst fldl (ea-for-lf-stack x))))
169 (define-move-fun (store-long 2) (vop x y)
170 ((long-reg) (long-stack))
171 (cond ((zerop (tn-offset x))
172 (store-long-float (ea-for-lf-stack y)))
175 (store-long-float (ea-for-lf-stack y))
176 ;; This may not be necessary as ST0 is likely invalid now.
179 ;;; The i387 has instructions to load some useful constants. This
180 ;;; doesn't save much time but might cut down on memory access and
181 ;;; reduce the size of the constant vector (CV). Intel claims they are
182 ;;; stored in a more precise form on chip. Anyhow, might as well use
183 ;;; the feature. It can be turned off by hacking the
184 ;;; "immediate-constant-sc" in vm.lisp.
185 (eval-when (:compile-toplevel :execute)
186 (setf *read-default-float-format*
187 #!+long-float 'long-float #!-long-float 'double-float))
188 (define-move-fun (load-fp-constant 2) (vop x y)
189 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
190 (let ((value (tn-value x)))
191 (with-empty-tn@fp-top(y)
192 (cond ((or (eql value 0f0) (eql value 0d0) #!+long-float (eql value 0l0))
197 ((= value (coerce pi *read-default-float-format*))
200 ((= value (log 10e0 2e0))
203 ((= value (log 2.718281828459045235360287471352662e0 2e0))
206 ((= value (log 2e0 10e0))
209 ((= value (log 2e0 2.718281828459045235360287471352662e0))
211 (t (warn "ignoring bogus i387 constant ~A" value))))))
213 (define-move-fun (load-fp-immediate 2) (vop x y)
214 ((fp-single-immediate) (single-reg)
215 (fp-double-immediate) (double-reg))
216 (let ((value (register-inline-constant (tn-value x))))
217 (with-empty-tn@fp-top(y)
222 (inst fldd value))))))
223 (eval-when (:compile-toplevel :execute)
224 (setf *read-default-float-format* 'single-float))
226 ;;;; complex float move functions
228 (defun complex-single-reg-real-tn (x)
229 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
230 :offset (tn-offset x)))
231 (defun complex-single-reg-imag-tn (x)
232 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
233 :offset (1+ (tn-offset x))))
235 (defun complex-double-reg-real-tn (x)
236 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
237 :offset (tn-offset x)))
238 (defun complex-double-reg-imag-tn (x)
239 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
240 :offset (1+ (tn-offset x))))
243 (defun complex-long-reg-real-tn (x)
244 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
245 :offset (tn-offset x)))
247 (defun complex-long-reg-imag-tn (x)
248 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
249 :offset (1+ (tn-offset x))))
251 ;;; X is source, Y is destination.
252 (define-move-fun (load-complex-single 2) (vop x y)
253 ((complex-single-stack) (complex-single-reg))
254 (let ((real-tn (complex-single-reg-real-tn y)))
255 (with-empty-tn@fp-top (real-tn)
256 (inst fld (ea-for-csf-real-stack x))))
257 (let ((imag-tn (complex-single-reg-imag-tn y)))
258 (with-empty-tn@fp-top (imag-tn)
259 (inst fld (ea-for-csf-imag-stack x)))))
261 (define-move-fun (store-complex-single 2) (vop x y)
262 ((complex-single-reg) (complex-single-stack))
263 (let ((real-tn (complex-single-reg-real-tn x)))
264 (cond ((zerop (tn-offset real-tn))
265 (inst fst (ea-for-csf-real-stack y)))
268 (inst fst (ea-for-csf-real-stack y))
269 (inst fxch real-tn))))
270 (let ((imag-tn (complex-single-reg-imag-tn x)))
272 (inst fst (ea-for-csf-imag-stack y))
273 (inst fxch imag-tn)))
275 (define-move-fun (load-complex-double 2) (vop x y)
276 ((complex-double-stack) (complex-double-reg))
277 (let ((real-tn (complex-double-reg-real-tn y)))
278 (with-empty-tn@fp-top(real-tn)
279 (inst fldd (ea-for-cdf-real-stack x))))
280 (let ((imag-tn (complex-double-reg-imag-tn y)))
281 (with-empty-tn@fp-top(imag-tn)
282 (inst fldd (ea-for-cdf-imag-stack x)))))
284 (define-move-fun (store-complex-double 2) (vop x y)
285 ((complex-double-reg) (complex-double-stack))
286 (let ((real-tn (complex-double-reg-real-tn x)))
287 (cond ((zerop (tn-offset real-tn))
288 (inst fstd (ea-for-cdf-real-stack y)))
291 (inst fstd (ea-for-cdf-real-stack y))
292 (inst fxch real-tn))))
293 (let ((imag-tn (complex-double-reg-imag-tn x)))
295 (inst fstd (ea-for-cdf-imag-stack y))
296 (inst fxch imag-tn)))
299 (define-move-fun (load-complex-long 2) (vop x y)
300 ((complex-long-stack) (complex-long-reg))
301 (let ((real-tn (complex-long-reg-real-tn y)))
302 (with-empty-tn@fp-top(real-tn)
303 (inst fldl (ea-for-clf-real-stack x))))
304 (let ((imag-tn (complex-long-reg-imag-tn y)))
305 (with-empty-tn@fp-top(imag-tn)
306 (inst fldl (ea-for-clf-imag-stack x)))))
309 (define-move-fun (store-complex-long 2) (vop x y)
310 ((complex-long-reg) (complex-long-stack))
311 (let ((real-tn (complex-long-reg-real-tn x)))
312 (cond ((zerop (tn-offset real-tn))
313 (store-long-float (ea-for-clf-real-stack y)))
316 (store-long-float (ea-for-clf-real-stack y))
317 (inst fxch real-tn))))
318 (let ((imag-tn (complex-long-reg-imag-tn x)))
320 (store-long-float (ea-for-clf-imag-stack y))
321 (inst fxch imag-tn)))
326 ;;; float register to register moves
327 (define-vop (float-move)
332 (unless (location= x y)
333 (cond ((zerop (tn-offset y))
334 (copy-fp-reg-to-fr0 x))
335 ((zerop (tn-offset x))
342 (define-vop (single-move float-move)
343 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
344 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
345 (define-move-vop single-move :move (single-reg) (single-reg))
347 (define-vop (double-move float-move)
348 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
349 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
350 (define-move-vop double-move :move (double-reg) (double-reg))
353 (define-vop (long-move float-move)
354 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
355 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
357 (define-move-vop long-move :move (long-reg) (long-reg))
359 ;;; complex float register to register moves
360 (define-vop (complex-float-move)
361 (:args (x :target y :load-if (not (location= x y))))
362 (:results (y :load-if (not (location= x y))))
363 (:note "complex float move")
365 (unless (location= x y)
366 ;; Note the complex-float-regs are aligned to every second
367 ;; float register so there is not need to worry about overlap.
368 (let ((x-real (complex-double-reg-real-tn x))
369 (y-real (complex-double-reg-real-tn y)))
370 (cond ((zerop (tn-offset y-real))
371 (copy-fp-reg-to-fr0 x-real))
372 ((zerop (tn-offset x-real))
377 (inst fxch x-real))))
378 (let ((x-imag (complex-double-reg-imag-tn x))
379 (y-imag (complex-double-reg-imag-tn y)))
382 (inst fxch x-imag)))))
384 (define-vop (complex-single-move complex-float-move)
385 (:args (x :scs (complex-single-reg) :target y
386 :load-if (not (location= x y))))
387 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
388 (define-move-vop complex-single-move :move
389 (complex-single-reg) (complex-single-reg))
391 (define-vop (complex-double-move complex-float-move)
392 (:args (x :scs (complex-double-reg)
393 :target y :load-if (not (location= x y))))
394 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
395 (define-move-vop complex-double-move :move
396 (complex-double-reg) (complex-double-reg))
399 (define-vop (complex-long-move complex-float-move)
400 (:args (x :scs (complex-long-reg)
401 :target y :load-if (not (location= x y))))
402 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
404 (define-move-vop complex-long-move :move
405 (complex-long-reg) (complex-long-reg))
407 ;;; Move from float to a descriptor reg. allocating a new float
408 ;;; object in the process.
409 (define-vop (move-from-single)
410 (:args (x :scs (single-reg) :to :save))
411 (:results (y :scs (descriptor-reg)))
413 (:note "float to pointer coercion")
415 (with-fixed-allocation (y
417 single-float-size node)
419 (inst fst (ea-for-sf-desc y))))))
420 (define-move-vop move-from-single :move
421 (single-reg) (descriptor-reg))
423 (define-vop (move-from-double)
424 (:args (x :scs (double-reg) :to :save))
425 (:results (y :scs (descriptor-reg)))
427 (:note "float to pointer coercion")
429 (with-fixed-allocation (y
434 (inst fstd (ea-for-df-desc y))))))
435 (define-move-vop move-from-double :move
436 (double-reg) (descriptor-reg))
439 (define-vop (move-from-long)
440 (:args (x :scs (long-reg) :to :save))
441 (:results (y :scs (descriptor-reg)))
443 (:note "float to pointer coercion")
445 (with-fixed-allocation (y
450 (store-long-float (ea-for-lf-desc y))))))
452 (define-move-vop move-from-long :move
453 (long-reg) (descriptor-reg))
455 (define-vop (move-from-fp-constant)
456 (:args (x :scs (fp-constant)))
457 (:results (y :scs (descriptor-reg)))
459 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
460 (0f0 (load-symbol-value y *fp-constant-0f0*))
461 (1f0 (load-symbol-value y *fp-constant-1f0*))
462 (0d0 (load-symbol-value y *fp-constant-0d0*))
463 (1d0 (load-symbol-value y *fp-constant-1d0*))
465 (0l0 (load-symbol-value y *fp-constant-0l0*))
467 (1l0 (load-symbol-value y *fp-constant-1l0*))
469 (#.pi (load-symbol-value y *fp-constant-pi*))
471 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
473 (#.(log 2.718281828459045235360287471352662L0 2l0)
474 (load-symbol-value y *fp-constant-l2e*))
476 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
478 (#.(log 2l0 2.718281828459045235360287471352662L0)
479 (load-symbol-value y *fp-constant-ln2*)))))
480 (define-move-vop move-from-fp-constant :move
481 (fp-constant) (descriptor-reg))
483 ;;; Move from a descriptor to a float register.
484 (define-vop (move-to-single)
485 (:args (x :scs (descriptor-reg)))
486 (:results (y :scs (single-reg)))
487 (:note "pointer to float coercion")
489 (with-empty-tn@fp-top(y)
490 (inst fld (ea-for-sf-desc x)))))
491 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
493 (define-vop (move-to-double)
494 (:args (x :scs (descriptor-reg)))
495 (:results (y :scs (double-reg)))
496 (:note "pointer to float coercion")
498 (with-empty-tn@fp-top(y)
499 (inst fldd (ea-for-df-desc x)))))
500 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
503 (define-vop (move-to-long)
504 (:args (x :scs (descriptor-reg)))
505 (:results (y :scs (long-reg)))
506 (:note "pointer to float coercion")
508 (with-empty-tn@fp-top(y)
509 (inst fldl (ea-for-lf-desc x)))))
511 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
513 ;;; Move from complex float to a descriptor reg. allocating a new
514 ;;; complex float object in the process.
515 (define-vop (move-from-complex-single)
516 (:args (x :scs (complex-single-reg) :to :save))
517 (:results (y :scs (descriptor-reg)))
519 (:note "complex float to pointer coercion")
521 (with-fixed-allocation (y
522 complex-single-float-widetag
523 complex-single-float-size
525 (let ((real-tn (complex-single-reg-real-tn x)))
526 (with-tn@fp-top(real-tn)
527 (inst fst (ea-for-csf-real-desc y))))
528 (let ((imag-tn (complex-single-reg-imag-tn x)))
529 (with-tn@fp-top(imag-tn)
530 (inst fst (ea-for-csf-imag-desc y)))))))
531 (define-move-vop move-from-complex-single :move
532 (complex-single-reg) (descriptor-reg))
534 (define-vop (move-from-complex-double)
535 (:args (x :scs (complex-double-reg) :to :save))
536 (:results (y :scs (descriptor-reg)))
538 (:note "complex float to pointer coercion")
540 (with-fixed-allocation (y
541 complex-double-float-widetag
542 complex-double-float-size
544 (let ((real-tn (complex-double-reg-real-tn x)))
545 (with-tn@fp-top(real-tn)
546 (inst fstd (ea-for-cdf-real-desc y))))
547 (let ((imag-tn (complex-double-reg-imag-tn x)))
548 (with-tn@fp-top(imag-tn)
549 (inst fstd (ea-for-cdf-imag-desc y)))))))
550 (define-move-vop move-from-complex-double :move
551 (complex-double-reg) (descriptor-reg))
554 (define-vop (move-from-complex-long)
555 (:args (x :scs (complex-long-reg) :to :save))
556 (:results (y :scs (descriptor-reg)))
558 (:note "complex float to pointer coercion")
560 (with-fixed-allocation (y
561 complex-long-float-widetag
562 complex-long-float-size
564 (let ((real-tn (complex-long-reg-real-tn x)))
565 (with-tn@fp-top(real-tn)
566 (store-long-float (ea-for-clf-real-desc y))))
567 (let ((imag-tn (complex-long-reg-imag-tn x)))
568 (with-tn@fp-top(imag-tn)
569 (store-long-float (ea-for-clf-imag-desc y)))))))
571 (define-move-vop move-from-complex-long :move
572 (complex-long-reg) (descriptor-reg))
574 ;;; Move from a descriptor to a complex float register.
575 (macrolet ((frob (name sc format)
578 (:args (x :scs (descriptor-reg)))
579 (:results (y :scs (,sc)))
580 (:note "pointer to complex float coercion")
582 (let ((real-tn (complex-double-reg-real-tn y)))
583 (with-empty-tn@fp-top(real-tn)
585 (:single '((inst fld (ea-for-csf-real-desc x))))
586 (:double '((inst fldd (ea-for-cdf-real-desc x))))
588 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
589 (let ((imag-tn (complex-double-reg-imag-tn y)))
590 (with-empty-tn@fp-top(imag-tn)
592 (:single '((inst fld (ea-for-csf-imag-desc x))))
593 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
595 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
596 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
597 (frob move-to-complex-single complex-single-reg :single)
598 (frob move-to-complex-double complex-double-reg :double)
600 (frob move-to-complex-double complex-long-reg :long))
602 ;;;; the move argument vops
604 ;;;; Note these are also used to stuff fp numbers onto the c-call
605 ;;;; stack so the order is different than the lisp-stack.
607 ;;; the general MOVE-ARG VOP
608 (macrolet ((frob (name sc stack-sc format)
611 (:args (x :scs (,sc) :target y)
613 :load-if (not (sc-is y ,sc))))
615 (:note "float argument move")
616 (:generator ,(case format (:single 2) (:double 3) (:long 4))
619 (unless (location= x y)
620 (cond ((zerop (tn-offset y))
621 (copy-fp-reg-to-fr0 x))
622 ((zerop (tn-offset x))
629 (if (= (tn-offset fp) esp-offset)
631 (let* ((offset (* (tn-offset y) n-word-bytes))
632 (ea (make-ea :dword :base fp :disp offset)))
635 (:single '((inst fst ea)))
636 (:double '((inst fstd ea)))
638 (:long '((store-long-float ea))))))
642 :disp (frame-byte-offset
650 (:single '((inst fst ea)))
651 (:double '((inst fstd ea)))
653 (:long '((store-long-float ea)))))))))))
654 (define-move-vop ,name :move-arg
655 (,sc descriptor-reg) (,sc)))))
656 (frob move-single-float-arg single-reg single-stack :single)
657 (frob move-double-float-arg double-reg double-stack :double)
659 (frob move-long-float-arg long-reg long-stack :long))
661 ;;;; complex float MOVE-ARG VOP
662 (macrolet ((frob (name sc stack-sc format)
665 (:args (x :scs (,sc) :target y)
667 :load-if (not (sc-is y ,sc))))
669 (:note "complex float argument move")
670 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
673 (unless (location= x y)
674 (let ((x-real (complex-double-reg-real-tn x))
675 (y-real (complex-double-reg-real-tn y)))
676 (cond ((zerop (tn-offset y-real))
677 (copy-fp-reg-to-fr0 x-real))
678 ((zerop (tn-offset x-real))
683 (inst fxch x-real))))
684 (let ((x-imag (complex-double-reg-imag-tn x))
685 (y-imag (complex-double-reg-imag-tn y)))
688 (inst fxch x-imag))))
690 (let ((real-tn (complex-double-reg-real-tn x)))
691 (cond ((zerop (tn-offset real-tn))
695 (ea-for-csf-real-stack y fp))))
698 (ea-for-cdf-real-stack y fp))))
702 (ea-for-clf-real-stack y fp))))))
708 (ea-for-csf-real-stack y fp))))
711 (ea-for-cdf-real-stack y fp))))
715 (ea-for-clf-real-stack y fp)))))
716 (inst fxch real-tn))))
717 (let ((imag-tn (complex-double-reg-imag-tn x)))
721 '((inst fst (ea-for-csf-imag-stack y fp))))
723 '((inst fstd (ea-for-cdf-imag-stack y fp))))
727 (ea-for-clf-imag-stack y fp)))))
728 (inst fxch imag-tn))))))
729 (define-move-vop ,name :move-arg
730 (,sc descriptor-reg) (,sc)))))
731 (frob move-complex-single-float-arg
732 complex-single-reg complex-single-stack :single)
733 (frob move-complex-double-float-arg
734 complex-double-reg complex-double-stack :double)
736 (frob move-complex-long-float-arg
737 complex-long-reg complex-long-stack :long))
739 (define-move-vop move-arg :move-arg
740 (single-reg double-reg #!+long-float long-reg
741 complex-single-reg complex-double-reg #!+long-float complex-long-reg)
747 ;;; dtc: the floating point arithmetic vops
749 ;;; Note: Although these can accept x and y on the stack or pointed to
750 ;;; from a descriptor register, they will work with register loading
751 ;;; without these. Same deal with the result - it need only be a
752 ;;; register. When load-tns are needed they will probably be in ST0
753 ;;; and the code below should be able to correctly handle all cases.
755 ;;; However it seems to produce better code if all arg. and result
756 ;;; options are used; on the P86 there is no extra cost in using a
757 ;;; memory operand to the FP instructions - not so on the PPro.
759 ;;; It may also be useful to handle constant args?
761 ;;; 22-Jul-97: descriptor args lose in some simple cases when
762 ;;; a function result computed in a loop. Then Python insists
763 ;;; on consing the intermediate values! For example
766 ;;; (declare (type (simple-array double-float (*)) a)
769 ;;; (declare (type double-float sum))
771 ;;; (incf sum (* (aref a i)(aref a i))))
774 ;;; So, disabling descriptor args until this can be fixed elsewhere.
776 ((frob (op fop-sti fopr-sti
778 fopd foprd dname dcost
780 #!-long-float (declare (ignore lcost lname))
784 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
786 (y :scs (single-reg single-stack #+nil descriptor-reg)
788 (:temporary (:sc single-reg :offset fr0-offset
789 :from :eval :to :result) fr0)
790 (:results (r :scs (single-reg single-stack)))
791 (:arg-types single-float single-float)
792 (:result-types single-float)
794 (:note "inline float arithmetic")
796 (:save-p :compute-only)
799 ;; Handle a few special cases
801 ;; x, y, and r are the same register.
802 ((and (sc-is x single-reg) (location= x r) (location= y r))
803 (cond ((zerop (tn-offset r))
808 ;; XX the source register will not be valid.
809 (note-next-instruction vop :internal-error)
812 ;; x and r are the same register.
813 ((and (sc-is x single-reg) (location= x r))
814 (cond ((zerop (tn-offset r))
817 ;; ST(0) = ST(0) op ST(y)
820 ;; ST(0) = ST(0) op Mem
821 (inst ,fop (ea-for-sf-stack y)))
823 (inst ,fop (ea-for-sf-desc y)))))
828 (unless (zerop (tn-offset y))
829 (copy-fp-reg-to-fr0 y)))
830 ((single-stack descriptor-reg)
832 (if (sc-is y single-stack)
833 (inst fld (ea-for-sf-stack y))
834 (inst fld (ea-for-sf-desc y)))))
835 ;; ST(i) = ST(i) op ST0
837 (maybe-fp-wait node vop))
838 ;; y and r are the same register.
839 ((and (sc-is y single-reg) (location= y r))
840 (cond ((zerop (tn-offset r))
843 ;; ST(0) = ST(x) op ST(0)
846 ;; ST(0) = Mem op ST(0)
847 (inst ,fopr (ea-for-sf-stack x)))
849 (inst ,fopr (ea-for-sf-desc x)))))
854 (unless (zerop (tn-offset x))
855 (copy-fp-reg-to-fr0 x)))
856 ((single-stack descriptor-reg)
858 (if (sc-is x single-stack)
859 (inst fld (ea-for-sf-stack x))
860 (inst fld (ea-for-sf-desc x)))))
861 ;; ST(i) = ST(0) op ST(i)
863 (maybe-fp-wait node vop))
866 ;; Get the result to ST0.
868 ;; Special handling is needed if x or y are in ST0, and
869 ;; simpler code is generated.
872 ((and (sc-is x single-reg) (zerop (tn-offset x)))
878 (inst ,fop (ea-for-sf-stack y)))
880 (inst ,fop (ea-for-sf-desc y)))))
882 ((and (sc-is y single-reg) (zerop (tn-offset y)))
888 (inst ,fopr (ea-for-sf-stack x)))
890 (inst ,fopr (ea-for-sf-desc x)))))
895 (copy-fp-reg-to-fr0 x))
898 (inst fld (ea-for-sf-stack x)))
901 (inst fld (ea-for-sf-desc x))))
907 (inst ,fop (ea-for-sf-stack y)))
909 (inst ,fop (ea-for-sf-desc y))))))
911 (note-next-instruction vop :internal-error)
913 ;; Finally save the result.
916 (cond ((zerop (tn-offset r))
917 (maybe-fp-wait node))
921 (inst fst (ea-for-sf-stack r))))))))
925 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
927 (y :scs (double-reg double-stack #+nil descriptor-reg)
929 (:temporary (:sc double-reg :offset fr0-offset
930 :from :eval :to :result) fr0)
931 (:results (r :scs (double-reg double-stack)))
932 (:arg-types double-float double-float)
933 (:result-types double-float)
935 (:note "inline float arithmetic")
937 (:save-p :compute-only)
940 ;; Handle a few special cases.
942 ;; x, y, and r are the same register.
943 ((and (sc-is x double-reg) (location= x r) (location= y r))
944 (cond ((zerop (tn-offset r))
949 ;; XX the source register will not be valid.
950 (note-next-instruction vop :internal-error)
953 ;; x and r are the same register.
954 ((and (sc-is x double-reg) (location= x r))
955 (cond ((zerop (tn-offset r))
958 ;; ST(0) = ST(0) op ST(y)
961 ;; ST(0) = ST(0) op Mem
962 (inst ,fopd (ea-for-df-stack y)))
964 (inst ,fopd (ea-for-df-desc y)))))
969 (unless (zerop (tn-offset y))
970 (copy-fp-reg-to-fr0 y)))
971 ((double-stack descriptor-reg)
973 (if (sc-is y double-stack)
974 (inst fldd (ea-for-df-stack y))
975 (inst fldd (ea-for-df-desc y)))))
976 ;; ST(i) = ST(i) op ST0
978 (maybe-fp-wait node vop))
979 ;; y and r are the same register.
980 ((and (sc-is y double-reg) (location= y r))
981 (cond ((zerop (tn-offset r))
984 ;; ST(0) = ST(x) op ST(0)
987 ;; ST(0) = Mem op ST(0)
988 (inst ,foprd (ea-for-df-stack x)))
990 (inst ,foprd (ea-for-df-desc x)))))
995 (unless (zerop (tn-offset x))
996 (copy-fp-reg-to-fr0 x)))
997 ((double-stack descriptor-reg)
999 (if (sc-is x double-stack)
1000 (inst fldd (ea-for-df-stack x))
1001 (inst fldd (ea-for-df-desc x)))))
1002 ;; ST(i) = ST(0) op ST(i)
1003 (inst ,fopr-sti r)))
1004 (maybe-fp-wait node vop))
1007 ;; Get the result to ST0.
1009 ;; Special handling is needed if x or y are in ST0, and
1010 ;; simpler code is generated.
1013 ((and (sc-is x double-reg) (zerop (tn-offset x)))
1019 (inst ,fopd (ea-for-df-stack y)))
1021 (inst ,fopd (ea-for-df-desc y)))))
1023 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1029 (inst ,foprd (ea-for-df-stack x)))
1031 (inst ,foprd (ea-for-df-desc x)))))
1036 (copy-fp-reg-to-fr0 x))
1039 (inst fldd (ea-for-df-stack x)))
1042 (inst fldd (ea-for-df-desc x))))
1048 (inst ,fopd (ea-for-df-stack y)))
1050 (inst ,fopd (ea-for-df-desc y))))))
1052 (note-next-instruction vop :internal-error)
1054 ;; Finally save the result.
1057 (cond ((zerop (tn-offset r))
1058 (maybe-fp-wait node))
1062 (inst fstd (ea-for-df-stack r))))))))
1065 (define-vop (,lname)
1067 (:args (x :scs (long-reg) :to :eval)
1068 (y :scs (long-reg) :to :eval))
1069 (:temporary (:sc long-reg :offset fr0-offset
1070 :from :eval :to :result) fr0)
1071 (:results (r :scs (long-reg)))
1072 (:arg-types long-float long-float)
1073 (:result-types long-float)
1074 (:policy :fast-safe)
1075 (:note "inline float arithmetic")
1077 (:save-p :compute-only)
1080 ;; Handle a few special cases.
1082 ;; x, y, and r are the same register.
1083 ((and (location= x r) (location= y r))
1084 (cond ((zerop (tn-offset r))
1089 ;; XX the source register will not be valid.
1090 (note-next-instruction vop :internal-error)
1093 ;; x and r are the same register.
1095 (cond ((zerop (tn-offset r))
1096 ;; ST(0) = ST(0) op ST(y)
1100 (unless (zerop (tn-offset y))
1101 (copy-fp-reg-to-fr0 y))
1102 ;; ST(i) = ST(i) op ST0
1104 (maybe-fp-wait node vop))
1105 ;; y and r are the same register.
1107 (cond ((zerop (tn-offset r))
1108 ;; ST(0) = ST(x) op ST(0)
1112 (unless (zerop (tn-offset x))
1113 (copy-fp-reg-to-fr0 x))
1114 ;; ST(i) = ST(0) op ST(i)
1115 (inst ,fopr-sti r)))
1116 (maybe-fp-wait node vop))
1119 ;; Get the result to ST0.
1121 ;; Special handling is needed if x or y are in ST0, and
1122 ;; simpler code is generated.
1125 ((zerop (tn-offset x))
1129 ((zerop (tn-offset y))
1134 (copy-fp-reg-to-fr0 x)
1138 (note-next-instruction vop :internal-error)
1140 ;; Finally save the result.
1141 (cond ((zerop (tn-offset r))
1142 (maybe-fp-wait node))
1144 (inst fst r))))))))))
1146 (frob + fadd-sti fadd-sti
1147 fadd fadd +/single-float 2
1148 faddd faddd +/double-float 2
1150 (frob - fsub-sti fsubr-sti
1151 fsub fsubr -/single-float 2
1152 fsubd fsubrd -/double-float 2
1154 (frob * fmul-sti fmul-sti
1155 fmul fmul */single-float 3
1156 fmuld fmuld */double-float 3
1158 (frob / fdiv-sti fdivr-sti
1159 fdiv fdivr //single-float 12
1160 fdivd fdivrd //double-float 12
1163 (macrolet ((frob (name inst translate sc type)
1164 `(define-vop (,name)
1165 (:args (x :scs (,sc) :target fr0))
1166 (:results (y :scs (,sc)))
1167 (:translate ,translate)
1168 (:policy :fast-safe)
1170 (:result-types ,type)
1171 (:temporary (:sc double-reg :offset fr0-offset
1172 :from :argument :to :result) fr0)
1174 (:note "inline float arithmetic")
1176 (:save-p :compute-only)
1178 (note-this-location vop :internal-error)
1179 (unless (zerop (tn-offset x))
1180 (inst fxch x) ; x to top of stack
1181 (unless (location= x y)
1182 (inst fst x))) ; Maybe save it.
1183 (inst ,inst) ; Clobber st0.
1184 (unless (zerop (tn-offset y))
1187 (frob abs/single-float fabs abs single-reg single-float)
1188 (frob abs/double-float fabs abs double-reg double-float)
1190 (frob abs/long-float fabs abs long-reg long-float)
1191 (frob %negate/single-float fchs %negate single-reg single-float)
1192 (frob %negate/double-float fchs %negate double-reg double-float)
1194 (frob %negate/long-float fchs %negate long-reg long-float))
1198 (define-vop (=/float)
1200 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1202 (:policy :fast-safe)
1204 (:save-p :compute-only)
1205 (:note "inline float comparison")
1208 (note-this-location vop :internal-error)
1210 ;; x is in ST0; y is in any reg.
1211 ((zerop (tn-offset x))
1213 ;; y is in ST0; x is in another reg.
1214 ((zerop (tn-offset y))
1216 ;; x and y are the same register, not ST0
1221 ;; x and y are different registers, neither ST0.
1226 (inst fnstsw) ; status word to ax
1227 (inst and ah-tn #x45) ; C3 C2 C0
1228 (inst cmp ah-tn #x40)))
1230 (define-vop (=/single-float =/float)
1232 (:args (x :scs (single-reg))
1233 (y :scs (single-reg)))
1234 (:arg-types single-float single-float))
1236 (define-vop (=/double-float =/float)
1238 (:args (x :scs (double-reg))
1239 (y :scs (double-reg)))
1240 (:arg-types double-float double-float))
1243 (define-vop (=/long-float =/float)
1245 (:args (x :scs (long-reg))
1246 (y :scs (long-reg)))
1247 (:arg-types long-float long-float))
1249 (define-vop (<single-float)
1251 (:args (x :scs (single-reg single-stack descriptor-reg))
1252 (y :scs (single-reg single-stack descriptor-reg)))
1253 (:arg-types single-float single-float)
1254 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1255 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1257 (:policy :fast-safe)
1258 (:note "inline float comparison")
1261 ;; Handle a few special cases.
1264 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1268 ((single-stack descriptor-reg)
1269 (if (sc-is x single-stack)
1270 (inst fcom (ea-for-sf-stack x))
1271 (inst fcom (ea-for-sf-desc x)))))
1272 (inst fnstsw) ; status word to ax
1273 (inst and ah-tn #x45))
1275 ;; general case when y is not in ST0
1280 (unless (zerop (tn-offset x))
1281 (copy-fp-reg-to-fr0 x)))
1282 ((single-stack descriptor-reg)
1284 (if (sc-is x single-stack)
1285 (inst fld (ea-for-sf-stack x))
1286 (inst fld (ea-for-sf-desc x)))))
1290 ((single-stack descriptor-reg)
1291 (if (sc-is y single-stack)
1292 (inst fcom (ea-for-sf-stack y))
1293 (inst fcom (ea-for-sf-desc y)))))
1294 (inst fnstsw) ; status word to ax
1295 (inst and ah-tn #x45) ; C3 C2 C0
1296 (inst cmp ah-tn #x01)))))
1298 (define-vop (<double-float)
1300 (:args (x :scs (double-reg double-stack descriptor-reg))
1301 (y :scs (double-reg double-stack descriptor-reg)))
1302 (:arg-types double-float double-float)
1303 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1304 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1306 (:policy :fast-safe)
1307 (:note "inline float comparison")
1310 ;; Handle a few special cases
1313 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1317 ((double-stack descriptor-reg)
1318 (if (sc-is x double-stack)
1319 (inst fcomd (ea-for-df-stack x))
1320 (inst fcomd (ea-for-df-desc x)))))
1321 (inst fnstsw) ; status word to ax
1322 (inst and ah-tn #x45))
1324 ;; General case when y is not in ST0.
1329 (unless (zerop (tn-offset x))
1330 (copy-fp-reg-to-fr0 x)))
1331 ((double-stack descriptor-reg)
1333 (if (sc-is x double-stack)
1334 (inst fldd (ea-for-df-stack x))
1335 (inst fldd (ea-for-df-desc x)))))
1339 ((double-stack descriptor-reg)
1340 (if (sc-is y double-stack)
1341 (inst fcomd (ea-for-df-stack y))
1342 (inst fcomd (ea-for-df-desc y)))))
1343 (inst fnstsw) ; status word to ax
1344 (inst and ah-tn #x45) ; C3 C2 C0
1345 (inst cmp ah-tn #x01)))))
1348 (define-vop (<long-float)
1350 (:args (x :scs (long-reg))
1351 (y :scs (long-reg)))
1352 (:arg-types long-float long-float)
1353 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1355 (:policy :fast-safe)
1356 (:note "inline float comparison")
1360 ;; x is in ST0; y is in any reg.
1361 ((zerop (tn-offset x))
1363 (inst fnstsw) ; status word to ax
1364 (inst and ah-tn #x45) ; C3 C2 C0
1365 (inst cmp ah-tn #x01))
1366 ;; y is in ST0; x is in another reg.
1367 ((zerop (tn-offset y))
1369 (inst fnstsw) ; status word to ax
1370 (inst and ah-tn #x45))
1371 ;; x and y are the same register, not ST0
1372 ;; x and y are different registers, neither ST0.
1377 (inst fnstsw) ; status word to ax
1378 (inst and ah-tn #x45))))) ; C3 C2 C0
1381 (define-vop (>single-float)
1383 (:args (x :scs (single-reg single-stack descriptor-reg))
1384 (y :scs (single-reg single-stack descriptor-reg)))
1385 (:arg-types single-float single-float)
1386 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1387 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1389 (:policy :fast-safe)
1390 (:note "inline float comparison")
1393 ;; Handle a few special cases.
1396 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1400 ((single-stack descriptor-reg)
1401 (if (sc-is x single-stack)
1402 (inst fcom (ea-for-sf-stack x))
1403 (inst fcom (ea-for-sf-desc x)))))
1404 (inst fnstsw) ; status word to ax
1405 (inst and ah-tn #x45)
1406 (inst cmp ah-tn #x01))
1408 ;; general case when y is not in ST0
1413 (unless (zerop (tn-offset x))
1414 (copy-fp-reg-to-fr0 x)))
1415 ((single-stack descriptor-reg)
1417 (if (sc-is x single-stack)
1418 (inst fld (ea-for-sf-stack x))
1419 (inst fld (ea-for-sf-desc x)))))
1423 ((single-stack descriptor-reg)
1424 (if (sc-is y single-stack)
1425 (inst fcom (ea-for-sf-stack y))
1426 (inst fcom (ea-for-sf-desc y)))))
1427 (inst fnstsw) ; status word to ax
1428 (inst and ah-tn #x45)))))
1430 (define-vop (>double-float)
1432 (:args (x :scs (double-reg double-stack descriptor-reg))
1433 (y :scs (double-reg double-stack descriptor-reg)))
1434 (:arg-types double-float double-float)
1435 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1436 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1438 (:policy :fast-safe)
1439 (:note "inline float comparison")
1442 ;; Handle a few special cases.
1445 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1449 ((double-stack descriptor-reg)
1450 (if (sc-is x double-stack)
1451 (inst fcomd (ea-for-df-stack x))
1452 (inst fcomd (ea-for-df-desc x)))))
1453 (inst fnstsw) ; status word to ax
1454 (inst and ah-tn #x45)
1455 (inst cmp ah-tn #x01))
1457 ;; general case when y is not in ST0
1462 (unless (zerop (tn-offset x))
1463 (copy-fp-reg-to-fr0 x)))
1464 ((double-stack descriptor-reg)
1466 (if (sc-is x double-stack)
1467 (inst fldd (ea-for-df-stack x))
1468 (inst fldd (ea-for-df-desc x)))))
1472 ((double-stack descriptor-reg)
1473 (if (sc-is y double-stack)
1474 (inst fcomd (ea-for-df-stack y))
1475 (inst fcomd (ea-for-df-desc y)))))
1476 (inst fnstsw) ; status word to ax
1477 (inst and ah-tn #x45)))))
1480 (define-vop (>long-float)
1482 (:args (x :scs (long-reg))
1483 (y :scs (long-reg)))
1484 (:arg-types long-float long-float)
1485 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1487 (:policy :fast-safe)
1488 (:note "inline float comparison")
1492 ;; y is in ST0; x is in any reg.
1493 ((zerop (tn-offset y))
1495 (inst fnstsw) ; status word to ax
1496 (inst and ah-tn #x45)
1497 (inst cmp ah-tn #x01))
1498 ;; x is in ST0; y is in another reg.
1499 ((zerop (tn-offset x))
1501 (inst fnstsw) ; status word to ax
1502 (inst and ah-tn #x45))
1503 ;; y and x are the same register, not ST0
1504 ;; y and x are different registers, neither ST0.
1509 (inst fnstsw) ; status word to ax
1510 (inst and ah-tn #x45)))))
1512 ;;; Comparisons with 0 can use the FTST instruction.
1514 (define-vop (float-test)
1516 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1519 (:variant-vars code)
1520 (:policy :fast-safe)
1522 (:save-p :compute-only)
1523 (:note "inline float comparison")
1526 (note-this-location vop :internal-error)
1529 ((zerop (tn-offset x))
1536 (inst fnstsw) ; status word to ax
1537 (inst and ah-tn #x45) ; C3 C2 C0
1538 (unless (zerop code)
1539 (inst cmp ah-tn code))))
1541 (define-vop (=0/single-float float-test)
1543 (:args (x :scs (single-reg)))
1544 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1546 (define-vop (=0/double-float float-test)
1548 (:args (x :scs (double-reg)))
1549 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1552 (define-vop (=0/long-float float-test)
1554 (:args (x :scs (long-reg)))
1555 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1558 (define-vop (<0/single-float float-test)
1560 (:args (x :scs (single-reg)))
1561 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1563 (define-vop (<0/double-float float-test)
1565 (:args (x :scs (double-reg)))
1566 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1569 (define-vop (<0/long-float float-test)
1571 (:args (x :scs (long-reg)))
1572 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1575 (define-vop (>0/single-float float-test)
1577 (:args (x :scs (single-reg)))
1578 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1580 (define-vop (>0/double-float float-test)
1582 (:args (x :scs (double-reg)))
1583 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1586 (define-vop (>0/long-float float-test)
1588 (:args (x :scs (long-reg)))
1589 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1593 (deftransform eql ((x y) (long-float long-float))
1594 `(and (= (long-float-low-bits x) (long-float-low-bits y))
1595 (= (long-float-high-bits x) (long-float-high-bits y))
1596 (= (long-float-exp-bits x) (long-float-exp-bits y))))
1600 (macrolet ((frob (name translate to-sc to-type)
1601 `(define-vop (,name)
1602 (:args (x :scs (signed-stack signed-reg) :target temp))
1603 (:temporary (:sc signed-stack) temp)
1604 (:results (y :scs (,to-sc)))
1605 (:arg-types signed-num)
1606 (:result-types ,to-type)
1607 (:policy :fast-safe)
1608 (:note "inline float coercion")
1609 (:translate ,translate)
1611 (:save-p :compute-only)
1616 (with-empty-tn@fp-top(y)
1617 (note-this-location vop :internal-error)
1620 (with-empty-tn@fp-top(y)
1621 (note-this-location vop :internal-error)
1622 (inst fild x))))))))
1623 (frob %single-float/signed %single-float single-reg single-float)
1624 (frob %double-float/signed %double-float double-reg double-float)
1626 (frob %long-float/signed %long-float long-reg long-float))
1628 (macrolet ((frob (name translate to-sc to-type)
1629 `(define-vop (,name)
1630 (:args (x :scs (unsigned-reg)))
1631 (:results (y :scs (,to-sc)))
1632 (:arg-types unsigned-num)
1633 (:result-types ,to-type)
1634 (:policy :fast-safe)
1635 (:note "inline float coercion")
1636 (:translate ,translate)
1638 (:save-p :compute-only)
1642 (with-empty-tn@fp-top(y)
1643 (note-this-location vop :internal-error)
1644 (inst fildl (make-ea :dword :base esp-tn)))
1645 (inst add esp-tn 8)))))
1646 (frob %single-float/unsigned %single-float single-reg single-float)
1647 (frob %double-float/unsigned %double-float double-reg double-float)
1649 (frob %long-float/unsigned %long-float long-reg long-float))
1651 ;;; These should be no-ops but the compiler might want to move some
1653 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1654 `(define-vop (,name)
1655 (:args (x :scs (,from-sc) :target y))
1656 (:results (y :scs (,to-sc)))
1657 (:arg-types ,from-type)
1658 (:result-types ,to-type)
1659 (:policy :fast-safe)
1660 (:note "inline float coercion")
1661 (:translate ,translate)
1663 (:save-p :compute-only)
1665 (note-this-location vop :internal-error)
1666 (unless (location= x y)
1668 ((zerop (tn-offset x))
1669 ;; x is in ST0, y is in another reg. not ST0
1671 ((zerop (tn-offset y))
1672 ;; y is in ST0, x is in another reg. not ST0
1673 (copy-fp-reg-to-fr0 x))
1675 ;; Neither x or y are in ST0, and they are not in
1679 (inst fxch x))))))))
1681 (frob %single-float/double-float %single-float double-reg
1682 double-float single-reg single-float)
1684 (frob %single-float/long-float %single-float long-reg
1685 long-float single-reg single-float)
1686 (frob %double-float/single-float %double-float single-reg single-float
1687 double-reg double-float)
1689 (frob %double-float/long-float %double-float long-reg long-float
1690 double-reg double-float)
1692 (frob %long-float/single-float %long-float single-reg single-float
1693 long-reg long-float)
1695 (frob %long-float/double-float %long-float double-reg double-float
1696 long-reg long-float))
1698 (macrolet ((frob (trans from-sc from-type round-p)
1699 `(define-vop (,(symbolicate trans "/" from-type))
1700 (:args (x :scs (,from-sc)))
1701 (:temporary (:sc signed-stack) stack-temp)
1703 '((:temporary (:sc unsigned-stack) scw)
1704 (:temporary (:sc any-reg) rcw)))
1705 (:results (y :scs (signed-reg)))
1706 (:arg-types ,from-type)
1707 (:result-types signed-num)
1709 (:policy :fast-safe)
1710 (:note "inline float truncate")
1712 (:save-p :compute-only)
1715 '((note-this-location vop :internal-error)
1716 ;; Catch any pending FPE exceptions.
1718 (,(if round-p 'progn 'pseudo-atomic)
1719 ;; Normal mode (for now) is "round to best".
1722 '((inst fnstcw scw) ; save current control word
1723 (move rcw scw) ; into 16-bit register
1724 (inst or rcw (ash #b11 10)) ; CHOP
1725 (move stack-temp rcw)
1726 (inst fldcw stack-temp)))
1731 (inst fist stack-temp)
1732 (inst mov y stack-temp)))
1734 '((inst fldcw scw)))))))))
1735 (frob %unary-truncate/single-float single-reg single-float nil)
1736 (frob %unary-truncate/double-float double-reg double-float nil)
1738 (frob %unary-truncate/long-float long-reg long-float nil)
1739 (frob %unary-round single-reg single-float t)
1740 (frob %unary-round double-reg double-float t)
1742 (frob %unary-round long-reg long-float t))
1744 (macrolet ((frob (trans from-sc from-type round-p)
1745 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1746 (:args (x :scs (,from-sc) :target fr0))
1747 (:temporary (:sc double-reg :offset fr0-offset
1748 :from :argument :to :result) fr0)
1750 '((:temporary (:sc unsigned-stack) stack-temp)
1751 (:temporary (:sc unsigned-stack) scw)
1752 (:temporary (:sc any-reg) rcw)))
1753 (:results (y :scs (unsigned-reg)))
1754 (:arg-types ,from-type)
1755 (:result-types unsigned-num)
1757 (:policy :fast-safe)
1758 (:note "inline float truncate")
1760 (:save-p :compute-only)
1763 '((note-this-location vop :internal-error)
1764 ;; Catch any pending FPE exceptions.
1766 ;; Normal mode (for now) is "round to best".
1767 (unless (zerop (tn-offset x))
1768 (copy-fp-reg-to-fr0 x))
1770 '((inst fnstcw scw) ; save current control word
1771 (move rcw scw) ; into 16-bit register
1772 (inst or rcw (ash #b11 10)) ; CHOP
1773 (move stack-temp rcw)
1774 (inst fldcw stack-temp)))
1776 (inst fistpl (make-ea :dword :base esp-tn))
1778 (inst fld fr0) ; copy fr0 to at least restore stack.
1781 '((inst fldcw scw)))))))
1782 (frob %unary-truncate/single-float single-reg single-float nil)
1783 (frob %unary-truncate/double-float double-reg double-float nil)
1785 (frob %unary-truncate/long-float long-reg long-float nil)
1786 (frob %unary-round single-reg single-float t)
1787 (frob %unary-round double-reg double-float t)
1789 (frob %unary-round long-reg long-float t))
1791 (define-vop (make-single-float)
1792 (:args (bits :scs (signed-reg) :target res
1793 :load-if (not (or (and (sc-is bits signed-stack)
1794 (sc-is res single-reg))
1795 (and (sc-is bits signed-stack)
1796 (sc-is res single-stack)
1797 (location= bits res))))))
1798 (:results (res :scs (single-reg single-stack)))
1799 (:temporary (:sc signed-stack) stack-temp)
1800 (:arg-types signed-num)
1801 (:result-types single-float)
1802 (:translate make-single-float)
1803 (:policy :fast-safe)
1810 (inst mov res bits))
1812 (aver (location= bits res)))))
1816 ;; source must be in memory
1817 (inst mov stack-temp bits)
1818 (with-empty-tn@fp-top(res)
1819 (inst fld stack-temp)))
1821 (with-empty-tn@fp-top(res)
1822 (inst fld bits))))))))
1824 (define-vop (make-single-float-c)
1825 (:results (res :scs (single-reg single-stack)))
1826 (:arg-types (:constant (signed-byte 32)))
1827 (:result-types single-float)
1829 (:translate make-single-float)
1830 (:policy :fast-safe)
1835 (inst mov res bits))
1837 (with-empty-tn@fp-top (res)
1838 (inst fld (register-inline-constant :dword bits)))))))
1840 (define-vop (make-double-float)
1841 (:args (hi-bits :scs (signed-reg))
1842 (lo-bits :scs (unsigned-reg)))
1843 (:results (res :scs (double-reg)))
1844 (:temporary (:sc double-stack) temp)
1845 (:arg-types signed-num unsigned-num)
1846 (:result-types double-float)
1847 (:translate make-double-float)
1848 (:policy :fast-safe)
1851 (let ((offset (tn-offset temp)))
1852 (storew hi-bits ebp-tn (frame-word-offset offset))
1853 (storew lo-bits ebp-tn (frame-word-offset (1+ offset)))
1854 (with-empty-tn@fp-top(res)
1855 (inst fldd (make-ea :dword :base ebp-tn
1856 :disp (frame-byte-offset (1+ offset))))))))
1858 (define-vop (make-double-float-c)
1859 (:results (res :scs (double-reg)))
1860 (:arg-types (:constant (signed-byte 32)) (:constant (unsigned-byte 32)))
1861 (:result-types double-float)
1863 (:translate make-double-float)
1864 (:policy :fast-safe)
1867 (with-empty-tn@fp-top(res)
1868 (inst fldd (register-inline-constant
1869 :double-float-bits (logior (ash hi 32) lo))))))
1872 (define-vop (make-long-float)
1873 (:args (exp-bits :scs (signed-reg))
1874 (hi-bits :scs (unsigned-reg))
1875 (lo-bits :scs (unsigned-reg)))
1876 (:results (res :scs (long-reg)))
1877 (:temporary (:sc long-stack) temp)
1878 (:arg-types signed-num unsigned-num unsigned-num)
1879 (:result-types long-float)
1880 (:translate make-long-float)
1881 (:policy :fast-safe)
1884 (let ((offset (tn-offset temp)))
1885 (storew exp-bits ebp-tn (frame-word-offset offset))
1886 (storew hi-bits ebp-tn (frame-word-offset (1+ offset)))
1887 (storew lo-bits ebp-tn (frame-word-offset (+ offset 2)))
1888 (with-empty-tn@fp-top(res)
1889 (inst fldl (make-ea :dword :base ebp-tn
1890 :disp (frame-byte-offset (+ offset 2))))))))
1892 (define-vop (single-float-bits)
1893 (:args (float :scs (single-reg descriptor-reg)
1894 :load-if (not (sc-is float single-stack))))
1895 (:results (bits :scs (signed-reg)))
1896 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1897 (:arg-types single-float)
1898 (:result-types signed-num)
1899 (:translate single-float-bits)
1900 (:policy :fast-safe)
1907 (with-tn@fp-top(float)
1908 (inst fst stack-temp)
1909 (inst mov bits stack-temp)))
1911 (inst mov bits float))
1914 bits float single-float-value-slot
1915 other-pointer-lowtag))))
1919 (with-tn@fp-top(float)
1920 (inst fst bits))))))))
1922 (define-vop (double-float-high-bits)
1923 (:args (float :scs (double-reg descriptor-reg)
1924 :load-if (not (sc-is float double-stack))))
1925 (:results (hi-bits :scs (signed-reg)))
1926 (:temporary (:sc double-stack) temp)
1927 (:arg-types double-float)
1928 (:result-types signed-num)
1929 (:translate double-float-high-bits)
1930 (:policy :fast-safe)
1935 (with-tn@fp-top(float)
1936 (let ((where (make-ea :dword :base ebp-tn
1937 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1939 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset temp))))
1941 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1943 (loadw hi-bits float (1+ double-float-value-slot)
1944 other-pointer-lowtag)))))
1946 (define-vop (double-float-low-bits)
1947 (:args (float :scs (double-reg descriptor-reg)
1948 :load-if (not (sc-is float double-stack))))
1949 (:results (lo-bits :scs (unsigned-reg)))
1950 (:temporary (:sc double-stack) temp)
1951 (:arg-types double-float)
1952 (:result-types unsigned-num)
1953 (:translate double-float-low-bits)
1954 (:policy :fast-safe)
1959 (with-tn@fp-top(float)
1960 (let ((where (make-ea :dword :base ebp-tn
1961 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1963 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1965 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset float)))))
1967 (loadw lo-bits float double-float-value-slot
1968 other-pointer-lowtag)))))
1971 (define-vop (long-float-exp-bits)
1972 (:args (float :scs (long-reg descriptor-reg)
1973 :load-if (not (sc-is float long-stack))))
1974 (:results (exp-bits :scs (signed-reg)))
1975 (:temporary (:sc long-stack) temp)
1976 (:arg-types long-float)
1977 (:result-types signed-num)
1978 (:translate long-float-exp-bits)
1979 (:policy :fast-safe)
1984 (with-tn@fp-top(float)
1985 (let ((where (make-ea :dword :base ebp-tn
1986 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1987 (store-long-float where)))
1988 (inst movsx exp-bits
1989 (make-ea :word :base ebp-tn
1990 :disp (frame-byte-offset (tn-offset temp)))))
1992 (inst movsx exp-bits
1993 (make-ea :word :base ebp-tn
1994 :disp (frame-byte-offset (tn-offset temp)))))
1996 (inst movsx exp-bits
1997 (make-ea-for-object-slot float (+ 2 long-float-value-slot)
1998 other-pointer-lowtag :word))))))
2001 (define-vop (long-float-high-bits)
2002 (:args (float :scs (long-reg descriptor-reg)
2003 :load-if (not (sc-is float long-stack))))
2004 (:results (hi-bits :scs (unsigned-reg)))
2005 (:temporary (:sc long-stack) temp)
2006 (:arg-types long-float)
2007 (:result-types unsigned-num)
2008 (:translate long-float-high-bits)
2009 (:policy :fast-safe)
2014 (with-tn@fp-top(float)
2015 (let ((where (make-ea :dword :base ebp-tn
2016 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2017 (store-long-float where)))
2018 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
2020 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
2022 (loadw hi-bits float (1+ long-float-value-slot)
2023 other-pointer-lowtag)))))
2026 (define-vop (long-float-low-bits)
2027 (:args (float :scs (long-reg descriptor-reg)
2028 :load-if (not (sc-is float long-stack))))
2029 (:results (lo-bits :scs (unsigned-reg)))
2030 (:temporary (:sc long-stack) temp)
2031 (:arg-types long-float)
2032 (:result-types unsigned-num)
2033 (:translate long-float-low-bits)
2034 (:policy :fast-safe)
2039 (with-tn@fp-top(float)
2040 (let ((where (make-ea :dword :base ebp-tn
2041 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2042 (store-long-float where)))
2043 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset temp) 2))))
2045 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset float) 2))))
2047 (loadw lo-bits float long-float-value-slot
2048 other-pointer-lowtag)))))
2050 ;;;; float mode hackery
2052 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2053 (defknown floating-point-modes () float-modes (flushable))
2054 (defknown ((setf floating-point-modes)) (float-modes)
2057 (def!constant npx-env-size (* 7 n-word-bytes))
2058 (def!constant npx-cw-offset 0)
2059 (def!constant npx-sw-offset 4)
2061 (define-vop (floating-point-modes)
2062 (:results (res :scs (unsigned-reg)))
2063 (:result-types unsigned-num)
2064 (:translate floating-point-modes)
2065 (:policy :fast-safe)
2066 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2069 (inst sub esp-tn npx-env-size) ; Make space on stack.
2070 (inst wait) ; Catch any pending FPE exceptions
2071 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2072 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2073 ;; Move current status to high word.
2074 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2075 ;; Move exception mask to low word.
2076 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2077 (inst add esp-tn npx-env-size) ; Pop stack.
2078 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2081 (define-vop (set-floating-point-modes)
2082 (:args (new :scs (unsigned-reg) :to :result :target res))
2083 (:results (res :scs (unsigned-reg)))
2084 (:arg-types unsigned-num)
2085 (:result-types unsigned-num)
2086 (:translate (setf floating-point-modes))
2087 (:policy :fast-safe)
2088 (:temporary (:sc unsigned-reg :offset eax-offset
2089 :from :eval :to :result) eax)
2091 (inst sub esp-tn npx-env-size) ; Make space on stack.
2092 (inst wait) ; Catch any pending FPE exceptions.
2093 (inst fstenv (make-ea :dword :base esp-tn))
2095 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2096 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2097 (inst shr eax 16) ; position status word
2098 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2099 (inst fldenv (make-ea :dword :base esp-tn))
2100 (inst add esp-tn npx-env-size) ; Pop stack.
2106 ;;; Let's use some of the 80387 special functions.
2108 ;;; These defs will not take effect unless code/irrat.lisp is modified
2109 ;;; to remove the inlined alien routine def.
2111 (macrolet ((frob (func trans op)
2112 `(define-vop (,func)
2113 (:args (x :scs (double-reg) :target fr0))
2114 (:temporary (:sc double-reg :offset fr0-offset
2115 :from :argument :to :result) fr0)
2117 (:results (y :scs (double-reg)))
2118 (:arg-types double-float)
2119 (:result-types double-float)
2121 (:policy :fast-safe)
2122 (:note "inline NPX function")
2124 (:save-p :compute-only)
2127 (note-this-location vop :internal-error)
2128 (unless (zerop (tn-offset x))
2129 (inst fxch x) ; x to top of stack
2130 (unless (location= x y)
2131 (inst fst x))) ; maybe save it
2132 (inst ,op) ; clobber st0
2133 (cond ((zerop (tn-offset y))
2134 (maybe-fp-wait node))
2138 ;; Quick versions of fsin and fcos that require the argument to be
2139 ;; within range 2^63.
2140 (frob fsin-quick %sin-quick fsin)
2141 (frob fcos-quick %cos-quick fcos)
2142 (frob fsqrt %sqrt fsqrt))
2144 ;;; Quick version of ftan that requires the argument to be within
2146 (define-vop (ftan-quick)
2147 (:translate %tan-quick)
2148 (:args (x :scs (double-reg) :target fr0))
2149 (:temporary (:sc double-reg :offset fr0-offset
2150 :from :argument :to :result) fr0)
2151 (:temporary (:sc double-reg :offset fr1-offset
2152 :from :argument :to :result) fr1)
2153 (:results (y :scs (double-reg)))
2154 (:arg-types double-float)
2155 (:result-types double-float)
2156 (:policy :fast-safe)
2157 (:note "inline tan function")
2159 (:save-p :compute-only)
2161 (note-this-location vop :internal-error)
2170 (inst fldd (make-random-tn :kind :normal
2171 :sc (sc-or-lose 'double-reg)
2172 :offset (- (tn-offset x) 2)))))
2183 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2184 ;;; result if the argument is out of range 2^63 and would thus be
2185 ;;; hopelessly inaccurate.
2186 (macrolet ((frob (func trans op)
2187 `(define-vop (,func)
2189 (:args (x :scs (double-reg) :target fr0))
2190 (:temporary (:sc double-reg :offset fr0-offset
2191 :from :argument :to :result) fr0)
2192 ;; FIXME: make that an arbitrary location and
2193 ;; FXCH only when range reduction needed
2194 (:temporary (:sc double-reg :offset fr1-offset
2195 :from :argument :to :result) fr1)
2196 (:temporary (:sc unsigned-reg :offset eax-offset
2197 :from :argument :to :result) eax)
2198 (:results (y :scs (double-reg)))
2199 (:arg-types double-float)
2200 (:result-types double-float)
2201 (:policy :fast-safe)
2202 (:note "inline sin/cos function")
2204 (:save-p :compute-only)
2207 (let ((DONE (gen-label))
2208 (REDUCE (gen-label))
2209 (REDUCE-LOOP (gen-label)))
2210 (note-this-location vop :internal-error)
2211 (unless (zerop (tn-offset x))
2212 (inst fxch x) ; x to top of stack
2213 (unless (location= x y)
2214 (inst fst x))) ; maybe save it
2216 (inst fnstsw) ; status word to ax
2217 (inst and ah-tn #x04) ; C2
2218 (inst jmp :nz REDUCE)
2220 (unless (zerop (tn-offset y))
2222 (assemble (*elsewhere*)
2224 ;; Else x was out of range so reduce it; ST0 is unchanged.
2225 (with-empty-tn@fp-top (fr1)
2228 (emit-label REDUCE-LOOP)
2231 (inst and ah-tn #x04)
2232 (inst jmp :nz REDUCE-LOOP)
2234 (inst jmp DONE)))))))
2235 (frob fsin %sin fsin)
2236 (frob fcos %cos fcos))
2240 (:args (x :scs (double-reg) :target fr0))
2241 (:temporary (:sc double-reg :offset fr0-offset
2242 :from :argument :to :result) fr0)
2243 (:temporary (:sc double-reg :offset fr1-offset
2244 :from :argument :to :result) fr1)
2245 (:temporary (:sc unsigned-reg :offset eax-offset
2246 :from :argument :to :result) eax)
2247 (:results (y :scs (double-reg)))
2248 (:arg-types double-float)
2249 (:result-types double-float)
2251 (:policy :fast-safe)
2252 (:note "inline tan function")
2254 (:save-p :compute-only)
2257 (note-this-location vop :internal-error)
2266 (inst fldd (make-random-tn :kind :normal
2267 :sc (sc-or-lose 'double-reg)
2268 :offset (- (tn-offset x) 2)))))
2270 (let ((REDUCE (gen-label))
2271 (REDUCE-LOOP (gen-label)))
2272 (inst fnstsw) ; status word to ax
2273 (inst and ah-tn #x04) ; C2
2274 (inst jmp :nz REDUCE)
2275 (assemble (*elsewhere*)
2277 ;; Else x was out of range so reduce it; ST0 is unchanged.
2278 (with-empty-tn@fp-top (fr1)
2281 (emit-label REDUCE-LOOP)
2284 (inst and ah-tn #x04)
2285 (inst jmp :nz REDUCE-LOOP)
2298 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2299 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2302 (:args (x :scs (double-reg) :target fr0))
2303 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2304 (:temporary (:sc double-reg :offset fr0-offset
2305 :from :argument :to :result) fr0)
2306 (:temporary (:sc double-reg :offset fr1-offset
2307 :from :argument :to :result) fr1)
2308 (:temporary (:sc double-reg :offset fr2-offset
2309 :from :argument :to :result) fr2)
2310 (:results (y :scs (double-reg)))
2311 (:arg-types double-float)
2312 (:result-types double-float)
2313 (:policy :fast-safe)
2314 (:note "inline exp function")
2316 (:save-p :compute-only)
2319 (note-this-location vop :internal-error)
2320 (unless (zerop (tn-offset x))
2321 (inst fxch x) ; x to top of stack
2322 (unless (location= x y)
2323 (inst fst x))) ; maybe save it
2324 ;; Check for Inf or NaN
2328 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2329 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2330 (inst and ah-tn #x02) ; Test sign of Inf.
2331 (inst jmp :z DONE) ; +Inf gives +Inf.
2332 (inst fstp fr0) ; -Inf gives 0
2334 (inst jmp-short DONE)
2339 ;; Now fr0=x log2(e)
2343 (inst fsubp-sti fr1)
2346 (inst faddp-sti fr1)
2350 (unless (zerop (tn-offset y))
2353 ;;; Expm1 = exp(x) - 1.
2354 ;;; Handles the following special cases:
2355 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2356 (define-vop (fexpm1)
2358 (:args (x :scs (double-reg) :target fr0))
2359 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2360 (:temporary (:sc double-reg :offset fr0-offset
2361 :from :argument :to :result) fr0)
2362 (:temporary (:sc double-reg :offset fr1-offset
2363 :from :argument :to :result) fr1)
2364 (:temporary (:sc double-reg :offset fr2-offset
2365 :from :argument :to :result) fr2)
2366 (:results (y :scs (double-reg)))
2367 (:arg-types double-float)
2368 (:result-types double-float)
2369 (:policy :fast-safe)
2370 (:note "inline expm1 function")
2372 (:save-p :compute-only)
2375 (note-this-location vop :internal-error)
2376 (unless (zerop (tn-offset x))
2377 (inst fxch x) ; x to top of stack
2378 (unless (location= x y)
2379 (inst fst x))) ; maybe save it
2380 ;; Check for Inf or NaN
2384 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2385 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2386 (inst and ah-tn #x02) ; Test sign of Inf.
2387 (inst jmp :z DONE) ; +Inf gives +Inf.
2388 (inst fstp fr0) ; -Inf gives -1.0
2391 (inst jmp-short DONE)
2393 ;; Free two stack slots leaving the argument on top.
2397 (inst fmul fr1) ; Now fr0 = x log2(e)
2412 (unless (zerop (tn-offset y))
2417 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2418 (:temporary (:sc double-reg :offset fr0-offset
2419 :from :argument :to :result) fr0)
2420 (:temporary (:sc double-reg :offset fr1-offset
2421 :from :argument :to :result) fr1)
2422 (:results (y :scs (double-reg)))
2423 (:arg-types double-float)
2424 (:result-types double-float)
2425 (:policy :fast-safe)
2426 (:note "inline log function")
2428 (:save-p :compute-only)
2430 (note-this-location vop :internal-error)
2445 ;; x is in a FP reg, not fr0 or fr1
2449 (inst fldd (make-random-tn :kind :normal
2450 :sc (sc-or-lose 'double-reg)
2451 :offset (1- (tn-offset x))))))
2453 ((double-stack descriptor-reg)
2457 (if (sc-is x double-stack)
2458 (inst fldd (ea-for-df-stack x))
2459 (inst fldd (ea-for-df-desc x)))
2464 (t (inst fstd y)))))
2466 (define-vop (flog10)
2468 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2469 (:temporary (:sc double-reg :offset fr0-offset
2470 :from :argument :to :result) fr0)
2471 (:temporary (:sc double-reg :offset fr1-offset
2472 :from :argument :to :result) fr1)
2473 (:results (y :scs (double-reg)))
2474 (:arg-types double-float)
2475 (:result-types double-float)
2476 (:policy :fast-safe)
2477 (:note "inline log10 function")
2479 (:save-p :compute-only)
2481 (note-this-location vop :internal-error)
2496 ;; x is in a FP reg, not fr0 or fr1
2500 (inst fldd (make-random-tn :kind :normal
2501 :sc (sc-or-lose 'double-reg)
2502 :offset (1- (tn-offset x))))))
2504 ((double-stack descriptor-reg)
2508 (if (sc-is x double-stack)
2509 (inst fldd (ea-for-df-stack x))
2510 (inst fldd (ea-for-df-desc x)))
2515 (t (inst fstd y)))))
2519 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2520 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2521 (:temporary (:sc double-reg :offset fr0-offset
2522 :from (:argument 0) :to :result) fr0)
2523 (:temporary (:sc double-reg :offset fr1-offset
2524 :from (:argument 1) :to :result) fr1)
2525 (:temporary (:sc double-reg :offset fr2-offset
2526 :from :load :to :result) fr2)
2527 (:results (r :scs (double-reg)))
2528 (:arg-types double-float double-float)
2529 (:result-types double-float)
2530 (:policy :fast-safe)
2531 (:note "inline pow function")
2533 (:save-p :compute-only)
2535 (note-this-location vop :internal-error)
2536 ;; Setup x in fr0 and y in fr1
2538 ;; x in fr0; y in fr1
2539 ((and (sc-is x double-reg) (zerop (tn-offset x))
2540 (sc-is y double-reg) (= 1 (tn-offset y))))
2541 ;; y in fr1; x not in fr0
2542 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2546 (copy-fp-reg-to-fr0 x))
2549 (inst fldd (ea-for-df-stack x)))
2552 (inst fldd (ea-for-df-desc x)))))
2553 ;; x in fr0; y not in fr1
2554 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2556 ;; Now load y to fr0
2559 (copy-fp-reg-to-fr0 y))
2562 (inst fldd (ea-for-df-stack y)))
2565 (inst fldd (ea-for-df-desc y))))
2567 ;; x in fr1; y not in fr1
2568 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2572 (copy-fp-reg-to-fr0 y))
2575 (inst fldd (ea-for-df-stack y)))
2578 (inst fldd (ea-for-df-desc y))))
2581 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2583 ;; Now load x to fr0
2586 (copy-fp-reg-to-fr0 x))
2589 (inst fldd (ea-for-df-stack x)))
2592 (inst fldd (ea-for-df-desc x)))))
2593 ;; Neither x or y are in either fr0 or fr1
2600 (inst fldd (make-random-tn :kind :normal
2601 :sc (sc-or-lose 'double-reg)
2602 :offset (- (tn-offset y) 2))))
2604 (inst fldd (ea-for-df-stack y)))
2606 (inst fldd (ea-for-df-desc y))))
2610 (inst fldd (make-random-tn :kind :normal
2611 :sc (sc-or-lose 'double-reg)
2612 :offset (1- (tn-offset x)))))
2614 (inst fldd (ea-for-df-stack x)))
2616 (inst fldd (ea-for-df-desc x))))))
2618 ;; Now have x at fr0; and y at fr1
2620 ;; Now fr0=y log2(x)
2624 (inst fsubp-sti fr1)
2627 (inst faddp-sti fr1)
2632 (t (inst fstd r)))))
2634 (define-vop (fscalen)
2635 (:translate %scalbn)
2636 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2637 (y :scs (signed-stack signed-reg) :target temp))
2638 (:temporary (:sc double-reg :offset fr0-offset
2639 :from (:argument 0) :to :result) fr0)
2640 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2641 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2642 (:results (r :scs (double-reg)))
2643 (:arg-types double-float signed-num)
2644 (:result-types double-float)
2645 (:policy :fast-safe)
2646 (:note "inline scalbn function")
2648 ;; Setup x in fr0 and y in fr1
2679 (inst fld (make-random-tn :kind :normal
2680 :sc (sc-or-lose 'double-reg)
2681 :offset (1- (tn-offset x)))))))
2682 ((double-stack descriptor-reg)
2691 (if (sc-is x double-stack)
2692 (inst fldd (ea-for-df-stack x))
2693 (inst fldd (ea-for-df-desc x)))))
2695 (unless (zerop (tn-offset r))
2698 (define-vop (fscale)
2700 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2701 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2702 (:temporary (:sc double-reg :offset fr0-offset
2703 :from (:argument 0) :to :result) fr0)
2704 (:temporary (:sc double-reg :offset fr1-offset
2705 :from (:argument 1) :to :result) fr1)
2706 (:results (r :scs (double-reg)))
2707 (:arg-types double-float double-float)
2708 (:result-types double-float)
2709 (:policy :fast-safe)
2710 (:note "inline scalb function")
2712 (:save-p :compute-only)
2714 (note-this-location vop :internal-error)
2715 ;; Setup x in fr0 and y in fr1
2717 ;; x in fr0; y in fr1
2718 ((and (sc-is x double-reg) (zerop (tn-offset x))
2719 (sc-is y double-reg) (= 1 (tn-offset y))))
2720 ;; y in fr1; x not in fr0
2721 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2725 (copy-fp-reg-to-fr0 x))
2728 (inst fldd (ea-for-df-stack x)))
2731 (inst fldd (ea-for-df-desc x)))))
2732 ;; x in fr0; y not in fr1
2733 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2735 ;; Now load y to fr0
2738 (copy-fp-reg-to-fr0 y))
2741 (inst fldd (ea-for-df-stack y)))
2744 (inst fldd (ea-for-df-desc y))))
2746 ;; x in fr1; y not in fr1
2747 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2751 (copy-fp-reg-to-fr0 y))
2754 (inst fldd (ea-for-df-stack y)))
2757 (inst fldd (ea-for-df-desc y))))
2760 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2762 ;; Now load x to fr0
2765 (copy-fp-reg-to-fr0 x))
2768 (inst fldd (ea-for-df-stack x)))
2771 (inst fldd (ea-for-df-desc x)))))
2772 ;; Neither x or y are in either fr0 or fr1
2779 (inst fldd (make-random-tn :kind :normal
2780 :sc (sc-or-lose 'double-reg)
2781 :offset (- (tn-offset y) 2))))
2783 (inst fldd (ea-for-df-stack y)))
2785 (inst fldd (ea-for-df-desc y))))
2789 (inst fldd (make-random-tn :kind :normal
2790 :sc (sc-or-lose 'double-reg)
2791 :offset (1- (tn-offset x)))))
2793 (inst fldd (ea-for-df-stack x)))
2795 (inst fldd (ea-for-df-desc x))))))
2797 ;; Now have x at fr0; and y at fr1
2799 (unless (zerop (tn-offset r))
2802 (define-vop (flog1p)
2804 (:args (x :scs (double-reg) :to :result))
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 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2810 (:results (y :scs (double-reg)))
2811 (:arg-types double-float)
2812 (:result-types double-float)
2813 (:policy :fast-safe)
2814 (:note "inline log1p function")
2817 ;; x is in a FP reg, not fr0, fr1.
2820 (inst fldd (make-random-tn :kind :normal
2821 :sc (sc-or-lose 'double-reg)
2822 :offset (- (tn-offset x) 2)))
2824 (inst push #x3e947ae1) ; Constant 0.29
2826 (inst fld (make-ea :dword :base esp-tn))
2829 (inst fnstsw) ; status word to ax
2830 (inst and ah-tn #x45)
2831 (inst jmp :z WITHIN-RANGE)
2832 ;; Out of range for fyl2xp1.
2834 (inst faddd (make-random-tn :kind :normal
2835 :sc (sc-or-lose 'double-reg)
2836 :offset (- (tn-offset x) 1)))
2844 (inst fldd (make-random-tn :kind :normal
2845 :sc (sc-or-lose 'double-reg)
2846 :offset (- (tn-offset x) 1)))
2852 (t (inst fstd y)))))
2854 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2855 ;;; instruction and a range check can be avoided.
2856 (define-vop (flog1p-pentium)
2858 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2859 (:temporary (:sc double-reg :offset fr0-offset
2860 :from :argument :to :result) fr0)
2861 (:temporary (:sc double-reg :offset fr1-offset
2862 :from :argument :to :result) fr1)
2863 (:results (y :scs (double-reg)))
2864 (:arg-types double-float)
2865 (:result-types double-float)
2866 (:policy :fast-safe)
2867 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2868 (:note "inline log1p with limited x range function")
2870 (:save-p :compute-only)
2872 (note-this-location vop :internal-error)
2887 ;; x is in a FP reg, not fr0 or fr1
2891 (inst fldd (make-random-tn :kind :normal
2892 :sc (sc-or-lose 'double-reg)
2893 :offset (1- (tn-offset x)))))))
2894 ((double-stack descriptor-reg)
2898 (if (sc-is x double-stack)
2899 (inst fldd (ea-for-df-stack x))
2900 (inst fldd (ea-for-df-desc x)))))
2905 (t (inst fstd y)))))
2909 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2910 (:temporary (:sc double-reg :offset fr0-offset
2911 :from :argument :to :result) fr0)
2912 (:temporary (:sc double-reg :offset fr1-offset
2913 :from :argument :to :result) fr1)
2914 (:results (y :scs (double-reg)))
2915 (:arg-types double-float)
2916 (:result-types double-float)
2917 (:policy :fast-safe)
2918 (:note "inline logb function")
2920 (:save-p :compute-only)
2922 (note-this-location vop :internal-error)
2933 ;; x is in a FP reg, not fr0 or fr1
2936 (inst fldd (make-random-tn :kind :normal
2937 :sc (sc-or-lose 'double-reg)
2938 :offset (- (tn-offset x) 2))))))
2939 ((double-stack descriptor-reg)
2942 (if (sc-is x double-stack)
2943 (inst fldd (ea-for-df-stack x))
2944 (inst fldd (ea-for-df-desc x)))))
2955 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2956 (:temporary (:sc double-reg :offset fr0-offset
2957 :from (:argument 0) :to :result) fr0)
2958 (:temporary (:sc double-reg :offset fr1-offset
2959 :from (:argument 0) :to :result) fr1)
2960 (:results (r :scs (double-reg)))
2961 (:arg-types double-float)
2962 (:result-types double-float)
2963 (:policy :fast-safe)
2964 (:note "inline atan function")
2966 (:save-p :compute-only)
2968 (note-this-location vop :internal-error)
2969 ;; Setup x in fr1 and 1.0 in fr0
2972 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2975 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2977 ;; x not in fr0 or fr1
2984 (inst fldd (make-random-tn :kind :normal
2985 :sc (sc-or-lose 'double-reg)
2986 :offset (- (tn-offset x) 2))))
2988 (inst fldd (ea-for-df-stack x)))
2990 (inst fldd (ea-for-df-desc x))))))
2992 ;; Now have x at fr1; and 1.0 at fr0
2997 (t (inst fstd r)))))
2999 (define-vop (fatan2)
3001 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
3002 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
3003 (:temporary (:sc double-reg :offset fr0-offset
3004 :from (:argument 1) :to :result) fr0)
3005 (:temporary (:sc double-reg :offset fr1-offset
3006 :from (:argument 0) :to :result) fr1)
3007 (:results (r :scs (double-reg)))
3008 (:arg-types double-float double-float)
3009 (:result-types double-float)
3010 (:policy :fast-safe)
3011 (:note "inline atan2 function")
3013 (:save-p :compute-only)
3015 (note-this-location vop :internal-error)
3016 ;; Setup x in fr1 and y in fr0
3018 ;; y in fr0; x in fr1
3019 ((and (sc-is y double-reg) (zerop (tn-offset y))
3020 (sc-is x double-reg) (= 1 (tn-offset x))))
3021 ;; x in fr1; y not in fr0
3022 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
3026 (copy-fp-reg-to-fr0 y))
3029 (inst fldd (ea-for-df-stack y)))
3032 (inst fldd (ea-for-df-desc y)))))
3033 ((and (sc-is x double-reg) (zerop (tn-offset x))
3034 (sc-is y double-reg) (zerop (tn-offset x)))
3037 ;; y in fr0; x not in fr1
3038 ((and (sc-is y double-reg) (zerop (tn-offset y)))
3040 ;; Now load x to fr0
3043 (copy-fp-reg-to-fr0 x))
3046 (inst fldd (ea-for-df-stack x)))
3049 (inst fldd (ea-for-df-desc x))))
3051 ;; y in fr1; x not in fr1
3052 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3056 (copy-fp-reg-to-fr0 x))
3059 (inst fldd (ea-for-df-stack x)))
3062 (inst fldd (ea-for-df-desc x))))
3065 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3067 ;; Now load y to fr0
3070 (copy-fp-reg-to-fr0 y))
3073 (inst fldd (ea-for-df-stack y)))
3076 (inst fldd (ea-for-df-desc y)))))
3077 ;; Neither y or x are in either fr0 or fr1
3084 (inst fldd (make-random-tn :kind :normal
3085 :sc (sc-or-lose 'double-reg)
3086 :offset (- (tn-offset x) 2))))
3088 (inst fldd (ea-for-df-stack x)))
3090 (inst fldd (ea-for-df-desc x))))
3094 (inst fldd (make-random-tn :kind :normal
3095 :sc (sc-or-lose 'double-reg)
3096 :offset (1- (tn-offset y)))))
3098 (inst fldd (ea-for-df-stack y)))
3100 (inst fldd (ea-for-df-desc y))))))
3102 ;; Now have y at fr0; and x at fr1
3107 (t (inst fstd r)))))
3108 ) ; PROGN #!-LONG-FLOAT
3113 ;;; Lets use some of the 80387 special functions.
3115 ;;; These defs will not take effect unless code/irrat.lisp is modified
3116 ;;; to remove the inlined alien routine def.
3118 (macrolet ((frob (func trans op)
3119 `(define-vop (,func)
3120 (:args (x :scs (long-reg) :target fr0))
3121 (:temporary (:sc long-reg :offset fr0-offset
3122 :from :argument :to :result) fr0)
3124 (:results (y :scs (long-reg)))
3125 (:arg-types long-float)
3126 (:result-types long-float)
3128 (:policy :fast-safe)
3129 (:note "inline NPX function")
3131 (:save-p :compute-only)
3134 (note-this-location vop :internal-error)
3135 (unless (zerop (tn-offset x))
3136 (inst fxch x) ; x to top of stack
3137 (unless (location= x y)
3138 (inst fst x))) ; maybe save it
3139 (inst ,op) ; clobber st0
3140 (cond ((zerop (tn-offset y))
3141 (maybe-fp-wait node))
3145 ;; Quick versions of FSIN and FCOS that require the argument to be
3146 ;; within range 2^63.
3147 (frob fsin-quick %sin-quick fsin)
3148 (frob fcos-quick %cos-quick fcos)
3149 (frob fsqrt %sqrt fsqrt))
3151 ;;; Quick version of ftan that requires the argument to be within
3153 (define-vop (ftan-quick)
3154 (:translate %tan-quick)
3155 (:args (x :scs (long-reg) :target fr0))
3156 (:temporary (:sc long-reg :offset fr0-offset
3157 :from :argument :to :result) fr0)
3158 (:temporary (:sc long-reg :offset fr1-offset
3159 :from :argument :to :result) fr1)
3160 (:results (y :scs (long-reg)))
3161 (:arg-types long-float)
3162 (:result-types long-float)
3163 (:policy :fast-safe)
3164 (:note "inline tan function")
3166 (:save-p :compute-only)
3168 (note-this-location vop :internal-error)
3177 (inst fldd (make-random-tn :kind :normal
3178 :sc (sc-or-lose 'double-reg)
3179 :offset (- (tn-offset x) 2)))))
3190 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3191 ;;; the argument is out of range 2^63 and would thus be hopelessly
3193 (macrolet ((frob (func trans op)
3194 `(define-vop (,func)
3196 (:args (x :scs (long-reg) :target fr0))
3197 (:temporary (:sc long-reg :offset fr0-offset
3198 :from :argument :to :result) fr0)
3199 (:temporary (:sc unsigned-reg :offset eax-offset
3200 :from :argument :to :result) eax)
3201 (:results (y :scs (long-reg)))
3202 (:arg-types long-float)
3203 (:result-types long-float)
3204 (:policy :fast-safe)
3205 (:note "inline sin/cos function")
3207 (:save-p :compute-only)
3210 (note-this-location vop :internal-error)
3211 (unless (zerop (tn-offset x))
3212 (inst fxch x) ; x to top of stack
3213 (unless (location= x y)
3214 (inst fst x))) ; maybe save it
3216 (inst fnstsw) ; status word to ax
3217 (inst and ah-tn #x04) ; C2
3219 ;; Else x was out of range so reduce it; ST0 is unchanged.
3220 (inst fstp fr0) ; Load 0.0
3223 (unless (zerop (tn-offset y))
3225 (frob fsin %sin fsin)
3226 (frob fcos %cos fcos))
3230 (:args (x :scs (long-reg) :target fr0))
3231 (:temporary (:sc long-reg :offset fr0-offset
3232 :from :argument :to :result) fr0)
3233 (:temporary (:sc long-reg :offset fr1-offset
3234 :from :argument :to :result) fr1)
3235 (:temporary (:sc unsigned-reg :offset eax-offset
3236 :from :argument :to :result) eax)
3237 (:results (y :scs (long-reg)))
3238 (:arg-types long-float)
3239 (:result-types long-float)
3241 (:policy :fast-safe)
3242 (:note "inline tan function")
3244 (:save-p :compute-only)
3247 (note-this-location vop :internal-error)
3256 (inst fldd (make-random-tn :kind :normal
3257 :sc (sc-or-lose 'double-reg)
3258 :offset (- (tn-offset x) 2)))))
3260 (inst fnstsw) ; status word to ax
3261 (inst and ah-tn #x04) ; C2
3263 ;; Else x was out of range so reduce it; ST0 is unchanged.
3264 (inst fldz) ; Load 0.0
3276 ;;; Modified exp that handles the following special cases:
3277 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3280 (:args (x :scs (long-reg) :target fr0))
3281 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3282 (:temporary (:sc long-reg :offset fr0-offset
3283 :from :argument :to :result) fr0)
3284 (:temporary (:sc long-reg :offset fr1-offset
3285 :from :argument :to :result) fr1)
3286 (:temporary (:sc long-reg :offset fr2-offset
3287 :from :argument :to :result) fr2)
3288 (:results (y :scs (long-reg)))
3289 (:arg-types long-float)
3290 (:result-types long-float)
3291 (:policy :fast-safe)
3292 (:note "inline exp function")
3294 (:save-p :compute-only)
3297 (note-this-location vop :internal-error)
3298 (unless (zerop (tn-offset x))
3299 (inst fxch x) ; x to top of stack
3300 (unless (location= x y)
3301 (inst fst x))) ; maybe save it
3302 ;; Check for Inf or NaN
3306 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3307 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3308 (inst and ah-tn #x02) ; Test sign of Inf.
3309 (inst jmp :z DONE) ; +Inf gives +Inf.
3310 (inst fstp fr0) ; -Inf gives 0
3312 (inst jmp-short DONE)
3317 ;; Now fr0=x log2(e)
3321 (inst fsubp-sti fr1)
3324 (inst faddp-sti fr1)
3328 (unless (zerop (tn-offset y))
3331 ;;; Expm1 = exp(x) - 1.
3332 ;;; Handles the following special cases:
3333 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3334 (define-vop (fexpm1)
3336 (:args (x :scs (long-reg) :target fr0))
3337 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3338 (:temporary (:sc long-reg :offset fr0-offset
3339 :from :argument :to :result) fr0)
3340 (:temporary (:sc long-reg :offset fr1-offset
3341 :from :argument :to :result) fr1)
3342 (:temporary (:sc long-reg :offset fr2-offset
3343 :from :argument :to :result) fr2)
3344 (:results (y :scs (long-reg)))
3345 (:arg-types long-float)
3346 (:result-types long-float)
3347 (:policy :fast-safe)
3348 (:note "inline expm1 function")
3350 (:save-p :compute-only)
3353 (note-this-location vop :internal-error)
3354 (unless (zerop (tn-offset x))
3355 (inst fxch x) ; x to top of stack
3356 (unless (location= x y)
3357 (inst fst x))) ; maybe save it
3358 ;; Check for Inf or NaN
3362 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3363 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3364 (inst and ah-tn #x02) ; Test sign of Inf.
3365 (inst jmp :z DONE) ; +Inf gives +Inf.
3366 (inst fstp fr0) ; -Inf gives -1.0
3369 (inst jmp-short DONE)
3371 ;; Free two stack slots leaving the argument on top.
3375 (inst fmul fr1) ; Now fr0 = x log2(e)
3390 (unless (zerop (tn-offset y))
3395 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3396 (:temporary (:sc long-reg :offset fr0-offset
3397 :from :argument :to :result) fr0)
3398 (:temporary (:sc long-reg :offset fr1-offset
3399 :from :argument :to :result) fr1)
3400 (:results (y :scs (long-reg)))
3401 (:arg-types long-float)
3402 (:result-types long-float)
3403 (:policy :fast-safe)
3404 (:note "inline log function")
3406 (:save-p :compute-only)
3408 (note-this-location vop :internal-error)
3423 ;; x is in a FP reg, not fr0 or fr1
3427 (inst fldd (make-random-tn :kind :normal
3428 :sc (sc-or-lose 'double-reg)
3429 :offset (1- (tn-offset x))))))
3431 ((long-stack descriptor-reg)
3435 (if (sc-is x long-stack)
3436 (inst fldl (ea-for-lf-stack x))
3437 (inst fldl (ea-for-lf-desc x)))
3442 (t (inst fstd y)))))
3444 (define-vop (flog10)
3446 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3447 (:temporary (:sc long-reg :offset fr0-offset
3448 :from :argument :to :result) fr0)
3449 (:temporary (:sc long-reg :offset fr1-offset
3450 :from :argument :to :result) fr1)
3451 (:results (y :scs (long-reg)))
3452 (:arg-types long-float)
3453 (:result-types long-float)
3454 (:policy :fast-safe)
3455 (:note "inline log10 function")
3457 (:save-p :compute-only)
3459 (note-this-location vop :internal-error)
3474 ;; x is in a FP reg, not fr0 or fr1
3478 (inst fldd (make-random-tn :kind :normal
3479 :sc (sc-or-lose 'double-reg)
3480 :offset (1- (tn-offset x))))))
3482 ((long-stack descriptor-reg)
3486 (if (sc-is x long-stack)
3487 (inst fldl (ea-for-lf-stack x))
3488 (inst fldl (ea-for-lf-desc x)))
3493 (t (inst fstd y)))))
3497 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3498 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3499 (:temporary (:sc long-reg :offset fr0-offset
3500 :from (:argument 0) :to :result) fr0)
3501 (:temporary (:sc long-reg :offset fr1-offset
3502 :from (:argument 1) :to :result) fr1)
3503 (:temporary (:sc long-reg :offset fr2-offset
3504 :from :load :to :result) fr2)
3505 (:results (r :scs (long-reg)))
3506 (:arg-types long-float long-float)
3507 (:result-types long-float)
3508 (:policy :fast-safe)
3509 (:note "inline pow function")
3511 (:save-p :compute-only)
3513 (note-this-location vop :internal-error)
3514 ;; Setup x in fr0 and y in fr1
3516 ;; x in fr0; y in fr1
3517 ((and (sc-is x long-reg) (zerop (tn-offset x))
3518 (sc-is y long-reg) (= 1 (tn-offset y))))
3519 ;; y in fr1; x not in fr0
3520 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3524 (copy-fp-reg-to-fr0 x))
3527 (inst fldl (ea-for-lf-stack x)))
3530 (inst fldl (ea-for-lf-desc x)))))
3531 ;; x in fr0; y not in fr1
3532 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3534 ;; Now load y to fr0
3537 (copy-fp-reg-to-fr0 y))
3540 (inst fldl (ea-for-lf-stack y)))
3543 (inst fldl (ea-for-lf-desc y))))
3545 ;; x in fr1; y not in fr1
3546 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3550 (copy-fp-reg-to-fr0 y))
3553 (inst fldl (ea-for-lf-stack y)))
3556 (inst fldl (ea-for-lf-desc y))))
3559 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3561 ;; Now load x to fr0
3564 (copy-fp-reg-to-fr0 x))
3567 (inst fldl (ea-for-lf-stack x)))
3570 (inst fldl (ea-for-lf-desc x)))))
3571 ;; Neither x or y are in either fr0 or fr1
3578 (inst fldd (make-random-tn :kind :normal
3579 :sc (sc-or-lose 'double-reg)
3580 :offset (- (tn-offset y) 2))))
3582 (inst fldl (ea-for-lf-stack y)))
3584 (inst fldl (ea-for-lf-desc y))))
3588 (inst fldd (make-random-tn :kind :normal
3589 :sc (sc-or-lose 'double-reg)
3590 :offset (1- (tn-offset x)))))
3592 (inst fldl (ea-for-lf-stack x)))
3594 (inst fldl (ea-for-lf-desc x))))))
3596 ;; Now have x at fr0; and y at fr1
3598 ;; Now fr0=y log2(x)
3602 (inst fsubp-sti fr1)
3605 (inst faddp-sti fr1)
3610 (t (inst fstd r)))))
3612 (define-vop (fscalen)
3613 (:translate %scalbn)
3614 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3615 (y :scs (signed-stack signed-reg) :target temp))
3616 (:temporary (:sc long-reg :offset fr0-offset
3617 :from (:argument 0) :to :result) fr0)
3618 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3619 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3620 (:results (r :scs (long-reg)))
3621 (:arg-types long-float signed-num)
3622 (:result-types long-float)
3623 (:policy :fast-safe)
3624 (:note "inline scalbn function")
3626 ;; Setup x in fr0 and y in fr1
3657 (inst fld (make-random-tn :kind :normal
3658 :sc (sc-or-lose 'double-reg)
3659 :offset (1- (tn-offset x)))))))
3660 ((long-stack descriptor-reg)
3669 (if (sc-is x long-stack)
3670 (inst fldl (ea-for-lf-stack x))
3671 (inst fldl (ea-for-lf-desc x)))))
3673 (unless (zerop (tn-offset r))
3676 (define-vop (fscale)
3678 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3679 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3680 (:temporary (:sc long-reg :offset fr0-offset
3681 :from (:argument 0) :to :result) fr0)
3682 (:temporary (:sc long-reg :offset fr1-offset
3683 :from (:argument 1) :to :result) fr1)
3684 (:results (r :scs (long-reg)))
3685 (:arg-types long-float long-float)
3686 (:result-types long-float)
3687 (:policy :fast-safe)
3688 (:note "inline scalb function")
3690 (:save-p :compute-only)
3692 (note-this-location vop :internal-error)
3693 ;; Setup x in fr0 and y in fr1
3695 ;; x in fr0; y in fr1
3696 ((and (sc-is x long-reg) (zerop (tn-offset x))
3697 (sc-is y long-reg) (= 1 (tn-offset y))))
3698 ;; y in fr1; x not in fr0
3699 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3703 (copy-fp-reg-to-fr0 x))
3706 (inst fldl (ea-for-lf-stack x)))
3709 (inst fldl (ea-for-lf-desc x)))))
3710 ;; x in fr0; y not in fr1
3711 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3713 ;; Now load y to fr0
3716 (copy-fp-reg-to-fr0 y))
3719 (inst fldl (ea-for-lf-stack y)))
3722 (inst fldl (ea-for-lf-desc y))))
3724 ;; x in fr1; y not in fr1
3725 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3729 (copy-fp-reg-to-fr0 y))
3732 (inst fldl (ea-for-lf-stack y)))
3735 (inst fldl (ea-for-lf-desc y))))
3738 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3740 ;; Now load x to fr0
3743 (copy-fp-reg-to-fr0 x))
3746 (inst fldl (ea-for-lf-stack x)))
3749 (inst fldl (ea-for-lf-desc x)))))
3750 ;; Neither x or y are in either fr0 or fr1
3757 (inst fldd (make-random-tn :kind :normal
3758 :sc (sc-or-lose 'double-reg)
3759 :offset (- (tn-offset y) 2))))
3761 (inst fldl (ea-for-lf-stack y)))
3763 (inst fldl (ea-for-lf-desc y))))
3767 (inst fldd (make-random-tn :kind :normal
3768 :sc (sc-or-lose 'double-reg)
3769 :offset (1- (tn-offset x)))))
3771 (inst fldl (ea-for-lf-stack x)))
3773 (inst fldl (ea-for-lf-desc x))))))
3775 ;; Now have x at fr0; and y at fr1
3777 (unless (zerop (tn-offset r))
3780 (define-vop (flog1p)
3782 (:args (x :scs (long-reg) :to :result))
3783 (:temporary (:sc long-reg :offset fr0-offset
3784 :from :argument :to :result) fr0)
3785 (:temporary (:sc long-reg :offset fr1-offset
3786 :from :argument :to :result) fr1)
3787 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3788 (:results (y :scs (long-reg)))
3789 (:arg-types long-float)
3790 (:result-types long-float)
3791 (:policy :fast-safe)
3792 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3793 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3794 ;; an enormous PROGN above. Still, it would be probably be good to
3795 ;; add some code to warn about redefining VOPs.
3796 (:note "inline log1p function")
3799 ;; x is in a FP reg, not fr0, fr1.
3802 (inst fldd (make-random-tn :kind :normal
3803 :sc (sc-or-lose 'double-reg)
3804 :offset (- (tn-offset x) 2)))
3806 (inst push #x3e947ae1) ; Constant 0.29
3808 (inst fld (make-ea :dword :base esp-tn))
3811 (inst fnstsw) ; status word to ax
3812 (inst and ah-tn #x45)
3813 (inst jmp :z WITHIN-RANGE)
3814 ;; Out of range for fyl2xp1.
3816 (inst faddd (make-random-tn :kind :normal
3817 :sc (sc-or-lose 'double-reg)
3818 :offset (- (tn-offset x) 1)))
3826 (inst fldd (make-random-tn :kind :normal
3827 :sc (sc-or-lose 'double-reg)
3828 :offset (- (tn-offset x) 1)))
3834 (t (inst fstd y)))))
3836 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3837 ;;; instruction and a range check can be avoided.
3838 (define-vop (flog1p-pentium)
3840 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3841 (:temporary (:sc long-reg :offset fr0-offset
3842 :from :argument :to :result) fr0)
3843 (:temporary (:sc long-reg :offset fr1-offset
3844 :from :argument :to :result) fr1)
3845 (:results (y :scs (long-reg)))
3846 (:arg-types long-float)
3847 (:result-types long-float)
3848 (:policy :fast-safe)
3849 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3850 (:note "inline log1p function")
3866 ;; x is in a FP reg, not fr0 or fr1
3870 (inst fldd (make-random-tn :kind :normal
3871 :sc (sc-or-lose 'double-reg)
3872 :offset (1- (tn-offset x)))))))
3873 ((long-stack descriptor-reg)
3877 (if (sc-is x long-stack)
3878 (inst fldl (ea-for-lf-stack x))
3879 (inst fldl (ea-for-lf-desc x)))))
3884 (t (inst fstd y)))))
3888 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3889 (:temporary (:sc long-reg :offset fr0-offset
3890 :from :argument :to :result) fr0)
3891 (:temporary (:sc long-reg :offset fr1-offset
3892 :from :argument :to :result) fr1)
3893 (:results (y :scs (long-reg)))
3894 (:arg-types long-float)
3895 (:result-types long-float)
3896 (:policy :fast-safe)
3897 (:note "inline logb function")
3899 (:save-p :compute-only)
3901 (note-this-location vop :internal-error)
3912 ;; x is in a FP reg, not fr0 or fr1
3915 (inst fldd (make-random-tn :kind :normal
3916 :sc (sc-or-lose 'double-reg)
3917 :offset (- (tn-offset x) 2))))))
3918 ((long-stack descriptor-reg)
3921 (if (sc-is x long-stack)
3922 (inst fldl (ea-for-lf-stack x))
3923 (inst fldl (ea-for-lf-desc x)))))
3934 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3935 (:temporary (:sc long-reg :offset fr0-offset
3936 :from (:argument 0) :to :result) fr0)
3937 (:temporary (:sc long-reg :offset fr1-offset
3938 :from (:argument 0) :to :result) fr1)
3939 (:results (r :scs (long-reg)))
3940 (:arg-types long-float)
3941 (:result-types long-float)
3942 (:policy :fast-safe)
3943 (:note "inline atan function")
3945 (:save-p :compute-only)
3947 (note-this-location vop :internal-error)
3948 ;; Setup x in fr1 and 1.0 in fr0
3951 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3954 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3956 ;; x not in fr0 or fr1
3963 (inst fldd (make-random-tn :kind :normal
3964 :sc (sc-or-lose 'double-reg)
3965 :offset (- (tn-offset x) 2))))
3967 (inst fldl (ea-for-lf-stack x)))
3969 (inst fldl (ea-for-lf-desc x))))))
3971 ;; Now have x at fr1; and 1.0 at fr0
3976 (t (inst fstd r)))))
3978 (define-vop (fatan2)
3980 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3981 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3982 (:temporary (:sc long-reg :offset fr0-offset
3983 :from (:argument 1) :to :result) fr0)
3984 (:temporary (:sc long-reg :offset fr1-offset
3985 :from (:argument 0) :to :result) fr1)
3986 (:results (r :scs (long-reg)))
3987 (:arg-types long-float long-float)
3988 (:result-types long-float)
3989 (:policy :fast-safe)
3990 (:note "inline atan2 function")
3992 (:save-p :compute-only)
3994 (note-this-location vop :internal-error)
3995 ;; Setup x in fr1 and y in fr0
3997 ;; y in fr0; x in fr1
3998 ((and (sc-is y long-reg) (zerop (tn-offset y))
3999 (sc-is x long-reg) (= 1 (tn-offset x))))
4000 ;; x in fr1; y not in fr0
4001 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
4005 (copy-fp-reg-to-fr0 y))
4008 (inst fldl (ea-for-lf-stack y)))
4011 (inst fldl (ea-for-lf-desc y)))))
4012 ;; y in fr0; x not in fr1
4013 ((and (sc-is y long-reg) (zerop (tn-offset y)))
4015 ;; Now load x to fr0
4018 (copy-fp-reg-to-fr0 x))
4021 (inst fldl (ea-for-lf-stack x)))
4024 (inst fldl (ea-for-lf-desc x))))
4026 ;; y in fr1; x not in fr1
4027 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
4031 (copy-fp-reg-to-fr0 x))
4034 (inst fldl (ea-for-lf-stack x)))
4037 (inst fldl (ea-for-lf-desc x))))
4040 ((and (sc-is x long-reg) (zerop (tn-offset x)))
4042 ;; Now load y to fr0
4045 (copy-fp-reg-to-fr0 y))
4048 (inst fldl (ea-for-lf-stack y)))
4051 (inst fldl (ea-for-lf-desc y)))))
4052 ;; Neither y or x are in either fr0 or fr1
4059 (inst fldd (make-random-tn :kind :normal
4060 :sc (sc-or-lose 'double-reg)
4061 :offset (- (tn-offset x) 2))))
4063 (inst fldl (ea-for-lf-stack x)))
4065 (inst fldl (ea-for-lf-desc x))))
4069 (inst fldd (make-random-tn :kind :normal
4070 :sc (sc-or-lose 'double-reg)
4071 :offset (1- (tn-offset y)))))
4073 (inst fldl (ea-for-lf-stack y)))
4075 (inst fldl (ea-for-lf-desc y))))))
4077 ;; Now have y at fr0; and x at fr1
4082 (t (inst fstd r)))))
4084 ) ; PROGN #!+LONG-FLOAT
4086 ;;;; complex float VOPs
4088 (define-vop (make-complex-single-float)
4089 (:translate complex)
4090 (:args (real :scs (single-reg) :to :result :target r
4091 :load-if (not (location= real r)))
4092 (imag :scs (single-reg) :to :save))
4093 (:arg-types single-float single-float)
4094 (:results (r :scs (complex-single-reg) :from (:argument 0)
4095 :load-if (not (sc-is r complex-single-stack))))
4096 (:result-types complex-single-float)
4097 (:note "inline complex single-float creation")
4098 (:policy :fast-safe)
4102 (let ((r-real (complex-double-reg-real-tn r)))
4103 (unless (location= real r-real)
4104 (cond ((zerop (tn-offset r-real))
4105 (copy-fp-reg-to-fr0 real))
4106 ((zerop (tn-offset real))
4111 (inst fxch real)))))
4112 (let ((r-imag (complex-double-reg-imag-tn r)))
4113 (unless (location= imag r-imag)
4114 (cond ((zerop (tn-offset imag))
4119 (inst fxch imag))))))
4120 (complex-single-stack
4121 (unless (location= real r)
4122 (cond ((zerop (tn-offset real))
4123 (inst fst (ea-for-csf-real-stack r)))
4126 (inst fst (ea-for-csf-real-stack r))
4129 (inst fst (ea-for-csf-imag-stack r))
4130 (inst fxch imag)))))
4132 (define-vop (make-complex-double-float)
4133 (:translate complex)
4134 (:args (real :scs (double-reg) :target r
4135 :load-if (not (location= real r)))
4136 (imag :scs (double-reg) :to :save))
4137 (:arg-types double-float double-float)
4138 (:results (r :scs (complex-double-reg) :from (:argument 0)
4139 :load-if (not (sc-is r complex-double-stack))))
4140 (:result-types complex-double-float)
4141 (:note "inline complex double-float creation")
4142 (:policy :fast-safe)
4146 (let ((r-real (complex-double-reg-real-tn r)))
4147 (unless (location= real r-real)
4148 (cond ((zerop (tn-offset r-real))
4149 (copy-fp-reg-to-fr0 real))
4150 ((zerop (tn-offset real))
4155 (inst fxch real)))))
4156 (let ((r-imag (complex-double-reg-imag-tn r)))
4157 (unless (location= imag r-imag)
4158 (cond ((zerop (tn-offset imag))
4163 (inst fxch imag))))))
4164 (complex-double-stack
4165 (unless (location= real r)
4166 (cond ((zerop (tn-offset real))
4167 (inst fstd (ea-for-cdf-real-stack r)))
4170 (inst fstd (ea-for-cdf-real-stack r))
4173 (inst fstd (ea-for-cdf-imag-stack r))
4174 (inst fxch imag)))))
4177 (define-vop (make-complex-long-float)
4178 (:translate complex)
4179 (:args (real :scs (long-reg) :target r
4180 :load-if (not (location= real r)))
4181 (imag :scs (long-reg) :to :save))
4182 (:arg-types long-float long-float)
4183 (:results (r :scs (complex-long-reg) :from (:argument 0)
4184 :load-if (not (sc-is r complex-long-stack))))
4185 (:result-types complex-long-float)
4186 (:note "inline complex long-float creation")
4187 (:policy :fast-safe)
4191 (let ((r-real (complex-double-reg-real-tn r)))
4192 (unless (location= real r-real)
4193 (cond ((zerop (tn-offset r-real))
4194 (copy-fp-reg-to-fr0 real))
4195 ((zerop (tn-offset real))
4200 (inst fxch real)))))
4201 (let ((r-imag (complex-double-reg-imag-tn r)))
4202 (unless (location= imag r-imag)
4203 (cond ((zerop (tn-offset imag))
4208 (inst fxch imag))))))
4210 (unless (location= real r)
4211 (cond ((zerop (tn-offset real))
4212 (store-long-float (ea-for-clf-real-stack r)))
4215 (store-long-float (ea-for-clf-real-stack r))
4218 (store-long-float (ea-for-clf-imag-stack r))
4219 (inst fxch imag)))))
4222 (define-vop (complex-float-value)
4223 (:args (x :target r))
4225 (:variant-vars offset)
4226 (:policy :fast-safe)
4228 (cond ((sc-is x complex-single-reg complex-double-reg
4229 #!+long-float complex-long-reg)
4231 (make-random-tn :kind :normal
4232 :sc (sc-or-lose 'double-reg)
4233 :offset (+ offset (tn-offset x)))))
4234 (unless (location= value-tn r)
4235 (cond ((zerop (tn-offset r))
4236 (copy-fp-reg-to-fr0 value-tn))
4237 ((zerop (tn-offset value-tn))
4240 (inst fxch value-tn)
4242 (inst fxch value-tn))))))
4243 ((sc-is r single-reg)
4244 (let ((ea (sc-case x
4245 (complex-single-stack
4247 (0 (ea-for-csf-real-stack x))
4248 (1 (ea-for-csf-imag-stack x))))
4251 (0 (ea-for-csf-real-desc x))
4252 (1 (ea-for-csf-imag-desc x)))))))
4253 (with-empty-tn@fp-top(r)
4255 ((sc-is r double-reg)
4256 (let ((ea (sc-case x
4257 (complex-double-stack
4259 (0 (ea-for-cdf-real-stack x))
4260 (1 (ea-for-cdf-imag-stack x))))
4263 (0 (ea-for-cdf-real-desc x))
4264 (1 (ea-for-cdf-imag-desc x)))))))
4265 (with-empty-tn@fp-top(r)
4269 (let ((ea (sc-case x
4272 (0 (ea-for-clf-real-stack x))
4273 (1 (ea-for-clf-imag-stack x))))
4276 (0 (ea-for-clf-real-desc x))
4277 (1 (ea-for-clf-imag-desc x)))))))
4278 (with-empty-tn@fp-top(r)
4280 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4282 (define-vop (realpart/complex-single-float complex-float-value)
4283 (:translate realpart)
4284 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4286 (:arg-types complex-single-float)
4287 (:results (r :scs (single-reg)))
4288 (:result-types single-float)
4289 (:note "complex float realpart")
4292 (define-vop (realpart/complex-double-float complex-float-value)
4293 (:translate realpart)
4294 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4296 (:arg-types complex-double-float)
4297 (:results (r :scs (double-reg)))
4298 (:result-types double-float)
4299 (:note "complex float realpart")
4303 (define-vop (realpart/complex-long-float complex-float-value)
4304 (:translate realpart)
4305 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4307 (:arg-types complex-long-float)
4308 (:results (r :scs (long-reg)))
4309 (:result-types long-float)
4310 (:note "complex float realpart")
4313 (define-vop (imagpart/complex-single-float complex-float-value)
4314 (:translate imagpart)
4315 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4317 (:arg-types complex-single-float)
4318 (:results (r :scs (single-reg)))
4319 (:result-types single-float)
4320 (:note "complex float imagpart")
4323 (define-vop (imagpart/complex-double-float complex-float-value)
4324 (:translate imagpart)
4325 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4327 (:arg-types complex-double-float)
4328 (:results (r :scs (double-reg)))
4329 (:result-types double-float)
4330 (:note "complex float imagpart")
4334 (define-vop (imagpart/complex-long-float complex-float-value)
4335 (:translate imagpart)
4336 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4338 (:arg-types complex-long-float)
4339 (:results (r :scs (long-reg)))
4340 (:result-types long-float)
4341 (:note "complex float imagpart")
4344 ;;; hack dummy VOPs to bias the representation selection of their
4345 ;;; arguments towards a FP register, which can help avoid consing at
4346 ;;; inappropriate locations
4347 (defknown double-float-reg-bias (double-float) (values))
4348 (define-vop (double-float-reg-bias)
4349 (:translate double-float-reg-bias)
4350 (:args (x :scs (double-reg double-stack) :load-if nil))
4351 (:arg-types double-float)
4352 (:policy :fast-safe)
4353 (:note "inline dummy FP register bias")
4356 (defknown single-float-reg-bias (single-float) (values))
4357 (define-vop (single-float-reg-bias)
4358 (:translate single-float-reg-bias)
4359 (:args (x :scs (single-reg single-stack) :load-if nil))
4360 (:arg-types single-float)
4361 (:policy :fast-safe)
4362 (:note "inline dummy FP register bias")