1 ;;;; floating point support for the x86
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 (macrolet ((ea-for-xf-desc (tn slot)
17 :disp (- (* ,slot sb!vm:word-bytes) sb!vm:other-pointer-type))))
18 (defun ea-for-sf-desc (tn)
19 (ea-for-xf-desc tn sb!vm:single-float-value-slot))
20 (defun ea-for-df-desc (tn)
21 (ea-for-xf-desc tn sb!vm:double-float-value-slot))
23 (defun ea-for-lf-desc (tn)
24 (ea-for-xf-desc tn sb!vm:long-float-value-slot))
26 (defun ea-for-csf-real-desc (tn)
27 (ea-for-xf-desc tn sb!vm:complex-single-float-real-slot))
28 (defun ea-for-csf-imag-desc (tn)
29 (ea-for-xf-desc tn sb!vm:complex-single-float-imag-slot))
30 (defun ea-for-cdf-real-desc (tn)
31 (ea-for-xf-desc tn sb!vm:complex-double-float-real-slot))
32 (defun ea-for-cdf-imag-desc (tn)
33 (ea-for-xf-desc tn sb!vm:complex-double-float-imag-slot))
35 (defun ea-for-clf-real-desc (tn)
36 (ea-for-xf-desc tn sb!vm:complex-long-float-real-slot))
38 (defun ea-for-clf-imag-desc (tn)
39 (ea-for-xf-desc tn sb!vm:complex-long-float-imag-slot)))
41 (macrolet ((ea-for-xf-stack (tn kind)
44 :disp (- (* (+ (tn-offset ,tn)
45 (ecase ,kind (:single 1) (:double 2) (:long 3)))
47 (defun ea-for-sf-stack (tn)
48 (ea-for-xf-stack tn :single))
49 (defun ea-for-df-stack (tn)
50 (ea-for-xf-stack tn :double))
52 (defun ea-for-lf-stack (tn)
53 (ea-for-xf-stack tn :long)))
55 ;;; Telling the FPU to wait is required in order to make signals occur
56 ;;; at the expected place, but naturally slows things down.
58 ;;; NODE is the node whose compilation policy controls the decision
59 ;;; whether to just blast through carelessly or carefully emit wait
60 ;;; instructions and whatnot.
62 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
63 ;;; #'NOTE-NEXT-INSTRUCTION.
64 (defun maybe-fp-wait (node &optional note-next-instruction)
65 (when (policy node (or (= debug 3) (> safety speed))))
66 (when note-next-instruction
67 (note-next-instruction note-next-instruction :internal-error))
70 ;;; complex float stack EAs
71 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
74 :disp (- (* (+ (tn-offset ,tn)
79 (ecase ,slot (:real 1) (:imag 2))))
81 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
82 (ea-for-cxf-stack tn :single :real base))
83 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
84 (ea-for-cxf-stack tn :single :imag base))
85 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
86 (ea-for-cxf-stack tn :double :real base))
87 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
88 (ea-for-cxf-stack tn :double :imag base))
90 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
91 (ea-for-cxf-stack tn :long :real base))
93 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
94 (ea-for-cxf-stack tn :long :imag base)))
96 ;;; Abstract out the copying of a FP register to the FP stack top, and
97 ;;; provide two alternatives for its implementation. Note: it's not
98 ;;; necessary to distinguish between a single or double register move
101 ;;; Using a Pop then load.
102 (defun copy-fp-reg-to-fr0 (reg)
103 (aver (not (zerop (tn-offset reg))))
105 (inst fld (make-random-tn :kind :normal
106 :sc (sc-or-lose 'double-reg)
107 :offset (1- (tn-offset reg)))))
108 ;;; Using Fxch then Fst to restore the original reg contents.
110 (defun copy-fp-reg-to-fr0 (reg)
111 (aver (not (zerop (tn-offset reg))))
115 ;;; The x86 can't store a long-float to memory without popping the
116 ;;; stack and marking a register as empty, so it is necessary to
117 ;;; restore the register from memory.
119 (defun store-long-float (ea)
125 ;;; x is source, y is destination
126 (define-move-function (load-single 2) (vop x y)
127 ((single-stack) (single-reg))
128 (with-empty-tn@fp-top(y)
129 (inst fld (ea-for-sf-stack x))))
131 (define-move-function (store-single 2) (vop x y)
132 ((single-reg) (single-stack))
133 (cond ((zerop (tn-offset x))
134 (inst fst (ea-for-sf-stack y)))
137 (inst fst (ea-for-sf-stack y))
138 ;; This may not be necessary as ST0 is likely invalid now.
141 (define-move-function (load-double 2) (vop x y)
142 ((double-stack) (double-reg))
143 (with-empty-tn@fp-top(y)
144 (inst fldd (ea-for-df-stack x))))
146 (define-move-function (store-double 2) (vop x y)
147 ((double-reg) (double-stack))
148 (cond ((zerop (tn-offset x))
149 (inst fstd (ea-for-df-stack y)))
152 (inst fstd (ea-for-df-stack y))
153 ;; This may not be necessary as ST0 is likely invalid now.
157 (define-move-function (load-long 2) (vop x y)
158 ((long-stack) (long-reg))
159 (with-empty-tn@fp-top(y)
160 (inst fldl (ea-for-lf-stack x))))
163 (define-move-function (store-long 2) (vop x y)
164 ((long-reg) (long-stack))
165 (cond ((zerop (tn-offset x))
166 (store-long-float (ea-for-lf-stack y)))
169 (store-long-float (ea-for-lf-stack y))
170 ;; This may not be necessary as ST0 is likely invalid now.
173 ;;; The i387 has instructions to load some useful constants. This
174 ;;; doesn't save much time but might cut down on memory access and
175 ;;; reduce the size of the constant vector (CV). Intel claims they are
176 ;;; stored in a more precise form on chip. Anyhow, might as well use
177 ;;; the feature. It can be turned off by hacking the
178 ;;; "immediate-constant-sc" in vm.lisp.
179 (define-move-function (load-fp-constant 2) (vop x y)
180 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
181 (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
182 (with-empty-tn@fp-top(y)
189 ((= value (log 10l0 2l0))
191 ((= value (log 2.718281828459045235360287471352662L0 2l0))
193 ((= value (log 2l0 10l0))
195 ((= value (log 2l0 2.718281828459045235360287471352662L0))
197 (t (warn "ignoring bogus i387 constant ~A" value))))))
200 ;;;; complex float move functions
202 (defun complex-single-reg-real-tn (x)
203 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
204 :offset (tn-offset x)))
205 (defun complex-single-reg-imag-tn (x)
206 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
207 :offset (1+ (tn-offset x))))
209 (defun complex-double-reg-real-tn (x)
210 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
211 :offset (tn-offset x)))
212 (defun complex-double-reg-imag-tn (x)
213 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
214 :offset (1+ (tn-offset x))))
217 (defun complex-long-reg-real-tn (x)
218 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
219 :offset (tn-offset x)))
221 (defun complex-long-reg-imag-tn (x)
222 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
223 :offset (1+ (tn-offset x))))
225 ;;; x is source, y is destination.
226 (define-move-function (load-complex-single 2) (vop x y)
227 ((complex-single-stack) (complex-single-reg))
228 (let ((real-tn (complex-single-reg-real-tn y)))
229 (with-empty-tn@fp-top (real-tn)
230 (inst fld (ea-for-csf-real-stack x))))
231 (let ((imag-tn (complex-single-reg-imag-tn y)))
232 (with-empty-tn@fp-top (imag-tn)
233 (inst fld (ea-for-csf-imag-stack x)))))
235 (define-move-function (store-complex-single 2) (vop x y)
236 ((complex-single-reg) (complex-single-stack))
237 (let ((real-tn (complex-single-reg-real-tn x)))
238 (cond ((zerop (tn-offset real-tn))
239 (inst fst (ea-for-csf-real-stack y)))
242 (inst fst (ea-for-csf-real-stack y))
243 (inst fxch real-tn))))
244 (let ((imag-tn (complex-single-reg-imag-tn x)))
246 (inst fst (ea-for-csf-imag-stack y))
247 (inst fxch imag-tn)))
249 (define-move-function (load-complex-double 2) (vop x y)
250 ((complex-double-stack) (complex-double-reg))
251 (let ((real-tn (complex-double-reg-real-tn y)))
252 (with-empty-tn@fp-top(real-tn)
253 (inst fldd (ea-for-cdf-real-stack x))))
254 (let ((imag-tn (complex-double-reg-imag-tn y)))
255 (with-empty-tn@fp-top(imag-tn)
256 (inst fldd (ea-for-cdf-imag-stack x)))))
258 (define-move-function (store-complex-double 2) (vop x y)
259 ((complex-double-reg) (complex-double-stack))
260 (let ((real-tn (complex-double-reg-real-tn x)))
261 (cond ((zerop (tn-offset real-tn))
262 (inst fstd (ea-for-cdf-real-stack y)))
265 (inst fstd (ea-for-cdf-real-stack y))
266 (inst fxch real-tn))))
267 (let ((imag-tn (complex-double-reg-imag-tn x)))
269 (inst fstd (ea-for-cdf-imag-stack y))
270 (inst fxch imag-tn)))
273 (define-move-function (load-complex-long 2) (vop x y)
274 ((complex-long-stack) (complex-long-reg))
275 (let ((real-tn (complex-long-reg-real-tn y)))
276 (with-empty-tn@fp-top(real-tn)
277 (inst fldl (ea-for-clf-real-stack x))))
278 (let ((imag-tn (complex-long-reg-imag-tn y)))
279 (with-empty-tn@fp-top(imag-tn)
280 (inst fldl (ea-for-clf-imag-stack x)))))
283 (define-move-function (store-complex-long 2) (vop x y)
284 ((complex-long-reg) (complex-long-stack))
285 (let ((real-tn (complex-long-reg-real-tn x)))
286 (cond ((zerop (tn-offset real-tn))
287 (store-long-float (ea-for-clf-real-stack y)))
290 (store-long-float (ea-for-clf-real-stack y))
291 (inst fxch real-tn))))
292 (let ((imag-tn (complex-long-reg-imag-tn x)))
294 (store-long-float (ea-for-clf-imag-stack y))
295 (inst fxch imag-tn)))
300 ;;; float register to register moves
301 (define-vop (float-move)
306 (unless (location= x y)
307 (cond ((zerop (tn-offset y))
308 (copy-fp-reg-to-fr0 x))
309 ((zerop (tn-offset x))
316 (define-vop (single-move float-move)
317 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
318 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
319 (define-move-vop single-move :move (single-reg) (single-reg))
321 (define-vop (double-move float-move)
322 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
323 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
324 (define-move-vop double-move :move (double-reg) (double-reg))
327 (define-vop (long-move float-move)
328 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
329 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
331 (define-move-vop long-move :move (long-reg) (long-reg))
333 ;;; complex float register to register moves
334 (define-vop (complex-float-move)
335 (:args (x :target y :load-if (not (location= x y))))
336 (:results (y :load-if (not (location= x y))))
337 (:note "complex float move")
339 (unless (location= x y)
340 ;; Note the complex-float-regs are aligned to every second
341 ;; float register so there is not need to worry about overlap.
342 (let ((x-real (complex-double-reg-real-tn x))
343 (y-real (complex-double-reg-real-tn y)))
344 (cond ((zerop (tn-offset y-real))
345 (copy-fp-reg-to-fr0 x-real))
346 ((zerop (tn-offset x-real))
351 (inst fxch x-real))))
352 (let ((x-imag (complex-double-reg-imag-tn x))
353 (y-imag (complex-double-reg-imag-tn y)))
356 (inst fxch x-imag)))))
358 (define-vop (complex-single-move complex-float-move)
359 (:args (x :scs (complex-single-reg) :target y
360 :load-if (not (location= x y))))
361 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
362 (define-move-vop complex-single-move :move
363 (complex-single-reg) (complex-single-reg))
365 (define-vop (complex-double-move complex-float-move)
366 (:args (x :scs (complex-double-reg)
367 :target y :load-if (not (location= x y))))
368 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
369 (define-move-vop complex-double-move :move
370 (complex-double-reg) (complex-double-reg))
373 (define-vop (complex-long-move complex-float-move)
374 (:args (x :scs (complex-long-reg)
375 :target y :load-if (not (location= x y))))
376 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
378 (define-move-vop complex-long-move :move
379 (complex-long-reg) (complex-long-reg))
381 ;;; Move from float to a descriptor reg. allocating a new float
382 ;;; object in the process.
383 (define-vop (move-from-single)
384 (:args (x :scs (single-reg) :to :save))
385 (:results (y :scs (descriptor-reg)))
387 (:note "float to pointer coercion")
389 (with-fixed-allocation (y
390 sb!vm:single-float-type
391 sb!vm:single-float-size node)
393 (inst fst (ea-for-sf-desc y))))))
394 (define-move-vop move-from-single :move
395 (single-reg) (descriptor-reg))
397 (define-vop (move-from-double)
398 (:args (x :scs (double-reg) :to :save))
399 (:results (y :scs (descriptor-reg)))
401 (:note "float to pointer coercion")
403 (with-fixed-allocation (y
404 sb!vm:double-float-type
405 sb!vm:double-float-size
408 (inst fstd (ea-for-df-desc y))))))
409 (define-move-vop move-from-double :move
410 (double-reg) (descriptor-reg))
413 (define-vop (move-from-long)
414 (:args (x :scs (long-reg) :to :save))
415 (:results (y :scs (descriptor-reg)))
417 (:note "float to pointer coercion")
419 (with-fixed-allocation (y
420 sb!vm:long-float-type
421 sb!vm:long-float-size
424 (store-long-float (ea-for-lf-desc y))))))
426 (define-move-vop move-from-long :move
427 (long-reg) (descriptor-reg))
429 (define-vop (move-from-fp-constant)
430 (:args (x :scs (fp-constant)))
431 (:results (y :scs (descriptor-reg)))
433 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
434 (0f0 (load-symbol-value y *fp-constant-0s0*))
435 (1f0 (load-symbol-value y *fp-constant-1s0*))
436 (0d0 (load-symbol-value y *fp-constant-0d0*))
437 (1d0 (load-symbol-value y *fp-constant-1d0*))
439 (0l0 (load-symbol-value y *fp-constant-0l0*))
441 (1l0 (load-symbol-value y *fp-constant-1l0*))
443 (#.pi (load-symbol-value y *fp-constant-pi*))
445 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
447 (#.(log 2.718281828459045235360287471352662L0 2l0)
448 (load-symbol-value y *fp-constant-l2e*))
450 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
452 (#.(log 2l0 2.718281828459045235360287471352662L0)
453 (load-symbol-value y *fp-constant-ln2*)))))
454 (define-move-vop move-from-fp-constant :move
455 (fp-constant) (descriptor-reg))
457 ;;; Move from a descriptor to a float register.
458 (define-vop (move-to-single)
459 (:args (x :scs (descriptor-reg)))
460 (:results (y :scs (single-reg)))
461 (:note "pointer to float coercion")
463 (with-empty-tn@fp-top(y)
464 (inst fld (ea-for-sf-desc x)))))
465 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
467 (define-vop (move-to-double)
468 (:args (x :scs (descriptor-reg)))
469 (:results (y :scs (double-reg)))
470 (:note "pointer to float coercion")
472 (with-empty-tn@fp-top(y)
473 (inst fldd (ea-for-df-desc x)))))
474 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
477 (define-vop (move-to-long)
478 (:args (x :scs (descriptor-reg)))
479 (:results (y :scs (long-reg)))
480 (:note "pointer to float coercion")
482 (with-empty-tn@fp-top(y)
483 (inst fldl (ea-for-lf-desc x)))))
485 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
487 ;;; Move from complex float to a descriptor reg. allocating a new
488 ;;; complex float object in the process.
489 (define-vop (move-from-complex-single)
490 (:args (x :scs (complex-single-reg) :to :save))
491 (:results (y :scs (descriptor-reg)))
493 (:note "complex float to pointer coercion")
495 (with-fixed-allocation (y
496 sb!vm:complex-single-float-type
497 sb!vm:complex-single-float-size node)
498 (let ((real-tn (complex-single-reg-real-tn x)))
499 (with-tn@fp-top(real-tn)
500 (inst fst (ea-for-csf-real-desc y))))
501 (let ((imag-tn (complex-single-reg-imag-tn x)))
502 (with-tn@fp-top(imag-tn)
503 (inst fst (ea-for-csf-imag-desc y)))))))
504 (define-move-vop move-from-complex-single :move
505 (complex-single-reg) (descriptor-reg))
507 (define-vop (move-from-complex-double)
508 (:args (x :scs (complex-double-reg) :to :save))
509 (:results (y :scs (descriptor-reg)))
511 (:note "complex float to pointer coercion")
513 (with-fixed-allocation (y
514 sb!vm:complex-double-float-type
515 sb!vm:complex-double-float-size
517 (let ((real-tn (complex-double-reg-real-tn x)))
518 (with-tn@fp-top(real-tn)
519 (inst fstd (ea-for-cdf-real-desc y))))
520 (let ((imag-tn (complex-double-reg-imag-tn x)))
521 (with-tn@fp-top(imag-tn)
522 (inst fstd (ea-for-cdf-imag-desc y)))))))
523 (define-move-vop move-from-complex-double :move
524 (complex-double-reg) (descriptor-reg))
527 (define-vop (move-from-complex-long)
528 (:args (x :scs (complex-long-reg) :to :save))
529 (:results (y :scs (descriptor-reg)))
531 (:note "complex float to pointer coercion")
533 (with-fixed-allocation (y
534 sb!vm:complex-long-float-type
535 sb!vm:complex-long-float-size
537 (let ((real-tn (complex-long-reg-real-tn x)))
538 (with-tn@fp-top(real-tn)
539 (store-long-float (ea-for-clf-real-desc y))))
540 (let ((imag-tn (complex-long-reg-imag-tn x)))
541 (with-tn@fp-top(imag-tn)
542 (store-long-float (ea-for-clf-imag-desc y)))))))
544 (define-move-vop move-from-complex-long :move
545 (complex-long-reg) (descriptor-reg))
547 ;;; Move from a descriptor to a complex float register.
548 (macrolet ((frob (name sc format)
551 (:args (x :scs (descriptor-reg)))
552 (:results (y :scs (,sc)))
553 (:note "pointer to complex float coercion")
555 (let ((real-tn (complex-double-reg-real-tn y)))
556 (with-empty-tn@fp-top(real-tn)
558 (:single '((inst fld (ea-for-csf-real-desc x))))
559 (:double '((inst fldd (ea-for-cdf-real-desc x))))
561 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
562 (let ((imag-tn (complex-double-reg-imag-tn y)))
563 (with-empty-tn@fp-top(imag-tn)
565 (:single '((inst fld (ea-for-csf-imag-desc x))))
566 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
568 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
569 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
570 (frob move-to-complex-single complex-single-reg :single)
571 (frob move-to-complex-double complex-double-reg :double)
573 (frob move-to-complex-double complex-long-reg :long))
575 ;;;; the move argument vops
577 ;;;; Note these are also used to stuff fp numbers onto the c-call
578 ;;;; stack so the order is different than the lisp-stack.
580 ;;; the general move-argument vop
581 (macrolet ((frob (name sc stack-sc format)
584 (:args (x :scs (,sc) :target y)
586 :load-if (not (sc-is y ,sc))))
588 (:note "float argument move")
589 (:generator ,(case format (:single 2) (:double 3) (:long 4))
592 (unless (location= x y)
593 (cond ((zerop (tn-offset y))
594 (copy-fp-reg-to-fr0 x))
595 ((zerop (tn-offset x))
602 (if (= (tn-offset fp) esp-offset)
603 (let* ((offset (* (tn-offset y) word-bytes))
604 (ea (make-ea :dword :base fp :disp offset)))
607 (:single '((inst fst ea)))
608 (:double '((inst fstd ea)))
610 (:long '((store-long-float ea))))))
613 :disp (- (* (+ (tn-offset y)
618 sb!vm:word-bytes)))))
621 (:single '((inst fst ea)))
622 (:double '((inst fstd ea)))
624 (:long '((store-long-float ea)))))))))))
625 (define-move-vop ,name :move-argument
626 (,sc descriptor-reg) (,sc)))))
627 (frob move-single-float-argument single-reg single-stack :single)
628 (frob move-double-float-argument double-reg double-stack :double)
630 (frob move-long-float-argument long-reg long-stack :long))
632 ;;;; complex float move-argument vop
633 (macrolet ((frob (name sc stack-sc format)
636 (:args (x :scs (,sc) :target y)
638 :load-if (not (sc-is y ,sc))))
640 (:note "complex float argument move")
641 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
644 (unless (location= x y)
645 (let ((x-real (complex-double-reg-real-tn x))
646 (y-real (complex-double-reg-real-tn y)))
647 (cond ((zerop (tn-offset y-real))
648 (copy-fp-reg-to-fr0 x-real))
649 ((zerop (tn-offset x-real))
654 (inst fxch x-real))))
655 (let ((x-imag (complex-double-reg-imag-tn x))
656 (y-imag (complex-double-reg-imag-tn y)))
659 (inst fxch x-imag))))
661 (let ((real-tn (complex-double-reg-real-tn x)))
662 (cond ((zerop (tn-offset real-tn))
666 (ea-for-csf-real-stack y fp))))
669 (ea-for-cdf-real-stack y fp))))
673 (ea-for-clf-real-stack y fp))))))
679 (ea-for-csf-real-stack y fp))))
682 (ea-for-cdf-real-stack y fp))))
686 (ea-for-clf-real-stack y fp)))))
687 (inst fxch real-tn))))
688 (let ((imag-tn (complex-double-reg-imag-tn x)))
692 '((inst fst (ea-for-csf-imag-stack y fp))))
694 '((inst fstd (ea-for-cdf-imag-stack y fp))))
698 (ea-for-clf-imag-stack y fp)))))
699 (inst fxch imag-tn))))))
700 (define-move-vop ,name :move-argument
701 (,sc descriptor-reg) (,sc)))))
702 (frob move-complex-single-float-argument
703 complex-single-reg complex-single-stack :single)
704 (frob move-complex-double-float-argument
705 complex-double-reg complex-double-stack :double)
707 (frob move-complex-long-float-argument
708 complex-long-reg complex-long-stack :long))
710 (define-move-vop move-argument :move-argument
711 (single-reg double-reg #!+long-float long-reg
712 complex-single-reg complex-double-reg #!+long-float complex-long-reg)
718 ;;; dtc: the floating point arithmetic vops
720 ;;; Note: Although these can accept x and y on the stack or pointed to
721 ;;; from a descriptor register, they will work with register loading
722 ;;; without these. Same deal with the result - it need only be a
723 ;;; register. When load-tns are needed they will probably be in ST0
724 ;;; and the code below should be able to correctly handle all cases.
726 ;;; However it seems to produce better code if all arg. and result
727 ;;; options are used; on the P86 there is no extra cost in using a
728 ;;; memory operand to the FP instructions - not so on the PPro.
730 ;;; It may also be useful to handle constant args?
732 ;;; 22-Jul-97: descriptor args lose in some simple cases when
733 ;;; a function result computed in a loop. Then Python insists
734 ;;; on consing the intermediate values! For example
737 (declare (type (simple-array double-float (*)) a)
740 (declare (type double-float sum))
742 (incf sum (* (aref a i)(aref a i))))
745 ;;; So, disabling descriptor args until this can be fixed elsewhere.
747 ((frob (op fop-sti fopr-sti
749 fopd foprd dname dcost
751 #!-long-float (declare (ignore lcost lname))
755 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
757 (y :scs (single-reg single-stack #+nil descriptor-reg)
759 (:temporary (:sc single-reg :offset fr0-offset
760 :from :eval :to :result) fr0)
761 (:results (r :scs (single-reg single-stack)))
762 (:arg-types single-float single-float)
763 (:result-types single-float)
765 (:note "inline float arithmetic")
767 (:save-p :compute-only)
770 ;; Handle a few special cases
772 ;; x, y, and r are the same register.
773 ((and (sc-is x single-reg) (location= x r) (location= y r))
774 (cond ((zerop (tn-offset r))
779 ;; XX the source register will not be valid.
780 (note-next-instruction vop :internal-error)
783 ;; x and r are the same register.
784 ((and (sc-is x single-reg) (location= x r))
785 (cond ((zerop (tn-offset r))
788 ;; ST(0) = ST(0) op ST(y)
791 ;; ST(0) = ST(0) op Mem
792 (inst ,fop (ea-for-sf-stack y)))
794 (inst ,fop (ea-for-sf-desc y)))))
799 (unless (zerop (tn-offset y))
800 (copy-fp-reg-to-fr0 y)))
801 ((single-stack descriptor-reg)
803 (if (sc-is y single-stack)
804 (inst fld (ea-for-sf-stack y))
805 (inst fld (ea-for-sf-desc y)))))
806 ;; ST(i) = ST(i) op ST0
808 (maybe-fp-wait node vop))
809 ;; y and r are the same register.
810 ((and (sc-is y single-reg) (location= y r))
811 (cond ((zerop (tn-offset r))
814 ;; ST(0) = ST(x) op ST(0)
817 ;; ST(0) = Mem op ST(0)
818 (inst ,fopr (ea-for-sf-stack x)))
820 (inst ,fopr (ea-for-sf-desc x)))))
825 (unless (zerop (tn-offset x))
826 (copy-fp-reg-to-fr0 x)))
827 ((single-stack descriptor-reg)
829 (if (sc-is x single-stack)
830 (inst fld (ea-for-sf-stack x))
831 (inst fld (ea-for-sf-desc x)))))
832 ;; ST(i) = ST(0) op ST(i)
834 (maybe-fp-wait node vop))
837 ;; Get the result to ST0.
839 ;; Special handling is needed if x or y are in ST0, and
840 ;; simpler code is generated.
843 ((and (sc-is x single-reg) (zerop (tn-offset x)))
849 (inst ,fop (ea-for-sf-stack y)))
851 (inst ,fop (ea-for-sf-desc y)))))
853 ((and (sc-is y single-reg) (zerop (tn-offset y)))
859 (inst ,fopr (ea-for-sf-stack x)))
861 (inst ,fopr (ea-for-sf-desc x)))))
866 (copy-fp-reg-to-fr0 x))
869 (inst fld (ea-for-sf-stack x)))
872 (inst fld (ea-for-sf-desc x))))
878 (inst ,fop (ea-for-sf-stack y)))
880 (inst ,fop (ea-for-sf-desc y))))))
882 (note-next-instruction vop :internal-error)
884 ;; Finally save the result.
887 (cond ((zerop (tn-offset r))
888 (maybe-fp-wait node))
892 (inst fst (ea-for-sf-stack r))))))))
896 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
898 (y :scs (double-reg double-stack #+nil descriptor-reg)
900 (:temporary (:sc double-reg :offset fr0-offset
901 :from :eval :to :result) fr0)
902 (:results (r :scs (double-reg double-stack)))
903 (:arg-types double-float double-float)
904 (:result-types double-float)
906 (:note "inline float arithmetic")
908 (:save-p :compute-only)
911 ;; Handle a few special cases.
913 ;; x, y, and r are the same register.
914 ((and (sc-is x double-reg) (location= x r) (location= y r))
915 (cond ((zerop (tn-offset r))
920 ;; XX the source register will not be valid.
921 (note-next-instruction vop :internal-error)
924 ;; x and r are the same register.
925 ((and (sc-is x double-reg) (location= x r))
926 (cond ((zerop (tn-offset r))
929 ;; ST(0) = ST(0) op ST(y)
932 ;; ST(0) = ST(0) op Mem
933 (inst ,fopd (ea-for-df-stack y)))
935 (inst ,fopd (ea-for-df-desc y)))))
940 (unless (zerop (tn-offset y))
941 (copy-fp-reg-to-fr0 y)))
942 ((double-stack descriptor-reg)
944 (if (sc-is y double-stack)
945 (inst fldd (ea-for-df-stack y))
946 (inst fldd (ea-for-df-desc y)))))
947 ;; ST(i) = ST(i) op ST0
949 (maybe-fp-wait node vop))
950 ;; y and r are the same register.
951 ((and (sc-is y double-reg) (location= y r))
952 (cond ((zerop (tn-offset r))
955 ;; ST(0) = ST(x) op ST(0)
958 ;; ST(0) = Mem op ST(0)
959 (inst ,foprd (ea-for-df-stack x)))
961 (inst ,foprd (ea-for-df-desc x)))))
966 (unless (zerop (tn-offset x))
967 (copy-fp-reg-to-fr0 x)))
968 ((double-stack descriptor-reg)
970 (if (sc-is x double-stack)
971 (inst fldd (ea-for-df-stack x))
972 (inst fldd (ea-for-df-desc x)))))
973 ;; ST(i) = ST(0) op ST(i)
975 (maybe-fp-wait node vop))
978 ;; Get the result to ST0.
980 ;; Special handling is needed if x or y are in ST0, and
981 ;; simpler code is generated.
984 ((and (sc-is x double-reg) (zerop (tn-offset x)))
990 (inst ,fopd (ea-for-df-stack y)))
992 (inst ,fopd (ea-for-df-desc y)))))
994 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1000 (inst ,foprd (ea-for-df-stack x)))
1002 (inst ,foprd (ea-for-df-desc x)))))
1007 (copy-fp-reg-to-fr0 x))
1010 (inst fldd (ea-for-df-stack x)))
1013 (inst fldd (ea-for-df-desc x))))
1019 (inst ,fopd (ea-for-df-stack y)))
1021 (inst ,fopd (ea-for-df-desc y))))))
1023 (note-next-instruction vop :internal-error)
1025 ;; Finally save the result.
1028 (cond ((zerop (tn-offset r))
1029 (maybe-fp-wait node))
1033 (inst fstd (ea-for-df-stack r))))))))
1036 (define-vop (,lname)
1038 (:args (x :scs (long-reg) :to :eval)
1039 (y :scs (long-reg) :to :eval))
1040 (:temporary (:sc long-reg :offset fr0-offset
1041 :from :eval :to :result) fr0)
1042 (:results (r :scs (long-reg)))
1043 (:arg-types long-float long-float)
1044 (:result-types long-float)
1045 (:policy :fast-safe)
1046 (:note "inline float arithmetic")
1048 (:save-p :compute-only)
1051 ;; Handle a few special cases.
1053 ;; x, y, and r are the same register.
1054 ((and (location= x r) (location= y r))
1055 (cond ((zerop (tn-offset r))
1060 ;; XX the source register will not be valid.
1061 (note-next-instruction vop :internal-error)
1064 ;; x and r are the same register.
1066 (cond ((zerop (tn-offset r))
1067 ;; ST(0) = ST(0) op ST(y)
1071 (unless (zerop (tn-offset y))
1072 (copy-fp-reg-to-fr0 y))
1073 ;; ST(i) = ST(i) op ST0
1075 (maybe-fp-wait node vop))
1076 ;; y and r are the same register.
1078 (cond ((zerop (tn-offset r))
1079 ;; ST(0) = ST(x) op ST(0)
1083 (unless (zerop (tn-offset x))
1084 (copy-fp-reg-to-fr0 x))
1085 ;; ST(i) = ST(0) op ST(i)
1086 (inst ,fopr-sti r)))
1087 (maybe-fp-wait node vop))
1090 ;; Get the result to ST0.
1092 ;; Special handling is needed if x or y are in ST0, and
1093 ;; simpler code is generated.
1096 ((zerop (tn-offset x))
1100 ((zerop (tn-offset y))
1105 (copy-fp-reg-to-fr0 x)
1109 (note-next-instruction vop :internal-error)
1111 ;; Finally save the result.
1112 (cond ((zerop (tn-offset r))
1113 (maybe-fp-wait node))
1115 (inst fst r))))))))))
1117 (frob + fadd-sti fadd-sti
1118 fadd fadd +/single-float 2
1119 faddd faddd +/double-float 2
1121 (frob - fsub-sti fsubr-sti
1122 fsub fsubr -/single-float 2
1123 fsubd fsubrd -/double-float 2
1125 (frob * fmul-sti fmul-sti
1126 fmul fmul */single-float 3
1127 fmuld fmuld */double-float 3
1129 (frob / fdiv-sti fdivr-sti
1130 fdiv fdivr //single-float 12
1131 fdivd fdivrd //double-float 12
1134 (macrolet ((frob (name inst translate sc type)
1135 `(define-vop (,name)
1136 (:args (x :scs (,sc) :target fr0))
1137 (:results (y :scs (,sc)))
1138 (:translate ,translate)
1139 (:policy :fast-safe)
1141 (:result-types ,type)
1142 (:temporary (:sc double-reg :offset fr0-offset
1143 :from :argument :to :result) fr0)
1145 (:note "inline float arithmetic")
1147 (:save-p :compute-only)
1149 (note-this-location vop :internal-error)
1150 (unless (zerop (tn-offset x))
1151 (inst fxch x) ; x to top of stack
1152 (unless (location= x y)
1153 (inst fst x))) ; Maybe save it.
1154 (inst ,inst) ; Clobber st0.
1155 (unless (zerop (tn-offset y))
1158 (frob abs/single-float fabs abs single-reg single-float)
1159 (frob abs/double-float fabs abs double-reg double-float)
1161 (frob abs/long-float fabs abs long-reg long-float)
1162 (frob %negate/single-float fchs %negate single-reg single-float)
1163 (frob %negate/double-float fchs %negate double-reg double-float)
1165 (frob %negate/long-float fchs %negate long-reg long-float))
1169 (define-vop (=/float)
1171 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1173 (:info target not-p)
1174 (:policy :fast-safe)
1176 (:save-p :compute-only)
1177 (:note "inline float comparison")
1180 (note-this-location vop :internal-error)
1182 ;; x is in ST0; y is in any reg.
1183 ((zerop (tn-offset x))
1185 ;; y is in ST0; x is in another reg.
1186 ((zerop (tn-offset y))
1188 ;; x and y are the same register, not ST0
1193 ;; x and y are different registers, neither ST0.
1198 (inst fnstsw) ; status word to ax
1199 (inst and ah-tn #x45) ; C3 C2 C0
1200 (inst cmp ah-tn #x40)
1201 (inst jmp (if not-p :ne :e) target)))
1203 (define-vop (=/single-float =/float)
1205 (:args (x :scs (single-reg))
1206 (y :scs (single-reg)))
1207 (:arg-types single-float single-float))
1209 (define-vop (=/double-float =/float)
1211 (:args (x :scs (double-reg))
1212 (y :scs (double-reg)))
1213 (:arg-types double-float double-float))
1216 (define-vop (=/long-float =/float)
1218 (:args (x :scs (long-reg))
1219 (y :scs (long-reg)))
1220 (:arg-types long-float long-float))
1222 (define-vop (<single-float)
1224 (:args (x :scs (single-reg single-stack descriptor-reg))
1225 (y :scs (single-reg single-stack descriptor-reg)))
1226 (:arg-types single-float single-float)
1227 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1228 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1230 (:info target not-p)
1231 (:policy :fast-safe)
1232 (:note "inline float comparison")
1235 ;; Handle a few special cases.
1238 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1242 ((single-stack descriptor-reg)
1243 (if (sc-is x single-stack)
1244 (inst fcom (ea-for-sf-stack x))
1245 (inst fcom (ea-for-sf-desc x)))))
1246 (inst fnstsw) ; status word to ax
1247 (inst and ah-tn #x45))
1249 ;; general case when y is not in ST0
1254 (unless (zerop (tn-offset x))
1255 (copy-fp-reg-to-fr0 x)))
1256 ((single-stack descriptor-reg)
1258 (if (sc-is x single-stack)
1259 (inst fld (ea-for-sf-stack x))
1260 (inst fld (ea-for-sf-desc x)))))
1264 ((single-stack descriptor-reg)
1265 (if (sc-is y single-stack)
1266 (inst fcom (ea-for-sf-stack y))
1267 (inst fcom (ea-for-sf-desc y)))))
1268 (inst fnstsw) ; status word to ax
1269 (inst and ah-tn #x45) ; C3 C2 C0
1270 (inst cmp ah-tn #x01)))
1271 (inst jmp (if not-p :ne :e) target)))
1273 (define-vop (<double-float)
1275 (:args (x :scs (double-reg double-stack descriptor-reg))
1276 (y :scs (double-reg double-stack descriptor-reg)))
1277 (:arg-types double-float double-float)
1278 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1279 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1281 (:info target not-p)
1282 (:policy :fast-safe)
1283 (:note "inline float comparison")
1286 ;; Handle a few special cases
1289 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1293 ((double-stack descriptor-reg)
1294 (if (sc-is x double-stack)
1295 (inst fcomd (ea-for-df-stack x))
1296 (inst fcomd (ea-for-df-desc x)))))
1297 (inst fnstsw) ; status word to ax
1298 (inst and ah-tn #x45))
1300 ;; General case when y is not in ST0.
1305 (unless (zerop (tn-offset x))
1306 (copy-fp-reg-to-fr0 x)))
1307 ((double-stack descriptor-reg)
1309 (if (sc-is x double-stack)
1310 (inst fldd (ea-for-df-stack x))
1311 (inst fldd (ea-for-df-desc x)))))
1315 ((double-stack descriptor-reg)
1316 (if (sc-is y double-stack)
1317 (inst fcomd (ea-for-df-stack y))
1318 (inst fcomd (ea-for-df-desc y)))))
1319 (inst fnstsw) ; status word to ax
1320 (inst and ah-tn #x45) ; C3 C2 C0
1321 (inst cmp ah-tn #x01)))
1322 (inst jmp (if not-p :ne :e) target)))
1325 (define-vop (<long-float)
1327 (:args (x :scs (long-reg))
1328 (y :scs (long-reg)))
1329 (:arg-types long-float long-float)
1330 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1332 (:info target not-p)
1333 (:policy :fast-safe)
1334 (:note "inline float comparison")
1338 ;; x is in ST0; y is in any reg.
1339 ((zerop (tn-offset x))
1341 (inst fnstsw) ; status word to ax
1342 (inst and ah-tn #x45) ; C3 C2 C0
1343 (inst cmp ah-tn #x01))
1344 ;; y is in ST0; x is in another reg.
1345 ((zerop (tn-offset y))
1347 (inst fnstsw) ; status word to ax
1348 (inst and ah-tn #x45))
1349 ;; x and y are the same register, not ST0
1350 ;; x and y are different registers, neither ST0.
1355 (inst fnstsw) ; status word to ax
1356 (inst and ah-tn #x45))) ; C3 C2 C0
1357 (inst jmp (if not-p :ne :e) target)))
1359 (define-vop (>single-float)
1361 (:args (x :scs (single-reg single-stack descriptor-reg))
1362 (y :scs (single-reg single-stack descriptor-reg)))
1363 (:arg-types single-float single-float)
1364 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1365 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1367 (:info target not-p)
1368 (:policy :fast-safe)
1369 (:note "inline float comparison")
1372 ;; Handle a few special cases.
1375 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1379 ((single-stack descriptor-reg)
1380 (if (sc-is x single-stack)
1381 (inst fcom (ea-for-sf-stack x))
1382 (inst fcom (ea-for-sf-desc x)))))
1383 (inst fnstsw) ; status word to ax
1384 (inst and ah-tn #x45)
1385 (inst cmp ah-tn #x01))
1387 ;; general case when y is not in ST0
1392 (unless (zerop (tn-offset x))
1393 (copy-fp-reg-to-fr0 x)))
1394 ((single-stack descriptor-reg)
1396 (if (sc-is x single-stack)
1397 (inst fld (ea-for-sf-stack x))
1398 (inst fld (ea-for-sf-desc x)))))
1402 ((single-stack descriptor-reg)
1403 (if (sc-is y single-stack)
1404 (inst fcom (ea-for-sf-stack y))
1405 (inst fcom (ea-for-sf-desc y)))))
1406 (inst fnstsw) ; status word to ax
1407 (inst and ah-tn #x45)))
1408 (inst jmp (if not-p :ne :e) target)))
1410 (define-vop (>double-float)
1412 (:args (x :scs (double-reg double-stack descriptor-reg))
1413 (y :scs (double-reg double-stack descriptor-reg)))
1414 (:arg-types double-float double-float)
1415 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1416 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1418 (:info target not-p)
1419 (:policy :fast-safe)
1420 (:note "inline float comparison")
1423 ;; Handle a few special cases.
1426 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1430 ((double-stack descriptor-reg)
1431 (if (sc-is x double-stack)
1432 (inst fcomd (ea-for-df-stack x))
1433 (inst fcomd (ea-for-df-desc x)))))
1434 (inst fnstsw) ; status word to ax
1435 (inst and ah-tn #x45)
1436 (inst cmp ah-tn #x01))
1438 ;; general case when y is not in ST0
1443 (unless (zerop (tn-offset x))
1444 (copy-fp-reg-to-fr0 x)))
1445 ((double-stack descriptor-reg)
1447 (if (sc-is x double-stack)
1448 (inst fldd (ea-for-df-stack x))
1449 (inst fldd (ea-for-df-desc x)))))
1453 ((double-stack descriptor-reg)
1454 (if (sc-is y double-stack)
1455 (inst fcomd (ea-for-df-stack y))
1456 (inst fcomd (ea-for-df-desc y)))))
1457 (inst fnstsw) ; status word to ax
1458 (inst and ah-tn #x45)))
1459 (inst jmp (if not-p :ne :e) target)))
1462 (define-vop (>long-float)
1464 (:args (x :scs (long-reg))
1465 (y :scs (long-reg)))
1466 (:arg-types long-float long-float)
1467 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1469 (:info target not-p)
1470 (:policy :fast-safe)
1471 (:note "inline float comparison")
1475 ;; y is in ST0; x is in any reg.
1476 ((zerop (tn-offset y))
1478 (inst fnstsw) ; status word to ax
1479 (inst and ah-tn #x45)
1480 (inst cmp ah-tn #x01))
1481 ;; x is in ST0; y is in another reg.
1482 ((zerop (tn-offset x))
1484 (inst fnstsw) ; status word to ax
1485 (inst and ah-tn #x45))
1486 ;; y and x are the same register, not ST0
1487 ;; y and x are different registers, neither ST0.
1492 (inst fnstsw) ; status word to ax
1493 (inst and ah-tn #x45)))
1494 (inst jmp (if not-p :ne :e) target)))
1496 ;;; Comparisons with 0 can use the FTST instruction.
1498 (define-vop (float-test)
1500 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1502 (:info target not-p y)
1503 (:variant-vars code)
1504 (:policy :fast-safe)
1506 (:save-p :compute-only)
1507 (:note "inline float comparison")
1510 (note-this-location vop :internal-error)
1513 ((zerop (tn-offset x))
1520 (inst fnstsw) ; status word to ax
1521 (inst and ah-tn #x45) ; C3 C2 C0
1522 (unless (zerop code)
1523 (inst cmp ah-tn code))
1524 (inst jmp (if not-p :ne :e) target)))
1526 (define-vop (=0/single-float float-test)
1528 (:args (x :scs (single-reg)))
1529 #!-negative-zero-is-not-zero
1530 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1531 #!+negative-zero-is-not-zero
1532 (:arg-types single-float (:constant (single-float -0f0 0f0)))
1534 (define-vop (=0/double-float float-test)
1536 (:args (x :scs (double-reg)))
1537 #!-negative-zero-is-not-zero
1538 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1539 #!+negative-zero-is-not-zero
1540 (:arg-types double-float (:constant (double-float -0d0 0d0)))
1543 (define-vop (=0/long-float float-test)
1545 (:args (x :scs (long-reg)))
1546 #!-negative-zero-is-not-zero
1547 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1548 #!+negative-zero-is-not-zero
1549 (:arg-types long-float (:constant (long-float -0l0 0l0)))
1552 (define-vop (<0/single-float float-test)
1554 (:args (x :scs (single-reg)))
1555 #!-negative-zero-is-not-zero
1556 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1557 #!+negative-zero-is-not-zero
1558 (:arg-types single-float (:constant (single-float -0f0 0f0)))
1560 (define-vop (<0/double-float float-test)
1562 (:args (x :scs (double-reg)))
1563 #!-negative-zero-is-not-zero
1564 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1565 #!+negative-zero-is-not-zero
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 #!-negative-zero-is-not-zero
1573 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1574 #!+negative-zero-is-not-zero
1575 (:arg-types long-float (:constant (long-float -0l0 0l0)))
1578 (define-vop (>0/single-float float-test)
1580 (:args (x :scs (single-reg)))
1581 #!-negative-zero-is-not-zero
1582 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1583 #!+negative-zero-is-not-zero
1584 (:arg-types single-float (:constant (single-float -0f0 0f0)))
1586 (define-vop (>0/double-float float-test)
1588 (:args (x :scs (double-reg)))
1589 #!-negative-zero-is-not-zero
1590 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1591 #!+negative-zero-is-not-zero
1592 (:arg-types double-float (:constant (double-float -0d0 0d0)))
1595 (define-vop (>0/long-float float-test)
1597 (:args (x :scs (long-reg)))
1598 #!-negative-zero-is-not-zero
1599 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1600 #!+negative-zero-is-not-zero
1601 (:arg-types long-float (:constant (long-float -0l0 0l0)))
1605 (deftransform eql ((x y) (long-float long-float))
1606 `(and (= (long-float-low-bits x) (long-float-low-bits y))
1607 (= (long-float-high-bits x) (long-float-high-bits y))
1608 (= (long-float-exp-bits x) (long-float-exp-bits y))))
1612 (macrolet ((frob (name translate to-sc to-type)
1613 `(define-vop (,name)
1614 (:args (x :scs (signed-stack signed-reg) :target temp))
1615 (:temporary (:sc signed-stack) temp)
1616 (:results (y :scs (,to-sc)))
1617 (:arg-types signed-num)
1618 (:result-types ,to-type)
1619 (:policy :fast-safe)
1620 (:note "inline float coercion")
1621 (:translate ,translate)
1623 (:save-p :compute-only)
1628 (with-empty-tn@fp-top(y)
1629 (note-this-location vop :internal-error)
1632 (with-empty-tn@fp-top(y)
1633 (note-this-location vop :internal-error)
1634 (inst fild x))))))))
1635 (frob %single-float/signed %single-float single-reg single-float)
1636 (frob %double-float/signed %double-float double-reg double-float)
1638 (frob %long-float/signed %long-float long-reg long-float))
1640 (macrolet ((frob (name translate to-sc to-type)
1641 `(define-vop (,name)
1642 (:args (x :scs (unsigned-reg)))
1643 (:results (y :scs (,to-sc)))
1644 (:arg-types unsigned-num)
1645 (:result-types ,to-type)
1646 (:policy :fast-safe)
1647 (:note "inline float coercion")
1648 (:translate ,translate)
1650 (:save-p :compute-only)
1654 (with-empty-tn@fp-top(y)
1655 (note-this-location vop :internal-error)
1656 (inst fildl (make-ea :dword :base esp-tn)))
1657 (inst add esp-tn 8)))))
1658 (frob %single-float/unsigned %single-float single-reg single-float)
1659 (frob %double-float/unsigned %double-float double-reg double-float)
1661 (frob %long-float/unsigned %long-float long-reg long-float))
1663 ;;; These should be no-ops but the compiler might want to move some
1665 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1666 `(define-vop (,name)
1667 (:args (x :scs (,from-sc) :target y))
1668 (:results (y :scs (,to-sc)))
1669 (:arg-types ,from-type)
1670 (:result-types ,to-type)
1671 (:policy :fast-safe)
1672 (:note "inline float coercion")
1673 (:translate ,translate)
1675 (:save-p :compute-only)
1677 (note-this-location vop :internal-error)
1678 (unless (location= x y)
1680 ((zerop (tn-offset x))
1681 ;; x is in ST0, y is in another reg. not ST0
1683 ((zerop (tn-offset y))
1684 ;; y is in ST0, x is in another reg. not ST0
1685 (copy-fp-reg-to-fr0 x))
1687 ;; Neither x or y are in ST0, and they are not in
1691 (inst fxch x))))))))
1693 (frob %single-float/double-float %single-float double-reg
1694 double-float single-reg single-float)
1696 (frob %single-float/long-float %single-float long-reg
1697 long-float single-reg single-float)
1698 (frob %double-float/single-float %double-float single-reg single-float
1699 double-reg double-float)
1701 (frob %double-float/long-float %double-float long-reg long-float
1702 double-reg double-float)
1704 (frob %long-float/single-float %long-float single-reg single-float
1705 long-reg long-float)
1707 (frob %long-float/double-float %long-float double-reg double-float
1708 long-reg long-float))
1710 (macrolet ((frob (trans from-sc from-type round-p)
1711 `(define-vop (,(symbolicate trans "/" from-type))
1712 (:args (x :scs (,from-sc)))
1713 (:temporary (:sc signed-stack) stack-temp)
1715 '((:temporary (:sc unsigned-stack) scw)
1716 (:temporary (:sc any-reg) rcw)))
1717 (:results (y :scs (signed-reg)))
1718 (:arg-types ,from-type)
1719 (:result-types signed-num)
1721 (:policy :fast-safe)
1722 (:note "inline float truncate")
1724 (:save-p :compute-only)
1727 '((note-this-location vop :internal-error)
1728 ;; Catch any pending FPE exceptions.
1730 (,(if round-p 'progn 'pseudo-atomic)
1731 ;; Normal mode (for now) is "round to best".
1734 '((inst fnstcw scw) ; save current control word
1735 (move rcw scw) ; into 16-bit register
1736 (inst or rcw (ash #b11 10)) ; CHOP
1737 (move stack-temp rcw)
1738 (inst fldcw stack-temp)))
1743 (inst fist stack-temp)
1744 (inst mov y stack-temp)))
1746 '((inst fldcw scw)))))))))
1747 (frob %unary-truncate single-reg single-float nil)
1748 (frob %unary-truncate double-reg double-float nil)
1750 (frob %unary-truncate long-reg long-float nil)
1751 (frob %unary-round single-reg single-float t)
1752 (frob %unary-round double-reg double-float t)
1754 (frob %unary-round long-reg long-float t))
1756 (macrolet ((frob (trans from-sc from-type round-p)
1757 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1758 (:args (x :scs (,from-sc) :target fr0))
1759 (:temporary (:sc double-reg :offset fr0-offset
1760 :from :argument :to :result) fr0)
1762 '((:temporary (:sc unsigned-stack) stack-temp)
1763 (:temporary (:sc unsigned-stack) scw)
1764 (:temporary (:sc any-reg) rcw)))
1765 (:results (y :scs (unsigned-reg)))
1766 (:arg-types ,from-type)
1767 (:result-types unsigned-num)
1769 (:policy :fast-safe)
1770 (:note "inline float truncate")
1772 (:save-p :compute-only)
1775 '((note-this-location vop :internal-error)
1776 ;; Catch any pending FPE exceptions.
1778 ;; Normal mode (for now) is "round to best".
1779 (unless (zerop (tn-offset x))
1780 (copy-fp-reg-to-fr0 x))
1782 '((inst fnstcw scw) ; save current control word
1783 (move rcw scw) ; into 16-bit register
1784 (inst or rcw (ash #b11 10)) ; CHOP
1785 (move stack-temp rcw)
1786 (inst fldcw stack-temp)))
1788 (inst fistpl (make-ea :dword :base esp-tn))
1790 (inst fld fr0) ; copy fr0 to at least restore stack.
1793 '((inst fldcw scw)))))))
1794 (frob %unary-truncate single-reg single-float nil)
1795 (frob %unary-truncate double-reg double-float nil)
1797 (frob %unary-truncate long-reg long-float nil)
1798 (frob %unary-round single-reg single-float t)
1799 (frob %unary-round double-reg double-float t)
1801 (frob %unary-round long-reg long-float t))
1803 (define-vop (make-single-float)
1804 (:args (bits :scs (signed-reg) :target res
1805 :load-if (not (or (and (sc-is bits signed-stack)
1806 (sc-is res single-reg))
1807 (and (sc-is bits signed-stack)
1808 (sc-is res single-stack)
1809 (location= bits res))))))
1810 (:results (res :scs (single-reg single-stack)))
1811 (:temporary (:sc signed-stack) stack-temp)
1812 (:arg-types signed-num)
1813 (:result-types single-float)
1814 (:translate make-single-float)
1815 (:policy :fast-safe)
1822 (inst mov res bits))
1824 (aver (location= bits res)))))
1828 ;; source must be in memory
1829 (inst mov stack-temp bits)
1830 (with-empty-tn@fp-top(res)
1831 (inst fld stack-temp)))
1833 (with-empty-tn@fp-top(res)
1834 (inst fld bits))))))))
1836 (define-vop (make-double-float)
1837 (:args (hi-bits :scs (signed-reg))
1838 (lo-bits :scs (unsigned-reg)))
1839 (:results (res :scs (double-reg)))
1840 (:temporary (:sc double-stack) temp)
1841 (:arg-types signed-num unsigned-num)
1842 (:result-types double-float)
1843 (:translate make-double-float)
1844 (:policy :fast-safe)
1847 (let ((offset (1+ (tn-offset temp))))
1848 (storew hi-bits ebp-tn (- offset))
1849 (storew lo-bits ebp-tn (- (1+ offset)))
1850 (with-empty-tn@fp-top(res)
1851 (inst fldd (make-ea :dword :base ebp-tn
1852 :disp (- (* (1+ offset) word-bytes))))))))
1855 (define-vop (make-long-float)
1856 (:args (exp-bits :scs (signed-reg))
1857 (hi-bits :scs (unsigned-reg))
1858 (lo-bits :scs (unsigned-reg)))
1859 (:results (res :scs (long-reg)))
1860 (:temporary (:sc long-stack) temp)
1861 (:arg-types signed-num unsigned-num unsigned-num)
1862 (:result-types long-float)
1863 (:translate make-long-float)
1864 (:policy :fast-safe)
1867 (let ((offset (1+ (tn-offset temp))))
1868 (storew exp-bits ebp-tn (- offset))
1869 (storew hi-bits ebp-tn (- (1+ offset)))
1870 (storew lo-bits ebp-tn (- (+ offset 2)))
1871 (with-empty-tn@fp-top(res)
1872 (inst fldl (make-ea :dword :base ebp-tn
1873 :disp (- (* (+ offset 2) word-bytes))))))))
1875 (define-vop (single-float-bits)
1876 (:args (float :scs (single-reg descriptor-reg)
1877 :load-if (not (sc-is float single-stack))))
1878 (:results (bits :scs (signed-reg)))
1879 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1880 (:arg-types single-float)
1881 (:result-types signed-num)
1882 (:translate single-float-bits)
1883 (:policy :fast-safe)
1890 (with-tn@fp-top(float)
1891 (inst fst stack-temp)
1892 (inst mov bits stack-temp)))
1894 (inst mov bits float))
1897 bits float sb!vm:single-float-value-slot
1898 sb!vm:other-pointer-type))))
1902 (with-tn@fp-top(float)
1903 (inst fst bits))))))))
1905 (define-vop (double-float-high-bits)
1906 (:args (float :scs (double-reg descriptor-reg)
1907 :load-if (not (sc-is float double-stack))))
1908 (:results (hi-bits :scs (signed-reg)))
1909 (:temporary (:sc double-stack) temp)
1910 (:arg-types double-float)
1911 (:result-types signed-num)
1912 (:translate double-float-high-bits)
1913 (:policy :fast-safe)
1918 (with-tn@fp-top(float)
1919 (let ((where (make-ea :dword :base ebp-tn
1920 :disp (- (* (+ 2 (tn-offset temp))
1923 (loadw hi-bits ebp-tn (- (1+ (tn-offset temp)))))
1925 (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
1927 (loadw hi-bits float (1+ sb!vm:double-float-value-slot)
1928 sb!vm:other-pointer-type)))))
1930 (define-vop (double-float-low-bits)
1931 (:args (float :scs (double-reg descriptor-reg)
1932 :load-if (not (sc-is float double-stack))))
1933 (:results (lo-bits :scs (unsigned-reg)))
1934 (:temporary (:sc double-stack) temp)
1935 (:arg-types double-float)
1936 (:result-types unsigned-num)
1937 (:translate double-float-low-bits)
1938 (:policy :fast-safe)
1943 (with-tn@fp-top(float)
1944 (let ((where (make-ea :dword :base ebp-tn
1945 :disp (- (* (+ 2 (tn-offset temp))
1948 (loadw lo-bits ebp-tn (- (+ 2 (tn-offset temp)))))
1950 (loadw lo-bits ebp-tn (- (+ 2 (tn-offset float)))))
1952 (loadw lo-bits float sb!vm:double-float-value-slot
1953 sb!vm:other-pointer-type)))))
1956 (define-vop (long-float-exp-bits)
1957 (:args (float :scs (long-reg descriptor-reg)
1958 :load-if (not (sc-is float long-stack))))
1959 (:results (exp-bits :scs (signed-reg)))
1960 (:temporary (:sc long-stack) temp)
1961 (:arg-types long-float)
1962 (:result-types signed-num)
1963 (:translate long-float-exp-bits)
1964 (:policy :fast-safe)
1969 (with-tn@fp-top(float)
1970 (let ((where (make-ea :dword :base ebp-tn
1971 :disp (- (* (+ 3 (tn-offset temp))
1973 (store-long-float where)))
1974 (inst movsx exp-bits
1975 (make-ea :word :base ebp-tn
1976 :disp (* (- (1+ (tn-offset temp))) word-bytes))))
1978 (inst movsx exp-bits
1979 (make-ea :word :base ebp-tn
1980 :disp (* (- (1+ (tn-offset float))) word-bytes))))
1982 (inst movsx exp-bits
1983 (make-ea :word :base float
1984 :disp (- (* (+ 2 sb!vm:long-float-value-slot)
1986 sb!vm:other-pointer-type)))))))
1989 (define-vop (long-float-high-bits)
1990 (:args (float :scs (long-reg descriptor-reg)
1991 :load-if (not (sc-is float long-stack))))
1992 (:results (hi-bits :scs (unsigned-reg)))
1993 (:temporary (:sc long-stack) temp)
1994 (:arg-types long-float)
1995 (:result-types unsigned-num)
1996 (:translate long-float-high-bits)
1997 (:policy :fast-safe)
2002 (with-tn@fp-top(float)
2003 (let ((where (make-ea :dword :base ebp-tn
2004 :disp (- (* (+ 3 (tn-offset temp))
2006 (store-long-float where)))
2007 (loadw hi-bits ebp-tn (- (+ (tn-offset temp) 2))))
2009 (loadw hi-bits ebp-tn (- (+ (tn-offset float) 2))))
2011 (loadw hi-bits float (1+ sb!vm:long-float-value-slot)
2012 sb!vm:other-pointer-type)))))
2015 (define-vop (long-float-low-bits)
2016 (:args (float :scs (long-reg descriptor-reg)
2017 :load-if (not (sc-is float long-stack))))
2018 (:results (lo-bits :scs (unsigned-reg)))
2019 (:temporary (:sc long-stack) temp)
2020 (:arg-types long-float)
2021 (:result-types unsigned-num)
2022 (:translate long-float-low-bits)
2023 (:policy :fast-safe)
2028 (with-tn@fp-top(float)
2029 (let ((where (make-ea :dword :base ebp-tn
2030 :disp (- (* (+ 3 (tn-offset temp))
2032 (store-long-float where)))
2033 (loadw lo-bits ebp-tn (- (+ (tn-offset temp) 3))))
2035 (loadw lo-bits ebp-tn (- (+ (tn-offset float) 3))))
2037 (loadw lo-bits float sb!vm:long-float-value-slot
2038 sb!vm:other-pointer-type)))))
2040 ;;;; float mode hackery
2042 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2043 (defknown floating-point-modes () float-modes (flushable))
2044 (defknown ((setf floating-point-modes)) (float-modes)
2047 (defconstant npx-env-size (* 7 sb!vm:word-bytes))
2048 (defconstant npx-cw-offset 0)
2049 (defconstant npx-sw-offset 4)
2051 (define-vop (floating-point-modes)
2052 (:results (res :scs (unsigned-reg)))
2053 (:result-types unsigned-num)
2054 (:translate floating-point-modes)
2055 (:policy :fast-safe)
2056 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2059 (inst sub esp-tn npx-env-size) ; Make space on stack.
2060 (inst wait) ; Catch any pending FPE exceptions
2061 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2062 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2063 ;; Move current status to high word.
2064 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2065 ;; Move exception mask to low word.
2066 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2067 (inst add esp-tn npx-env-size) ; Pop stack.
2068 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2071 (define-vop (set-floating-point-modes)
2072 (:args (new :scs (unsigned-reg) :to :result :target res))
2073 (:results (res :scs (unsigned-reg)))
2074 (:arg-types unsigned-num)
2075 (:result-types unsigned-num)
2076 (:translate (setf floating-point-modes))
2077 (:policy :fast-safe)
2078 (:temporary (:sc unsigned-reg :offset eax-offset
2079 :from :eval :to :result) eax)
2081 (inst sub esp-tn npx-env-size) ; Make space on stack.
2082 (inst wait) ; Catch any pending FPE exceptions.
2083 (inst fstenv (make-ea :dword :base esp-tn))
2085 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2086 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2087 (inst shr eax 16) ; position status word
2088 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2089 (inst fldenv (make-ea :dword :base esp-tn))
2090 (inst add esp-tn npx-env-size) ; Pop stack.
2096 ;;; Let's use some of the 80387 special functions.
2098 ;;; These defs will not take effect unless code/irrat.lisp is modified
2099 ;;; to remove the inlined alien routine def.
2101 (macrolet ((frob (func trans op)
2102 `(define-vop (,func)
2103 (:args (x :scs (double-reg) :target fr0))
2104 (:temporary (:sc double-reg :offset fr0-offset
2105 :from :argument :to :result) fr0)
2107 (:results (y :scs (double-reg)))
2108 (:arg-types double-float)
2109 (:result-types double-float)
2111 (:policy :fast-safe)
2112 (:note "inline NPX function")
2114 (:save-p :compute-only)
2117 (note-this-location vop :internal-error)
2118 (unless (zerop (tn-offset x))
2119 (inst fxch x) ; x to top of stack
2120 (unless (location= x y)
2121 (inst fst x))) ; maybe save it
2122 (inst ,op) ; clobber st0
2123 (cond ((zerop (tn-offset y))
2124 (maybe-fp-wait node))
2128 ;; Quick versions of fsin and fcos that require the argument to be
2129 ;; within range 2^63.
2130 (frob fsin-quick %sin-quick fsin)
2131 (frob fcos-quick %cos-quick fcos)
2132 (frob fsqrt %sqrt fsqrt))
2134 ;;; Quick version of ftan that requires the argument to be within
2136 (define-vop (ftan-quick)
2137 (:translate %tan-quick)
2138 (:args (x :scs (double-reg) :target fr0))
2139 (:temporary (:sc double-reg :offset fr0-offset
2140 :from :argument :to :result) fr0)
2141 (:temporary (:sc double-reg :offset fr1-offset
2142 :from :argument :to :result) fr1)
2143 (:results (y :scs (double-reg)))
2144 (:arg-types double-float)
2145 (:result-types double-float)
2146 (:policy :fast-safe)
2147 (:note "inline tan function")
2149 (:save-p :compute-only)
2151 (note-this-location vop :internal-error)
2160 (inst fldd (make-random-tn :kind :normal
2161 :sc (sc-or-lose 'double-reg)
2162 :offset (- (tn-offset x) 2)))))
2173 ;;; These versions of fsin, fcos, and ftan try to use argument
2174 ;;; reduction but to do this accurately requires greater precision and
2175 ;;; it is hopelessly inaccurate.
2177 (macrolet ((frob (func trans op)
2178 `(define-vop (,func)
2180 (:args (x :scs (double-reg) :target fr0))
2181 (:temporary (:sc unsigned-reg :offset eax-offset
2182 :from :eval :to :result) eax)
2183 (:temporary (:sc unsigned-reg :offset fr0-offset
2184 :from :argument :to :result) fr0)
2185 (:temporary (:sc unsigned-reg :offset fr1-offset
2186 :from :argument :to :result) fr1)
2187 (:results (y :scs (double-reg)))
2188 (:arg-types double-float)
2189 (:result-types double-float)
2190 (:policy :fast-safe)
2191 (:note "inline sin/cos function")
2193 (:save-p :compute-only)
2196 (note-this-location vop :internal-error)
2197 (unless (zerop (tn-offset x))
2198 (inst fxch x) ; x to top of stack
2199 (unless (location= x y)
2200 (inst fst x))) ; maybe save it
2202 (inst fnstsw) ; status word to ax
2203 (inst and ah-tn #x04) ; C2
2205 ;; Else x was out of range so reduce it; ST0 is unchanged.
2206 (inst fstp fr1) ; Load 2*PI
2212 (inst fnstsw) ; status word to ax
2213 (inst and ah-tn #x04) ; C2
2217 (unless (zerop (tn-offset y))
2219 (frob fsin %sin fsin)
2220 (frob fcos %cos fcos))
2225 (:args (x :scs (double-reg) :target fr0))
2226 (:temporary (:sc unsigned-reg :offset eax-offset
2227 :from :argument :to :result) eax)
2228 (:temporary (:sc double-reg :offset fr0-offset
2229 :from :argument :to :result) fr0)
2230 (:temporary (:sc double-reg :offset fr1-offset
2231 :from :argument :to :result) fr1)
2232 (:results (y :scs (double-reg)))
2233 (:arg-types double-float)
2234 (:result-types double-float)
2235 (:policy :fast-safe)
2236 (:note "inline tan function")
2238 (:save-p :compute-only)
2241 (note-this-location vop :internal-error)
2250 (inst fldd (make-random-tn :kind :normal
2251 :sc (sc-or-lose 'double-reg)
2252 :offset (- (tn-offset x) 2)))))
2254 (inst fnstsw) ; status word to ax
2255 (inst and ah-tn #x04) ; C2
2257 ;; Else x was out of range so reduce it; ST0 is unchanged.
2258 (inst fldpi) ; Load 2*PI
2263 (inst fnstsw) ; status word to ax
2264 (inst and ah-tn #x04) ; C2
2278 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
2279 ;;; the argument is out of range 2^63 and would thus be hopelessly
2281 (macrolet ((frob (func trans op)
2282 `(define-vop (,func)
2284 (:args (x :scs (double-reg) :target fr0))
2285 (:temporary (:sc double-reg :offset fr0-offset
2286 :from :argument :to :result) fr0)
2287 (:temporary (:sc unsigned-reg :offset eax-offset
2288 :from :argument :to :result) eax)
2289 (:results (y :scs (double-reg)))
2290 (:arg-types double-float)
2291 (:result-types double-float)
2292 (:policy :fast-safe)
2293 (:note "inline sin/cos function")
2295 (:save-p :compute-only)
2298 (note-this-location vop :internal-error)
2299 (unless (zerop (tn-offset x))
2300 (inst fxch x) ; x to top of stack
2301 (unless (location= x y)
2302 (inst fst x))) ; maybe save it
2304 (inst fnstsw) ; status word to ax
2305 (inst and ah-tn #x04) ; C2
2307 ;; Else x was out of range so reduce it; ST0 is unchanged.
2308 (inst fstp fr0) ; Load 0.0
2311 (unless (zerop (tn-offset y))
2313 (frob fsin %sin fsin)
2314 (frob fcos %cos fcos))
2318 (:args (x :scs (double-reg) :target fr0))
2319 (:temporary (:sc double-reg :offset fr0-offset
2320 :from :argument :to :result) fr0)
2321 (:temporary (:sc double-reg :offset fr1-offset
2322 :from :argument :to :result) fr1)
2323 (:temporary (:sc unsigned-reg :offset eax-offset
2324 :from :argument :to :result) eax)
2325 (:results (y :scs (double-reg)))
2326 (:arg-types double-float)
2327 (:result-types double-float)
2329 (:policy :fast-safe)
2330 (:note "inline tan function")
2332 (:save-p :compute-only)
2335 (note-this-location vop :internal-error)
2344 (inst fldd (make-random-tn :kind :normal
2345 :sc (sc-or-lose 'double-reg)
2346 :offset (- (tn-offset x) 2)))))
2348 (inst fnstsw) ; status word to ax
2349 (inst and ah-tn #x04) ; C2
2351 ;; Else x was out of range so reduce it; ST0 is unchanged.
2352 (inst fldz) ; Load 0.0
2367 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2368 (:temporary (:sc double-reg :offset fr0-offset
2369 :from :argument :to :result) fr0)
2370 (:temporary (:sc double-reg :offset fr1-offset
2371 :from :argument :to :result) fr1)
2372 (:temporary (:sc double-reg :offset fr2-offset
2373 :from :argument :to :result) fr2)
2374 (:results (y :scs (double-reg)))
2375 (:arg-types double-float)
2376 (:result-types double-float)
2377 (:policy :fast-safe)
2378 (:note "inline exp function")
2380 (:save-p :compute-only)
2382 (note-this-location vop :internal-error)
2385 (cond ((zerop (tn-offset x))
2391 ;; x is in a FP reg, not fr0
2395 ((double-stack descriptor-reg)
2398 (if (sc-is x double-stack)
2399 (inst fmuld (ea-for-df-stack x))
2400 (inst fmuld (ea-for-df-desc x)))))
2401 ;; Now fr0=x log2(e)
2405 (inst fsubp-sti fr1)
2408 (inst faddp-sti fr1)
2413 (t (inst fstd y)))))
2415 ;;; Modified exp that handles the following special cases:
2416 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
2419 (:args (x :scs (double-reg) :target fr0))
2420 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2421 (:temporary (:sc double-reg :offset fr0-offset
2422 :from :argument :to :result) fr0)
2423 (:temporary (:sc double-reg :offset fr1-offset
2424 :from :argument :to :result) fr1)
2425 (:temporary (:sc double-reg :offset fr2-offset
2426 :from :argument :to :result) fr2)
2427 (:results (y :scs (double-reg)))
2428 (:arg-types double-float)
2429 (:result-types double-float)
2430 (:policy :fast-safe)
2431 (:note "inline exp function")
2433 (:save-p :compute-only)
2436 (note-this-location vop :internal-error)
2437 (unless (zerop (tn-offset x))
2438 (inst fxch x) ; x to top of stack
2439 (unless (location= x y)
2440 (inst fst x))) ; maybe save it
2441 ;; Check for Inf or NaN
2445 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2446 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2447 (inst and ah-tn #x02) ; Test sign of Inf.
2448 (inst jmp :z DONE) ; +Inf gives +Inf.
2449 (inst fstp fr0) ; -Inf gives 0
2451 (inst jmp-short DONE)
2456 ;; Now fr0=x log2(e)
2460 (inst fsubp-sti fr1)
2463 (inst faddp-sti fr1)
2467 (unless (zerop (tn-offset y))
2470 ;;; Expm1 = exp(x) - 1.
2471 ;;; Handles the following special cases:
2472 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2473 (define-vop (fexpm1)
2475 (:args (x :scs (double-reg) :target fr0))
2476 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2477 (:temporary (:sc double-reg :offset fr0-offset
2478 :from :argument :to :result) fr0)
2479 (:temporary (:sc double-reg :offset fr1-offset
2480 :from :argument :to :result) fr1)
2481 (:temporary (:sc double-reg :offset fr2-offset
2482 :from :argument :to :result) fr2)
2483 (:results (y :scs (double-reg)))
2484 (:arg-types double-float)
2485 (:result-types double-float)
2486 (:policy :fast-safe)
2487 (:note "inline expm1 function")
2489 (:save-p :compute-only)
2492 (note-this-location vop :internal-error)
2493 (unless (zerop (tn-offset x))
2494 (inst fxch x) ; x to top of stack
2495 (unless (location= x y)
2496 (inst fst x))) ; maybe save it
2497 ;; Check for Inf or NaN
2501 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2502 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2503 (inst and ah-tn #x02) ; Test sign of Inf.
2504 (inst jmp :z DONE) ; +Inf gives +Inf.
2505 (inst fstp fr0) ; -Inf gives -1.0
2508 (inst jmp-short DONE)
2510 ;; Free two stack slots leaving the argument on top.
2514 (inst fmul fr1) ; Now fr0 = x log2(e)
2529 (unless (zerop (tn-offset y))
2534 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2535 (:temporary (:sc double-reg :offset fr0-offset
2536 :from :argument :to :result) fr0)
2537 (:temporary (:sc double-reg :offset fr1-offset
2538 :from :argument :to :result) fr1)
2539 (:results (y :scs (double-reg)))
2540 (:arg-types double-float)
2541 (:result-types double-float)
2542 (:policy :fast-safe)
2543 (:note "inline log function")
2545 (:save-p :compute-only)
2547 (note-this-location vop :internal-error)
2562 ;; x is in a FP reg, not fr0 or fr1
2566 (inst fldd (make-random-tn :kind :normal
2567 :sc (sc-or-lose 'double-reg)
2568 :offset (1- (tn-offset x))))))
2570 ((double-stack descriptor-reg)
2574 (if (sc-is x double-stack)
2575 (inst fldd (ea-for-df-stack x))
2576 (inst fldd (ea-for-df-desc x)))
2581 (t (inst fstd y)))))
2583 (define-vop (flog10)
2585 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2586 (:temporary (:sc double-reg :offset fr0-offset
2587 :from :argument :to :result) fr0)
2588 (:temporary (:sc double-reg :offset fr1-offset
2589 :from :argument :to :result) fr1)
2590 (:results (y :scs (double-reg)))
2591 (:arg-types double-float)
2592 (:result-types double-float)
2593 (:policy :fast-safe)
2594 (:note "inline log10 function")
2596 (:save-p :compute-only)
2598 (note-this-location vop :internal-error)
2613 ;; x is in a FP reg, not fr0 or fr1
2617 (inst fldd (make-random-tn :kind :normal
2618 :sc (sc-or-lose 'double-reg)
2619 :offset (1- (tn-offset x))))))
2621 ((double-stack descriptor-reg)
2625 (if (sc-is x double-stack)
2626 (inst fldd (ea-for-df-stack x))
2627 (inst fldd (ea-for-df-desc x)))
2632 (t (inst fstd y)))))
2636 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2637 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2638 (:temporary (:sc double-reg :offset fr0-offset
2639 :from (:argument 0) :to :result) fr0)
2640 (:temporary (:sc double-reg :offset fr1-offset
2641 :from (:argument 1) :to :result) fr1)
2642 (:temporary (:sc double-reg :offset fr2-offset
2643 :from :load :to :result) fr2)
2644 (:results (r :scs (double-reg)))
2645 (:arg-types double-float double-float)
2646 (:result-types double-float)
2647 (:policy :fast-safe)
2648 (:note "inline pow function")
2650 (:save-p :compute-only)
2652 (note-this-location vop :internal-error)
2653 ;; Setup x in fr0 and y in fr1
2655 ;; x in fr0; y in fr1
2656 ((and (sc-is x double-reg) (zerop (tn-offset x))
2657 (sc-is y double-reg) (= 1 (tn-offset y))))
2658 ;; y in fr1; x not in fr0
2659 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2663 (copy-fp-reg-to-fr0 x))
2666 (inst fldd (ea-for-df-stack x)))
2669 (inst fldd (ea-for-df-desc x)))))
2670 ;; x in fr0; y not in fr1
2671 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2673 ;; Now load y to fr0
2676 (copy-fp-reg-to-fr0 y))
2679 (inst fldd (ea-for-df-stack y)))
2682 (inst fldd (ea-for-df-desc y))))
2684 ;; x in fr1; y not in fr1
2685 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2689 (copy-fp-reg-to-fr0 y))
2692 (inst fldd (ea-for-df-stack y)))
2695 (inst fldd (ea-for-df-desc y))))
2698 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2700 ;; Now load x to fr0
2703 (copy-fp-reg-to-fr0 x))
2706 (inst fldd (ea-for-df-stack x)))
2709 (inst fldd (ea-for-df-desc x)))))
2710 ;; Neither x or y are in either fr0 or fr1
2717 (inst fldd (make-random-tn :kind :normal
2718 :sc (sc-or-lose 'double-reg)
2719 :offset (- (tn-offset y) 2))))
2721 (inst fldd (ea-for-df-stack y)))
2723 (inst fldd (ea-for-df-desc y))))
2727 (inst fldd (make-random-tn :kind :normal
2728 :sc (sc-or-lose 'double-reg)
2729 :offset (1- (tn-offset x)))))
2731 (inst fldd (ea-for-df-stack x)))
2733 (inst fldd (ea-for-df-desc x))))))
2735 ;; Now have x at fr0; and y at fr1
2737 ;; Now fr0=y log2(x)
2741 (inst fsubp-sti fr1)
2744 (inst faddp-sti fr1)
2749 (t (inst fstd r)))))
2751 (define-vop (fscalen)
2752 (:translate %scalbn)
2753 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2754 (y :scs (signed-stack signed-reg) :target temp))
2755 (:temporary (:sc double-reg :offset fr0-offset
2756 :from (:argument 0) :to :result) fr0)
2757 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2758 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2759 (:results (r :scs (double-reg)))
2760 (:arg-types double-float signed-num)
2761 (:result-types double-float)
2762 (:policy :fast-safe)
2763 (:note "inline scalbn function")
2765 ;; Setup x in fr0 and y in fr1
2796 (inst fld (make-random-tn :kind :normal
2797 :sc (sc-or-lose 'double-reg)
2798 :offset (1- (tn-offset x)))))))
2799 ((double-stack descriptor-reg)
2808 (if (sc-is x double-stack)
2809 (inst fldd (ea-for-df-stack x))
2810 (inst fldd (ea-for-df-desc x)))))
2812 (unless (zerop (tn-offset r))
2815 (define-vop (fscale)
2817 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2818 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2819 (:temporary (:sc double-reg :offset fr0-offset
2820 :from (:argument 0) :to :result) fr0)
2821 (:temporary (:sc double-reg :offset fr1-offset
2822 :from (:argument 1) :to :result) fr1)
2823 (:results (r :scs (double-reg)))
2824 (:arg-types double-float double-float)
2825 (:result-types double-float)
2826 (:policy :fast-safe)
2827 (:note "inline scalb function")
2829 (:save-p :compute-only)
2831 (note-this-location vop :internal-error)
2832 ;; Setup x in fr0 and y in fr1
2834 ;; x in fr0; y in fr1
2835 ((and (sc-is x double-reg) (zerop (tn-offset x))
2836 (sc-is y double-reg) (= 1 (tn-offset y))))
2837 ;; y in fr1; x not in fr0
2838 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2842 (copy-fp-reg-to-fr0 x))
2845 (inst fldd (ea-for-df-stack x)))
2848 (inst fldd (ea-for-df-desc x)))))
2849 ;; x in fr0; y not in fr1
2850 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2852 ;; Now load y to fr0
2855 (copy-fp-reg-to-fr0 y))
2858 (inst fldd (ea-for-df-stack y)))
2861 (inst fldd (ea-for-df-desc y))))
2863 ;; x in fr1; y not in fr1
2864 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2868 (copy-fp-reg-to-fr0 y))
2871 (inst fldd (ea-for-df-stack y)))
2874 (inst fldd (ea-for-df-desc y))))
2877 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2879 ;; Now load x to fr0
2882 (copy-fp-reg-to-fr0 x))
2885 (inst fldd (ea-for-df-stack x)))
2888 (inst fldd (ea-for-df-desc x)))))
2889 ;; Neither x or y are in either fr0 or fr1
2896 (inst fldd (make-random-tn :kind :normal
2897 :sc (sc-or-lose 'double-reg)
2898 :offset (- (tn-offset y) 2))))
2900 (inst fldd (ea-for-df-stack y)))
2902 (inst fldd (ea-for-df-desc y))))
2906 (inst fldd (make-random-tn :kind :normal
2907 :sc (sc-or-lose 'double-reg)
2908 :offset (1- (tn-offset x)))))
2910 (inst fldd (ea-for-df-stack x)))
2912 (inst fldd (ea-for-df-desc x))))))
2914 ;; Now have x at fr0; and y at fr1
2916 (unless (zerop (tn-offset r))
2919 (define-vop (flog1p)
2921 (:args (x :scs (double-reg) :to :result))
2922 (:temporary (:sc double-reg :offset fr0-offset
2923 :from :argument :to :result) fr0)
2924 (:temporary (:sc double-reg :offset fr1-offset
2925 :from :argument :to :result) fr1)
2926 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2927 (:results (y :scs (double-reg)))
2928 (:arg-types double-float)
2929 (:result-types double-float)
2930 (:policy :fast-safe)
2931 ;; FIXME: PENTIUM isn't used on the *FEATURES* list of the CMU CL I based
2932 ;; SBCL on, even when it is running on a Pentium. Find out what's going
2933 ;; on here and see what the proper value should be. (Perhaps just use the
2934 ;; apparently-conservative value of T always?) For more confusion, see also
2935 ;; apparently-reversed-sense test for the FLOG1P-PENTIUM vop below.
2936 (:guard #!+pentium nil #!-pentium t)
2937 (:note "inline log1p function")
2940 ;; x is in a FP reg, not fr0, fr1.
2943 (inst fldd (make-random-tn :kind :normal
2944 :sc (sc-or-lose 'double-reg)
2945 :offset (- (tn-offset x) 2)))
2947 (inst push #x3e947ae1) ; Constant 0.29
2949 (inst fld (make-ea :dword :base esp-tn))
2952 (inst fnstsw) ; status word to ax
2953 (inst and ah-tn #x45)
2954 (inst jmp :z WITHIN-RANGE)
2955 ;; Out of range for fyl2xp1.
2957 (inst faddd (make-random-tn :kind :normal
2958 :sc (sc-or-lose 'double-reg)
2959 :offset (- (tn-offset x) 1)))
2967 (inst fldd (make-random-tn :kind :normal
2968 :sc (sc-or-lose 'double-reg)
2969 :offset (- (tn-offset x) 1)))
2975 (t (inst fstd y)))))
2977 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2978 ;;; instruction and a range check can be avoided.
2979 (define-vop (flog1p-pentium)
2981 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2982 (:temporary (:sc double-reg :offset fr0-offset
2983 :from :argument :to :result) fr0)
2984 (:temporary (:sc double-reg :offset fr1-offset
2985 :from :argument :to :result) fr1)
2986 (:results (y :scs (double-reg)))
2987 (:arg-types double-float)
2988 (:result-types double-float)
2989 (:policy :fast-safe)
2990 ;; FIXME: See comments on DEFINE-VOP FLOG1P :GUARD above.
2991 (:guard #!+pentium t #!-pentium nil)
2992 (:note "inline log1p with limited x range function")
2994 (:save-p :compute-only)
2996 (note-this-location vop :internal-error)
3011 ;; x is in a FP reg, not fr0 or fr1
3015 (inst fldd (make-random-tn :kind :normal
3016 :sc (sc-or-lose 'double-reg)
3017 :offset (1- (tn-offset x)))))))
3018 ((double-stack descriptor-reg)
3022 (if (sc-is x double-stack)
3023 (inst fldd (ea-for-df-stack x))
3024 (inst fldd (ea-for-df-desc x)))))
3029 (t (inst fstd y)))))
3033 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
3034 (:temporary (:sc double-reg :offset fr0-offset
3035 :from :argument :to :result) fr0)
3036 (:temporary (:sc double-reg :offset fr1-offset
3037 :from :argument :to :result) fr1)
3038 (:results (y :scs (double-reg)))
3039 (:arg-types double-float)
3040 (:result-types double-float)
3041 (:policy :fast-safe)
3042 (:note "inline logb function")
3044 (:save-p :compute-only)
3046 (note-this-location vop :internal-error)
3057 ;; x is in a FP reg, not fr0 or fr1
3060 (inst fldd (make-random-tn :kind :normal
3061 :sc (sc-or-lose 'double-reg)
3062 :offset (- (tn-offset x) 2))))))
3063 ((double-stack descriptor-reg)
3066 (if (sc-is x double-stack)
3067 (inst fldd (ea-for-df-stack x))
3068 (inst fldd (ea-for-df-desc x)))))
3079 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
3080 (:temporary (:sc double-reg :offset fr0-offset
3081 :from (:argument 0) :to :result) fr0)
3082 (:temporary (:sc double-reg :offset fr1-offset
3083 :from (:argument 0) :to :result) fr1)
3084 (:results (r :scs (double-reg)))
3085 (:arg-types double-float)
3086 (:result-types double-float)
3087 (:policy :fast-safe)
3088 (:note "inline atan function")
3090 (:save-p :compute-only)
3092 (note-this-location vop :internal-error)
3093 ;; Setup x in fr1 and 1.0 in fr0
3096 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3099 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
3101 ;; x not in fr0 or fr1
3108 (inst fldd (make-random-tn :kind :normal
3109 :sc (sc-or-lose 'double-reg)
3110 :offset (- (tn-offset x) 2))))
3112 (inst fldd (ea-for-df-stack x)))
3114 (inst fldd (ea-for-df-desc x))))))
3116 ;; Now have x at fr1; and 1.0 at fr0
3121 (t (inst fstd r)))))
3123 (define-vop (fatan2)
3125 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
3126 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
3127 (:temporary (:sc double-reg :offset fr0-offset
3128 :from (:argument 1) :to :result) fr0)
3129 (:temporary (:sc double-reg :offset fr1-offset
3130 :from (:argument 0) :to :result) fr1)
3131 (:results (r :scs (double-reg)))
3132 (:arg-types double-float double-float)
3133 (:result-types double-float)
3134 (:policy :fast-safe)
3135 (:note "inline atan2 function")
3137 (:save-p :compute-only)
3139 (note-this-location vop :internal-error)
3140 ;; Setup x in fr1 and y in fr0
3142 ;; y in fr0; x in fr1
3143 ((and (sc-is y double-reg) (zerop (tn-offset y))
3144 (sc-is x double-reg) (= 1 (tn-offset x))))
3145 ;; x in fr1; y not in fr0
3146 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
3150 (copy-fp-reg-to-fr0 y))
3153 (inst fldd (ea-for-df-stack y)))
3156 (inst fldd (ea-for-df-desc y)))))
3157 ;; y in fr0; x not in fr1
3158 ((and (sc-is y double-reg) (zerop (tn-offset y)))
3160 ;; Now load x to fr0
3163 (copy-fp-reg-to-fr0 x))
3166 (inst fldd (ea-for-df-stack x)))
3169 (inst fldd (ea-for-df-desc x))))
3171 ;; y in fr1; x not in fr1
3172 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
3176 (copy-fp-reg-to-fr0 x))
3179 (inst fldd (ea-for-df-stack x)))
3182 (inst fldd (ea-for-df-desc x))))
3185 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3187 ;; Now load y to fr0
3190 (copy-fp-reg-to-fr0 y))
3193 (inst fldd (ea-for-df-stack y)))
3196 (inst fldd (ea-for-df-desc y)))))
3197 ;; Neither y or x are in either fr0 or fr1
3204 (inst fldd (make-random-tn :kind :normal
3205 :sc (sc-or-lose 'double-reg)
3206 :offset (- (tn-offset x) 2))))
3208 (inst fldd (ea-for-df-stack x)))
3210 (inst fldd (ea-for-df-desc x))))
3214 (inst fldd (make-random-tn :kind :normal
3215 :sc (sc-or-lose 'double-reg)
3216 :offset (1- (tn-offset y)))))
3218 (inst fldd (ea-for-df-stack y)))
3220 (inst fldd (ea-for-df-desc y))))))
3222 ;; Now have y at fr0; and x at fr1
3227 (t (inst fstd r)))))
3228 ) ; PROGN #!-LONG-FLOAT
3233 ;;; Lets use some of the 80387 special functions.
3235 ;;; These defs will not take effect unless code/irrat.lisp is modified
3236 ;;; to remove the inlined alien routine def.
3238 (macrolet ((frob (func trans op)
3239 `(define-vop (,func)
3240 (:args (x :scs (long-reg) :target fr0))
3241 (:temporary (:sc long-reg :offset fr0-offset
3242 :from :argument :to :result) fr0)
3244 (:results (y :scs (long-reg)))
3245 (:arg-types long-float)
3246 (:result-types long-float)
3248 (:policy :fast-safe)
3249 (:note "inline NPX function")
3251 (:save-p :compute-only)
3254 (note-this-location vop :internal-error)
3255 (unless (zerop (tn-offset x))
3256 (inst fxch x) ; x to top of stack
3257 (unless (location= x y)
3258 (inst fst x))) ; maybe save it
3259 (inst ,op) ; clobber st0
3260 (cond ((zerop (tn-offset y))
3261 (maybe-fp-wait node))
3265 ;; Quick versions of FSIN and FCOS that require the argument to be
3266 ;; within range 2^63.
3267 (frob fsin-quick %sin-quick fsin)
3268 (frob fcos-quick %cos-quick fcos)
3269 (frob fsqrt %sqrt fsqrt))
3271 ;;; Quick version of ftan that requires the argument to be within
3273 (define-vop (ftan-quick)
3274 (:translate %tan-quick)
3275 (:args (x :scs (long-reg) :target fr0))
3276 (:temporary (:sc long-reg :offset fr0-offset
3277 :from :argument :to :result) fr0)
3278 (:temporary (:sc long-reg :offset fr1-offset
3279 :from :argument :to :result) fr1)
3280 (:results (y :scs (long-reg)))
3281 (:arg-types long-float)
3282 (:result-types long-float)
3283 (:policy :fast-safe)
3284 (:note "inline tan function")
3286 (:save-p :compute-only)
3288 (note-this-location vop :internal-error)
3297 (inst fldd (make-random-tn :kind :normal
3298 :sc (sc-or-lose 'double-reg)
3299 :offset (- (tn-offset x) 2)))))
3310 ;;; These versions of fsin, fcos, and ftan try to use argument
3311 ;;; reduction but to do this accurately requires greater precision and
3312 ;;; it is hopelessly inaccurate.
3314 (macrolet ((frob (func trans op)
3315 `(define-vop (,func)
3317 (:args (x :scs (long-reg) :target fr0))
3318 (:temporary (:sc unsigned-reg :offset eax-offset
3319 :from :eval :to :result) eax)
3320 (:temporary (:sc long-reg :offset fr0-offset
3321 :from :argument :to :result) fr0)
3322 (:temporary (:sc long-reg :offset fr1-offset
3323 :from :argument :to :result) fr1)
3324 (:results (y :scs (long-reg)))
3325 (:arg-types long-float)
3326 (:result-types long-float)
3327 (:policy :fast-safe)
3328 (:note "inline sin/cos function")
3330 (:save-p :compute-only)
3333 (note-this-location vop :internal-error)
3334 (unless (zerop (tn-offset x))
3335 (inst fxch x) ; x to top of stack
3336 (unless (location= x y)
3337 (inst fst x))) ; maybe save it
3339 (inst fnstsw) ; status word to ax
3340 (inst and ah-tn #x04) ; C2
3342 ;; Else x was out of range so reduce it; ST0 is unchanged.
3343 (inst fstp fr1) ; Load 2*PI
3349 (inst fnstsw) ; status word to ax
3350 (inst and ah-tn #x04) ; C2
3354 (unless (zerop (tn-offset y))
3356 (frob fsin %sin fsin)
3357 (frob fcos %cos fcos))
3362 (:args (x :scs (long-reg) :target fr0))
3363 (:temporary (:sc unsigned-reg :offset eax-offset
3364 :from :argument :to :result) eax)
3365 (:temporary (:sc long-reg :offset fr0-offset
3366 :from :argument :to :result) fr0)
3367 (:temporary (:sc long-reg :offset fr1-offset
3368 :from :argument :to :result) fr1)
3369 (:results (y :scs (long-reg)))
3370 (:arg-types long-float)
3371 (:result-types long-float)
3372 (:policy :fast-safe)
3373 (:note "inline tan function")
3375 (:save-p :compute-only)
3378 (note-this-location vop :internal-error)
3387 (inst fldd (make-random-tn :kind :normal
3388 :sc (sc-or-lose 'double-reg)
3389 :offset (- (tn-offset x) 2)))))
3391 (inst fnstsw) ; status word to ax
3392 (inst and ah-tn #x04) ; C2
3394 ;; Else x was out of range so reduce it; ST0 is unchanged.
3395 (inst fldpi) ; Load 2*PI
3400 (inst fnstsw) ; status word to ax
3401 (inst and ah-tn #x04) ; C2
3415 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3416 ;;; the argument is out of range 2^63 and would thus be hopelessly
3418 (macrolet ((frob (func trans op)
3419 `(define-vop (,func)
3421 (:args (x :scs (long-reg) :target fr0))
3422 (:temporary (:sc long-reg :offset fr0-offset
3423 :from :argument :to :result) fr0)
3424 (:temporary (:sc unsigned-reg :offset eax-offset
3425 :from :argument :to :result) eax)
3426 (:results (y :scs (long-reg)))
3427 (:arg-types long-float)
3428 (:result-types long-float)
3429 (:policy :fast-safe)
3430 (:note "inline sin/cos function")
3432 (:save-p :compute-only)
3435 (note-this-location vop :internal-error)
3436 (unless (zerop (tn-offset x))
3437 (inst fxch x) ; x to top of stack
3438 (unless (location= x y)
3439 (inst fst x))) ; maybe save it
3441 (inst fnstsw) ; status word to ax
3442 (inst and ah-tn #x04) ; C2
3444 ;; Else x was out of range so reduce it; ST0 is unchanged.
3445 (inst fstp fr0) ; Load 0.0
3448 (unless (zerop (tn-offset y))
3450 (frob fsin %sin fsin)
3451 (frob fcos %cos fcos))
3455 (:args (x :scs (long-reg) :target fr0))
3456 (:temporary (:sc long-reg :offset fr0-offset
3457 :from :argument :to :result) fr0)
3458 (:temporary (:sc long-reg :offset fr1-offset
3459 :from :argument :to :result) fr1)
3460 (:temporary (:sc unsigned-reg :offset eax-offset
3461 :from :argument :to :result) eax)
3462 (:results (y :scs (long-reg)))
3463 (:arg-types long-float)
3464 (:result-types long-float)
3466 (:policy :fast-safe)
3467 (:note "inline tan function")
3469 (:save-p :compute-only)
3472 (note-this-location vop :internal-error)
3481 (inst fldd (make-random-tn :kind :normal
3482 :sc (sc-or-lose 'double-reg)
3483 :offset (- (tn-offset x) 2)))))
3485 (inst fnstsw) ; status word to ax
3486 (inst and ah-tn #x04) ; C2
3488 ;; Else x was out of range so reduce it; ST0 is unchanged.
3489 (inst fldz) ; Load 0.0
3501 ;;; Modified exp that handles the following special cases:
3502 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3505 (:args (x :scs (long-reg) :target fr0))
3506 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3507 (:temporary (:sc long-reg :offset fr0-offset
3508 :from :argument :to :result) fr0)
3509 (:temporary (:sc long-reg :offset fr1-offset
3510 :from :argument :to :result) fr1)
3511 (:temporary (:sc long-reg :offset fr2-offset
3512 :from :argument :to :result) fr2)
3513 (:results (y :scs (long-reg)))
3514 (:arg-types long-float)
3515 (:result-types long-float)
3516 (:policy :fast-safe)
3517 (:note "inline exp function")
3519 (:save-p :compute-only)
3522 (note-this-location vop :internal-error)
3523 (unless (zerop (tn-offset x))
3524 (inst fxch x) ; x to top of stack
3525 (unless (location= x y)
3526 (inst fst x))) ; maybe save it
3527 ;; Check for Inf or NaN
3531 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3532 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3533 (inst and ah-tn #x02) ; Test sign of Inf.
3534 (inst jmp :z DONE) ; +Inf gives +Inf.
3535 (inst fstp fr0) ; -Inf gives 0
3537 (inst jmp-short DONE)
3542 ;; Now fr0=x log2(e)
3546 (inst fsubp-sti fr1)
3549 (inst faddp-sti fr1)
3553 (unless (zerop (tn-offset y))
3556 ;;; Expm1 = exp(x) - 1.
3557 ;;; Handles the following special cases:
3558 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3559 (define-vop (fexpm1)
3561 (:args (x :scs (long-reg) :target fr0))
3562 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3563 (:temporary (:sc long-reg :offset fr0-offset
3564 :from :argument :to :result) fr0)
3565 (:temporary (:sc long-reg :offset fr1-offset
3566 :from :argument :to :result) fr1)
3567 (:temporary (:sc long-reg :offset fr2-offset
3568 :from :argument :to :result) fr2)
3569 (:results (y :scs (long-reg)))
3570 (:arg-types long-float)
3571 (:result-types long-float)
3572 (:policy :fast-safe)
3573 (:note "inline expm1 function")
3575 (:save-p :compute-only)
3578 (note-this-location vop :internal-error)
3579 (unless (zerop (tn-offset x))
3580 (inst fxch x) ; x to top of stack
3581 (unless (location= x y)
3582 (inst fst x))) ; maybe save it
3583 ;; Check for Inf or NaN
3587 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3588 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3589 (inst and ah-tn #x02) ; Test sign of Inf.
3590 (inst jmp :z DONE) ; +Inf gives +Inf.
3591 (inst fstp fr0) ; -Inf gives -1.0
3594 (inst jmp-short DONE)
3596 ;; Free two stack slots leaving the argument on top.
3600 (inst fmul fr1) ; Now fr0 = x log2(e)
3615 (unless (zerop (tn-offset y))
3620 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3621 (:temporary (:sc long-reg :offset fr0-offset
3622 :from :argument :to :result) fr0)
3623 (:temporary (:sc long-reg :offset fr1-offset
3624 :from :argument :to :result) fr1)
3625 (:results (y :scs (long-reg)))
3626 (:arg-types long-float)
3627 (:result-types long-float)
3628 (:policy :fast-safe)
3629 (:note "inline log function")
3631 (:save-p :compute-only)
3633 (note-this-location vop :internal-error)
3648 ;; x is in a FP reg, not fr0 or fr1
3652 (inst fldd (make-random-tn :kind :normal
3653 :sc (sc-or-lose 'double-reg)
3654 :offset (1- (tn-offset x))))))
3656 ((long-stack descriptor-reg)
3660 (if (sc-is x long-stack)
3661 (inst fldl (ea-for-lf-stack x))
3662 (inst fldl (ea-for-lf-desc x)))
3667 (t (inst fstd y)))))
3669 (define-vop (flog10)
3671 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3672 (:temporary (:sc long-reg :offset fr0-offset
3673 :from :argument :to :result) fr0)
3674 (:temporary (:sc long-reg :offset fr1-offset
3675 :from :argument :to :result) fr1)
3676 (:results (y :scs (long-reg)))
3677 (:arg-types long-float)
3678 (:result-types long-float)
3679 (:policy :fast-safe)
3680 (:note "inline log10 function")
3682 (:save-p :compute-only)
3684 (note-this-location vop :internal-error)
3699 ;; x is in a FP reg, not fr0 or fr1
3703 (inst fldd (make-random-tn :kind :normal
3704 :sc (sc-or-lose 'double-reg)
3705 :offset (1- (tn-offset x))))))
3707 ((long-stack descriptor-reg)
3711 (if (sc-is x long-stack)
3712 (inst fldl (ea-for-lf-stack x))
3713 (inst fldl (ea-for-lf-desc x)))
3718 (t (inst fstd y)))))
3722 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3723 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3724 (:temporary (:sc long-reg :offset fr0-offset
3725 :from (:argument 0) :to :result) fr0)
3726 (:temporary (:sc long-reg :offset fr1-offset
3727 :from (:argument 1) :to :result) fr1)
3728 (:temporary (:sc long-reg :offset fr2-offset
3729 :from :load :to :result) fr2)
3730 (:results (r :scs (long-reg)))
3731 (:arg-types long-float long-float)
3732 (:result-types long-float)
3733 (:policy :fast-safe)
3734 (:note "inline pow function")
3736 (:save-p :compute-only)
3738 (note-this-location vop :internal-error)
3739 ;; Setup x in fr0 and y in fr1
3741 ;; x in fr0; y in fr1
3742 ((and (sc-is x long-reg) (zerop (tn-offset x))
3743 (sc-is y long-reg) (= 1 (tn-offset y))))
3744 ;; y in fr1; x not in fr0
3745 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3749 (copy-fp-reg-to-fr0 x))
3752 (inst fldl (ea-for-lf-stack x)))
3755 (inst fldl (ea-for-lf-desc x)))))
3756 ;; x in fr0; y not in fr1
3757 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3759 ;; Now load y to fr0
3762 (copy-fp-reg-to-fr0 y))
3765 (inst fldl (ea-for-lf-stack y)))
3768 (inst fldl (ea-for-lf-desc y))))
3770 ;; x in fr1; y not in fr1
3771 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3775 (copy-fp-reg-to-fr0 y))
3778 (inst fldl (ea-for-lf-stack y)))
3781 (inst fldl (ea-for-lf-desc y))))
3784 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3786 ;; Now load x to fr0
3789 (copy-fp-reg-to-fr0 x))
3792 (inst fldl (ea-for-lf-stack x)))
3795 (inst fldl (ea-for-lf-desc x)))))
3796 ;; Neither x or y are in either fr0 or fr1
3803 (inst fldd (make-random-tn :kind :normal
3804 :sc (sc-or-lose 'double-reg)
3805 :offset (- (tn-offset y) 2))))
3807 (inst fldl (ea-for-lf-stack y)))
3809 (inst fldl (ea-for-lf-desc y))))
3813 (inst fldd (make-random-tn :kind :normal
3814 :sc (sc-or-lose 'double-reg)
3815 :offset (1- (tn-offset x)))))
3817 (inst fldl (ea-for-lf-stack x)))
3819 (inst fldl (ea-for-lf-desc x))))))
3821 ;; Now have x at fr0; and y at fr1
3823 ;; Now fr0=y log2(x)
3827 (inst fsubp-sti fr1)
3830 (inst faddp-sti fr1)
3835 (t (inst fstd r)))))
3837 (define-vop (fscalen)
3838 (:translate %scalbn)
3839 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3840 (y :scs (signed-stack signed-reg) :target temp))
3841 (:temporary (:sc long-reg :offset fr0-offset
3842 :from (:argument 0) :to :result) fr0)
3843 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3844 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3845 (:results (r :scs (long-reg)))
3846 (:arg-types long-float signed-num)
3847 (:result-types long-float)
3848 (:policy :fast-safe)
3849 (:note "inline scalbn function")
3851 ;; Setup x in fr0 and y in fr1
3882 (inst fld (make-random-tn :kind :normal
3883 :sc (sc-or-lose 'double-reg)
3884 :offset (1- (tn-offset x)))))))
3885 ((long-stack descriptor-reg)
3894 (if (sc-is x long-stack)
3895 (inst fldl (ea-for-lf-stack x))
3896 (inst fldl (ea-for-lf-desc x)))))
3898 (unless (zerop (tn-offset r))
3901 (define-vop (fscale)
3903 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3904 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3905 (:temporary (:sc long-reg :offset fr0-offset
3906 :from (:argument 0) :to :result) fr0)
3907 (:temporary (:sc long-reg :offset fr1-offset
3908 :from (:argument 1) :to :result) fr1)
3909 (:results (r :scs (long-reg)))
3910 (:arg-types long-float long-float)
3911 (:result-types long-float)
3912 (:policy :fast-safe)
3913 (:note "inline scalb function")
3915 (:save-p :compute-only)
3917 (note-this-location vop :internal-error)
3918 ;; Setup x in fr0 and y in fr1
3920 ;; x in fr0; y in fr1
3921 ((and (sc-is x long-reg) (zerop (tn-offset x))
3922 (sc-is y long-reg) (= 1 (tn-offset y))))
3923 ;; y in fr1; x not in fr0
3924 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3928 (copy-fp-reg-to-fr0 x))
3931 (inst fldl (ea-for-lf-stack x)))
3934 (inst fldl (ea-for-lf-desc x)))))
3935 ;; x in fr0; y not in fr1
3936 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3938 ;; Now load y to fr0
3941 (copy-fp-reg-to-fr0 y))
3944 (inst fldl (ea-for-lf-stack y)))
3947 (inst fldl (ea-for-lf-desc y))))
3949 ;; x in fr1; y not in fr1
3950 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3954 (copy-fp-reg-to-fr0 y))
3957 (inst fldl (ea-for-lf-stack y)))
3960 (inst fldl (ea-for-lf-desc y))))
3963 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3965 ;; Now load x to fr0
3968 (copy-fp-reg-to-fr0 x))
3971 (inst fldl (ea-for-lf-stack x)))
3974 (inst fldl (ea-for-lf-desc x)))))
3975 ;; Neither x or y are in either fr0 or fr1
3982 (inst fldd (make-random-tn :kind :normal
3983 :sc (sc-or-lose 'double-reg)
3984 :offset (- (tn-offset y) 2))))
3986 (inst fldl (ea-for-lf-stack y)))
3988 (inst fldl (ea-for-lf-desc y))))
3992 (inst fldd (make-random-tn :kind :normal
3993 :sc (sc-or-lose 'double-reg)
3994 :offset (1- (tn-offset x)))))
3996 (inst fldl (ea-for-lf-stack x)))
3998 (inst fldl (ea-for-lf-desc x))))))
4000 ;; Now have x at fr0; and y at fr1
4002 (unless (zerop (tn-offset r))
4005 (define-vop (flog1p)
4007 (:args (x :scs (long-reg) :to :result))
4008 (:temporary (:sc long-reg :offset fr0-offset
4009 :from :argument :to :result) fr0)
4010 (:temporary (:sc long-reg :offset fr1-offset
4011 :from :argument :to :result) fr1)
4012 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
4013 (:results (y :scs (long-reg)))
4014 (:arg-types long-float)
4015 (:result-types long-float)
4016 (:policy :fast-safe)
4017 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
4018 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
4019 ;; an enormous PROGN above. Still, it would be probably be good to
4020 ;; add some code to warn about redefining VOPs.
4021 ;; FIXME 2: See comments on DEFINE-VOP FLOG1P :GUARD above.
4022 (:guard #!+pentium nil #!-pentium t)
4023 (:note "inline log1p function")
4026 ;; x is in a FP reg, not fr0, fr1.
4029 (inst fldd (make-random-tn :kind :normal
4030 :sc (sc-or-lose 'double-reg)
4031 :offset (- (tn-offset x) 2)))
4033 (inst push #x3e947ae1) ; Constant 0.29
4035 (inst fld (make-ea :dword :base esp-tn))
4038 (inst fnstsw) ; status word to ax
4039 (inst and ah-tn #x45)
4040 (inst jmp :z WITHIN-RANGE)
4041 ;; Out of range for fyl2xp1.
4043 (inst faddd (make-random-tn :kind :normal
4044 :sc (sc-or-lose 'double-reg)
4045 :offset (- (tn-offset x) 1)))
4053 (inst fldd (make-random-tn :kind :normal
4054 :sc (sc-or-lose 'double-reg)
4055 :offset (- (tn-offset x) 1)))
4061 (t (inst fstd y)))))
4063 ;;; The Pentium has a less restricted implementation of the fyl2xp1
4064 ;;; instruction and a range check can be avoided.
4065 (define-vop (flog1p-pentium)
4067 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
4068 (:temporary (:sc long-reg :offset fr0-offset
4069 :from :argument :to :result) fr0)
4070 (:temporary (:sc long-reg :offset fr1-offset
4071 :from :argument :to :result) fr1)
4072 (:results (y :scs (long-reg)))
4073 (:arg-types long-float)
4074 (:result-types long-float)
4075 (:policy :fast-safe)
4076 ;; FIXME: See comments on DEFINE-VOP FLOG1P :GUARD above.
4077 (:guard #!+pentium t #!-pentium)
4078 (:note "inline log1p function")
4094 ;; x is in a FP reg, not fr0 or fr1
4098 (inst fldd (make-random-tn :kind :normal
4099 :sc (sc-or-lose 'double-reg)
4100 :offset (1- (tn-offset x)))))))
4101 ((long-stack descriptor-reg)
4105 (if (sc-is x long-stack)
4106 (inst fldl (ea-for-lf-stack x))
4107 (inst fldl (ea-for-lf-desc x)))))
4112 (t (inst fstd y)))))
4116 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
4117 (:temporary (:sc long-reg :offset fr0-offset
4118 :from :argument :to :result) fr0)
4119 (:temporary (:sc long-reg :offset fr1-offset
4120 :from :argument :to :result) fr1)
4121 (:results (y :scs (long-reg)))
4122 (:arg-types long-float)
4123 (:result-types long-float)
4124 (:policy :fast-safe)
4125 (:note "inline logb function")
4127 (:save-p :compute-only)
4129 (note-this-location vop :internal-error)
4140 ;; x is in a FP reg, not fr0 or fr1
4143 (inst fldd (make-random-tn :kind :normal
4144 :sc (sc-or-lose 'double-reg)
4145 :offset (- (tn-offset x) 2))))))
4146 ((long-stack descriptor-reg)
4149 (if (sc-is x long-stack)
4150 (inst fldl (ea-for-lf-stack x))
4151 (inst fldl (ea-for-lf-desc x)))))
4162 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
4163 (:temporary (:sc long-reg :offset fr0-offset
4164 :from (:argument 0) :to :result) fr0)
4165 (:temporary (:sc long-reg :offset fr1-offset
4166 :from (:argument 0) :to :result) fr1)
4167 (:results (r :scs (long-reg)))
4168 (:arg-types long-float)
4169 (:result-types long-float)
4170 (:policy :fast-safe)
4171 (:note "inline atan function")
4173 (:save-p :compute-only)
4175 (note-this-location vop :internal-error)
4176 ;; Setup x in fr1 and 1.0 in fr0
4179 ((and (sc-is x long-reg) (zerop (tn-offset x)))
4182 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
4184 ;; x not in fr0 or fr1
4191 (inst fldd (make-random-tn :kind :normal
4192 :sc (sc-or-lose 'double-reg)
4193 :offset (- (tn-offset x) 2))))
4195 (inst fldl (ea-for-lf-stack x)))
4197 (inst fldl (ea-for-lf-desc x))))))
4199 ;; Now have x at fr1; and 1.0 at fr0
4204 (t (inst fstd r)))))
4206 (define-vop (fatan2)
4208 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
4209 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
4210 (:temporary (:sc long-reg :offset fr0-offset
4211 :from (:argument 1) :to :result) fr0)
4212 (:temporary (:sc long-reg :offset fr1-offset
4213 :from (:argument 0) :to :result) fr1)
4214 (:results (r :scs (long-reg)))
4215 (:arg-types long-float long-float)
4216 (:result-types long-float)
4217 (:policy :fast-safe)
4218 (:note "inline atan2 function")
4220 (:save-p :compute-only)
4222 (note-this-location vop :internal-error)
4223 ;; Setup x in fr1 and y in fr0
4225 ;; y in fr0; x in fr1
4226 ((and (sc-is y long-reg) (zerop (tn-offset y))
4227 (sc-is x long-reg) (= 1 (tn-offset x))))
4228 ;; x in fr1; y not in fr0
4229 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
4233 (copy-fp-reg-to-fr0 y))
4236 (inst fldl (ea-for-lf-stack y)))
4239 (inst fldl (ea-for-lf-desc y)))))
4240 ;; y in fr0; x not in fr1
4241 ((and (sc-is y long-reg) (zerop (tn-offset y)))
4243 ;; Now load x to fr0
4246 (copy-fp-reg-to-fr0 x))
4249 (inst fldl (ea-for-lf-stack x)))
4252 (inst fldl (ea-for-lf-desc x))))
4254 ;; y in fr1; x not in fr1
4255 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
4259 (copy-fp-reg-to-fr0 x))
4262 (inst fldl (ea-for-lf-stack x)))
4265 (inst fldl (ea-for-lf-desc x))))
4268 ((and (sc-is x long-reg) (zerop (tn-offset x)))
4270 ;; Now load y to fr0
4273 (copy-fp-reg-to-fr0 y))
4276 (inst fldl (ea-for-lf-stack y)))
4279 (inst fldl (ea-for-lf-desc y)))))
4280 ;; Neither y or x are in either fr0 or fr1
4287 (inst fldd (make-random-tn :kind :normal
4288 :sc (sc-or-lose 'double-reg)
4289 :offset (- (tn-offset x) 2))))
4291 (inst fldl (ea-for-lf-stack x)))
4293 (inst fldl (ea-for-lf-desc x))))
4297 (inst fldd (make-random-tn :kind :normal
4298 :sc (sc-or-lose 'double-reg)
4299 :offset (1- (tn-offset y)))))
4301 (inst fldl (ea-for-lf-stack y)))
4303 (inst fldl (ea-for-lf-desc y))))))
4305 ;; Now have y at fr0; and x at fr1
4310 (t (inst fstd r)))))
4312 ) ; PROGN #!+LONG-FLOAT
4314 ;;;; complex float VOPs
4316 (define-vop (make-complex-single-float)
4317 (:translate complex)
4318 (:args (real :scs (single-reg) :to :result :target r
4319 :load-if (not (location= real r)))
4320 (imag :scs (single-reg) :to :save))
4321 (:arg-types single-float single-float)
4322 (:results (r :scs (complex-single-reg) :from (:argument 0)
4323 :load-if (not (sc-is r complex-single-stack))))
4324 (:result-types complex-single-float)
4325 (:note "inline complex single-float creation")
4326 (:policy :fast-safe)
4330 (let ((r-real (complex-double-reg-real-tn r)))
4331 (unless (location= real r-real)
4332 (cond ((zerop (tn-offset r-real))
4333 (copy-fp-reg-to-fr0 real))
4334 ((zerop (tn-offset real))
4339 (inst fxch real)))))
4340 (let ((r-imag (complex-double-reg-imag-tn r)))
4341 (unless (location= imag r-imag)
4342 (cond ((zerop (tn-offset imag))
4347 (inst fxch imag))))))
4348 (complex-single-stack
4349 (unless (location= real r)
4350 (cond ((zerop (tn-offset real))
4351 (inst fst (ea-for-csf-real-stack r)))
4354 (inst fst (ea-for-csf-real-stack r))
4357 (inst fst (ea-for-csf-imag-stack r))
4358 (inst fxch imag)))))
4360 (define-vop (make-complex-double-float)
4361 (:translate complex)
4362 (:args (real :scs (double-reg) :target r
4363 :load-if (not (location= real r)))
4364 (imag :scs (double-reg) :to :save))
4365 (:arg-types double-float double-float)
4366 (:results (r :scs (complex-double-reg) :from (:argument 0)
4367 :load-if (not (sc-is r complex-double-stack))))
4368 (:result-types complex-double-float)
4369 (:note "inline complex double-float creation")
4370 (:policy :fast-safe)
4374 (let ((r-real (complex-double-reg-real-tn r)))
4375 (unless (location= real r-real)
4376 (cond ((zerop (tn-offset r-real))
4377 (copy-fp-reg-to-fr0 real))
4378 ((zerop (tn-offset real))
4383 (inst fxch real)))))
4384 (let ((r-imag (complex-double-reg-imag-tn r)))
4385 (unless (location= imag r-imag)
4386 (cond ((zerop (tn-offset imag))
4391 (inst fxch imag))))))
4392 (complex-double-stack
4393 (unless (location= real r)
4394 (cond ((zerop (tn-offset real))
4395 (inst fstd (ea-for-cdf-real-stack r)))
4398 (inst fstd (ea-for-cdf-real-stack r))
4401 (inst fstd (ea-for-cdf-imag-stack r))
4402 (inst fxch imag)))))
4405 (define-vop (make-complex-long-float)
4406 (:translate complex)
4407 (:args (real :scs (long-reg) :target r
4408 :load-if (not (location= real r)))
4409 (imag :scs (long-reg) :to :save))
4410 (:arg-types long-float long-float)
4411 (:results (r :scs (complex-long-reg) :from (:argument 0)
4412 :load-if (not (sc-is r complex-long-stack))))
4413 (:result-types complex-long-float)
4414 (:note "inline complex long-float creation")
4415 (:policy :fast-safe)
4419 (let ((r-real (complex-double-reg-real-tn r)))
4420 (unless (location= real r-real)
4421 (cond ((zerop (tn-offset r-real))
4422 (copy-fp-reg-to-fr0 real))
4423 ((zerop (tn-offset real))
4428 (inst fxch real)))))
4429 (let ((r-imag (complex-double-reg-imag-tn r)))
4430 (unless (location= imag r-imag)
4431 (cond ((zerop (tn-offset imag))
4436 (inst fxch imag))))))
4438 (unless (location= real r)
4439 (cond ((zerop (tn-offset real))
4440 (store-long-float (ea-for-clf-real-stack r)))
4443 (store-long-float (ea-for-clf-real-stack r))
4446 (store-long-float (ea-for-clf-imag-stack r))
4447 (inst fxch imag)))))
4450 (define-vop (complex-float-value)
4451 (:args (x :target r))
4453 (:variant-vars offset)
4454 (:policy :fast-safe)
4456 (cond ((sc-is x complex-single-reg complex-double-reg
4457 #!+long-float complex-long-reg)
4459 (make-random-tn :kind :normal
4460 :sc (sc-or-lose 'double-reg)
4461 :offset (+ offset (tn-offset x)))))
4462 (unless (location= value-tn r)
4463 (cond ((zerop (tn-offset r))
4464 (copy-fp-reg-to-fr0 value-tn))
4465 ((zerop (tn-offset value-tn))
4468 (inst fxch value-tn)
4470 (inst fxch value-tn))))))
4471 ((sc-is r single-reg)
4472 (let ((ea (sc-case x
4473 (complex-single-stack
4475 (0 (ea-for-csf-real-stack x))
4476 (1 (ea-for-csf-imag-stack x))))
4479 (0 (ea-for-csf-real-desc x))
4480 (1 (ea-for-csf-imag-desc x)))))))
4481 (with-empty-tn@fp-top(r)
4483 ((sc-is r double-reg)
4484 (let ((ea (sc-case x
4485 (complex-double-stack
4487 (0 (ea-for-cdf-real-stack x))
4488 (1 (ea-for-cdf-imag-stack x))))
4491 (0 (ea-for-cdf-real-desc x))
4492 (1 (ea-for-cdf-imag-desc x)))))))
4493 (with-empty-tn@fp-top(r)
4497 (let ((ea (sc-case x
4500 (0 (ea-for-clf-real-stack x))
4501 (1 (ea-for-clf-imag-stack x))))
4504 (0 (ea-for-clf-real-desc x))
4505 (1 (ea-for-clf-imag-desc x)))))))
4506 (with-empty-tn@fp-top(r)
4508 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4510 (define-vop (realpart/complex-single-float complex-float-value)
4511 (:translate realpart)
4512 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4514 (:arg-types complex-single-float)
4515 (:results (r :scs (single-reg)))
4516 (:result-types single-float)
4517 (:note "complex float realpart")
4520 (define-vop (realpart/complex-double-float complex-float-value)
4521 (:translate realpart)
4522 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4524 (:arg-types complex-double-float)
4525 (:results (r :scs (double-reg)))
4526 (:result-types double-float)
4527 (:note "complex float realpart")
4531 (define-vop (realpart/complex-long-float complex-float-value)
4532 (:translate realpart)
4533 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4535 (:arg-types complex-long-float)
4536 (:results (r :scs (long-reg)))
4537 (:result-types long-float)
4538 (:note "complex float realpart")
4541 (define-vop (imagpart/complex-single-float complex-float-value)
4542 (:translate imagpart)
4543 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4545 (:arg-types complex-single-float)
4546 (:results (r :scs (single-reg)))
4547 (:result-types single-float)
4548 (:note "complex float imagpart")
4551 (define-vop (imagpart/complex-double-float complex-float-value)
4552 (:translate imagpart)
4553 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4555 (:arg-types complex-double-float)
4556 (:results (r :scs (double-reg)))
4557 (:result-types double-float)
4558 (:note "complex float imagpart")
4562 (define-vop (imagpart/complex-long-float complex-float-value)
4563 (:translate imagpart)
4564 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4566 (:arg-types complex-long-float)
4567 (:results (r :scs (long-reg)))
4568 (:result-types long-float)
4569 (:note "complex float imagpart")
4572 ;;; hack dummy VOPs to bias the representation selection of their
4573 ;;; arguments towards a FP register, which can help avoid consing at
4574 ;;; inappropriate locations
4575 (defknown double-float-reg-bias (double-float) (values))
4576 (define-vop (double-float-reg-bias)
4577 (:translate double-float-reg-bias)
4578 (:args (x :scs (double-reg double-stack) :load-if nil))
4579 (:arg-types double-float)
4580 (:policy :fast-safe)
4581 (:note "inline dummy FP register bias")
4584 (defknown single-float-reg-bias (single-float) (values))
4585 (define-vop (single-float-reg-bias)
4586 (:translate single-float-reg-bias)
4587 (:args (x :scs (single-reg single-stack) :load-if nil))
4588 (:arg-types single-float)
4589 (:policy :fast-safe)
4590 (:note "inline dummy FP register bias")