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 (macrolet ((frob (name translate from-sc from-type to-sc to-type
1652 &optional to-stack-sc store-inst load-inst)
1653 `(define-vop (,name)
1654 (:args (x :scs (,from-sc) :target y))
1656 `((:temporary (:sc ,to-stack-sc) temp)))
1657 (:results (y :scs (,to-sc)))
1658 (:arg-types ,from-type)
1659 (:result-types ,to-type)
1660 (:policy :fast-safe)
1661 (:note "inline float coercion")
1662 (:translate ,translate)
1664 (:save-p :compute-only)
1666 (note-this-location vop :internal-error)
1670 (inst ,store-inst temp))
1671 (with-empty-tn@fp-top (y)
1672 (inst ,load-inst temp)))
1673 `(unless (location= x y)
1675 ((zerop (tn-offset x))
1676 ;; x is in ST0, y is in another reg. not ST0
1678 ((zerop (tn-offset y))
1679 ;; y is in ST0, x is in another reg. not ST0
1680 (copy-fp-reg-to-fr0 x))
1682 ;; Neither x or y are in ST0, and they are not in
1686 (inst fxch x)))))))))
1688 (frob %single-float/double-float %single-float double-reg double-float
1689 single-reg single-float
1690 single-stack fst fld)
1692 (frob %single-float/long-float %single-float long-reg
1693 long-float single-reg single-float
1694 single-stack fst fld)
1695 (frob %double-float/single-float %double-float single-reg single-float
1696 double-reg double-float)
1698 (frob %double-float/long-float %double-float long-reg long-float
1699 double-reg double-float
1700 double-stack fstd fldd)
1702 (frob %long-float/single-float %long-float single-reg single-float
1703 long-reg long-float)
1705 (frob %long-float/double-float %long-float double-reg double-float
1706 long-reg long-float))
1708 (macrolet ((frob (trans from-sc from-type round-p)
1709 `(define-vop (,(symbolicate trans "/" from-type))
1710 (:args (x :scs (,from-sc)))
1711 (:temporary (:sc signed-stack) stack-temp)
1713 '((:temporary (:sc unsigned-stack) scw)
1714 (:temporary (:sc any-reg) rcw)))
1715 (:results (y :scs (signed-reg)))
1716 (:arg-types ,from-type)
1717 (:result-types signed-num)
1719 (:policy :fast-safe)
1720 (:note "inline float truncate")
1722 (:save-p :compute-only)
1725 '((note-this-location vop :internal-error)
1726 ;; Catch any pending FPE exceptions.
1728 (,(if round-p 'progn 'pseudo-atomic)
1729 ;; Normal mode (for now) is "round to best".
1732 '((inst fnstcw scw) ; save current control word
1733 (move rcw scw) ; into 16-bit register
1734 (inst or rcw (ash #b11 10)) ; CHOP
1735 (move stack-temp rcw)
1736 (inst fldcw stack-temp)))
1741 (inst fist stack-temp)
1742 (inst mov y stack-temp)))
1744 '((inst fldcw scw)))))))))
1745 (frob %unary-truncate/single-float single-reg single-float nil)
1746 (frob %unary-truncate/double-float double-reg double-float nil)
1748 (frob %unary-truncate/long-float long-reg long-float nil)
1749 (frob %unary-round single-reg single-float t)
1750 (frob %unary-round double-reg double-float t)
1752 (frob %unary-round long-reg long-float t))
1754 (macrolet ((frob (trans from-sc from-type round-p)
1755 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1756 (:args (x :scs (,from-sc) :target fr0))
1757 (:temporary (:sc double-reg :offset fr0-offset
1758 :from :argument :to :result) fr0)
1760 '((:temporary (:sc unsigned-stack) stack-temp)
1761 (:temporary (:sc unsigned-stack) scw)
1762 (:temporary (:sc any-reg) rcw)))
1763 (:results (y :scs (unsigned-reg)))
1764 (:arg-types ,from-type)
1765 (:result-types unsigned-num)
1767 (:policy :fast-safe)
1768 (:note "inline float truncate")
1770 (:save-p :compute-only)
1773 '((note-this-location vop :internal-error)
1774 ;; Catch any pending FPE exceptions.
1776 ;; Normal mode (for now) is "round to best".
1777 (unless (zerop (tn-offset x))
1778 (copy-fp-reg-to-fr0 x))
1780 '((inst fnstcw scw) ; save current control word
1781 (move rcw scw) ; into 16-bit register
1782 (inst or rcw (ash #b11 10)) ; CHOP
1783 (move stack-temp rcw)
1784 (inst fldcw stack-temp)))
1786 (inst fistpl (make-ea :dword :base esp-tn))
1788 (inst fld fr0) ; copy fr0 to at least restore stack.
1791 '((inst fldcw scw)))))))
1792 (frob %unary-truncate/single-float single-reg single-float nil)
1793 (frob %unary-truncate/double-float double-reg double-float nil)
1795 (frob %unary-truncate/long-float long-reg long-float nil)
1796 (frob %unary-round single-reg single-float t)
1797 (frob %unary-round double-reg double-float t)
1799 (frob %unary-round long-reg long-float t))
1801 (define-vop (make-single-float)
1802 (:args (bits :scs (signed-reg) :target res
1803 :load-if (not (or (and (sc-is bits signed-stack)
1804 (sc-is res single-reg))
1805 (and (sc-is bits signed-stack)
1806 (sc-is res single-stack)
1807 (location= bits res))))))
1808 (:results (res :scs (single-reg single-stack)))
1809 (:temporary (:sc signed-stack) stack-temp)
1810 (:arg-types signed-num)
1811 (:result-types single-float)
1812 (:translate make-single-float)
1813 (:policy :fast-safe)
1820 (inst mov res bits))
1822 (aver (location= bits res)))))
1826 ;; source must be in memory
1827 (inst mov stack-temp bits)
1828 (with-empty-tn@fp-top(res)
1829 (inst fld stack-temp)))
1831 (with-empty-tn@fp-top(res)
1832 (inst fld bits))))))))
1834 (define-vop (make-single-float-c)
1835 (:results (res :scs (single-reg single-stack)))
1836 (:arg-types (:constant (signed-byte 32)))
1837 (:result-types single-float)
1839 (:translate make-single-float)
1840 (:policy :fast-safe)
1845 (inst mov res bits))
1847 (with-empty-tn@fp-top (res)
1848 (inst fld (register-inline-constant :dword bits)))))))
1850 (define-vop (make-double-float)
1851 (:args (hi-bits :scs (signed-reg))
1852 (lo-bits :scs (unsigned-reg)))
1853 (:results (res :scs (double-reg)))
1854 (:temporary (:sc double-stack) temp)
1855 (:arg-types signed-num unsigned-num)
1856 (:result-types double-float)
1857 (:translate make-double-float)
1858 (:policy :fast-safe)
1861 (let ((offset (tn-offset temp)))
1862 (storew hi-bits ebp-tn (frame-word-offset offset))
1863 (storew lo-bits ebp-tn (frame-word-offset (1+ offset)))
1864 (with-empty-tn@fp-top(res)
1865 (inst fldd (make-ea :dword :base ebp-tn
1866 :disp (frame-byte-offset (1+ offset))))))))
1868 (define-vop (make-double-float-c)
1869 (:results (res :scs (double-reg)))
1870 (:arg-types (:constant (signed-byte 32)) (:constant (unsigned-byte 32)))
1871 (:result-types double-float)
1873 (:translate make-double-float)
1874 (:policy :fast-safe)
1877 (with-empty-tn@fp-top(res)
1878 (inst fldd (register-inline-constant
1879 :double-float-bits (logior (ash hi 32) lo))))))
1882 (define-vop (make-long-float)
1883 (:args (exp-bits :scs (signed-reg))
1884 (hi-bits :scs (unsigned-reg))
1885 (lo-bits :scs (unsigned-reg)))
1886 (:results (res :scs (long-reg)))
1887 (:temporary (:sc long-stack) temp)
1888 (:arg-types signed-num unsigned-num unsigned-num)
1889 (:result-types long-float)
1890 (:translate make-long-float)
1891 (:policy :fast-safe)
1894 (let ((offset (tn-offset temp)))
1895 (storew exp-bits ebp-tn (frame-word-offset offset))
1896 (storew hi-bits ebp-tn (frame-word-offset (1+ offset)))
1897 (storew lo-bits ebp-tn (frame-word-offset (+ offset 2)))
1898 (with-empty-tn@fp-top(res)
1899 (inst fldl (make-ea :dword :base ebp-tn
1900 :disp (frame-byte-offset (+ offset 2))))))))
1902 (define-vop (single-float-bits)
1903 (:args (float :scs (single-reg descriptor-reg)
1904 :load-if (not (sc-is float single-stack))))
1905 (:results (bits :scs (signed-reg)))
1906 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1907 (:arg-types single-float)
1908 (:result-types signed-num)
1909 (:translate single-float-bits)
1910 (:policy :fast-safe)
1917 (with-tn@fp-top(float)
1918 (inst fst stack-temp)
1919 (inst mov bits stack-temp)))
1921 (inst mov bits float))
1924 bits float single-float-value-slot
1925 other-pointer-lowtag))))
1929 (with-tn@fp-top(float)
1930 (inst fst bits))))))))
1932 (define-vop (double-float-high-bits)
1933 (:args (float :scs (double-reg descriptor-reg)
1934 :load-if (not (sc-is float double-stack))))
1935 (:results (hi-bits :scs (signed-reg)))
1936 (:temporary (:sc double-stack) temp)
1937 (:arg-types double-float)
1938 (:result-types signed-num)
1939 (:translate double-float-high-bits)
1940 (:policy :fast-safe)
1945 (with-tn@fp-top(float)
1946 (let ((where (make-ea :dword :base ebp-tn
1947 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1949 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset temp))))
1951 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1953 (loadw hi-bits float (1+ double-float-value-slot)
1954 other-pointer-lowtag)))))
1956 (define-vop (double-float-low-bits)
1957 (:args (float :scs (double-reg descriptor-reg)
1958 :load-if (not (sc-is float double-stack))))
1959 (:results (lo-bits :scs (unsigned-reg)))
1960 (:temporary (:sc double-stack) temp)
1961 (:arg-types double-float)
1962 (:result-types unsigned-num)
1963 (:translate double-float-low-bits)
1964 (:policy :fast-safe)
1969 (with-tn@fp-top(float)
1970 (let ((where (make-ea :dword :base ebp-tn
1971 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1973 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1975 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset float)))))
1977 (loadw lo-bits float double-float-value-slot
1978 other-pointer-lowtag)))))
1981 (define-vop (long-float-exp-bits)
1982 (:args (float :scs (long-reg descriptor-reg)
1983 :load-if (not (sc-is float long-stack))))
1984 (:results (exp-bits :scs (signed-reg)))
1985 (:temporary (:sc long-stack) temp)
1986 (:arg-types long-float)
1987 (:result-types signed-num)
1988 (:translate long-float-exp-bits)
1989 (:policy :fast-safe)
1994 (with-tn@fp-top(float)
1995 (let ((where (make-ea :dword :base ebp-tn
1996 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1997 (store-long-float where)))
1998 (inst movsx exp-bits
1999 (make-ea :word :base ebp-tn
2000 :disp (frame-byte-offset (tn-offset temp)))))
2002 (inst movsx exp-bits
2003 (make-ea :word :base ebp-tn
2004 :disp (frame-byte-offset (tn-offset temp)))))
2006 (inst movsx exp-bits
2007 (make-ea-for-object-slot float (+ 2 long-float-value-slot)
2008 other-pointer-lowtag :word))))))
2011 (define-vop (long-float-high-bits)
2012 (:args (float :scs (long-reg descriptor-reg)
2013 :load-if (not (sc-is float long-stack))))
2014 (:results (hi-bits :scs (unsigned-reg)))
2015 (:temporary (:sc long-stack) temp)
2016 (:arg-types long-float)
2017 (:result-types unsigned-num)
2018 (:translate long-float-high-bits)
2019 (:policy :fast-safe)
2024 (with-tn@fp-top(float)
2025 (let ((where (make-ea :dword :base ebp-tn
2026 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2027 (store-long-float where)))
2028 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
2030 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
2032 (loadw hi-bits float (1+ long-float-value-slot)
2033 other-pointer-lowtag)))))
2036 (define-vop (long-float-low-bits)
2037 (:args (float :scs (long-reg descriptor-reg)
2038 :load-if (not (sc-is float long-stack))))
2039 (:results (lo-bits :scs (unsigned-reg)))
2040 (:temporary (:sc long-stack) temp)
2041 (:arg-types long-float)
2042 (:result-types unsigned-num)
2043 (:translate long-float-low-bits)
2044 (:policy :fast-safe)
2049 (with-tn@fp-top(float)
2050 (let ((where (make-ea :dword :base ebp-tn
2051 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2052 (store-long-float where)))
2053 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset temp) 2))))
2055 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset float) 2))))
2057 (loadw lo-bits float long-float-value-slot
2058 other-pointer-lowtag)))))
2060 ;;;; float mode hackery
2062 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2063 (defknown floating-point-modes () float-modes (flushable))
2064 (defknown ((setf floating-point-modes)) (float-modes)
2067 (def!constant npx-env-size (* 7 n-word-bytes))
2068 (def!constant npx-cw-offset 0)
2069 (def!constant npx-sw-offset 4)
2071 (define-vop (floating-point-modes)
2072 (:results (res :scs (unsigned-reg)))
2073 (:result-types unsigned-num)
2074 (:translate floating-point-modes)
2075 (:policy :fast-safe)
2076 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2079 (inst sub esp-tn npx-env-size) ; Make space on stack.
2080 (inst wait) ; Catch any pending FPE exceptions
2081 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2082 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2083 ;; Move current status to high word.
2084 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2085 ;; Move exception mask to low word.
2086 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2087 (inst add esp-tn npx-env-size) ; Pop stack.
2088 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2091 (define-vop (set-floating-point-modes)
2092 (:args (new :scs (unsigned-reg) :to :result :target res))
2093 (:results (res :scs (unsigned-reg)))
2094 (:arg-types unsigned-num)
2095 (:result-types unsigned-num)
2096 (:translate (setf floating-point-modes))
2097 (:policy :fast-safe)
2098 (:temporary (:sc unsigned-reg :offset eax-offset
2099 :from :eval :to :result) eax)
2101 (inst sub esp-tn npx-env-size) ; Make space on stack.
2102 (inst wait) ; Catch any pending FPE exceptions.
2103 (inst fstenv (make-ea :dword :base esp-tn))
2105 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2106 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2107 (inst shr eax 16) ; position status word
2108 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2109 (inst fldenv (make-ea :dword :base esp-tn))
2110 (inst add esp-tn npx-env-size) ; Pop stack.
2116 ;;; Let's use some of the 80387 special functions.
2118 ;;; These defs will not take effect unless code/irrat.lisp is modified
2119 ;;; to remove the inlined alien routine def.
2121 (macrolet ((frob (func trans op)
2122 `(define-vop (,func)
2123 (:args (x :scs (double-reg) :target fr0))
2124 (:temporary (:sc double-reg :offset fr0-offset
2125 :from :argument :to :result) fr0)
2127 (:results (y :scs (double-reg)))
2128 (:arg-types double-float)
2129 (:result-types double-float)
2131 (:policy :fast-safe)
2132 (:note "inline NPX function")
2134 (:save-p :compute-only)
2137 (note-this-location vop :internal-error)
2138 (unless (zerop (tn-offset x))
2139 (inst fxch x) ; x to top of stack
2140 (unless (location= x y)
2141 (inst fst x))) ; maybe save it
2142 (inst ,op) ; clobber st0
2143 (cond ((zerop (tn-offset y))
2144 (maybe-fp-wait node))
2148 ;; Quick versions of fsin and fcos that require the argument to be
2149 ;; within range 2^63.
2150 (frob fsin-quick %sin-quick fsin)
2151 (frob fcos-quick %cos-quick fcos)
2152 (frob fsqrt %sqrt fsqrt))
2154 ;;; Quick version of ftan that requires the argument to be within
2156 (define-vop (ftan-quick)
2157 (:translate %tan-quick)
2158 (:args (x :scs (double-reg) :target fr0))
2159 (:temporary (:sc double-reg :offset fr0-offset
2160 :from :argument :to :result) fr0)
2161 (:temporary (:sc double-reg :offset fr1-offset
2162 :from :argument :to :result) fr1)
2163 (:results (y :scs (double-reg)))
2164 (:arg-types double-float)
2165 (:result-types double-float)
2166 (:policy :fast-safe)
2167 (:note "inline tan function")
2169 (:save-p :compute-only)
2171 (note-this-location vop :internal-error)
2180 (inst fldd (make-random-tn :kind :normal
2181 :sc (sc-or-lose 'double-reg)
2182 :offset (- (tn-offset x) 2)))))
2193 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2194 ;;; result if the argument is out of range 2^63 and would thus be
2195 ;;; hopelessly inaccurate.
2196 (macrolet ((frob (func trans op)
2197 `(define-vop (,func)
2199 (:args (x :scs (double-reg) :target fr0))
2200 (:temporary (:sc double-reg :offset fr0-offset
2201 :from :argument :to :result) fr0)
2202 ;; FIXME: make that an arbitrary location and
2203 ;; FXCH only when range reduction needed
2204 (:temporary (:sc double-reg :offset fr1-offset
2205 :from :argument :to :result) fr1)
2206 (:temporary (:sc unsigned-reg :offset eax-offset
2207 :from :argument :to :result) eax)
2208 (:results (y :scs (double-reg)))
2209 (:arg-types double-float)
2210 (:result-types double-float)
2211 (:policy :fast-safe)
2212 (:note "inline sin/cos function")
2214 (:save-p :compute-only)
2217 (let ((DONE (gen-label))
2218 (REDUCE (gen-label))
2219 (REDUCE-LOOP (gen-label)))
2220 (note-this-location vop :internal-error)
2221 (unless (zerop (tn-offset x))
2222 (inst fxch x) ; x to top of stack
2223 (unless (location= x y)
2224 (inst fst x))) ; maybe save it
2226 (inst fnstsw) ; status word to ax
2227 (inst and ah-tn #x04) ; C2
2228 (inst jmp :nz REDUCE)
2230 (unless (zerop (tn-offset y))
2232 (assemble (*elsewhere*)
2234 ;; Else x was out of range so reduce it; ST0 is unchanged.
2235 (with-empty-tn@fp-top (fr1)
2238 (emit-label REDUCE-LOOP)
2241 (inst and ah-tn #x04)
2242 (inst jmp :nz REDUCE-LOOP)
2244 (inst jmp DONE)))))))
2245 (frob fsin %sin fsin)
2246 (frob fcos %cos fcos))
2250 (:args (x :scs (double-reg) :target fr0))
2251 (:temporary (:sc double-reg :offset fr0-offset
2252 :from :argument :to :result) fr0)
2253 (:temporary (:sc double-reg :offset fr1-offset
2254 :from :argument :to :result) fr1)
2255 (:temporary (:sc unsigned-reg :offset eax-offset
2256 :from :argument :to :result) eax)
2257 (:results (y :scs (double-reg)))
2258 (:arg-types double-float)
2259 (:result-types double-float)
2261 (:policy :fast-safe)
2262 (:note "inline tan function")
2264 (:save-p :compute-only)
2267 (note-this-location vop :internal-error)
2276 (inst fldd (make-random-tn :kind :normal
2277 :sc (sc-or-lose 'double-reg)
2278 :offset (- (tn-offset x) 2)))))
2280 (let ((REDUCE (gen-label))
2281 (REDUCE-LOOP (gen-label)))
2282 (inst fnstsw) ; status word to ax
2283 (inst and ah-tn #x04) ; C2
2284 (inst jmp :nz REDUCE)
2285 (assemble (*elsewhere*)
2287 ;; Else x was out of range so reduce it; ST0 is unchanged.
2288 (with-empty-tn@fp-top (fr1)
2291 (emit-label REDUCE-LOOP)
2294 (inst and ah-tn #x04)
2295 (inst jmp :nz REDUCE-LOOP)
2308 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2309 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2312 (:args (x :scs (double-reg) :target fr0))
2313 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2314 (:temporary (:sc double-reg :offset fr0-offset
2315 :from :argument :to :result) fr0)
2316 (:temporary (:sc double-reg :offset fr1-offset
2317 :from :argument :to :result) fr1)
2318 (:temporary (:sc double-reg :offset fr2-offset
2319 :from :argument :to :result) fr2)
2320 (:results (y :scs (double-reg)))
2321 (:arg-types double-float)
2322 (:result-types double-float)
2323 (:policy :fast-safe)
2324 (:note "inline exp function")
2326 (:save-p :compute-only)
2329 (note-this-location vop :internal-error)
2330 (unless (zerop (tn-offset x))
2331 (inst fxch x) ; x to top of stack
2332 (unless (location= x y)
2333 (inst fst x))) ; maybe save it
2334 ;; Check for Inf or NaN
2338 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2339 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2340 (inst and ah-tn #x02) ; Test sign of Inf.
2341 (inst jmp :z DONE) ; +Inf gives +Inf.
2342 (inst fstp fr0) ; -Inf gives 0
2344 (inst jmp-short DONE)
2349 ;; Now fr0=x log2(e)
2353 (inst fsubp-sti fr1)
2356 (inst faddp-sti fr1)
2360 (unless (zerop (tn-offset y))
2363 ;;; Expm1 = exp(x) - 1.
2364 ;;; Handles the following special cases:
2365 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2366 (define-vop (fexpm1)
2368 (:args (x :scs (double-reg) :target fr0))
2369 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2370 (:temporary (:sc double-reg :offset fr0-offset
2371 :from :argument :to :result) fr0)
2372 (:temporary (:sc double-reg :offset fr1-offset
2373 :from :argument :to :result) fr1)
2374 (:temporary (:sc double-reg :offset fr2-offset
2375 :from :argument :to :result) fr2)
2376 (:results (y :scs (double-reg)))
2377 (:arg-types double-float)
2378 (:result-types double-float)
2379 (:policy :fast-safe)
2380 (:note "inline expm1 function")
2382 (:save-p :compute-only)
2385 (note-this-location vop :internal-error)
2386 (unless (zerop (tn-offset x))
2387 (inst fxch x) ; x to top of stack
2388 (unless (location= x y)
2389 (inst fst x))) ; maybe save it
2390 ;; Check for Inf or NaN
2394 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2395 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2396 (inst and ah-tn #x02) ; Test sign of Inf.
2397 (inst jmp :z DONE) ; +Inf gives +Inf.
2398 (inst fstp fr0) ; -Inf gives -1.0
2401 (inst jmp-short DONE)
2403 ;; Free two stack slots leaving the argument on top.
2407 (inst fmul fr1) ; Now fr0 = x log2(e)
2422 (unless (zerop (tn-offset y))
2427 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2428 (:temporary (:sc double-reg :offset fr0-offset
2429 :from :argument :to :result) fr0)
2430 (:temporary (:sc double-reg :offset fr1-offset
2431 :from :argument :to :result) fr1)
2432 (:results (y :scs (double-reg)))
2433 (:arg-types double-float)
2434 (:result-types double-float)
2435 (:policy :fast-safe)
2436 (:note "inline log function")
2438 (:save-p :compute-only)
2440 (note-this-location vop :internal-error)
2455 ;; x is in a FP reg, not fr0 or fr1
2459 (inst fldd (make-random-tn :kind :normal
2460 :sc (sc-or-lose 'double-reg)
2461 :offset (1- (tn-offset x))))))
2463 ((double-stack descriptor-reg)
2467 (if (sc-is x double-stack)
2468 (inst fldd (ea-for-df-stack x))
2469 (inst fldd (ea-for-df-desc x)))
2474 (t (inst fstd y)))))
2476 (define-vop (flog10)
2478 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2479 (:temporary (:sc double-reg :offset fr0-offset
2480 :from :argument :to :result) fr0)
2481 (:temporary (:sc double-reg :offset fr1-offset
2482 :from :argument :to :result) fr1)
2483 (:results (y :scs (double-reg)))
2484 (:arg-types double-float)
2485 (:result-types double-float)
2486 (:policy :fast-safe)
2487 (:note "inline log10 function")
2489 (:save-p :compute-only)
2491 (note-this-location vop :internal-error)
2506 ;; x is in a FP reg, not fr0 or fr1
2510 (inst fldd (make-random-tn :kind :normal
2511 :sc (sc-or-lose 'double-reg)
2512 :offset (1- (tn-offset x))))))
2514 ((double-stack descriptor-reg)
2518 (if (sc-is x double-stack)
2519 (inst fldd (ea-for-df-stack x))
2520 (inst fldd (ea-for-df-desc x)))
2525 (t (inst fstd y)))))
2529 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2530 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2531 (:temporary (:sc double-reg :offset fr0-offset
2532 :from (:argument 0) :to :result) fr0)
2533 (:temporary (:sc double-reg :offset fr1-offset
2534 :from (:argument 1) :to :result) fr1)
2535 (:temporary (:sc double-reg :offset fr2-offset
2536 :from :load :to :result) fr2)
2537 (:results (r :scs (double-reg)))
2538 (:arg-types double-float double-float)
2539 (:result-types double-float)
2540 (:policy :fast-safe)
2541 (:note "inline pow function")
2543 (:save-p :compute-only)
2545 (note-this-location vop :internal-error)
2546 ;; Setup x in fr0 and y in fr1
2548 ;; x in fr0; y in fr1
2549 ((and (sc-is x double-reg) (zerop (tn-offset x))
2550 (sc-is y double-reg) (= 1 (tn-offset y))))
2551 ;; y in fr1; x not in fr0
2552 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2556 (copy-fp-reg-to-fr0 x))
2559 (inst fldd (ea-for-df-stack x)))
2562 (inst fldd (ea-for-df-desc x)))))
2563 ;; x in fr0; y not in fr1
2564 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2566 ;; Now load y to fr0
2569 (copy-fp-reg-to-fr0 y))
2572 (inst fldd (ea-for-df-stack y)))
2575 (inst fldd (ea-for-df-desc y))))
2577 ;; x in fr1; y not in fr1
2578 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2582 (copy-fp-reg-to-fr0 y))
2585 (inst fldd (ea-for-df-stack y)))
2588 (inst fldd (ea-for-df-desc y))))
2591 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2593 ;; Now load x to fr0
2596 (copy-fp-reg-to-fr0 x))
2599 (inst fldd (ea-for-df-stack x)))
2602 (inst fldd (ea-for-df-desc x)))))
2603 ;; Neither x or y are in either fr0 or fr1
2610 (inst fldd (make-random-tn :kind :normal
2611 :sc (sc-or-lose 'double-reg)
2612 :offset (- (tn-offset y) 2))))
2614 (inst fldd (ea-for-df-stack y)))
2616 (inst fldd (ea-for-df-desc y))))
2620 (inst fldd (make-random-tn :kind :normal
2621 :sc (sc-or-lose 'double-reg)
2622 :offset (1- (tn-offset x)))))
2624 (inst fldd (ea-for-df-stack x)))
2626 (inst fldd (ea-for-df-desc x))))))
2628 ;; Now have x at fr0; and y at fr1
2630 ;; Now fr0=y log2(x)
2634 (inst fsubp-sti fr1)
2637 (inst faddp-sti fr1)
2642 (t (inst fstd r)))))
2644 (define-vop (fscalen)
2645 (:translate %scalbn)
2646 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2647 (y :scs (signed-stack signed-reg) :target temp))
2648 (:temporary (:sc double-reg :offset fr0-offset
2649 :from (:argument 0) :to :result) fr0)
2650 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2651 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2652 (:results (r :scs (double-reg)))
2653 (:arg-types double-float signed-num)
2654 (:result-types double-float)
2655 (:policy :fast-safe)
2656 (:note "inline scalbn function")
2658 ;; Setup x in fr0 and y in fr1
2689 (inst fld (make-random-tn :kind :normal
2690 :sc (sc-or-lose 'double-reg)
2691 :offset (1- (tn-offset x)))))))
2692 ((double-stack descriptor-reg)
2701 (if (sc-is x double-stack)
2702 (inst fldd (ea-for-df-stack x))
2703 (inst fldd (ea-for-df-desc x)))))
2705 (unless (zerop (tn-offset r))
2708 (define-vop (fscale)
2710 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2711 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2712 (:temporary (:sc double-reg :offset fr0-offset
2713 :from (:argument 0) :to :result) fr0)
2714 (:temporary (:sc double-reg :offset fr1-offset
2715 :from (:argument 1) :to :result) fr1)
2716 (:results (r :scs (double-reg)))
2717 (:arg-types double-float double-float)
2718 (:result-types double-float)
2719 (:policy :fast-safe)
2720 (:note "inline scalb function")
2722 (:save-p :compute-only)
2724 (note-this-location vop :internal-error)
2725 ;; Setup x in fr0 and y in fr1
2727 ;; x in fr0; y in fr1
2728 ((and (sc-is x double-reg) (zerop (tn-offset x))
2729 (sc-is y double-reg) (= 1 (tn-offset y))))
2730 ;; y in fr1; x not in fr0
2731 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2735 (copy-fp-reg-to-fr0 x))
2738 (inst fldd (ea-for-df-stack x)))
2741 (inst fldd (ea-for-df-desc x)))))
2742 ;; x in fr0; y not in fr1
2743 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2745 ;; Now load y to fr0
2748 (copy-fp-reg-to-fr0 y))
2751 (inst fldd (ea-for-df-stack y)))
2754 (inst fldd (ea-for-df-desc y))))
2756 ;; x in fr1; y not in fr1
2757 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2761 (copy-fp-reg-to-fr0 y))
2764 (inst fldd (ea-for-df-stack y)))
2767 (inst fldd (ea-for-df-desc y))))
2770 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2772 ;; Now load x to fr0
2775 (copy-fp-reg-to-fr0 x))
2778 (inst fldd (ea-for-df-stack x)))
2781 (inst fldd (ea-for-df-desc x)))))
2782 ;; Neither x or y are in either fr0 or fr1
2789 (inst fldd (make-random-tn :kind :normal
2790 :sc (sc-or-lose 'double-reg)
2791 :offset (- (tn-offset y) 2))))
2793 (inst fldd (ea-for-df-stack y)))
2795 (inst fldd (ea-for-df-desc y))))
2799 (inst fldd (make-random-tn :kind :normal
2800 :sc (sc-or-lose 'double-reg)
2801 :offset (1- (tn-offset x)))))
2803 (inst fldd (ea-for-df-stack x)))
2805 (inst fldd (ea-for-df-desc x))))))
2807 ;; Now have x at fr0; and y at fr1
2809 (unless (zerop (tn-offset r))
2812 (define-vop (flog1p)
2814 (:args (x :scs (double-reg) :to :result))
2815 (:temporary (:sc double-reg :offset fr0-offset
2816 :from :argument :to :result) fr0)
2817 (:temporary (:sc double-reg :offset fr1-offset
2818 :from :argument :to :result) fr1)
2819 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2820 (:results (y :scs (double-reg)))
2821 (:arg-types double-float)
2822 (:result-types double-float)
2823 (:policy :fast-safe)
2824 (:note "inline log1p function")
2827 ;; x is in a FP reg, not fr0, fr1.
2830 (inst fldd (make-random-tn :kind :normal
2831 :sc (sc-or-lose 'double-reg)
2832 :offset (- (tn-offset x) 2)))
2834 (inst push #x3e947ae1) ; Constant 0.29
2836 (inst fld (make-ea :dword :base esp-tn))
2839 (inst fnstsw) ; status word to ax
2840 (inst and ah-tn #x45)
2841 (inst jmp :z WITHIN-RANGE)
2842 ;; Out of range for fyl2xp1.
2844 (inst faddd (make-random-tn :kind :normal
2845 :sc (sc-or-lose 'double-reg)
2846 :offset (- (tn-offset x) 1)))
2854 (inst fldd (make-random-tn :kind :normal
2855 :sc (sc-or-lose 'double-reg)
2856 :offset (- (tn-offset x) 1)))
2862 (t (inst fstd y)))))
2864 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2865 ;;; instruction and a range check can be avoided.
2866 (define-vop (flog1p-pentium)
2868 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2869 (:temporary (:sc double-reg :offset fr0-offset
2870 :from :argument :to :result) fr0)
2871 (:temporary (:sc double-reg :offset fr1-offset
2872 :from :argument :to :result) fr1)
2873 (:results (y :scs (double-reg)))
2874 (:arg-types double-float)
2875 (:result-types double-float)
2876 (:policy :fast-safe)
2877 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2878 (:note "inline log1p with limited x range function")
2880 (:save-p :compute-only)
2882 (note-this-location vop :internal-error)
2897 ;; x is in a FP reg, not fr0 or fr1
2901 (inst fldd (make-random-tn :kind :normal
2902 :sc (sc-or-lose 'double-reg)
2903 :offset (1- (tn-offset x)))))))
2904 ((double-stack descriptor-reg)
2908 (if (sc-is x double-stack)
2909 (inst fldd (ea-for-df-stack x))
2910 (inst fldd (ea-for-df-desc x)))))
2915 (t (inst fstd y)))))
2919 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2920 (:temporary (:sc double-reg :offset fr0-offset
2921 :from :argument :to :result) fr0)
2922 (:temporary (:sc double-reg :offset fr1-offset
2923 :from :argument :to :result) fr1)
2924 (:results (y :scs (double-reg)))
2925 (:arg-types double-float)
2926 (:result-types double-float)
2927 (:policy :fast-safe)
2928 (:note "inline logb function")
2930 (:save-p :compute-only)
2932 (note-this-location vop :internal-error)
2943 ;; x is in a FP reg, not fr0 or fr1
2946 (inst fldd (make-random-tn :kind :normal
2947 :sc (sc-or-lose 'double-reg)
2948 :offset (- (tn-offset x) 2))))))
2949 ((double-stack descriptor-reg)
2952 (if (sc-is x double-stack)
2953 (inst fldd (ea-for-df-stack x))
2954 (inst fldd (ea-for-df-desc x)))))
2965 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2966 (:temporary (:sc double-reg :offset fr0-offset
2967 :from (:argument 0) :to :result) fr0)
2968 (:temporary (:sc double-reg :offset fr1-offset
2969 :from (:argument 0) :to :result) fr1)
2970 (:results (r :scs (double-reg)))
2971 (:arg-types double-float)
2972 (:result-types double-float)
2973 (:policy :fast-safe)
2974 (:note "inline atan function")
2976 (:save-p :compute-only)
2978 (note-this-location vop :internal-error)
2979 ;; Setup x in fr1 and 1.0 in fr0
2982 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2985 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2987 ;; x not in fr0 or fr1
2994 (inst fldd (make-random-tn :kind :normal
2995 :sc (sc-or-lose 'double-reg)
2996 :offset (- (tn-offset x) 2))))
2998 (inst fldd (ea-for-df-stack x)))
3000 (inst fldd (ea-for-df-desc x))))))
3002 ;; Now have x at fr1; and 1.0 at fr0
3007 (t (inst fstd r)))))
3009 (define-vop (fatan2)
3011 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
3012 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
3013 (:temporary (:sc double-reg :offset fr0-offset
3014 :from (:argument 1) :to :result) fr0)
3015 (:temporary (:sc double-reg :offset fr1-offset
3016 :from (:argument 0) :to :result) fr1)
3017 (:results (r :scs (double-reg)))
3018 (:arg-types double-float double-float)
3019 (:result-types double-float)
3020 (:policy :fast-safe)
3021 (:note "inline atan2 function")
3023 (:save-p :compute-only)
3025 (note-this-location vop :internal-error)
3026 ;; Setup x in fr1 and y in fr0
3028 ;; y in fr0; x in fr1
3029 ((and (sc-is y double-reg) (zerop (tn-offset y))
3030 (sc-is x double-reg) (= 1 (tn-offset x))))
3031 ;; x in fr1; y not in fr0
3032 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
3036 (copy-fp-reg-to-fr0 y))
3039 (inst fldd (ea-for-df-stack y)))
3042 (inst fldd (ea-for-df-desc y)))))
3043 ((and (sc-is x double-reg) (zerop (tn-offset x))
3044 (sc-is y double-reg) (zerop (tn-offset x)))
3047 ;; y in fr0; x not in fr1
3048 ((and (sc-is y double-reg) (zerop (tn-offset y)))
3050 ;; Now load x to fr0
3053 (copy-fp-reg-to-fr0 x))
3056 (inst fldd (ea-for-df-stack x)))
3059 (inst fldd (ea-for-df-desc x))))
3061 ;; y in fr1; x not in fr1
3062 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3066 (copy-fp-reg-to-fr0 x))
3069 (inst fldd (ea-for-df-stack x)))
3072 (inst fldd (ea-for-df-desc x))))
3075 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3077 ;; Now load y to fr0
3080 (copy-fp-reg-to-fr0 y))
3083 (inst fldd (ea-for-df-stack y)))
3086 (inst fldd (ea-for-df-desc y)))))
3087 ;; Neither y or x are in either fr0 or fr1
3094 (inst fldd (make-random-tn :kind :normal
3095 :sc (sc-or-lose 'double-reg)
3096 :offset (- (tn-offset x) 2))))
3098 (inst fldd (ea-for-df-stack x)))
3100 (inst fldd (ea-for-df-desc x))))
3104 (inst fldd (make-random-tn :kind :normal
3105 :sc (sc-or-lose 'double-reg)
3106 :offset (1- (tn-offset y)))))
3108 (inst fldd (ea-for-df-stack y)))
3110 (inst fldd (ea-for-df-desc y))))))
3112 ;; Now have y at fr0; and x at fr1
3117 (t (inst fstd r)))))
3118 ) ; PROGN #!-LONG-FLOAT
3123 ;;; Lets use some of the 80387 special functions.
3125 ;;; These defs will not take effect unless code/irrat.lisp is modified
3126 ;;; to remove the inlined alien routine def.
3128 (macrolet ((frob (func trans op)
3129 `(define-vop (,func)
3130 (:args (x :scs (long-reg) :target fr0))
3131 (:temporary (:sc long-reg :offset fr0-offset
3132 :from :argument :to :result) fr0)
3134 (:results (y :scs (long-reg)))
3135 (:arg-types long-float)
3136 (:result-types long-float)
3138 (:policy :fast-safe)
3139 (:note "inline NPX function")
3141 (:save-p :compute-only)
3144 (note-this-location vop :internal-error)
3145 (unless (zerop (tn-offset x))
3146 (inst fxch x) ; x to top of stack
3147 (unless (location= x y)
3148 (inst fst x))) ; maybe save it
3149 (inst ,op) ; clobber st0
3150 (cond ((zerop (tn-offset y))
3151 (maybe-fp-wait node))
3155 ;; Quick versions of FSIN and FCOS that require the argument to be
3156 ;; within range 2^63.
3157 (frob fsin-quick %sin-quick fsin)
3158 (frob fcos-quick %cos-quick fcos)
3159 (frob fsqrt %sqrt fsqrt))
3161 ;;; Quick version of ftan that requires the argument to be within
3163 (define-vop (ftan-quick)
3164 (:translate %tan-quick)
3165 (:args (x :scs (long-reg) :target fr0))
3166 (:temporary (:sc long-reg :offset fr0-offset
3167 :from :argument :to :result) fr0)
3168 (:temporary (:sc long-reg :offset fr1-offset
3169 :from :argument :to :result) fr1)
3170 (:results (y :scs (long-reg)))
3171 (:arg-types long-float)
3172 (:result-types long-float)
3173 (:policy :fast-safe)
3174 (:note "inline tan function")
3176 (:save-p :compute-only)
3178 (note-this-location vop :internal-error)
3187 (inst fldd (make-random-tn :kind :normal
3188 :sc (sc-or-lose 'double-reg)
3189 :offset (- (tn-offset x) 2)))))
3200 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3201 ;;; the argument is out of range 2^63 and would thus be hopelessly
3203 (macrolet ((frob (func trans op)
3204 `(define-vop (,func)
3206 (:args (x :scs (long-reg) :target fr0))
3207 (:temporary (:sc long-reg :offset fr0-offset
3208 :from :argument :to :result) fr0)
3209 (:temporary (:sc unsigned-reg :offset eax-offset
3210 :from :argument :to :result) eax)
3211 (:results (y :scs (long-reg)))
3212 (:arg-types long-float)
3213 (:result-types long-float)
3214 (:policy :fast-safe)
3215 (:note "inline sin/cos function")
3217 (:save-p :compute-only)
3220 (note-this-location vop :internal-error)
3221 (unless (zerop (tn-offset x))
3222 (inst fxch x) ; x to top of stack
3223 (unless (location= x y)
3224 (inst fst x))) ; maybe save it
3226 (inst fnstsw) ; status word to ax
3227 (inst and ah-tn #x04) ; C2
3229 ;; Else x was out of range so reduce it; ST0 is unchanged.
3230 (inst fstp fr0) ; Load 0.0
3233 (unless (zerop (tn-offset y))
3235 (frob fsin %sin fsin)
3236 (frob fcos %cos fcos))
3240 (:args (x :scs (long-reg) :target fr0))
3241 (:temporary (:sc long-reg :offset fr0-offset
3242 :from :argument :to :result) fr0)
3243 (:temporary (:sc long-reg :offset fr1-offset
3244 :from :argument :to :result) fr1)
3245 (:temporary (:sc unsigned-reg :offset eax-offset
3246 :from :argument :to :result) eax)
3247 (:results (y :scs (long-reg)))
3248 (:arg-types long-float)
3249 (:result-types long-float)
3251 (:policy :fast-safe)
3252 (:note "inline tan function")
3254 (:save-p :compute-only)
3257 (note-this-location vop :internal-error)
3266 (inst fldd (make-random-tn :kind :normal
3267 :sc (sc-or-lose 'double-reg)
3268 :offset (- (tn-offset x) 2)))))
3270 (inst fnstsw) ; status word to ax
3271 (inst and ah-tn #x04) ; C2
3273 ;; Else x was out of range so reduce it; ST0 is unchanged.
3274 (inst fldz) ; Load 0.0
3286 ;;; Modified exp that handles the following special cases:
3287 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3290 (:args (x :scs (long-reg) :target fr0))
3291 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3292 (:temporary (:sc long-reg :offset fr0-offset
3293 :from :argument :to :result) fr0)
3294 (:temporary (:sc long-reg :offset fr1-offset
3295 :from :argument :to :result) fr1)
3296 (:temporary (:sc long-reg :offset fr2-offset
3297 :from :argument :to :result) fr2)
3298 (:results (y :scs (long-reg)))
3299 (:arg-types long-float)
3300 (:result-types long-float)
3301 (:policy :fast-safe)
3302 (:note "inline exp function")
3304 (:save-p :compute-only)
3307 (note-this-location vop :internal-error)
3308 (unless (zerop (tn-offset x))
3309 (inst fxch x) ; x to top of stack
3310 (unless (location= x y)
3311 (inst fst x))) ; maybe save it
3312 ;; Check for Inf or NaN
3316 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3317 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3318 (inst and ah-tn #x02) ; Test sign of Inf.
3319 (inst jmp :z DONE) ; +Inf gives +Inf.
3320 (inst fstp fr0) ; -Inf gives 0
3322 (inst jmp-short DONE)
3327 ;; Now fr0=x log2(e)
3331 (inst fsubp-sti fr1)
3334 (inst faddp-sti fr1)
3338 (unless (zerop (tn-offset y))
3341 ;;; Expm1 = exp(x) - 1.
3342 ;;; Handles the following special cases:
3343 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3344 (define-vop (fexpm1)
3346 (:args (x :scs (long-reg) :target fr0))
3347 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3348 (:temporary (:sc long-reg :offset fr0-offset
3349 :from :argument :to :result) fr0)
3350 (:temporary (:sc long-reg :offset fr1-offset
3351 :from :argument :to :result) fr1)
3352 (:temporary (:sc long-reg :offset fr2-offset
3353 :from :argument :to :result) fr2)
3354 (:results (y :scs (long-reg)))
3355 (:arg-types long-float)
3356 (:result-types long-float)
3357 (:policy :fast-safe)
3358 (:note "inline expm1 function")
3360 (:save-p :compute-only)
3363 (note-this-location vop :internal-error)
3364 (unless (zerop (tn-offset x))
3365 (inst fxch x) ; x to top of stack
3366 (unless (location= x y)
3367 (inst fst x))) ; maybe save it
3368 ;; Check for Inf or NaN
3372 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3373 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3374 (inst and ah-tn #x02) ; Test sign of Inf.
3375 (inst jmp :z DONE) ; +Inf gives +Inf.
3376 (inst fstp fr0) ; -Inf gives -1.0
3379 (inst jmp-short DONE)
3381 ;; Free two stack slots leaving the argument on top.
3385 (inst fmul fr1) ; Now fr0 = x log2(e)
3400 (unless (zerop (tn-offset y))
3405 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3406 (:temporary (:sc long-reg :offset fr0-offset
3407 :from :argument :to :result) fr0)
3408 (:temporary (:sc long-reg :offset fr1-offset
3409 :from :argument :to :result) fr1)
3410 (:results (y :scs (long-reg)))
3411 (:arg-types long-float)
3412 (:result-types long-float)
3413 (:policy :fast-safe)
3414 (:note "inline log function")
3416 (:save-p :compute-only)
3418 (note-this-location vop :internal-error)
3433 ;; x is in a FP reg, not fr0 or fr1
3437 (inst fldd (make-random-tn :kind :normal
3438 :sc (sc-or-lose 'double-reg)
3439 :offset (1- (tn-offset x))))))
3441 ((long-stack descriptor-reg)
3445 (if (sc-is x long-stack)
3446 (inst fldl (ea-for-lf-stack x))
3447 (inst fldl (ea-for-lf-desc x)))
3452 (t (inst fstd y)))))
3454 (define-vop (flog10)
3456 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3457 (:temporary (:sc long-reg :offset fr0-offset
3458 :from :argument :to :result) fr0)
3459 (:temporary (:sc long-reg :offset fr1-offset
3460 :from :argument :to :result) fr1)
3461 (:results (y :scs (long-reg)))
3462 (:arg-types long-float)
3463 (:result-types long-float)
3464 (:policy :fast-safe)
3465 (:note "inline log10 function")
3467 (:save-p :compute-only)
3469 (note-this-location vop :internal-error)
3484 ;; x is in a FP reg, not fr0 or fr1
3488 (inst fldd (make-random-tn :kind :normal
3489 :sc (sc-or-lose 'double-reg)
3490 :offset (1- (tn-offset x))))))
3492 ((long-stack descriptor-reg)
3496 (if (sc-is x long-stack)
3497 (inst fldl (ea-for-lf-stack x))
3498 (inst fldl (ea-for-lf-desc x)))
3503 (t (inst fstd y)))))
3507 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3508 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3509 (:temporary (:sc long-reg :offset fr0-offset
3510 :from (:argument 0) :to :result) fr0)
3511 (:temporary (:sc long-reg :offset fr1-offset
3512 :from (:argument 1) :to :result) fr1)
3513 (:temporary (:sc long-reg :offset fr2-offset
3514 :from :load :to :result) fr2)
3515 (:results (r :scs (long-reg)))
3516 (:arg-types long-float long-float)
3517 (:result-types long-float)
3518 (:policy :fast-safe)
3519 (:note "inline pow function")
3521 (:save-p :compute-only)
3523 (note-this-location vop :internal-error)
3524 ;; Setup x in fr0 and y in fr1
3526 ;; x in fr0; y in fr1
3527 ((and (sc-is x long-reg) (zerop (tn-offset x))
3528 (sc-is y long-reg) (= 1 (tn-offset y))))
3529 ;; y in fr1; x not in fr0
3530 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3534 (copy-fp-reg-to-fr0 x))
3537 (inst fldl (ea-for-lf-stack x)))
3540 (inst fldl (ea-for-lf-desc x)))))
3541 ;; x in fr0; y not in fr1
3542 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3544 ;; Now load y to fr0
3547 (copy-fp-reg-to-fr0 y))
3550 (inst fldl (ea-for-lf-stack y)))
3553 (inst fldl (ea-for-lf-desc y))))
3555 ;; x in fr1; y not in fr1
3556 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3560 (copy-fp-reg-to-fr0 y))
3563 (inst fldl (ea-for-lf-stack y)))
3566 (inst fldl (ea-for-lf-desc y))))
3569 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3571 ;; Now load x to fr0
3574 (copy-fp-reg-to-fr0 x))
3577 (inst fldl (ea-for-lf-stack x)))
3580 (inst fldl (ea-for-lf-desc x)))))
3581 ;; Neither x or y are in either fr0 or fr1
3588 (inst fldd (make-random-tn :kind :normal
3589 :sc (sc-or-lose 'double-reg)
3590 :offset (- (tn-offset y) 2))))
3592 (inst fldl (ea-for-lf-stack y)))
3594 (inst fldl (ea-for-lf-desc y))))
3598 (inst fldd (make-random-tn :kind :normal
3599 :sc (sc-or-lose 'double-reg)
3600 :offset (1- (tn-offset x)))))
3602 (inst fldl (ea-for-lf-stack x)))
3604 (inst fldl (ea-for-lf-desc x))))))
3606 ;; Now have x at fr0; and y at fr1
3608 ;; Now fr0=y log2(x)
3612 (inst fsubp-sti fr1)
3615 (inst faddp-sti fr1)
3620 (t (inst fstd r)))))
3622 (define-vop (fscalen)
3623 (:translate %scalbn)
3624 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3625 (y :scs (signed-stack signed-reg) :target temp))
3626 (:temporary (:sc long-reg :offset fr0-offset
3627 :from (:argument 0) :to :result) fr0)
3628 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3629 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3630 (:results (r :scs (long-reg)))
3631 (:arg-types long-float signed-num)
3632 (:result-types long-float)
3633 (:policy :fast-safe)
3634 (:note "inline scalbn function")
3636 ;; Setup x in fr0 and y in fr1
3667 (inst fld (make-random-tn :kind :normal
3668 :sc (sc-or-lose 'double-reg)
3669 :offset (1- (tn-offset x)))))))
3670 ((long-stack descriptor-reg)
3679 (if (sc-is x long-stack)
3680 (inst fldl (ea-for-lf-stack x))
3681 (inst fldl (ea-for-lf-desc x)))))
3683 (unless (zerop (tn-offset r))
3686 (define-vop (fscale)
3688 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3689 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3690 (:temporary (:sc long-reg :offset fr0-offset
3691 :from (:argument 0) :to :result) fr0)
3692 (:temporary (:sc long-reg :offset fr1-offset
3693 :from (:argument 1) :to :result) fr1)
3694 (:results (r :scs (long-reg)))
3695 (:arg-types long-float long-float)
3696 (:result-types long-float)
3697 (:policy :fast-safe)
3698 (:note "inline scalb function")
3700 (:save-p :compute-only)
3702 (note-this-location vop :internal-error)
3703 ;; Setup x in fr0 and y in fr1
3705 ;; x in fr0; y in fr1
3706 ((and (sc-is x long-reg) (zerop (tn-offset x))
3707 (sc-is y long-reg) (= 1 (tn-offset y))))
3708 ;; y in fr1; x not in fr0
3709 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3713 (copy-fp-reg-to-fr0 x))
3716 (inst fldl (ea-for-lf-stack x)))
3719 (inst fldl (ea-for-lf-desc x)))))
3720 ;; x in fr0; y not in fr1
3721 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3723 ;; Now load y to fr0
3726 (copy-fp-reg-to-fr0 y))
3729 (inst fldl (ea-for-lf-stack y)))
3732 (inst fldl (ea-for-lf-desc y))))
3734 ;; x in fr1; y not in fr1
3735 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3739 (copy-fp-reg-to-fr0 y))
3742 (inst fldl (ea-for-lf-stack y)))
3745 (inst fldl (ea-for-lf-desc y))))
3748 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3750 ;; Now load x to fr0
3753 (copy-fp-reg-to-fr0 x))
3756 (inst fldl (ea-for-lf-stack x)))
3759 (inst fldl (ea-for-lf-desc x)))))
3760 ;; Neither x or y are in either fr0 or fr1
3767 (inst fldd (make-random-tn :kind :normal
3768 :sc (sc-or-lose 'double-reg)
3769 :offset (- (tn-offset y) 2))))
3771 (inst fldl (ea-for-lf-stack y)))
3773 (inst fldl (ea-for-lf-desc y))))
3777 (inst fldd (make-random-tn :kind :normal
3778 :sc (sc-or-lose 'double-reg)
3779 :offset (1- (tn-offset x)))))
3781 (inst fldl (ea-for-lf-stack x)))
3783 (inst fldl (ea-for-lf-desc x))))))
3785 ;; Now have x at fr0; and y at fr1
3787 (unless (zerop (tn-offset r))
3790 (define-vop (flog1p)
3792 (:args (x :scs (long-reg) :to :result))
3793 (:temporary (:sc long-reg :offset fr0-offset
3794 :from :argument :to :result) fr0)
3795 (:temporary (:sc long-reg :offset fr1-offset
3796 :from :argument :to :result) fr1)
3797 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3798 (:results (y :scs (long-reg)))
3799 (:arg-types long-float)
3800 (:result-types long-float)
3801 (:policy :fast-safe)
3802 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3803 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3804 ;; an enormous PROGN above. Still, it would be probably be good to
3805 ;; add some code to warn about redefining VOPs.
3806 (:note "inline log1p function")
3809 ;; x is in a FP reg, not fr0, fr1.
3812 (inst fldd (make-random-tn :kind :normal
3813 :sc (sc-or-lose 'double-reg)
3814 :offset (- (tn-offset x) 2)))
3816 (inst push #x3e947ae1) ; Constant 0.29
3818 (inst fld (make-ea :dword :base esp-tn))
3821 (inst fnstsw) ; status word to ax
3822 (inst and ah-tn #x45)
3823 (inst jmp :z WITHIN-RANGE)
3824 ;; Out of range for fyl2xp1.
3826 (inst faddd (make-random-tn :kind :normal
3827 :sc (sc-or-lose 'double-reg)
3828 :offset (- (tn-offset x) 1)))
3836 (inst fldd (make-random-tn :kind :normal
3837 :sc (sc-or-lose 'double-reg)
3838 :offset (- (tn-offset x) 1)))
3844 (t (inst fstd y)))))
3846 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3847 ;;; instruction and a range check can be avoided.
3848 (define-vop (flog1p-pentium)
3850 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3851 (:temporary (:sc long-reg :offset fr0-offset
3852 :from :argument :to :result) fr0)
3853 (:temporary (:sc long-reg :offset fr1-offset
3854 :from :argument :to :result) fr1)
3855 (:results (y :scs (long-reg)))
3856 (:arg-types long-float)
3857 (:result-types long-float)
3858 (:policy :fast-safe)
3859 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3860 (:note "inline log1p function")
3876 ;; x is in a FP reg, not fr0 or fr1
3880 (inst fldd (make-random-tn :kind :normal
3881 :sc (sc-or-lose 'double-reg)
3882 :offset (1- (tn-offset x)))))))
3883 ((long-stack descriptor-reg)
3887 (if (sc-is x long-stack)
3888 (inst fldl (ea-for-lf-stack x))
3889 (inst fldl (ea-for-lf-desc x)))))
3894 (t (inst fstd y)))))
3898 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3899 (:temporary (:sc long-reg :offset fr0-offset
3900 :from :argument :to :result) fr0)
3901 (:temporary (:sc long-reg :offset fr1-offset
3902 :from :argument :to :result) fr1)
3903 (:results (y :scs (long-reg)))
3904 (:arg-types long-float)
3905 (:result-types long-float)
3906 (:policy :fast-safe)
3907 (:note "inline logb function")
3909 (:save-p :compute-only)
3911 (note-this-location vop :internal-error)
3922 ;; x is in a FP reg, not fr0 or fr1
3925 (inst fldd (make-random-tn :kind :normal
3926 :sc (sc-or-lose 'double-reg)
3927 :offset (- (tn-offset x) 2))))))
3928 ((long-stack descriptor-reg)
3931 (if (sc-is x long-stack)
3932 (inst fldl (ea-for-lf-stack x))
3933 (inst fldl (ea-for-lf-desc x)))))
3944 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3945 (:temporary (:sc long-reg :offset fr0-offset
3946 :from (:argument 0) :to :result) fr0)
3947 (:temporary (:sc long-reg :offset fr1-offset
3948 :from (:argument 0) :to :result) fr1)
3949 (:results (r :scs (long-reg)))
3950 (:arg-types long-float)
3951 (:result-types long-float)
3952 (:policy :fast-safe)
3953 (:note "inline atan function")
3955 (:save-p :compute-only)
3957 (note-this-location vop :internal-error)
3958 ;; Setup x in fr1 and 1.0 in fr0
3961 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3964 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3966 ;; x not in fr0 or fr1
3973 (inst fldd (make-random-tn :kind :normal
3974 :sc (sc-or-lose 'double-reg)
3975 :offset (- (tn-offset x) 2))))
3977 (inst fldl (ea-for-lf-stack x)))
3979 (inst fldl (ea-for-lf-desc x))))))
3981 ;; Now have x at fr1; and 1.0 at fr0
3986 (t (inst fstd r)))))
3988 (define-vop (fatan2)
3990 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3991 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3992 (:temporary (:sc long-reg :offset fr0-offset
3993 :from (:argument 1) :to :result) fr0)
3994 (:temporary (:sc long-reg :offset fr1-offset
3995 :from (:argument 0) :to :result) fr1)
3996 (:results (r :scs (long-reg)))
3997 (:arg-types long-float long-float)
3998 (:result-types long-float)
3999 (:policy :fast-safe)
4000 (:note "inline atan2 function")
4002 (:save-p :compute-only)
4004 (note-this-location vop :internal-error)
4005 ;; Setup x in fr1 and y in fr0
4007 ;; y in fr0; x in fr1
4008 ((and (sc-is y long-reg) (zerop (tn-offset y))
4009 (sc-is x long-reg) (= 1 (tn-offset x))))
4010 ;; x in fr1; y not in fr0
4011 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
4015 (copy-fp-reg-to-fr0 y))
4018 (inst fldl (ea-for-lf-stack y)))
4021 (inst fldl (ea-for-lf-desc y)))))
4022 ;; y in fr0; x not in fr1
4023 ((and (sc-is y long-reg) (zerop (tn-offset y)))
4025 ;; Now load x to fr0
4028 (copy-fp-reg-to-fr0 x))
4031 (inst fldl (ea-for-lf-stack x)))
4034 (inst fldl (ea-for-lf-desc x))))
4036 ;; y in fr1; x not in fr1
4037 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
4041 (copy-fp-reg-to-fr0 x))
4044 (inst fldl (ea-for-lf-stack x)))
4047 (inst fldl (ea-for-lf-desc x))))
4050 ((and (sc-is x long-reg) (zerop (tn-offset x)))
4052 ;; Now load y to fr0
4055 (copy-fp-reg-to-fr0 y))
4058 (inst fldl (ea-for-lf-stack y)))
4061 (inst fldl (ea-for-lf-desc y)))))
4062 ;; Neither y or x are in either fr0 or fr1
4069 (inst fldd (make-random-tn :kind :normal
4070 :sc (sc-or-lose 'double-reg)
4071 :offset (- (tn-offset x) 2))))
4073 (inst fldl (ea-for-lf-stack x)))
4075 (inst fldl (ea-for-lf-desc x))))
4079 (inst fldd (make-random-tn :kind :normal
4080 :sc (sc-or-lose 'double-reg)
4081 :offset (1- (tn-offset y)))))
4083 (inst fldl (ea-for-lf-stack y)))
4085 (inst fldl (ea-for-lf-desc y))))))
4087 ;; Now have y at fr0; and x at fr1
4092 (t (inst fstd r)))))
4094 ) ; PROGN #!+LONG-FLOAT
4096 ;;;; complex float VOPs
4098 (define-vop (make-complex-single-float)
4099 (:translate complex)
4100 (:args (real :scs (single-reg) :to :result :target r
4101 :load-if (not (location= real r)))
4102 (imag :scs (single-reg) :to :save))
4103 (:arg-types single-float single-float)
4104 (:results (r :scs (complex-single-reg) :from (:argument 0)
4105 :load-if (not (sc-is r complex-single-stack))))
4106 (:result-types complex-single-float)
4107 (:note "inline complex single-float creation")
4108 (:policy :fast-safe)
4112 (let ((r-real (complex-double-reg-real-tn r)))
4113 (unless (location= real r-real)
4114 (cond ((zerop (tn-offset r-real))
4115 (copy-fp-reg-to-fr0 real))
4116 ((zerop (tn-offset real))
4121 (inst fxch real)))))
4122 (let ((r-imag (complex-double-reg-imag-tn r)))
4123 (unless (location= imag r-imag)
4124 (cond ((zerop (tn-offset imag))
4129 (inst fxch imag))))))
4130 (complex-single-stack
4131 (unless (location= real r)
4132 (cond ((zerop (tn-offset real))
4133 (inst fst (ea-for-csf-real-stack r)))
4136 (inst fst (ea-for-csf-real-stack r))
4139 (inst fst (ea-for-csf-imag-stack r))
4140 (inst fxch imag)))))
4142 (define-vop (make-complex-double-float)
4143 (:translate complex)
4144 (:args (real :scs (double-reg) :target r
4145 :load-if (not (location= real r)))
4146 (imag :scs (double-reg) :to :save))
4147 (:arg-types double-float double-float)
4148 (:results (r :scs (complex-double-reg) :from (:argument 0)
4149 :load-if (not (sc-is r complex-double-stack))))
4150 (:result-types complex-double-float)
4151 (:note "inline complex double-float creation")
4152 (:policy :fast-safe)
4156 (let ((r-real (complex-double-reg-real-tn r)))
4157 (unless (location= real r-real)
4158 (cond ((zerop (tn-offset r-real))
4159 (copy-fp-reg-to-fr0 real))
4160 ((zerop (tn-offset real))
4165 (inst fxch real)))))
4166 (let ((r-imag (complex-double-reg-imag-tn r)))
4167 (unless (location= imag r-imag)
4168 (cond ((zerop (tn-offset imag))
4173 (inst fxch imag))))))
4174 (complex-double-stack
4175 (unless (location= real r)
4176 (cond ((zerop (tn-offset real))
4177 (inst fstd (ea-for-cdf-real-stack r)))
4180 (inst fstd (ea-for-cdf-real-stack r))
4183 (inst fstd (ea-for-cdf-imag-stack r))
4184 (inst fxch imag)))))
4187 (define-vop (make-complex-long-float)
4188 (:translate complex)
4189 (:args (real :scs (long-reg) :target r
4190 :load-if (not (location= real r)))
4191 (imag :scs (long-reg) :to :save))
4192 (:arg-types long-float long-float)
4193 (:results (r :scs (complex-long-reg) :from (:argument 0)
4194 :load-if (not (sc-is r complex-long-stack))))
4195 (:result-types complex-long-float)
4196 (:note "inline complex long-float creation")
4197 (:policy :fast-safe)
4201 (let ((r-real (complex-double-reg-real-tn r)))
4202 (unless (location= real r-real)
4203 (cond ((zerop (tn-offset r-real))
4204 (copy-fp-reg-to-fr0 real))
4205 ((zerop (tn-offset real))
4210 (inst fxch real)))))
4211 (let ((r-imag (complex-double-reg-imag-tn r)))
4212 (unless (location= imag r-imag)
4213 (cond ((zerop (tn-offset imag))
4218 (inst fxch imag))))))
4220 (unless (location= real r)
4221 (cond ((zerop (tn-offset real))
4222 (store-long-float (ea-for-clf-real-stack r)))
4225 (store-long-float (ea-for-clf-real-stack r))
4228 (store-long-float (ea-for-clf-imag-stack r))
4229 (inst fxch imag)))))
4232 (define-vop (complex-float-value)
4233 (:args (x :target r))
4235 (:variant-vars offset)
4236 (:policy :fast-safe)
4238 (cond ((sc-is x complex-single-reg complex-double-reg
4239 #!+long-float complex-long-reg)
4241 (make-random-tn :kind :normal
4242 :sc (sc-or-lose 'double-reg)
4243 :offset (+ offset (tn-offset x)))))
4244 (unless (location= value-tn r)
4245 (cond ((zerop (tn-offset r))
4246 (copy-fp-reg-to-fr0 value-tn))
4247 ((zerop (tn-offset value-tn))
4250 (inst fxch value-tn)
4252 (inst fxch value-tn))))))
4253 ((sc-is r single-reg)
4254 (let ((ea (sc-case x
4255 (complex-single-stack
4257 (0 (ea-for-csf-real-stack x))
4258 (1 (ea-for-csf-imag-stack x))))
4261 (0 (ea-for-csf-real-desc x))
4262 (1 (ea-for-csf-imag-desc x)))))))
4263 (with-empty-tn@fp-top(r)
4265 ((sc-is r double-reg)
4266 (let ((ea (sc-case x
4267 (complex-double-stack
4269 (0 (ea-for-cdf-real-stack x))
4270 (1 (ea-for-cdf-imag-stack x))))
4273 (0 (ea-for-cdf-real-desc x))
4274 (1 (ea-for-cdf-imag-desc x)))))))
4275 (with-empty-tn@fp-top(r)
4279 (let ((ea (sc-case x
4282 (0 (ea-for-clf-real-stack x))
4283 (1 (ea-for-clf-imag-stack x))))
4286 (0 (ea-for-clf-real-desc x))
4287 (1 (ea-for-clf-imag-desc x)))))))
4288 (with-empty-tn@fp-top(r)
4290 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4292 (define-vop (realpart/complex-single-float complex-float-value)
4293 (:translate realpart)
4294 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4296 (:arg-types complex-single-float)
4297 (:results (r :scs (single-reg)))
4298 (:result-types single-float)
4299 (:note "complex float realpart")
4302 (define-vop (realpart/complex-double-float complex-float-value)
4303 (:translate realpart)
4304 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4306 (:arg-types complex-double-float)
4307 (:results (r :scs (double-reg)))
4308 (:result-types double-float)
4309 (:note "complex float realpart")
4313 (define-vop (realpart/complex-long-float complex-float-value)
4314 (:translate realpart)
4315 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4317 (:arg-types complex-long-float)
4318 (:results (r :scs (long-reg)))
4319 (:result-types long-float)
4320 (:note "complex float realpart")
4323 (define-vop (imagpart/complex-single-float complex-float-value)
4324 (:translate imagpart)
4325 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4327 (:arg-types complex-single-float)
4328 (:results (r :scs (single-reg)))
4329 (:result-types single-float)
4330 (:note "complex float imagpart")
4333 (define-vop (imagpart/complex-double-float complex-float-value)
4334 (:translate imagpart)
4335 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4337 (:arg-types complex-double-float)
4338 (:results (r :scs (double-reg)))
4339 (:result-types double-float)
4340 (:note "complex float imagpart")
4344 (define-vop (imagpart/complex-long-float complex-float-value)
4345 (:translate imagpart)
4346 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4348 (:arg-types complex-long-float)
4349 (:results (r :scs (long-reg)))
4350 (:result-types long-float)
4351 (:note "complex float imagpart")
4354 ;;; hack dummy VOPs to bias the representation selection of their
4355 ;;; arguments towards a FP register, which can help avoid consing at
4356 ;;; inappropriate locations
4357 (defknown double-float-reg-bias (double-float) (values))
4358 (define-vop (double-float-reg-bias)
4359 (:translate double-float-reg-bias)
4360 (:args (x :scs (double-reg double-stack) :load-if nil))
4361 (:arg-types double-float)
4362 (:policy :fast-safe)
4363 (:note "inline dummy FP register bias")
4366 (defknown single-float-reg-bias (single-float) (values))
4367 (define-vop (single-float-reg-bias)
4368 (:translate single-float-reg-bias)
4369 (:args (x :scs (single-reg single-stack) :load-if nil))
4370 (:arg-types single-float)
4371 (:policy :fast-safe)
4372 (:note "inline dummy FP register bias")