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