1 ;;;; floating point support for the x86
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 (macrolet ((ea-for-xf-desc (tn slot)
17 :disp (- (* ,slot n-word-bytes)
18 other-pointer-lowtag))))
19 (defun ea-for-sf-desc (tn)
20 (ea-for-xf-desc tn single-float-value-slot))
21 (defun ea-for-df-desc (tn)
22 (ea-for-xf-desc tn double-float-value-slot))
24 (defun ea-for-csf-real-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-real-slot))
26 (defun ea-for-csf-imag-desc (tn)
27 (ea-for-xf-desc tn complex-single-float-imag-slot))
28 (defun ea-for-cdf-real-desc (tn)
29 (ea-for-xf-desc tn complex-double-float-real-slot))
30 (defun ea-for-cdf-imag-desc (tn)
31 (ea-for-xf-desc tn complex-double-float-imag-slot)))
33 (macrolet ((ea-for-xf-stack (tn kind)
36 :disp (- (* (+ (tn-offset ,tn) 1)
38 (defun ea-for-sf-stack (tn)
39 (ea-for-xf-stack tn :single))
40 (defun ea-for-df-stack (tn)
41 (ea-for-xf-stack tn :double)))
43 ;;; Telling the FPU to wait is required in order to make signals occur
44 ;;; at the expected place, but naturally slows things down.
46 ;;; NODE is the node whose compilation policy controls the decision
47 ;;; whether to just blast through carelessly or carefully emit wait
48 ;;; instructions and whatnot.
50 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
51 ;;; #'NOTE-NEXT-INSTRUCTION.
52 (defun maybe-fp-wait (node &optional note-next-instruction)
53 (when (policy node (or (= debug 3) (> safety speed))))
54 (when note-next-instruction
55 (note-next-instruction note-next-instruction :internal-error))
59 ;;; complex float stack EAs
60 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
61 (declare (ignore kind))
64 :disp (- (* (+ (tn-offset ,tn)
65 (* 1 (ecase ,slot (:real 1) (:imag 2))))
67 (defun ea-for-csf-real-stack (tn &optional (base rbp-tn))
68 (ea-for-cxf-stack tn :single :real base))
69 (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn))
70 (ea-for-cxf-stack tn :single :imag base))
71 (defun ea-for-cdf-real-stack (tn &optional (base rbp-tn))
72 (ea-for-cxf-stack tn :double :real base))
73 (defun ea-for-cdf-imag-stack (tn &optional (base rbp-tn))
74 (ea-for-cxf-stack tn :double :imag base)))
79 ;;; X is source, Y is destination.
80 (define-move-fun (load-single 2) (vop x y)
81 ((single-stack) (single-reg))
82 (inst movss y (ea-for-sf-stack x)))
84 ;;; got this far 20040627
86 (define-move-fun (store-single 2) (vop x y)
87 ((single-reg) (single-stack))
88 (cond ((zerop (tn-offset x))
89 (inst fst (ea-for-sf-stack y)))
92 (inst fst (ea-for-sf-stack y))
93 ;; This may not be necessary as ST0 is likely invalid now.
96 (define-move-fun (load-double 2) (vop x y)
97 ((double-stack) (double-reg))
98 (with-empty-tn@fp-top(y)
99 (inst fldd (ea-for-df-stack x))))
101 (define-move-fun (store-double 2) (vop x y)
102 ((double-reg) (double-stack))
103 (cond ((zerop (tn-offset x))
104 (inst fstd (ea-for-df-stack y)))
107 (inst fstd (ea-for-df-stack y))
108 ;; This may not be necessary as ST0 is likely invalid now.
113 ;;; The i387 has instructions to load some useful constants. This
114 ;;; doesn't save much time but might cut down on memory access and
115 ;;; reduce the size of the constant vector (CV). Intel claims they are
116 ;;; stored in a more precise form on chip. Anyhow, might as well use
117 ;;; the feature. It can be turned off by hacking the
118 ;;; "immediate-constant-sc" in vm.lisp.
119 (eval-when (:compile-toplevel :execute)
120 (setf *read-default-float-format* 'double-float))
121 (define-move-fun (load-fp-constant 2) (vop x y)
122 ((fp-constant) (single-reg double-reg))
123 (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
124 (with-empty-tn@fp-top(y)
129 ((= value (coerce pi *read-default-float-format*))
131 ((= value (log 10e0 2e0))
133 ((= value (log 2.718281828459045235360287471352662e0 2e0))
135 ((= value (log 2e0 10e0))
137 ((= value (log 2e0 2.718281828459045235360287471352662e0))
139 (t (warn "ignoring bogus i387 constant ~A" value))))))
140 (eval-when (:compile-toplevel :execute)
141 (setf *read-default-float-format* 'single-float))
143 ;;;; complex float move functions
145 (defun complex-single-reg-real-tn (x)
146 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
147 :offset (tn-offset x)))
148 (defun complex-single-reg-imag-tn (x)
149 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
150 :offset (1+ (tn-offset x))))
152 (defun complex-double-reg-real-tn (x)
153 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
154 :offset (tn-offset x)))
155 (defun complex-double-reg-imag-tn (x)
156 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
157 :offset (1+ (tn-offset x))))
159 ;;; X is source, Y is destination.
160 (define-move-fun (load-complex-single 2) (vop x y)
161 ((complex-single-stack) (complex-single-reg))
162 (let ((real-tn (complex-single-reg-real-tn y)))
163 (with-empty-tn@fp-top (real-tn)
164 (inst fld (ea-for-csf-real-stack x))))
165 (let ((imag-tn (complex-single-reg-imag-tn y)))
166 (with-empty-tn@fp-top (imag-tn)
167 (inst fld (ea-for-csf-imag-stack x)))))
169 (define-move-fun (store-complex-single 2) (vop x y)
170 ((complex-single-reg) (complex-single-stack))
171 (let ((real-tn (complex-single-reg-real-tn x)))
172 (cond ((zerop (tn-offset real-tn))
173 (inst fst (ea-for-csf-real-stack y)))
176 (inst fst (ea-for-csf-real-stack y))
177 (inst fxch real-tn))))
178 (let ((imag-tn (complex-single-reg-imag-tn x)))
180 (inst fst (ea-for-csf-imag-stack y))
181 (inst fxch imag-tn)))
183 (define-move-fun (load-complex-double 2) (vop x y)
184 ((complex-double-stack) (complex-double-reg))
185 (let ((real-tn (complex-double-reg-real-tn y)))
186 (with-empty-tn@fp-top(real-tn)
187 (inst fldd (ea-for-cdf-real-stack x))))
188 (let ((imag-tn (complex-double-reg-imag-tn y)))
189 (with-empty-tn@fp-top(imag-tn)
190 (inst fldd (ea-for-cdf-imag-stack x)))))
192 (define-move-fun (store-complex-double 2) (vop x y)
193 ((complex-double-reg) (complex-double-stack))
194 (let ((real-tn (complex-double-reg-real-tn x)))
195 (cond ((zerop (tn-offset real-tn))
196 (inst fstd (ea-for-cdf-real-stack y)))
199 (inst fstd (ea-for-cdf-real-stack y))
200 (inst fxch real-tn))))
201 (let ((imag-tn (complex-double-reg-imag-tn x)))
203 (inst fstd (ea-for-cdf-imag-stack y))
204 (inst fxch imag-tn)))
209 ;;; float register to register moves
210 (define-vop (float-move)
215 (unless (location= x y)
216 (cond ((zerop (tn-offset y))
217 (copy-fp-reg-to-fr0 x))
218 ((zerop (tn-offset x))
225 (define-vop (single-move float-move)
226 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
227 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
228 (define-move-vop single-move :move (single-reg) (single-reg))
230 (define-vop (double-move float-move)
231 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
232 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
233 (define-move-vop double-move :move (double-reg) (double-reg))
235 ;;; complex float register to register moves
236 (define-vop (complex-float-move)
237 (:args (x :target y :load-if (not (location= x y))))
238 (:results (y :load-if (not (location= x y))))
239 (:note "complex float move")
241 (unless (location= x y)
242 ;; Note the complex-float-regs are aligned to every second
243 ;; float register so there is not need to worry about overlap.
244 (let ((x-real (complex-double-reg-real-tn x))
245 (y-real (complex-double-reg-real-tn y)))
246 (cond ((zerop (tn-offset y-real))
247 (copy-fp-reg-to-fr0 x-real))
248 ((zerop (tn-offset x-real))
253 (inst fxch x-real))))
254 (let ((x-imag (complex-double-reg-imag-tn x))
255 (y-imag (complex-double-reg-imag-tn y)))
258 (inst fxch x-imag)))))
260 (define-vop (complex-single-move complex-float-move)
261 (:args (x :scs (complex-single-reg) :target y
262 :load-if (not (location= x y))))
263 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
264 (define-move-vop complex-single-move :move
265 (complex-single-reg) (complex-single-reg))
267 (define-vop (complex-double-move complex-float-move)
268 (:args (x :scs (complex-double-reg)
269 :target y :load-if (not (location= x y))))
270 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
271 (define-move-vop complex-double-move :move
272 (complex-double-reg) (complex-double-reg))
275 ;;; Move from float to a descriptor reg. allocating a new float
276 ;;; object in the process.
277 (define-vop (move-from-single)
278 (:args (x :scs (single-reg) :to :save))
279 (:results (y :scs (descriptor-reg)))
281 (:note "float to pointer coercion")
283 (with-fixed-allocation (y
285 single-float-size node)
287 (inst fst (ea-for-sf-desc y))))))
288 (define-move-vop move-from-single :move
289 (single-reg) (descriptor-reg))
291 (define-vop (move-from-double)
292 (:args (x :scs (double-reg) :to :save))
293 (:results (y :scs (descriptor-reg)))
295 (:note "float to pointer coercion")
297 (with-fixed-allocation (y
302 (inst fstd (ea-for-df-desc y))))))
303 (define-move-vop move-from-double :move
304 (double-reg) (descriptor-reg))
306 (define-vop (move-from-fp-constant)
307 (:args (x :scs (fp-constant)))
308 (:results (y :scs (descriptor-reg)))
310 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
311 (0f0 (load-symbol-value y *fp-constant-0f0*))
312 (1f0 (load-symbol-value y *fp-constant-1f0*))
313 (0d0 (load-symbol-value y *fp-constant-0d0*))
314 (1d0 (load-symbol-value y *fp-constant-1d0*)))))
315 (define-move-vop move-from-fp-constant :move
316 (fp-constant) (descriptor-reg))
318 ;;; Move from a descriptor to a float register.
319 (define-vop (move-to-single)
320 (:args (x :scs (descriptor-reg)))
321 (:results (y :scs (single-reg)))
322 (:note "pointer to float coercion")
324 (with-empty-tn@fp-top(y)
325 (inst fld (ea-for-sf-desc x)))))
326 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
328 (define-vop (move-to-double)
329 (:args (x :scs (descriptor-reg)))
330 (:results (y :scs (double-reg)))
331 (:note "pointer to float coercion")
333 (with-empty-tn@fp-top(y)
334 (inst fldd (ea-for-df-desc x)))))
335 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
338 ;;; Move from complex float to a descriptor reg. allocating a new
339 ;;; complex float object in the process.
340 (define-vop (move-from-complex-single)
341 (:args (x :scs (complex-single-reg) :to :save))
342 (:results (y :scs (descriptor-reg)))
344 (:note "complex float to pointer coercion")
346 (with-fixed-allocation (y
347 complex-single-float-widetag
348 complex-single-float-size
350 (let ((real-tn (complex-single-reg-real-tn x)))
351 (with-tn@fp-top(real-tn)
352 (inst fst (ea-for-csf-real-desc y))))
353 (let ((imag-tn (complex-single-reg-imag-tn x)))
354 (with-tn@fp-top(imag-tn)
355 (inst fst (ea-for-csf-imag-desc y)))))))
356 (define-move-vop move-from-complex-single :move
357 (complex-single-reg) (descriptor-reg))
359 (define-vop (move-from-complex-double)
360 (:args (x :scs (complex-double-reg) :to :save))
361 (:results (y :scs (descriptor-reg)))
363 (:note "complex float to pointer coercion")
365 (with-fixed-allocation (y
366 complex-double-float-widetag
367 complex-double-float-size
369 (let ((real-tn (complex-double-reg-real-tn x)))
370 (with-tn@fp-top(real-tn)
371 (inst fstd (ea-for-cdf-real-desc y))))
372 (let ((imag-tn (complex-double-reg-imag-tn x)))
373 (with-tn@fp-top(imag-tn)
374 (inst fstd (ea-for-cdf-imag-desc y)))))))
375 (define-move-vop move-from-complex-double :move
376 (complex-double-reg) (descriptor-reg))
378 ;;; Move from a descriptor to a complex float register.
379 (macrolet ((frob (name sc format)
382 (:args (x :scs (descriptor-reg)))
383 (:results (y :scs (,sc)))
384 (:note "pointer to complex float coercion")
386 (let ((real-tn (complex-double-reg-real-tn y)))
387 (with-empty-tn@fp-top(real-tn)
389 (:single '((inst fld (ea-for-csf-real-desc x))))
390 (:double '((inst fldd (ea-for-cdf-real-desc x)))))))
391 (let ((imag-tn (complex-double-reg-imag-tn y)))
392 (with-empty-tn@fp-top(imag-tn)
394 (:single '((inst fld (ea-for-csf-imag-desc x))))
395 (:double '((inst fldd (ea-for-cdf-imag-desc x)))))))))
396 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
397 (frob move-to-complex-single complex-single-reg :single)
398 (frob move-to-complex-double complex-double-reg :double))
400 ;;;; the move argument vops
402 ;;;; Note these are also used to stuff fp numbers onto the c-call
403 ;;;; stack so the order is different than the lisp-stack.
405 ;;; the general MOVE-ARG VOP
406 (macrolet ((frob (name sc stack-sc format)
409 (:args (x :scs (,sc) :target y)
411 :load-if (not (sc-is y ,sc))))
413 (:note "float argument move")
414 (:generator ,(case format (:single 2) (:double 3) (:long 4))
417 (unless (location= x y)
418 (cond ((zerop (tn-offset y))
419 (copy-fp-reg-to-fr0 x))
420 ((zerop (tn-offset x))
427 (if (= (tn-offset fp) esp-offset)
428 (let* ((offset (* (tn-offset y) n-word-bytes))
429 (ea (make-ea :dword :base fp :disp offset)))
432 (:single '((inst fst ea)))
433 (:double '((inst fstd ea))))))
436 :disp (- (* (+ (tn-offset y)
444 (:single '((inst fst ea)))
445 (:double '((inst fstd ea)))))))))))
446 (define-move-vop ,name :move-arg
447 (,sc descriptor-reg) (,sc)))))
448 (frob move-single-float-arg single-reg single-stack :single)
449 (frob move-double-float-arg double-reg double-stack :double))
451 ;;;; complex float MOVE-ARG VOP
452 (macrolet ((frob (name sc stack-sc format)
455 (:args (x :scs (,sc) :target y)
457 :load-if (not (sc-is y ,sc))))
459 (:note "complex float argument move")
460 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
463 (unless (location= x y)
464 (let ((x-real (complex-double-reg-real-tn x))
465 (y-real (complex-double-reg-real-tn y)))
466 (cond ((zerop (tn-offset y-real))
467 (copy-fp-reg-to-fr0 x-real))
468 ((zerop (tn-offset x-real))
473 (inst fxch x-real))))
474 (let ((x-imag (complex-double-reg-imag-tn x))
475 (y-imag (complex-double-reg-imag-tn y)))
478 (inst fxch x-imag))))
480 (let ((real-tn (complex-double-reg-real-tn x)))
481 (cond ((zerop (tn-offset real-tn))
485 (ea-for-csf-real-stack y fp))))
488 (ea-for-cdf-real-stack y fp))))))
494 (ea-for-csf-real-stack y fp))))
497 (ea-for-cdf-real-stack y fp)))))
498 (inst fxch real-tn))))
499 (let ((imag-tn (complex-double-reg-imag-tn x)))
503 '((inst fst (ea-for-csf-imag-stack y fp))))
505 '((inst fstd (ea-for-cdf-imag-stack y fp)))))
506 (inst fxch imag-tn))))))
507 (define-move-vop ,name :move-arg
508 (,sc descriptor-reg) (,sc)))))
509 (frob move-complex-single-float-arg
510 complex-single-reg complex-single-stack :single)
511 (frob move-complex-double-float-arg
512 complex-double-reg complex-double-stack :double))
514 (define-move-vop move-arg :move-arg
515 (single-reg double-reg
516 complex-single-reg complex-double-reg)
522 ;;; dtc: the floating point arithmetic vops
524 ;;; Note: Although these can accept x and y on the stack or pointed to
525 ;;; from a descriptor register, they will work with register loading
526 ;;; without these. Same deal with the result - it need only be a
527 ;;; register. When load-tns are needed they will probably be in ST0
528 ;;; and the code below should be able to correctly handle all cases.
530 ;;; However it seems to produce better code if all arg. and result
531 ;;; options are used; on the P86 there is no extra cost in using a
532 ;;; memory operand to the FP instructions - not so on the PPro.
534 ;;; It may also be useful to handle constant args?
536 ;;; 22-Jul-97: descriptor args lose in some simple cases when
537 ;;; a function result computed in a loop. Then Python insists
538 ;;; on consing the intermediate values! For example
541 (declare (type (simple-array double-float (*)) a)
544 (declare (type double-float sum))
546 (incf sum (* (aref a i)(aref a i))))
549 ;;; So, disabling descriptor args until this can be fixed elsewhere.
551 ((frob (op fop-sti fopr-sti
553 fopd foprd dname dcost
555 #!-long-float (declare (ignore lcost lname))
559 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
561 (y :scs (single-reg single-stack #+nil descriptor-reg)
563 (:temporary (:sc single-reg :offset fr0-offset
564 :from :eval :to :result) fr0)
565 (:results (r :scs (single-reg single-stack)))
566 (:arg-types single-float single-float)
567 (:result-types single-float)
569 (:note "inline float arithmetic")
571 (:save-p :compute-only)
574 ;; Handle a few special cases
576 ;; x, y, and r are the same register.
577 ((and (sc-is x single-reg) (location= x r) (location= y r))
578 (cond ((zerop (tn-offset r))
583 ;; XX the source register will not be valid.
584 (note-next-instruction vop :internal-error)
587 ;; x and r are the same register.
588 ((and (sc-is x single-reg) (location= x r))
589 (cond ((zerop (tn-offset r))
592 ;; ST(0) = ST(0) op ST(y)
595 ;; ST(0) = ST(0) op Mem
596 (inst ,fop (ea-for-sf-stack y)))
598 (inst ,fop (ea-for-sf-desc y)))))
603 (unless (zerop (tn-offset y))
604 (copy-fp-reg-to-fr0 y)))
605 ((single-stack descriptor-reg)
607 (if (sc-is y single-stack)
608 (inst fld (ea-for-sf-stack y))
609 (inst fld (ea-for-sf-desc y)))))
610 ;; ST(i) = ST(i) op ST0
612 (maybe-fp-wait node vop))
613 ;; y and r are the same register.
614 ((and (sc-is y single-reg) (location= y r))
615 (cond ((zerop (tn-offset r))
618 ;; ST(0) = ST(x) op ST(0)
621 ;; ST(0) = Mem op ST(0)
622 (inst ,fopr (ea-for-sf-stack x)))
624 (inst ,fopr (ea-for-sf-desc x)))))
629 (unless (zerop (tn-offset x))
630 (copy-fp-reg-to-fr0 x)))
631 ((single-stack descriptor-reg)
633 (if (sc-is x single-stack)
634 (inst fld (ea-for-sf-stack x))
635 (inst fld (ea-for-sf-desc x)))))
636 ;; ST(i) = ST(0) op ST(i)
638 (maybe-fp-wait node vop))
641 ;; Get the result to ST0.
643 ;; Special handling is needed if x or y are in ST0, and
644 ;; simpler code is generated.
647 ((and (sc-is x single-reg) (zerop (tn-offset x)))
653 (inst ,fop (ea-for-sf-stack y)))
655 (inst ,fop (ea-for-sf-desc y)))))
657 ((and (sc-is y single-reg) (zerop (tn-offset y)))
663 (inst ,fopr (ea-for-sf-stack x)))
665 (inst ,fopr (ea-for-sf-desc x)))))
670 (copy-fp-reg-to-fr0 x))
673 (inst fld (ea-for-sf-stack x)))
676 (inst fld (ea-for-sf-desc x))))
682 (inst ,fop (ea-for-sf-stack y)))
684 (inst ,fop (ea-for-sf-desc y))))))
686 (note-next-instruction vop :internal-error)
688 ;; Finally save the result.
691 (cond ((zerop (tn-offset r))
692 (maybe-fp-wait node))
696 (inst fst (ea-for-sf-stack r))))))))
700 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
702 (y :scs (double-reg double-stack #+nil descriptor-reg)
704 (:temporary (:sc double-reg :offset fr0-offset
705 :from :eval :to :result) fr0)
706 (:results (r :scs (double-reg double-stack)))
707 (:arg-types double-float double-float)
708 (:result-types double-float)
710 (:note "inline float arithmetic")
712 (:save-p :compute-only)
715 ;; Handle a few special cases.
717 ;; x, y, and r are the same register.
718 ((and (sc-is x double-reg) (location= x r) (location= y r))
719 (cond ((zerop (tn-offset r))
724 ;; XX the source register will not be valid.
725 (note-next-instruction vop :internal-error)
728 ;; x and r are the same register.
729 ((and (sc-is x double-reg) (location= x r))
730 (cond ((zerop (tn-offset r))
733 ;; ST(0) = ST(0) op ST(y)
736 ;; ST(0) = ST(0) op Mem
737 (inst ,fopd (ea-for-df-stack y)))
739 (inst ,fopd (ea-for-df-desc y)))))
744 (unless (zerop (tn-offset y))
745 (copy-fp-reg-to-fr0 y)))
746 ((double-stack descriptor-reg)
748 (if (sc-is y double-stack)
749 (inst fldd (ea-for-df-stack y))
750 (inst fldd (ea-for-df-desc y)))))
751 ;; ST(i) = ST(i) op ST0
753 (maybe-fp-wait node vop))
754 ;; y and r are the same register.
755 ((and (sc-is y double-reg) (location= y r))
756 (cond ((zerop (tn-offset r))
759 ;; ST(0) = ST(x) op ST(0)
762 ;; ST(0) = Mem op ST(0)
763 (inst ,foprd (ea-for-df-stack x)))
765 (inst ,foprd (ea-for-df-desc x)))))
770 (unless (zerop (tn-offset x))
771 (copy-fp-reg-to-fr0 x)))
772 ((double-stack descriptor-reg)
774 (if (sc-is x double-stack)
775 (inst fldd (ea-for-df-stack x))
776 (inst fldd (ea-for-df-desc x)))))
777 ;; ST(i) = ST(0) op ST(i)
779 (maybe-fp-wait node vop))
782 ;; Get the result to ST0.
784 ;; Special handling is needed if x or y are in ST0, and
785 ;; simpler code is generated.
788 ((and (sc-is x double-reg) (zerop (tn-offset x)))
794 (inst ,fopd (ea-for-df-stack y)))
796 (inst ,fopd (ea-for-df-desc y)))))
798 ((and (sc-is y double-reg) (zerop (tn-offset y)))
804 (inst ,foprd (ea-for-df-stack x)))
806 (inst ,foprd (ea-for-df-desc x)))))
811 (copy-fp-reg-to-fr0 x))
814 (inst fldd (ea-for-df-stack x)))
817 (inst fldd (ea-for-df-desc x))))
823 (inst ,fopd (ea-for-df-stack y)))
825 (inst ,fopd (ea-for-df-desc y))))))
827 (note-next-instruction vop :internal-error)
829 ;; Finally save the result.
832 (cond ((zerop (tn-offset r))
833 (maybe-fp-wait node))
837 (inst fstd (ea-for-df-stack r))))))))
840 (frob + fadd-sti fadd-sti
841 fadd fadd +/single-float 2
842 faddd faddd +/double-float 2
844 (frob - fsub-sti fsubr-sti
845 fsub fsubr -/single-float 2
846 fsubd fsubrd -/double-float 2
848 (frob * fmul-sti fmul-sti
849 fmul fmul */single-float 3
850 fmuld fmuld */double-float 3
852 (frob / fdiv-sti fdivr-sti
853 fdiv fdivr //single-float 12
854 fdivd fdivrd //double-float 12
857 (macrolet ((frob (name inst translate sc type)
859 (:args (x :scs (,sc) :target fr0))
860 (:results (y :scs (,sc)))
861 (:translate ,translate)
864 (:result-types ,type)
865 (:temporary (:sc double-reg :offset fr0-offset
866 :from :argument :to :result) fr0)
868 (:note "inline float arithmetic")
870 (:save-p :compute-only)
872 (note-this-location vop :internal-error)
873 (unless (zerop (tn-offset x))
874 (inst fxch x) ; x to top of stack
875 (unless (location= x y)
876 (inst fst x))) ; Maybe save it.
877 (inst ,inst) ; Clobber st0.
878 (unless (zerop (tn-offset y))
881 (frob abs/single-float fabs abs single-reg single-float)
882 (frob abs/double-float fabs abs double-reg double-float)
884 (frob %negate/single-float fchs %negate single-reg single-float)
885 (frob %negate/double-float fchs %negate double-reg double-float))
889 (define-vop (=/float)
891 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
896 (:save-p :compute-only)
897 (:note "inline float comparison")
900 (note-this-location vop :internal-error)
902 ;; x is in ST0; y is in any reg.
903 ((zerop (tn-offset x))
905 ;; y is in ST0; x is in another reg.
906 ((zerop (tn-offset y))
908 ;; x and y are the same register, not ST0
913 ;; x and y are different registers, neither ST0.
918 (inst fnstsw) ; status word to ax
919 (inst and ah-tn #x45) ; C3 C2 C0
920 (inst cmp ah-tn #x40)
921 (inst jmp (if not-p :ne :e) target)))
923 (define-vop (=/single-float =/float)
925 (:args (x :scs (single-reg))
926 (y :scs (single-reg)))
927 (:arg-types single-float single-float))
929 (define-vop (=/double-float =/float)
931 (:args (x :scs (double-reg))
932 (y :scs (double-reg)))
933 (:arg-types double-float double-float))
935 (define-vop (<single-float)
937 (:args (x :scs (single-reg single-stack descriptor-reg))
938 (y :scs (single-reg single-stack descriptor-reg)))
939 (:arg-types single-float single-float)
940 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
941 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
945 (:note "inline float comparison")
948 ;; Handle a few special cases.
951 ((and (sc-is y single-reg) (zerop (tn-offset y)))
955 ((single-stack descriptor-reg)
956 (if (sc-is x single-stack)
957 (inst fcom (ea-for-sf-stack x))
958 (inst fcom (ea-for-sf-desc x)))))
959 (inst fnstsw) ; status word to ax
960 (inst and ah-tn #x45))
962 ;; general case when y is not in ST0
967 (unless (zerop (tn-offset x))
968 (copy-fp-reg-to-fr0 x)))
969 ((single-stack descriptor-reg)
971 (if (sc-is x single-stack)
972 (inst fld (ea-for-sf-stack x))
973 (inst fld (ea-for-sf-desc x)))))
977 ((single-stack descriptor-reg)
978 (if (sc-is y single-stack)
979 (inst fcom (ea-for-sf-stack y))
980 (inst fcom (ea-for-sf-desc y)))))
981 (inst fnstsw) ; status word to ax
982 (inst and ah-tn #x45) ; C3 C2 C0
983 (inst cmp ah-tn #x01)))
984 (inst jmp (if not-p :ne :e) target)))
986 (define-vop (<double-float)
988 (:args (x :scs (double-reg double-stack descriptor-reg))
989 (y :scs (double-reg double-stack descriptor-reg)))
990 (:arg-types double-float double-float)
991 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
992 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
996 (:note "inline float comparison")
999 ;; Handle a few special cases
1002 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1006 ((double-stack descriptor-reg)
1007 (if (sc-is x double-stack)
1008 (inst fcomd (ea-for-df-stack x))
1009 (inst fcomd (ea-for-df-desc x)))))
1010 (inst fnstsw) ; status word to ax
1011 (inst and ah-tn #x45))
1013 ;; General case when y is not in ST0.
1018 (unless (zerop (tn-offset x))
1019 (copy-fp-reg-to-fr0 x)))
1020 ((double-stack descriptor-reg)
1022 (if (sc-is x double-stack)
1023 (inst fldd (ea-for-df-stack x))
1024 (inst fldd (ea-for-df-desc x)))))
1028 ((double-stack descriptor-reg)
1029 (if (sc-is y double-stack)
1030 (inst fcomd (ea-for-df-stack y))
1031 (inst fcomd (ea-for-df-desc y)))))
1032 (inst fnstsw) ; status word to ax
1033 (inst and ah-tn #x45) ; C3 C2 C0
1034 (inst cmp ah-tn #x01)))
1035 (inst jmp (if not-p :ne :e) target)))
1037 (define-vop (>single-float)
1039 (:args (x :scs (single-reg single-stack descriptor-reg))
1040 (y :scs (single-reg single-stack descriptor-reg)))
1041 (:arg-types single-float single-float)
1042 (:temporary (:sc single-reg :offset fr0-offset :from :eval) fr0)
1043 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1045 (:info target not-p)
1046 (:policy :fast-safe)
1047 (:note "inline float comparison")
1050 ;; Handle a few special cases.
1053 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1057 ((single-stack descriptor-reg)
1058 (if (sc-is x single-stack)
1059 (inst fcom (ea-for-sf-stack x))
1060 (inst fcom (ea-for-sf-desc x)))))
1061 (inst fnstsw) ; status word to ax
1062 (inst and ah-tn #x45)
1063 (inst cmp ah-tn #x01))
1065 ;; general case when y is not in ST0
1070 (unless (zerop (tn-offset x))
1071 (copy-fp-reg-to-fr0 x)))
1072 ((single-stack descriptor-reg)
1074 (if (sc-is x single-stack)
1075 (inst fld (ea-for-sf-stack x))
1076 (inst fld (ea-for-sf-desc x)))))
1080 ((single-stack descriptor-reg)
1081 (if (sc-is y single-stack)
1082 (inst fcom (ea-for-sf-stack y))
1083 (inst fcom (ea-for-sf-desc y)))))
1084 (inst fnstsw) ; status word to ax
1085 (inst and ah-tn #x45)))
1086 (inst jmp (if not-p :ne :e) target)))
1088 (define-vop (>double-float)
1090 (:args (x :scs (double-reg double-stack descriptor-reg))
1091 (y :scs (double-reg double-stack descriptor-reg)))
1092 (:arg-types double-float double-float)
1093 (:temporary (:sc double-reg :offset fr0-offset :from :eval) fr0)
1094 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1096 (:info target not-p)
1097 (:policy :fast-safe)
1098 (:note "inline float comparison")
1101 ;; Handle a few special cases.
1104 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1108 ((double-stack descriptor-reg)
1109 (if (sc-is x double-stack)
1110 (inst fcomd (ea-for-df-stack x))
1111 (inst fcomd (ea-for-df-desc x)))))
1112 (inst fnstsw) ; status word to ax
1113 (inst and ah-tn #x45)
1114 (inst cmp ah-tn #x01))
1116 ;; general case when y is not in ST0
1121 (unless (zerop (tn-offset x))
1122 (copy-fp-reg-to-fr0 x)))
1123 ((double-stack descriptor-reg)
1125 (if (sc-is x double-stack)
1126 (inst fldd (ea-for-df-stack x))
1127 (inst fldd (ea-for-df-desc x)))))
1131 ((double-stack descriptor-reg)
1132 (if (sc-is y double-stack)
1133 (inst fcomd (ea-for-df-stack y))
1134 (inst fcomd (ea-for-df-desc y)))))
1135 (inst fnstsw) ; status word to ax
1136 (inst and ah-tn #x45)))
1137 (inst jmp (if not-p :ne :e) target)))
1139 ;;; Comparisons with 0 can use the FTST instruction.
1141 (define-vop (float-test)
1143 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1145 (:info target not-p y)
1146 (:variant-vars code)
1147 (:policy :fast-safe)
1149 (:save-p :compute-only)
1150 (:note "inline float comparison")
1153 (note-this-location vop :internal-error)
1156 ((zerop (tn-offset x))
1163 (inst fnstsw) ; status word to ax
1164 (inst and ah-tn #x45) ; C3 C2 C0
1165 (unless (zerop code)
1166 (inst cmp ah-tn code))
1167 (inst jmp (if not-p :ne :e) target)))
1169 (define-vop (=0/single-float float-test)
1171 (:args (x :scs (single-reg)))
1172 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1174 (define-vop (=0/double-float float-test)
1176 (:args (x :scs (double-reg)))
1177 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1180 (define-vop (<0/single-float float-test)
1182 (:args (x :scs (single-reg)))
1183 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1185 (define-vop (<0/double-float float-test)
1187 (:args (x :scs (double-reg)))
1188 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1191 (define-vop (>0/single-float float-test)
1193 (:args (x :scs (single-reg)))
1194 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1196 (define-vop (>0/double-float float-test)
1198 (:args (x :scs (double-reg)))
1199 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1205 (macrolet ((frob (name translate to-sc to-type)
1206 `(define-vop (,name)
1207 (:args (x :scs (signed-stack signed-reg) :target temp))
1208 (:temporary (:sc signed-stack) temp)
1209 (:results (y :scs (,to-sc)))
1210 (:arg-types signed-num)
1211 (:result-types ,to-type)
1212 (:policy :fast-safe)
1213 (:note "inline float coercion")
1214 (:translate ,translate)
1216 (:save-p :compute-only)
1221 (with-empty-tn@fp-top(y)
1222 (note-this-location vop :internal-error)
1225 (with-empty-tn@fp-top(y)
1226 (note-this-location vop :internal-error)
1227 (inst fild x))))))))
1228 (frob %single-float/signed %single-float single-reg single-float)
1229 (frob %double-float/signed %double-float double-reg double-float))
1231 (macrolet ((frob (name translate to-sc to-type)
1232 `(define-vop (,name)
1233 (:args (x :scs (unsigned-reg)))
1234 (:results (y :scs (,to-sc)))
1235 (:arg-types unsigned-num)
1236 (:result-types ,to-type)
1237 (:policy :fast-safe)
1238 (:note "inline float coercion")
1239 (:translate ,translate)
1241 (:save-p :compute-only)
1245 (with-empty-tn@fp-top(y)
1246 (note-this-location vop :internal-error)
1247 (inst fildl (make-ea :dword :base rsp-tn)))
1248 (inst add rsp-tn 16)))))
1249 (frob %single-float/unsigned %single-float single-reg single-float)
1250 (frob %double-float/unsigned %double-float double-reg double-float))
1252 ;;; These should be no-ops but the compiler might want to move some
1254 (macrolet ((frob (name translate from-sc from-type to-sc to-type)
1255 `(define-vop (,name)
1256 (:args (x :scs (,from-sc) :target y))
1257 (:results (y :scs (,to-sc)))
1258 (:arg-types ,from-type)
1259 (:result-types ,to-type)
1260 (:policy :fast-safe)
1261 (:note "inline float coercion")
1262 (:translate ,translate)
1264 (:save-p :compute-only)
1266 (note-this-location vop :internal-error)
1267 (unless (location= x y)
1269 ((zerop (tn-offset x))
1270 ;; x is in ST0, y is in another reg. not ST0
1272 ((zerop (tn-offset y))
1273 ;; y is in ST0, x is in another reg. not ST0
1274 (copy-fp-reg-to-fr0 x))
1276 ;; Neither x or y are in ST0, and they are not in
1280 (inst fxch x))))))))
1282 (frob %single-float/double-float %single-float double-reg
1283 double-float single-reg single-float)
1285 (frob %double-float/single-float %double-float single-reg single-float
1286 double-reg double-float))
1288 (macrolet ((frob (trans from-sc from-type round-p)
1289 `(define-vop (,(symbolicate trans "/" from-type))
1290 (:args (x :scs (,from-sc)))
1291 (:temporary (:sc signed-stack) stack-temp)
1293 '((:temporary (:sc unsigned-stack) scw)
1294 (:temporary (:sc any-reg) rcw)))
1295 (:results (y :scs (signed-reg)))
1296 (:arg-types ,from-type)
1297 (:result-types signed-num)
1299 (:policy :fast-safe)
1300 (:note "inline float truncate")
1302 (:save-p :compute-only)
1305 '((note-this-location vop :internal-error)
1306 ;; Catch any pending FPE exceptions.
1308 (,(if round-p 'progn 'pseudo-atomic)
1309 ;; Normal mode (for now) is "round to best".
1312 '((inst fnstcw scw) ; save current control word
1313 (move rcw scw) ; into 16-bit register
1314 (inst or rcw (ash #b11 10)) ; CHOP
1315 (move stack-temp rcw)
1316 (inst fldcw stack-temp)))
1321 (inst fist stack-temp)
1322 (inst mov y stack-temp)))
1324 '((inst fldcw scw)))))))))
1325 (frob %unary-truncate single-reg single-float nil)
1326 (frob %unary-truncate double-reg double-float nil)
1328 (frob %unary-round single-reg single-float t)
1329 (frob %unary-round double-reg double-float t))
1331 (macrolet ((frob (trans from-sc from-type round-p)
1332 `(define-vop (,(symbolicate trans "/" from-type "=>UNSIGNED"))
1333 (:args (x :scs (,from-sc) :target fr0))
1334 (:temporary (:sc double-reg :offset fr0-offset
1335 :from :argument :to :result) fr0)
1337 '((:temporary (:sc unsigned-stack) stack-temp)
1338 (:temporary (:sc unsigned-stack) scw)
1339 (:temporary (:sc any-reg) rcw)))
1340 (:results (y :scs (unsigned-reg)))
1341 (:arg-types ,from-type)
1342 (:result-types unsigned-num)
1344 (:policy :fast-safe)
1345 (:note "inline float truncate")
1347 (:save-p :compute-only)
1350 '((note-this-location vop :internal-error)
1351 ;; Catch any pending FPE exceptions.
1353 ;; Normal mode (for now) is "round to best".
1354 (unless (zerop (tn-offset x))
1355 (copy-fp-reg-to-fr0 x))
1357 '((inst fnstcw scw) ; save current control word
1358 (move rcw scw) ; into 16-bit register
1359 (inst or rcw (ash #b11 10)) ; CHOP
1360 (move stack-temp rcw)
1361 (inst fldcw stack-temp)))
1363 (inst fistpl (make-ea :dword :base rsp-tn))
1365 (inst fld fr0) ; copy fr0 to at least restore stack.
1368 '((inst fldcw scw)))))))
1369 (frob %unary-truncate single-reg single-float nil)
1370 (frob %unary-truncate double-reg double-float nil)
1371 (frob %unary-round single-reg single-float t)
1372 (frob %unary-round double-reg double-float t))
1374 (define-vop (make-single-float)
1375 (:args (bits :scs (signed-reg) :target res
1376 :load-if (not (or (and (sc-is bits signed-stack)
1377 (sc-is res single-reg))
1378 (and (sc-is bits signed-stack)
1379 (sc-is res single-stack)
1380 (location= bits res))))))
1381 (:results (res :scs (single-reg single-stack)))
1382 (:temporary (:sc signed-stack) stack-temp)
1383 (:arg-types signed-num)
1384 (:result-types single-float)
1385 (:translate make-single-float)
1386 (:policy :fast-safe)
1393 (inst mov res bits))
1395 (aver (location= bits res)))))
1399 ;; source must be in memory
1400 (inst mov stack-temp bits)
1401 (with-empty-tn@fp-top(res)
1402 (inst fld stack-temp)))
1404 (with-empty-tn@fp-top(res)
1405 (inst fld bits))))))))
1407 (define-vop (make-double-float)
1408 (:args (hi-bits :scs (signed-reg))
1409 (lo-bits :scs (unsigned-reg)))
1410 (:results (res :scs (double-reg)))
1411 (:temporary (:sc double-stack) temp)
1412 (:arg-types signed-num unsigned-num)
1413 (:result-types double-float)
1414 (:translate make-double-float)
1415 (:policy :fast-safe)
1418 (let ((offset (1+ (tn-offset temp))))
1419 (storew hi-bits rbp-tn (- offset))
1420 (storew lo-bits rbp-tn (- (1+ offset)))
1421 (with-empty-tn@fp-top(res)
1422 (inst fldd (make-ea :dword :base rbp-tn
1423 :disp (- (* (1+ offset) n-word-bytes))))))))
1425 (define-vop (single-float-bits)
1426 (:args (float :scs (single-reg descriptor-reg)
1427 :load-if (not (sc-is float single-stack))))
1428 (:results (bits :scs (signed-reg)))
1429 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
1430 (:arg-types single-float)
1431 (:result-types signed-num)
1432 (:translate single-float-bits)
1433 (:policy :fast-safe)
1440 (with-tn@fp-top(float)
1441 (inst fst stack-temp)
1442 (inst mov bits stack-temp)))
1444 (inst mov bits float))
1447 bits float single-float-value-slot
1448 other-pointer-lowtag))))
1452 (with-tn@fp-top(float)
1453 (inst fst bits))))))))
1455 (define-vop (double-float-high-bits)
1456 (:args (float :scs (double-reg descriptor-reg)
1457 :load-if (not (sc-is float double-stack))))
1458 (:results (hi-bits :scs (signed-reg)))
1459 (:temporary (:sc double-stack) temp)
1460 (:arg-types double-float)
1461 (:result-types signed-num)
1462 (:translate double-float-high-bits)
1463 (:policy :fast-safe)
1468 (with-tn@fp-top(float)
1469 (let ((where (make-ea :dword :base rbp-tn
1470 :disp (- (* (+ 2 (tn-offset temp))
1473 (loadw hi-bits rbp-tn (- (1+ (tn-offset temp)))))
1475 (loadw hi-bits rbp-tn (- (1+ (tn-offset float)))))
1477 (loadw hi-bits float (1+ double-float-value-slot)
1478 other-pointer-lowtag)))))
1480 (define-vop (double-float-low-bits)
1481 (:args (float :scs (double-reg descriptor-reg)
1482 :load-if (not (sc-is float double-stack))))
1483 (:results (lo-bits :scs (unsigned-reg)))
1484 (:temporary (:sc double-stack) temp)
1485 (:arg-types double-float)
1486 (:result-types unsigned-num)
1487 (:translate double-float-low-bits)
1488 (:policy :fast-safe)
1493 (with-tn@fp-top(float)
1494 (let ((where (make-ea :dword :base rbp-tn
1495 :disp (- (* (+ 2 (tn-offset temp))
1498 (loadw lo-bits rbp-tn (- (+ 2 (tn-offset temp)))))
1500 (loadw lo-bits rbp-tn (- (+ 2 (tn-offset float)))))
1502 (loadw lo-bits float double-float-value-slot
1503 other-pointer-lowtag)))))
1506 ;;;; float mode hackery
1508 (sb!xc:deftype float-modes () '(unsigned-byte 64)) ; really only 16
1509 (defknown floating-point-modes () float-modes (flushable))
1510 (defknown ((setf floating-point-modes)) (float-modes)
1513 (def!constant npx-env-size (* 7 n-word-bytes))
1514 (def!constant npx-cw-offset 0)
1515 (def!constant npx-sw-offset 4)
1517 (define-vop (floating-point-modes)
1518 (:results (res :scs (unsigned-reg)))
1519 (:result-types unsigned-num)
1520 (:translate floating-point-modes)
1521 (:policy :fast-safe)
1522 (:temporary (:sc unsigned-reg :offset eax-offset :target res
1525 (inst sub rsp-tn npx-env-size) ; Make space on stack.
1526 (inst wait) ; Catch any pending FPE exceptions
1527 (inst fstenv (make-ea :dword :base rsp-tn)) ; masks all exceptions
1528 (inst fldenv (make-ea :dword :base rsp-tn)) ; Restore previous state.
1529 ;; Move current status to high word.
1530 (inst movzxd eax (make-ea :dword :base rsp-tn :disp (- npx-sw-offset 2)))
1531 ;; Move exception mask to low word.
1532 (inst mov ax-tn (make-ea :word :base rsp-tn :disp npx-cw-offset))
1533 (inst add rsp-tn npx-env-size) ; Pop stack.
1534 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
1538 (define-vop (set-floating-point-modes)
1539 (:args (new :scs (unsigned-reg) :to :result :target res))
1540 (:results (res :scs (unsigned-reg)))
1541 (:arg-types unsigned-num)
1542 (:result-types unsigned-num)
1543 (:translate (setf floating-point-modes))
1544 (:policy :fast-safe)
1545 (:temporary (:sc unsigned-reg :offset eax-offset
1546 :from :eval :to :result) eax)
1548 (inst sub rsp-tn npx-env-size) ; Make space on stack.
1549 (inst wait) ; Catch any pending FPE exceptions.
1550 (inst fstenv (make-ea :dword :base rsp-tn))
1552 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
1553 (inst mov (make-ea :word :base rsp-tn :disp npx-cw-offset) ax-tn)
1554 (inst shr eax 16) ; position status word
1555 (inst mov (make-ea :word :base rsp-tn :disp npx-sw-offset) ax-tn)
1556 (inst fldenv (make-ea :dword :base rsp-tn))
1557 (inst add rsp-tn npx-env-size) ; Pop stack.
1563 ;;; Let's use some of the 80387 special functions.
1565 ;;; These defs will not take effect unless code/irrat.lisp is modified
1566 ;;; to remove the inlined alien routine def.
1568 (macrolet ((frob (func trans op)
1569 `(define-vop (,func)
1570 (:args (x :scs (double-reg) :target fr0))
1571 (:temporary (:sc double-reg :offset fr0-offset
1572 :from :argument :to :result) fr0)
1574 (:results (y :scs (double-reg)))
1575 (:arg-types double-float)
1576 (:result-types double-float)
1578 (:policy :fast-safe)
1579 (:note "inline NPX function")
1581 (:save-p :compute-only)
1584 (note-this-location vop :internal-error)
1585 (unless (zerop (tn-offset x))
1586 (inst fxch x) ; x to top of stack
1587 (unless (location= x y)
1588 (inst fst x))) ; maybe save it
1589 (inst ,op) ; clobber st0
1590 (cond ((zerop (tn-offset y))
1591 (maybe-fp-wait node))
1595 ;; Quick versions of fsin and fcos that require the argument to be
1596 ;; within range 2^63.
1597 (frob fsin-quick %sin-quick fsin)
1598 (frob fcos-quick %cos-quick fcos)
1599 (frob fsqrt %sqrt fsqrt))
1601 ;;; Quick version of ftan that requires the argument to be within
1603 (define-vop (ftan-quick)
1604 (:translate %tan-quick)
1605 (:args (x :scs (double-reg) :target fr0))
1606 (:temporary (:sc double-reg :offset fr0-offset
1607 :from :argument :to :result) fr0)
1608 (:temporary (:sc double-reg :offset fr1-offset
1609 :from :argument :to :result) fr1)
1610 (:results (y :scs (double-reg)))
1611 (:arg-types double-float)
1612 (:result-types double-float)
1613 (:policy :fast-safe)
1614 (:note "inline tan function")
1616 (:save-p :compute-only)
1618 (note-this-location vop :internal-error)
1627 (inst fldd (make-random-tn :kind :normal
1628 :sc (sc-or-lose 'double-reg)
1629 :offset (- (tn-offset x) 2)))))
1640 ;;; These versions of fsin, fcos, and ftan try to use argument
1641 ;;; reduction but to do this accurately requires greater precision and
1642 ;;; it is hopelessly inaccurate.
1644 (macrolet ((frob (func trans op)
1645 `(define-vop (,func)
1647 (:args (x :scs (double-reg) :target fr0))
1648 (:temporary (:sc unsigned-reg :offset eax-offset
1649 :from :eval :to :result) eax)
1650 (:temporary (:sc unsigned-reg :offset fr0-offset
1651 :from :argument :to :result) fr0)
1652 (:temporary (:sc unsigned-reg :offset fr1-offset
1653 :from :argument :to :result) fr1)
1654 (:results (y :scs (double-reg)))
1655 (:arg-types double-float)
1656 (:result-types double-float)
1657 (:policy :fast-safe)
1658 (:note "inline sin/cos function")
1660 (:save-p :compute-only)
1663 (note-this-location vop :internal-error)
1664 (unless (zerop (tn-offset x))
1665 (inst fxch x) ; x to top of stack
1666 (unless (location= x y)
1667 (inst fst x))) ; maybe save it
1669 (inst fnstsw) ; status word to ax
1670 (inst and ah-tn #x04) ; C2
1672 ;; Else x was out of range so reduce it; ST0 is unchanged.
1673 (inst fstp fr1) ; Load 2*PI
1679 (inst fnstsw) ; status word to ax
1680 (inst and ah-tn #x04) ; C2
1684 (unless (zerop (tn-offset y))
1686 (frob fsin %sin fsin)
1687 (frob fcos %cos fcos))
1691 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
1692 ;;; the argument is out of range 2^63 and would thus be hopelessly
1694 (macrolet ((frob (func trans op)
1695 `(define-vop (,func)
1697 (:args (x :scs (double-reg) :target fr0))
1698 (:temporary (:sc double-reg :offset fr0-offset
1699 :from :argument :to :result) fr0)
1700 (:temporary (:sc unsigned-reg :offset eax-offset
1701 :from :argument :to :result) eax)
1702 (:results (y :scs (double-reg)))
1703 (:arg-types double-float)
1704 (:result-types double-float)
1705 (:policy :fast-safe)
1706 (:note "inline sin/cos function")
1708 (:save-p :compute-only)
1711 (note-this-location vop :internal-error)
1712 (unless (zerop (tn-offset x))
1713 (inst fxch x) ; x to top of stack
1714 (unless (location= x y)
1715 (inst fst x))) ; maybe save it
1717 (inst fnstsw) ; status word to ax
1718 (inst and ah-tn #x04) ; C2
1720 ;; Else x was out of range so reduce it; ST0 is unchanged.
1721 (inst fstp fr0) ; Load 0.0
1724 (unless (zerop (tn-offset y))
1726 (frob fsin %sin fsin)
1727 (frob fcos %cos fcos))
1731 (:args (x :scs (double-reg) :target fr0))
1732 (:temporary (:sc double-reg :offset fr0-offset
1733 :from :argument :to :result) fr0)
1734 (:temporary (:sc double-reg :offset fr1-offset
1735 :from :argument :to :result) fr1)
1736 (:temporary (:sc unsigned-reg :offset eax-offset
1737 :from :argument :to :result) eax)
1738 (:results (y :scs (double-reg)))
1739 (:arg-types double-float)
1740 (:result-types double-float)
1742 (:policy :fast-safe)
1743 (:note "inline tan function")
1745 (:save-p :compute-only)
1748 (note-this-location vop :internal-error)
1757 (inst fldd (make-random-tn :kind :normal
1758 :sc (sc-or-lose 'double-reg)
1759 :offset (- (tn-offset x) 2)))))
1761 (inst fnstsw) ; status word to ax
1762 (inst and ah-tn #x04) ; C2
1764 ;; Else x was out of range so reduce it; ST0 is unchanged.
1765 (inst fldz) ; Load 0.0
1780 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
1781 (:temporary (:sc double-reg :offset fr0-offset
1782 :from :argument :to :result) fr0)
1783 (:temporary (:sc double-reg :offset fr1-offset
1784 :from :argument :to :result) fr1)
1785 (:temporary (:sc double-reg :offset fr2-offset
1786 :from :argument :to :result) fr2)
1787 (:results (y :scs (double-reg)))
1788 (:arg-types double-float)
1789 (:result-types double-float)
1790 (:policy :fast-safe)
1791 (:note "inline exp function")
1793 (:save-p :compute-only)
1795 (note-this-location vop :internal-error)
1798 (cond ((zerop (tn-offset x))
1804 ;; x is in a FP reg, not fr0
1808 ((double-stack descriptor-reg)
1811 (if (sc-is x double-stack)
1812 (inst fmuld (ea-for-df-stack x))
1813 (inst fmuld (ea-for-df-desc x)))))
1814 ;; Now fr0=x log2(e)
1818 (inst fsubp-sti fr1)
1821 (inst faddp-sti fr1)
1826 (t (inst fstd y)))))
1828 ;;; Modified exp that handles the following special cases:
1829 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
1832 (:args (x :scs (double-reg) :target fr0))
1833 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
1834 (:temporary (:sc double-reg :offset fr0-offset
1835 :from :argument :to :result) fr0)
1836 (:temporary (:sc double-reg :offset fr1-offset
1837 :from :argument :to :result) fr1)
1838 (:temporary (:sc double-reg :offset fr2-offset
1839 :from :argument :to :result) fr2)
1840 (:results (y :scs (double-reg)))
1841 (:arg-types double-float)
1842 (:result-types double-float)
1843 (:policy :fast-safe)
1844 (:note "inline exp function")
1846 (:save-p :compute-only)
1849 (note-this-location vop :internal-error)
1850 (unless (zerop (tn-offset x))
1851 (inst fxch x) ; x to top of stack
1852 (unless (location= x y)
1853 (inst fst x))) ; maybe save it
1854 ;; Check for Inf or NaN
1858 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
1859 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
1860 (inst and ah-tn #x02) ; Test sign of Inf.
1861 (inst jmp :z DONE) ; +Inf gives +Inf.
1862 (inst fstp fr0) ; -Inf gives 0
1864 (inst jmp-short DONE)
1869 ;; Now fr0=x log2(e)
1873 (inst fsubp-sti fr1)
1876 (inst faddp-sti fr1)
1880 (unless (zerop (tn-offset y))
1883 ;;; Expm1 = exp(x) - 1.
1884 ;;; Handles the following special cases:
1885 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
1886 (define-vop (fexpm1)
1888 (:args (x :scs (double-reg) :target fr0))
1889 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
1890 (:temporary (:sc double-reg :offset fr0-offset
1891 :from :argument :to :result) fr0)
1892 (:temporary (:sc double-reg :offset fr1-offset
1893 :from :argument :to :result) fr1)
1894 (:temporary (:sc double-reg :offset fr2-offset
1895 :from :argument :to :result) fr2)
1896 (:results (y :scs (double-reg)))
1897 (:arg-types double-float)
1898 (:result-types double-float)
1899 (:policy :fast-safe)
1900 (:note "inline expm1 function")
1902 (:save-p :compute-only)
1905 (note-this-location vop :internal-error)
1906 (unless (zerop (tn-offset x))
1907 (inst fxch x) ; x to top of stack
1908 (unless (location= x y)
1909 (inst fst x))) ; maybe save it
1910 ;; Check for Inf or NaN
1914 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
1915 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
1916 (inst and ah-tn #x02) ; Test sign of Inf.
1917 (inst jmp :z DONE) ; +Inf gives +Inf.
1918 (inst fstp fr0) ; -Inf gives -1.0
1921 (inst jmp-short DONE)
1923 ;; Free two stack slots leaving the argument on top.
1927 (inst fmul fr1) ; Now fr0 = x log2(e)
1942 (unless (zerop (tn-offset y))
1947 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
1948 (:temporary (:sc double-reg :offset fr0-offset
1949 :from :argument :to :result) fr0)
1950 (:temporary (:sc double-reg :offset fr1-offset
1951 :from :argument :to :result) fr1)
1952 (:results (y :scs (double-reg)))
1953 (:arg-types double-float)
1954 (:result-types double-float)
1955 (:policy :fast-safe)
1956 (:note "inline log function")
1958 (:save-p :compute-only)
1960 (note-this-location vop :internal-error)
1975 ;; x is in a FP reg, not fr0 or fr1
1979 (inst fldd (make-random-tn :kind :normal
1980 :sc (sc-or-lose 'double-reg)
1981 :offset (1- (tn-offset x))))))
1983 ((double-stack descriptor-reg)
1987 (if (sc-is x double-stack)
1988 (inst fldd (ea-for-df-stack x))
1989 (inst fldd (ea-for-df-desc x)))
1994 (t (inst fstd y)))))
1996 (define-vop (flog10)
1998 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
1999 (:temporary (:sc double-reg :offset fr0-offset
2000 :from :argument :to :result) fr0)
2001 (:temporary (:sc double-reg :offset fr1-offset
2002 :from :argument :to :result) fr1)
2003 (:results (y :scs (double-reg)))
2004 (:arg-types double-float)
2005 (:result-types double-float)
2006 (:policy :fast-safe)
2007 (:note "inline log10 function")
2009 (:save-p :compute-only)
2011 (note-this-location vop :internal-error)
2026 ;; x is in a FP reg, not fr0 or fr1
2030 (inst fldd (make-random-tn :kind :normal
2031 :sc (sc-or-lose 'double-reg)
2032 :offset (1- (tn-offset x))))))
2034 ((double-stack descriptor-reg)
2038 (if (sc-is x double-stack)
2039 (inst fldd (ea-for-df-stack x))
2040 (inst fldd (ea-for-df-desc x)))
2045 (t (inst fstd y)))))
2049 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2050 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2051 (:temporary (:sc double-reg :offset fr0-offset
2052 :from (:argument 0) :to :result) fr0)
2053 (:temporary (:sc double-reg :offset fr1-offset
2054 :from (:argument 1) :to :result) fr1)
2055 (:temporary (:sc double-reg :offset fr2-offset
2056 :from :load :to :result) fr2)
2057 (:results (r :scs (double-reg)))
2058 (:arg-types double-float double-float)
2059 (:result-types double-float)
2060 (:policy :fast-safe)
2061 (:note "inline pow function")
2063 (:save-p :compute-only)
2065 (note-this-location vop :internal-error)
2066 ;; Setup x in fr0 and y in fr1
2068 ;; x in fr0; y in fr1
2069 ((and (sc-is x double-reg) (zerop (tn-offset x))
2070 (sc-is y double-reg) (= 1 (tn-offset y))))
2071 ;; y in fr1; x not in fr0
2072 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2076 (copy-fp-reg-to-fr0 x))
2079 (inst fldd (ea-for-df-stack x)))
2082 (inst fldd (ea-for-df-desc x)))))
2083 ;; x in fr0; y not in fr1
2084 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2086 ;; Now load y to fr0
2089 (copy-fp-reg-to-fr0 y))
2092 (inst fldd (ea-for-df-stack y)))
2095 (inst fldd (ea-for-df-desc y))))
2097 ;; x in fr1; y not in fr1
2098 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2102 (copy-fp-reg-to-fr0 y))
2105 (inst fldd (ea-for-df-stack y)))
2108 (inst fldd (ea-for-df-desc y))))
2111 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2113 ;; Now load x to fr0
2116 (copy-fp-reg-to-fr0 x))
2119 (inst fldd (ea-for-df-stack x)))
2122 (inst fldd (ea-for-df-desc x)))))
2123 ;; Neither x or y are in either fr0 or fr1
2130 (inst fldd (make-random-tn :kind :normal
2131 :sc (sc-or-lose 'double-reg)
2132 :offset (- (tn-offset y) 2))))
2134 (inst fldd (ea-for-df-stack y)))
2136 (inst fldd (ea-for-df-desc y))))
2140 (inst fldd (make-random-tn :kind :normal
2141 :sc (sc-or-lose 'double-reg)
2142 :offset (1- (tn-offset x)))))
2144 (inst fldd (ea-for-df-stack x)))
2146 (inst fldd (ea-for-df-desc x))))))
2148 ;; Now have x at fr0; and y at fr1
2150 ;; Now fr0=y log2(x)
2154 (inst fsubp-sti fr1)
2157 (inst faddp-sti fr1)
2162 (t (inst fstd r)))))
2164 (define-vop (fscalen)
2165 (:translate %scalbn)
2166 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2167 (y :scs (signed-stack signed-reg) :target temp))
2168 (:temporary (:sc double-reg :offset fr0-offset
2169 :from (:argument 0) :to :result) fr0)
2170 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2171 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2172 (:results (r :scs (double-reg)))
2173 (:arg-types double-float signed-num)
2174 (:result-types double-float)
2175 (:policy :fast-safe)
2176 (:note "inline scalbn function")
2178 ;; Setup x in fr0 and y in fr1
2209 (inst fld (make-random-tn :kind :normal
2210 :sc (sc-or-lose 'double-reg)
2211 :offset (1- (tn-offset x)))))))
2212 ((double-stack descriptor-reg)
2221 (if (sc-is x double-stack)
2222 (inst fldd (ea-for-df-stack x))
2223 (inst fldd (ea-for-df-desc x)))))
2225 (unless (zerop (tn-offset r))
2228 (define-vop (fscale)
2230 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2231 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2232 (:temporary (:sc double-reg :offset fr0-offset
2233 :from (:argument 0) :to :result) fr0)
2234 (:temporary (:sc double-reg :offset fr1-offset
2235 :from (:argument 1) :to :result) fr1)
2236 (:results (r :scs (double-reg)))
2237 (:arg-types double-float double-float)
2238 (:result-types double-float)
2239 (:policy :fast-safe)
2240 (:note "inline scalb function")
2242 (:save-p :compute-only)
2244 (note-this-location vop :internal-error)
2245 ;; Setup x in fr0 and y in fr1
2247 ;; x in fr0; y in fr1
2248 ((and (sc-is x double-reg) (zerop (tn-offset x))
2249 (sc-is y double-reg) (= 1 (tn-offset y))))
2250 ;; y in fr1; x not in fr0
2251 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2255 (copy-fp-reg-to-fr0 x))
2258 (inst fldd (ea-for-df-stack x)))
2261 (inst fldd (ea-for-df-desc x)))))
2262 ;; x in fr0; y not in fr1
2263 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2265 ;; Now load y to fr0
2268 (copy-fp-reg-to-fr0 y))
2271 (inst fldd (ea-for-df-stack y)))
2274 (inst fldd (ea-for-df-desc y))))
2276 ;; x in fr1; y not in fr1
2277 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2281 (copy-fp-reg-to-fr0 y))
2284 (inst fldd (ea-for-df-stack y)))
2287 (inst fldd (ea-for-df-desc y))))
2290 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2292 ;; Now load x to fr0
2295 (copy-fp-reg-to-fr0 x))
2298 (inst fldd (ea-for-df-stack x)))
2301 (inst fldd (ea-for-df-desc x)))))
2302 ;; Neither x or y are in either fr0 or fr1
2309 (inst fldd (make-random-tn :kind :normal
2310 :sc (sc-or-lose 'double-reg)
2311 :offset (- (tn-offset y) 2))))
2313 (inst fldd (ea-for-df-stack y)))
2315 (inst fldd (ea-for-df-desc y))))
2319 (inst fldd (make-random-tn :kind :normal
2320 :sc (sc-or-lose 'double-reg)
2321 :offset (1- (tn-offset x)))))
2323 (inst fldd (ea-for-df-stack x)))
2325 (inst fldd (ea-for-df-desc x))))))
2327 ;; Now have x at fr0; and y at fr1
2329 (unless (zerop (tn-offset r))
2332 (define-vop (flog1p)
2334 (:args (x :scs (double-reg) :to :result))
2335 (:temporary (:sc double-reg :offset fr0-offset
2336 :from :argument :to :result) fr0)
2337 (:temporary (:sc double-reg :offset fr1-offset
2338 :from :argument :to :result) fr1)
2339 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2340 (:results (y :scs (double-reg)))
2341 (:arg-types double-float)
2342 (:result-types double-float)
2343 (:policy :fast-safe)
2344 (:note "inline log1p function")
2347 ;; x is in a FP reg, not fr0, fr1.
2350 (inst fldd (make-random-tn :kind :normal
2351 :sc (sc-or-lose 'double-reg)
2352 :offset (- (tn-offset x) 2)))
2354 (inst push #x3e947ae1) ; Constant 0.29
2356 (inst fld (make-ea :dword :base rsp-tn))
2359 (inst fnstsw) ; status word to ax
2360 (inst and ah-tn #x45)
2361 (inst jmp :z WITHIN-RANGE)
2362 ;; Out of range for fyl2xp1.
2364 (inst faddd (make-random-tn :kind :normal
2365 :sc (sc-or-lose 'double-reg)
2366 :offset (- (tn-offset x) 1)))
2374 (inst fldd (make-random-tn :kind :normal
2375 :sc (sc-or-lose 'double-reg)
2376 :offset (- (tn-offset x) 1)))
2382 (t (inst fstd y)))))
2384 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2385 ;;; instruction and a range check can be avoided.
2386 (define-vop (flog1p-pentium)
2388 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2389 (:temporary (:sc double-reg :offset fr0-offset
2390 :from :argument :to :result) fr0)
2391 (:temporary (:sc double-reg :offset fr1-offset
2392 :from :argument :to :result) fr1)
2393 (:results (y :scs (double-reg)))
2394 (:arg-types double-float)
2395 (:result-types double-float)
2396 (:policy :fast-safe)
2397 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2398 (:note "inline log1p with limited x range function")
2400 (:save-p :compute-only)
2402 (note-this-location vop :internal-error)
2417 ;; x is in a FP reg, not fr0 or fr1
2421 (inst fldd (make-random-tn :kind :normal
2422 :sc (sc-or-lose 'double-reg)
2423 :offset (1- (tn-offset x)))))))
2424 ((double-stack descriptor-reg)
2428 (if (sc-is x double-stack)
2429 (inst fldd (ea-for-df-stack x))
2430 (inst fldd (ea-for-df-desc x)))))
2435 (t (inst fstd y)))))
2439 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2440 (:temporary (:sc double-reg :offset fr0-offset
2441 :from :argument :to :result) fr0)
2442 (:temporary (:sc double-reg :offset fr1-offset
2443 :from :argument :to :result) fr1)
2444 (:results (y :scs (double-reg)))
2445 (:arg-types double-float)
2446 (:result-types double-float)
2447 (:policy :fast-safe)
2448 (:note "inline logb function")
2450 (:save-p :compute-only)
2452 (note-this-location vop :internal-error)
2463 ;; x is in a FP reg, not fr0 or fr1
2466 (inst fldd (make-random-tn :kind :normal
2467 :sc (sc-or-lose 'double-reg)
2468 :offset (- (tn-offset x) 2))))))
2469 ((double-stack descriptor-reg)
2472 (if (sc-is x double-stack)
2473 (inst fldd (ea-for-df-stack x))
2474 (inst fldd (ea-for-df-desc x)))))
2485 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2486 (:temporary (:sc double-reg :offset fr0-offset
2487 :from (:argument 0) :to :result) fr0)
2488 (:temporary (:sc double-reg :offset fr1-offset
2489 :from (:argument 0) :to :result) fr1)
2490 (:results (r :scs (double-reg)))
2491 (:arg-types double-float)
2492 (:result-types double-float)
2493 (:policy :fast-safe)
2494 (:note "inline atan function")
2496 (:save-p :compute-only)
2498 (note-this-location vop :internal-error)
2499 ;; Setup x in fr1 and 1.0 in fr0
2502 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2505 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2507 ;; x not in fr0 or fr1
2514 (inst fldd (make-random-tn :kind :normal
2515 :sc (sc-or-lose 'double-reg)
2516 :offset (- (tn-offset x) 2))))
2518 (inst fldd (ea-for-df-stack x)))
2520 (inst fldd (ea-for-df-desc x))))))
2522 ;; Now have x at fr1; and 1.0 at fr0
2527 (t (inst fstd r)))))
2529 (define-vop (fatan2)
2531 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2532 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2533 (:temporary (:sc double-reg :offset fr0-offset
2534 :from (:argument 1) :to :result) fr0)
2535 (:temporary (:sc double-reg :offset fr1-offset
2536 :from (:argument 0) :to :result) fr1)
2537 (:results (r :scs (double-reg)))
2538 (:arg-types double-float double-float)
2539 (:result-types double-float)
2540 (:policy :fast-safe)
2541 (:note "inline atan2 function")
2543 (:save-p :compute-only)
2545 (note-this-location vop :internal-error)
2546 ;; Setup x in fr1 and y in fr0
2548 ;; y in fr0; x in fr1
2549 ((and (sc-is y double-reg) (zerop (tn-offset y))
2550 (sc-is x double-reg) (= 1 (tn-offset x))))
2551 ;; x in fr1; y not in fr0
2552 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2556 (copy-fp-reg-to-fr0 y))
2559 (inst fldd (ea-for-df-stack y)))
2562 (inst fldd (ea-for-df-desc y)))))
2563 ((and (sc-is x double-reg) (zerop (tn-offset x))
2564 (sc-is y double-reg) (zerop (tn-offset x)))
2567 ;; y in fr0; x not in fr1
2568 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2570 ;; Now load x to fr0
2573 (copy-fp-reg-to-fr0 x))
2576 (inst fldd (ea-for-df-stack x)))
2579 (inst fldd (ea-for-df-desc x))))
2581 ;; y in fr1; x not in fr1
2582 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2586 (copy-fp-reg-to-fr0 x))
2589 (inst fldd (ea-for-df-stack x)))
2592 (inst fldd (ea-for-df-desc x))))
2595 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2597 ;; Now load y to fr0
2600 (copy-fp-reg-to-fr0 y))
2603 (inst fldd (ea-for-df-stack y)))
2606 (inst fldd (ea-for-df-desc y)))))
2607 ;; Neither y or x are in either fr0 or fr1
2614 (inst fldd (make-random-tn :kind :normal
2615 :sc (sc-or-lose 'double-reg)
2616 :offset (- (tn-offset x) 2))))
2618 (inst fldd (ea-for-df-stack x)))
2620 (inst fldd (ea-for-df-desc x))))
2624 (inst fldd (make-random-tn :kind :normal
2625 :sc (sc-or-lose 'double-reg)
2626 :offset (1- (tn-offset y)))))
2628 (inst fldd (ea-for-df-stack y)))
2630 (inst fldd (ea-for-df-desc y))))))
2632 ;; Now have y at fr0; and x at fr1
2637 (t (inst fstd r)))))
2638 ) ; PROGN #!-LONG-FLOAT
2641 ;;;; complex float VOPs
2643 (define-vop (make-complex-single-float)
2644 (:translate complex)
2645 (:args (real :scs (single-reg) :to :result :target r
2646 :load-if (not (location= real r)))
2647 (imag :scs (single-reg) :to :save))
2648 (:arg-types single-float single-float)
2649 (:results (r :scs (complex-single-reg) :from (:argument 0)
2650 :load-if (not (sc-is r complex-single-stack))))
2651 (:result-types complex-single-float)
2652 (:note "inline complex single-float creation")
2653 (:policy :fast-safe)
2657 (let ((r-real (complex-double-reg-real-tn r)))
2658 (unless (location= real r-real)
2659 (cond ((zerop (tn-offset r-real))
2660 (copy-fp-reg-to-fr0 real))
2661 ((zerop (tn-offset real))
2666 (inst fxch real)))))
2667 (let ((r-imag (complex-double-reg-imag-tn r)))
2668 (unless (location= imag r-imag)
2669 (cond ((zerop (tn-offset imag))
2674 (inst fxch imag))))))
2675 (complex-single-stack
2676 (unless (location= real r)
2677 (cond ((zerop (tn-offset real))
2678 (inst fst (ea-for-csf-real-stack r)))
2681 (inst fst (ea-for-csf-real-stack r))
2684 (inst fst (ea-for-csf-imag-stack r))
2685 (inst fxch imag)))))
2687 (define-vop (make-complex-double-float)
2688 (:translate complex)
2689 (:args (real :scs (double-reg) :target r
2690 :load-if (not (location= real r)))
2691 (imag :scs (double-reg) :to :save))
2692 (:arg-types double-float double-float)
2693 (:results (r :scs (complex-double-reg) :from (:argument 0)
2694 :load-if (not (sc-is r complex-double-stack))))
2695 (:result-types complex-double-float)
2696 (:note "inline complex double-float creation")
2697 (:policy :fast-safe)
2701 (let ((r-real (complex-double-reg-real-tn r)))
2702 (unless (location= real r-real)
2703 (cond ((zerop (tn-offset r-real))
2704 (copy-fp-reg-to-fr0 real))
2705 ((zerop (tn-offset real))
2710 (inst fxch real)))))
2711 (let ((r-imag (complex-double-reg-imag-tn r)))
2712 (unless (location= imag r-imag)
2713 (cond ((zerop (tn-offset imag))
2718 (inst fxch imag))))))
2719 (complex-double-stack
2720 (unless (location= real r)
2721 (cond ((zerop (tn-offset real))
2722 (inst fstd (ea-for-cdf-real-stack r)))
2725 (inst fstd (ea-for-cdf-real-stack r))
2728 (inst fstd (ea-for-cdf-imag-stack r))
2729 (inst fxch imag)))))
2731 (define-vop (complex-float-value)
2732 (:args (x :target r))
2734 (:variant-vars offset)
2735 (:policy :fast-safe)
2737 (cond ((sc-is x complex-single-reg complex-double-reg)
2739 (make-random-tn :kind :normal
2740 :sc (sc-or-lose 'double-reg)
2741 :offset (+ offset (tn-offset x)))))
2742 (unless (location= value-tn r)
2743 (cond ((zerop (tn-offset r))
2744 (copy-fp-reg-to-fr0 value-tn))
2745 ((zerop (tn-offset value-tn))
2748 (inst fxch value-tn)
2750 (inst fxch value-tn))))))
2751 ((sc-is r single-reg)
2752 (let ((ea (sc-case x
2753 (complex-single-stack
2755 (0 (ea-for-csf-real-stack x))
2756 (1 (ea-for-csf-imag-stack x))))
2759 (0 (ea-for-csf-real-desc x))
2760 (1 (ea-for-csf-imag-desc x)))))))
2761 (with-empty-tn@fp-top(r)
2763 ((sc-is r double-reg)
2764 (let ((ea (sc-case x
2765 (complex-double-stack
2767 (0 (ea-for-cdf-real-stack x))
2768 (1 (ea-for-cdf-imag-stack x))))
2771 (0 (ea-for-cdf-real-desc x))
2772 (1 (ea-for-cdf-imag-desc x)))))))
2773 (with-empty-tn@fp-top(r)
2775 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
2777 (define-vop (realpart/complex-single-float complex-float-value)
2778 (:translate realpart)
2779 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
2781 (:arg-types complex-single-float)
2782 (:results (r :scs (single-reg)))
2783 (:result-types single-float)
2784 (:note "complex float realpart")
2787 (define-vop (realpart/complex-double-float complex-float-value)
2788 (:translate realpart)
2789 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
2791 (:arg-types complex-double-float)
2792 (:results (r :scs (double-reg)))
2793 (:result-types double-float)
2794 (:note "complex float realpart")
2797 (define-vop (imagpart/complex-single-float complex-float-value)
2798 (:translate imagpart)
2799 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
2801 (:arg-types complex-single-float)
2802 (:results (r :scs (single-reg)))
2803 (:result-types single-float)
2804 (:note "complex float imagpart")
2807 (define-vop (imagpart/complex-double-float complex-float-value)
2808 (:translate imagpart)
2809 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
2811 (:arg-types complex-double-float)
2812 (:results (r :scs (double-reg)))
2813 (:result-types double-float)
2814 (:note "complex float imagpart")
2818 ;;; hack dummy VOPs to bias the representation selection of their
2819 ;;; arguments towards a FP register, which can help avoid consing at
2820 ;;; inappropriate locations
2821 (defknown double-float-reg-bias (double-float) (values))
2822 (define-vop (double-float-reg-bias)
2823 (:translate double-float-reg-bias)
2824 (:args (x :scs (double-reg double-stack) :load-if nil))
2825 (:arg-types double-float)
2826 (:policy :fast-safe)
2827 (:note "inline dummy FP register bias")
2830 (defknown single-float-reg-bias (single-float) (values))
2831 (define-vop (single-float-reg-bias)
2832 (:translate single-float-reg-bias)
2833 (:args (x :scs (single-reg single-stack) :load-if nil))
2834 (:arg-types single-float)
2835 (:policy :fast-safe)
2836 (:note "inline dummy FP register bias")