Aesthetic tweaks
[sbcl/simd.git] / src / compiler / x86 / float.lisp
blobd5ac329ca08ad53031ceb2dd65bcf87cb5a76e9a
1 ;;;; floating point support for the x86
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
12 (in-package "SB!VM")
14 (macrolet ((ea-for-xf-desc (tn slot)
15 `(make-ea-for-object-slot ,tn ,slot other-pointer-lowtag)))
16 (defun ea-for-sf-desc (tn)
17 (ea-for-xf-desc tn single-float-value-slot))
18 (defun ea-for-df-desc (tn)
19 (ea-for-xf-desc tn double-float-value-slot))
20 #!+long-float
21 (defun ea-for-lf-desc (tn)
22 (ea-for-xf-desc tn long-float-value-slot))
23 ;; complex floats
24 (defun ea-for-csf-real-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-real-slot))
26 (defun ea-for-csf-imag-desc (tn)
27 (ea-for-xf-desc tn complex-single-float-imag-slot))
28 (defun ea-for-cdf-real-desc (tn)
29 (ea-for-xf-desc tn complex-double-float-real-slot))
30 (defun ea-for-cdf-imag-desc (tn)
31 (ea-for-xf-desc tn complex-double-float-imag-slot))
32 #!+long-float
33 (defun ea-for-clf-real-desc (tn)
34 (ea-for-xf-desc tn complex-long-float-real-slot))
35 #!+long-float
36 (defun ea-for-clf-imag-desc (tn)
37 (ea-for-xf-desc tn complex-long-float-imag-slot)))
39 (macrolet ((ea-for-xf-stack (tn kind)
40 `(make-ea
41 :dword :base ebp-tn
42 :disp (frame-byte-offset
43 (+ (tn-offset ,tn)
44 (ecase ,kind (:single 0) (:double 1) (:long 2)))))))
45 (defun ea-for-sf-stack (tn)
46 (ea-for-xf-stack tn :single))
47 (defun ea-for-df-stack (tn)
48 (ea-for-xf-stack tn :double))
49 #!+long-float
50 (defun ea-for-lf-stack (tn)
51 (ea-for-xf-stack tn :long)))
53 ;;; Telling the FPU to wait is required in order to make signals occur
54 ;;; at the expected place, but naturally slows things down.
55 ;;;
56 ;;; NODE is the node whose compilation policy controls the decision
57 ;;; whether to just blast through carelessly or carefully emit wait
58 ;;; instructions and whatnot.
59 ;;;
60 ;;; NOTE-NEXT-INSTRUCTION, if supplied, is to be passed to
61 ;;; #'NOTE-NEXT-INSTRUCTION.
62 ;;;
63 ;;; Until 2004-03-15, the implementation of this was buggy; it
64 ;;; unconditionally emitted the WAIT instruction. It turns out that
65 ;;; this is the right thing to do anyway; omitting them can lead to
66 ;;; system corruption on conforming code. -- CSR
67 (defun maybe-fp-wait (node &optional note-next-instruction)
68 (declare (ignore node))
69 #+nil
70 (when (policy node (or (= debug 3) (> safety speed))))
71 (when note-next-instruction
72 (note-next-instruction note-next-instruction :internal-error))
73 (inst wait))
75 ;;; complex float stack EAs
76 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
77 `(make-ea
78 :dword :base ,base
79 :disp (frame-byte-offset
80 (+ (tn-offset ,tn)
82 (* (ecase ,kind
83 (:single 1)
84 (:double 2)
85 (:long 3))
86 (ecase ,slot (:real 1) (:imag 2))))))))
87 (defun ea-for-csf-real-stack (tn &optional (base ebp-tn))
88 (ea-for-cxf-stack tn :single :real base))
89 (defun ea-for-csf-imag-stack (tn &optional (base ebp-tn))
90 (ea-for-cxf-stack tn :single :imag base))
91 (defun ea-for-cdf-real-stack (tn &optional (base ebp-tn))
92 (ea-for-cxf-stack tn :double :real base))
93 (defun ea-for-cdf-imag-stack (tn &optional (base ebp-tn))
94 (ea-for-cxf-stack tn :double :imag base))
95 #!+long-float
96 (defun ea-for-clf-real-stack (tn &optional (base ebp-tn))
97 (ea-for-cxf-stack tn :long :real base))
98 #!+long-float
99 (defun ea-for-clf-imag-stack (tn &optional (base ebp-tn))
100 (ea-for-cxf-stack tn :long :imag base)))
102 ;;; Abstract out the copying of a FP register to the FP stack top, and
103 ;;; provide two alternatives for its implementation. Note: it's not
104 ;;; necessary to distinguish between a single or double register move
105 ;;; here.
107 ;;; Using a Pop then load.
108 (defun copy-fp-reg-to-fr0 (reg)
109 (aver (not (zerop (tn-offset reg))))
110 (inst fstp fr0-tn)
111 (inst fld (make-random-tn :kind :normal
112 :sc (sc-or-lose 'double-reg)
113 :offset (1- (tn-offset reg)))))
114 ;;; Using Fxch then Fst to restore the original reg contents.
115 #+nil
116 (defun copy-fp-reg-to-fr0 (reg)
117 (aver (not (zerop (tn-offset reg))))
118 (inst fxch reg)
119 (inst fst reg))
121 ;;; The x86 can't store a long-float to memory without popping the
122 ;;; stack and marking a register as empty, so it is necessary to
123 ;;; restore the register from memory.
124 #!+long-float
125 (defun store-long-float (ea)
126 (inst fstpl ea)
127 (inst fldl ea))
129 ;;;; move functions
131 ;;; X is source, Y is destination.
132 (define-move-fun (load-single 2) (vop x y)
133 ((single-stack) (single-reg))
134 (with-empty-tn@fp-top(y)
135 (inst fld (ea-for-sf-stack x))))
137 (define-move-fun (store-single 2) (vop x y)
138 ((single-reg) (single-stack))
139 (cond ((zerop (tn-offset x))
140 (inst fst (ea-for-sf-stack y)))
142 (inst fxch x)
143 (inst fst (ea-for-sf-stack y))
144 ;; This may not be necessary as ST0 is likely invalid now.
145 (inst fxch x))))
147 (define-move-fun (load-double 2) (vop x y)
148 ((double-stack) (double-reg))
149 (with-empty-tn@fp-top(y)
150 (inst fldd (ea-for-df-stack x))))
152 (define-move-fun (store-double 2) (vop x y)
153 ((double-reg) (double-stack))
154 (cond ((zerop (tn-offset x))
155 (inst fstd (ea-for-df-stack y)))
157 (inst fxch x)
158 (inst fstd (ea-for-df-stack y))
159 ;; This may not be necessary as ST0 is likely invalid now.
160 (inst fxch x))))
162 #!+long-float
163 (define-move-fun (load-long 2) (vop x y)
164 ((long-stack) (long-reg))
165 (with-empty-tn@fp-top(y)
166 (inst fldl (ea-for-lf-stack x))))
168 #!+long-float
169 (define-move-fun (store-long 2) (vop x y)
170 ((long-reg) (long-stack))
171 (cond ((zerop (tn-offset x))
172 (store-long-float (ea-for-lf-stack y)))
174 (inst fxch x)
175 (store-long-float (ea-for-lf-stack y))
176 ;; This may not be necessary as ST0 is likely invalid now.
177 (inst fxch x))))
179 ;;; The i387 has instructions to load some useful constants. This
180 ;;; doesn't save much time but might cut down on memory access and
181 ;;; reduce the size of the constant vector (CV). Intel claims they are
182 ;;; stored in a more precise form on chip. Anyhow, might as well use
183 ;;; the feature. It can be turned off by hacking the
184 ;;; "immediate-constant-sc" in vm.lisp.
185 (eval-when (:compile-toplevel :execute)
186 (setf *read-default-float-format*
187 #!+long-float 'long-float #!-long-float 'double-float))
188 (define-move-fun (load-fp-constant 2) (vop x y)
189 ((fp-constant) (single-reg double-reg #!+long-float long-reg))
190 (let ((value (sb!c::constant-value (sb!c::tn-leaf x))))
191 (with-empty-tn@fp-top(y)
192 (cond ((zerop value)
193 (inst fldz))
194 ((= value 1e0)
195 (inst fld1))
196 ((= value (coerce pi *read-default-float-format*))
197 (inst fldpi))
198 ((= value (log 10e0 2e0))
199 (inst fldl2t))
200 ((= value (log 2.718281828459045235360287471352662e0 2e0))
201 (inst fldl2e))
202 ((= value (log 2e0 10e0))
203 (inst fldlg2))
204 ((= value (log 2e0 2.718281828459045235360287471352662e0))
205 (inst fldln2))
206 (t (warn "ignoring bogus i387 constant ~A" value))))))
207 (eval-when (:compile-toplevel :execute)
208 (setf *read-default-float-format* 'single-float))
210 ;;;; complex float move functions
212 (defun complex-single-reg-real-tn (x)
213 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
214 :offset (tn-offset x)))
215 (defun complex-single-reg-imag-tn (x)
216 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
217 :offset (1+ (tn-offset x))))
219 (defun complex-double-reg-real-tn (x)
220 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
221 :offset (tn-offset x)))
222 (defun complex-double-reg-imag-tn (x)
223 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
224 :offset (1+ (tn-offset x))))
226 #!+long-float
227 (defun complex-long-reg-real-tn (x)
228 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
229 :offset (tn-offset x)))
230 #!+long-float
231 (defun complex-long-reg-imag-tn (x)
232 (make-random-tn :kind :normal :sc (sc-or-lose 'long-reg)
233 :offset (1+ (tn-offset x))))
235 ;;; X is source, Y is destination.
236 (define-move-fun (load-complex-single 2) (vop x y)
237 ((complex-single-stack) (complex-single-reg))
238 (let ((real-tn (complex-single-reg-real-tn y)))
239 (with-empty-tn@fp-top (real-tn)
240 (inst fld (ea-for-csf-real-stack x))))
241 (let ((imag-tn (complex-single-reg-imag-tn y)))
242 (with-empty-tn@fp-top (imag-tn)
243 (inst fld (ea-for-csf-imag-stack x)))))
245 (define-move-fun (store-complex-single 2) (vop x y)
246 ((complex-single-reg) (complex-single-stack))
247 (let ((real-tn (complex-single-reg-real-tn x)))
248 (cond ((zerop (tn-offset real-tn))
249 (inst fst (ea-for-csf-real-stack y)))
251 (inst fxch real-tn)
252 (inst fst (ea-for-csf-real-stack y))
253 (inst fxch real-tn))))
254 (let ((imag-tn (complex-single-reg-imag-tn x)))
255 (inst fxch imag-tn)
256 (inst fst (ea-for-csf-imag-stack y))
257 (inst fxch imag-tn)))
259 (define-move-fun (load-complex-double 2) (vop x y)
260 ((complex-double-stack) (complex-double-reg))
261 (let ((real-tn (complex-double-reg-real-tn y)))
262 (with-empty-tn@fp-top(real-tn)
263 (inst fldd (ea-for-cdf-real-stack x))))
264 (let ((imag-tn (complex-double-reg-imag-tn y)))
265 (with-empty-tn@fp-top(imag-tn)
266 (inst fldd (ea-for-cdf-imag-stack x)))))
268 (define-move-fun (store-complex-double 2) (vop x y)
269 ((complex-double-reg) (complex-double-stack))
270 (let ((real-tn (complex-double-reg-real-tn x)))
271 (cond ((zerop (tn-offset real-tn))
272 (inst fstd (ea-for-cdf-real-stack y)))
274 (inst fxch real-tn)
275 (inst fstd (ea-for-cdf-real-stack y))
276 (inst fxch real-tn))))
277 (let ((imag-tn (complex-double-reg-imag-tn x)))
278 (inst fxch imag-tn)
279 (inst fstd (ea-for-cdf-imag-stack y))
280 (inst fxch imag-tn)))
282 #!+long-float
283 (define-move-fun (load-complex-long 2) (vop x y)
284 ((complex-long-stack) (complex-long-reg))
285 (let ((real-tn (complex-long-reg-real-tn y)))
286 (with-empty-tn@fp-top(real-tn)
287 (inst fldl (ea-for-clf-real-stack x))))
288 (let ((imag-tn (complex-long-reg-imag-tn y)))
289 (with-empty-tn@fp-top(imag-tn)
290 (inst fldl (ea-for-clf-imag-stack x)))))
292 #!+long-float
293 (define-move-fun (store-complex-long 2) (vop x y)
294 ((complex-long-reg) (complex-long-stack))
295 (let ((real-tn (complex-long-reg-real-tn x)))
296 (cond ((zerop (tn-offset real-tn))
297 (store-long-float (ea-for-clf-real-stack y)))
299 (inst fxch real-tn)
300 (store-long-float (ea-for-clf-real-stack y))
301 (inst fxch real-tn))))
302 (let ((imag-tn (complex-long-reg-imag-tn x)))
303 (inst fxch imag-tn)
304 (store-long-float (ea-for-clf-imag-stack y))
305 (inst fxch imag-tn)))
308 ;;;; move VOPs
310 ;;; float register to register moves
311 (define-vop (float-move)
312 (:args (x))
313 (:results (y))
314 (:note "float move")
315 (:generator 0
316 (unless (location= x y)
317 (cond ((zerop (tn-offset y))
318 (copy-fp-reg-to-fr0 x))
319 ((zerop (tn-offset x))
320 (inst fstd y))
322 (inst fxch x)
323 (inst fstd y)
324 (inst fxch x))))))
326 (define-vop (single-move float-move)
327 (:args (x :scs (single-reg) :target y :load-if (not (location= x y))))
328 (:results (y :scs (single-reg) :load-if (not (location= x y)))))
329 (define-move-vop single-move :move (single-reg) (single-reg))
331 (define-vop (double-move float-move)
332 (:args (x :scs (double-reg) :target y :load-if (not (location= x y))))
333 (:results (y :scs (double-reg) :load-if (not (location= x y)))))
334 (define-move-vop double-move :move (double-reg) (double-reg))
336 #!+long-float
337 (define-vop (long-move float-move)
338 (:args (x :scs (long-reg) :target y :load-if (not (location= x y))))
339 (:results (y :scs (long-reg) :load-if (not (location= x y)))))
340 #!+long-float
341 (define-move-vop long-move :move (long-reg) (long-reg))
343 ;;; complex float register to register moves
344 (define-vop (complex-float-move)
345 (:args (x :target y :load-if (not (location= x y))))
346 (:results (y :load-if (not (location= x y))))
347 (:note "complex float move")
348 (:generator 0
349 (unless (location= x y)
350 ;; Note the complex-float-regs are aligned to every second
351 ;; float register so there is not need to worry about overlap.
352 (let ((x-real (complex-double-reg-real-tn x))
353 (y-real (complex-double-reg-real-tn y)))
354 (cond ((zerop (tn-offset y-real))
355 (copy-fp-reg-to-fr0 x-real))
356 ((zerop (tn-offset x-real))
357 (inst fstd y-real))
359 (inst fxch x-real)
360 (inst fstd y-real)
361 (inst fxch x-real))))
362 (let ((x-imag (complex-double-reg-imag-tn x))
363 (y-imag (complex-double-reg-imag-tn y)))
364 (inst fxch x-imag)
365 (inst fstd y-imag)
366 (inst fxch x-imag)))))
368 (define-vop (complex-single-move complex-float-move)
369 (:args (x :scs (complex-single-reg) :target y
370 :load-if (not (location= x y))))
371 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
372 (define-move-vop complex-single-move :move
373 (complex-single-reg) (complex-single-reg))
375 (define-vop (complex-double-move complex-float-move)
376 (:args (x :scs (complex-double-reg)
377 :target y :load-if (not (location= x y))))
378 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
379 (define-move-vop complex-double-move :move
380 (complex-double-reg) (complex-double-reg))
382 #!+long-float
383 (define-vop (complex-long-move complex-float-move)
384 (:args (x :scs (complex-long-reg)
385 :target y :load-if (not (location= x y))))
386 (:results (y :scs (complex-long-reg) :load-if (not (location= x y)))))
387 #!+long-float
388 (define-move-vop complex-long-move :move
389 (complex-long-reg) (complex-long-reg))
391 ;;; Move from float to a descriptor reg. allocating a new float
392 ;;; object in the process.
393 (define-vop (move-from-single)
394 (:args (x :scs (single-reg) :to :save))
395 (:results (y :scs (descriptor-reg)))
396 (:node-var node)
397 (:note "float to pointer coercion")
398 (:generator 13
399 (with-fixed-allocation (y
400 single-float-widetag
401 single-float-size node)
402 (with-tn@fp-top(x)
403 (inst fst (ea-for-sf-desc y))))))
404 (define-move-vop move-from-single :move
405 (single-reg) (descriptor-reg))
407 (define-vop (move-from-double)
408 (:args (x :scs (double-reg) :to :save))
409 (:results (y :scs (descriptor-reg)))
410 (:node-var node)
411 (:note "float to pointer coercion")
412 (:generator 13
413 (with-fixed-allocation (y
414 double-float-widetag
415 double-float-size
416 node)
417 (with-tn@fp-top(x)
418 (inst fstd (ea-for-df-desc y))))))
419 (define-move-vop move-from-double :move
420 (double-reg) (descriptor-reg))
422 #!+long-float
423 (define-vop (move-from-long)
424 (:args (x :scs (long-reg) :to :save))
425 (:results (y :scs (descriptor-reg)))
426 (:node-var node)
427 (:note "float to pointer coercion")
428 (:generator 13
429 (with-fixed-allocation (y
430 long-float-widetag
431 long-float-size
432 node)
433 (with-tn@fp-top(x)
434 (store-long-float (ea-for-lf-desc y))))))
435 #!+long-float
436 (define-move-vop move-from-long :move
437 (long-reg) (descriptor-reg))
439 (define-vop (move-from-fp-constant)
440 (:args (x :scs (fp-constant)))
441 (:results (y :scs (descriptor-reg)))
442 (:generator 2
443 (ecase (sb!c::constant-value (sb!c::tn-leaf x))
444 (0f0 (load-symbol-value y *fp-constant-0f0*))
445 (1f0 (load-symbol-value y *fp-constant-1f0*))
446 (0d0 (load-symbol-value y *fp-constant-0d0*))
447 (1d0 (load-symbol-value y *fp-constant-1d0*))
448 #!+long-float
449 (0l0 (load-symbol-value y *fp-constant-0l0*))
450 #!+long-float
451 (1l0 (load-symbol-value y *fp-constant-1l0*))
452 #!+long-float
453 (#.pi (load-symbol-value y *fp-constant-pi*))
454 #!+long-float
455 (#.(log 10l0 2l0) (load-symbol-value y *fp-constant-l2t*))
456 #!+long-float
457 (#.(log 2.718281828459045235360287471352662L0 2l0)
458 (load-symbol-value y *fp-constant-l2e*))
459 #!+long-float
460 (#.(log 2l0 10l0) (load-symbol-value y *fp-constant-lg2*))
461 #!+long-float
462 (#.(log 2l0 2.718281828459045235360287471352662L0)
463 (load-symbol-value y *fp-constant-ln2*)))))
464 (define-move-vop move-from-fp-constant :move
465 (fp-constant) (descriptor-reg))
467 ;;; Move from a descriptor to a float register.
468 (define-vop (move-to-single)
469 (:args (x :scs (descriptor-reg)))
470 (:results (y :scs (single-reg)))
471 (:note "pointer to float coercion")
472 (:generator 2
473 (with-empty-tn@fp-top(y)
474 (inst fld (ea-for-sf-desc x)))))
475 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
477 (define-vop (move-to-double)
478 (:args (x :scs (descriptor-reg)))
479 (:results (y :scs (double-reg)))
480 (:note "pointer to float coercion")
481 (:generator 2
482 (with-empty-tn@fp-top(y)
483 (inst fldd (ea-for-df-desc x)))))
484 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
486 #!+long-float
487 (define-vop (move-to-long)
488 (:args (x :scs (descriptor-reg)))
489 (:results (y :scs (long-reg)))
490 (:note "pointer to float coercion")
491 (:generator 2
492 (with-empty-tn@fp-top(y)
493 (inst fldl (ea-for-lf-desc x)))))
494 #!+long-float
495 (define-move-vop move-to-long :move (descriptor-reg) (long-reg))
497 ;;; Move from complex float to a descriptor reg. allocating a new
498 ;;; complex float object in the process.
499 (define-vop (move-from-complex-single)
500 (:args (x :scs (complex-single-reg) :to :save))
501 (:results (y :scs (descriptor-reg)))
502 (:node-var node)
503 (:note "complex float to pointer coercion")
504 (:generator 13
505 (with-fixed-allocation (y
506 complex-single-float-widetag
507 complex-single-float-size
508 node)
509 (let ((real-tn (complex-single-reg-real-tn x)))
510 (with-tn@fp-top(real-tn)
511 (inst fst (ea-for-csf-real-desc y))))
512 (let ((imag-tn (complex-single-reg-imag-tn x)))
513 (with-tn@fp-top(imag-tn)
514 (inst fst (ea-for-csf-imag-desc y)))))))
515 (define-move-vop move-from-complex-single :move
516 (complex-single-reg) (descriptor-reg))
518 (define-vop (move-from-complex-double)
519 (:args (x :scs (complex-double-reg) :to :save))
520 (:results (y :scs (descriptor-reg)))
521 (:node-var node)
522 (:note "complex float to pointer coercion")
523 (:generator 13
524 (with-fixed-allocation (y
525 complex-double-float-widetag
526 complex-double-float-size
527 node)
528 (let ((real-tn (complex-double-reg-real-tn x)))
529 (with-tn@fp-top(real-tn)
530 (inst fstd (ea-for-cdf-real-desc y))))
531 (let ((imag-tn (complex-double-reg-imag-tn x)))
532 (with-tn@fp-top(imag-tn)
533 (inst fstd (ea-for-cdf-imag-desc y)))))))
534 (define-move-vop move-from-complex-double :move
535 (complex-double-reg) (descriptor-reg))
537 #!+long-float
538 (define-vop (move-from-complex-long)
539 (:args (x :scs (complex-long-reg) :to :save))
540 (:results (y :scs (descriptor-reg)))
541 (:node-var node)
542 (:note "complex float to pointer coercion")
543 (:generator 13
544 (with-fixed-allocation (y
545 complex-long-float-widetag
546 complex-long-float-size
547 node)
548 (let ((real-tn (complex-long-reg-real-tn x)))
549 (with-tn@fp-top(real-tn)
550 (store-long-float (ea-for-clf-real-desc y))))
551 (let ((imag-tn (complex-long-reg-imag-tn x)))
552 (with-tn@fp-top(imag-tn)
553 (store-long-float (ea-for-clf-imag-desc y)))))))
554 #!+long-float
555 (define-move-vop move-from-complex-long :move
556 (complex-long-reg) (descriptor-reg))
558 ;;; Move from a descriptor to a complex float register.
559 (macrolet ((frob (name sc format)
560 `(progn
561 (define-vop (,name)
562 (:args (x :scs (descriptor-reg)))
563 (:results (y :scs (,sc)))
564 (:note "pointer to complex float coercion")
565 (:generator 2
566 (let ((real-tn (complex-double-reg-real-tn y)))
567 (with-empty-tn@fp-top(real-tn)
568 ,@(ecase format
569 (:single '((inst fld (ea-for-csf-real-desc x))))
570 (:double '((inst fldd (ea-for-cdf-real-desc x))))
571 #!+long-float
572 (:long '((inst fldl (ea-for-clf-real-desc x)))))))
573 (let ((imag-tn (complex-double-reg-imag-tn y)))
574 (with-empty-tn@fp-top(imag-tn)
575 ,@(ecase format
576 (:single '((inst fld (ea-for-csf-imag-desc x))))
577 (:double '((inst fldd (ea-for-cdf-imag-desc x))))
578 #!+long-float
579 (:long '((inst fldl (ea-for-clf-imag-desc x)))))))))
580 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
581 (frob move-to-complex-single complex-single-reg :single)
582 (frob move-to-complex-double complex-double-reg :double)
583 #!+long-float
584 (frob move-to-complex-double complex-long-reg :long))
586 ;;;; the move argument vops
587 ;;;;
588 ;;;; Note these are also used to stuff fp numbers onto the c-call
589 ;;;; stack so the order is different than the lisp-stack.
591 ;;; the general MOVE-ARG VOP
592 (macrolet ((frob (name sc stack-sc format)
593 `(progn
594 (define-vop (,name)
595 (:args (x :scs (,sc) :target y)
596 (fp :scs (any-reg)
597 :load-if (not (sc-is y ,sc))))
598 (:results (y))
599 (:note "float argument move")
600 (:generator ,(case format (:single 2) (:double 3) (:long 4))
601 (sc-case y
602 (,sc
603 (unless (location= x y)
604 (cond ((zerop (tn-offset y))
605 (copy-fp-reg-to-fr0 x))
606 ((zerop (tn-offset x))
607 (inst fstd y))
609 (inst fxch x)
610 (inst fstd y)
611 (inst fxch x)))))
612 (,stack-sc
613 (if (= (tn-offset fp) esp-offset)
614 ;; C-call
615 (let* ((offset (* (tn-offset y) n-word-bytes))
616 (ea (make-ea :dword :base fp :disp offset)))
617 (with-tn@fp-top(x)
618 ,@(ecase format
619 (:single '((inst fst ea)))
620 (:double '((inst fstd ea)))
621 #!+long-float
622 (:long '((store-long-float ea))))))
623 ;; Lisp stack
624 (let ((ea (make-ea
625 :dword :base fp
626 :disp (frame-byte-offset
627 (+ (tn-offset y)
628 ,(case format
629 (:single 0)
630 (:double 1)
631 (:long 2)))))))
632 (with-tn@fp-top(x)
633 ,@(ecase format
634 (:single '((inst fst ea)))
635 (:double '((inst fstd ea)))
636 #!+long-float
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)
642 #!+long-float
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)
647 `(progn
648 (define-vop (,name)
649 (:args (x :scs (,sc) :target y)
650 (fp :scs (any-reg)
651 :load-if (not (sc-is y ,sc))))
652 (:results (y))
653 (:note "complex float argument move")
654 (:generator ,(ecase format (:single 2) (:double 3) (:long 4))
655 (sc-case y
656 (,sc
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))
663 (inst fstd y-real))
665 (inst fxch x-real)
666 (inst fstd y-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)))
670 (inst fxch x-imag)
671 (inst fstd y-imag)
672 (inst fxch x-imag))))
673 (,stack-sc
674 (let ((real-tn (complex-double-reg-real-tn x)))
675 (cond ((zerop (tn-offset real-tn))
676 ,@(ecase format
677 (:single
678 '((inst fst
679 (ea-for-csf-real-stack y fp))))
680 (:double
681 '((inst fstd
682 (ea-for-cdf-real-stack y fp))))
683 #!+long-float
684 (:long
685 '((store-long-float
686 (ea-for-clf-real-stack y fp))))))
688 (inst fxch real-tn)
689 ,@(ecase format
690 (:single
691 '((inst fst
692 (ea-for-csf-real-stack y fp))))
693 (:double
694 '((inst fstd
695 (ea-for-cdf-real-stack y fp))))
696 #!+long-float
697 (:long
698 '((store-long-float
699 (ea-for-clf-real-stack y fp)))))
700 (inst fxch real-tn))))
701 (let ((imag-tn (complex-double-reg-imag-tn x)))
702 (inst fxch imag-tn)
703 ,@(ecase format
704 (:single
705 '((inst fst (ea-for-csf-imag-stack y fp))))
706 (:double
707 '((inst fstd (ea-for-cdf-imag-stack y fp))))
708 #!+long-float
709 (:long
710 '((store-long-float
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)
719 #!+long-float
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)
726 (descriptor-reg))
729 ;;;; arithmetic VOPs
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
749 ;;; (defun test(a n)
750 ;;; (declare (type (simple-array double-float (*)) a)
751 ;;; (fixnum n))
752 ;;; (let ((sum 0d0))
753 ;;; (declare (type double-float sum))
754 ;;; (dotimes (i n)
755 ;;; (incf sum (* (aref a i)(aref a i))))
756 ;;; sum))
758 ;;; So, disabling descriptor args until this can be fixed elsewhere.
759 (macrolet
760 ((frob (op fop-sti fopr-sti
761 fop fopr sname scost
762 fopd foprd dname dcost
763 lname lcost)
764 #!-long-float (declare (ignore lcost lname))
765 `(progn
766 (define-vop (,sname)
767 (:translate ,op)
768 (:args (x :scs (single-reg single-stack #+nil descriptor-reg)
769 :to :eval)
770 (y :scs (single-reg single-stack #+nil descriptor-reg)
771 :to :eval))
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)
777 (:policy :fast-safe)
778 (:note "inline float arithmetic")
779 (:vop-var vop)
780 (:save-p :compute-only)
781 (:node-var node)
782 (:generator ,scost
783 ;; Handle a few special cases
784 (cond
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))
788 (inst ,fop fr0))
790 (inst fxch r)
791 (inst ,fop fr0)
792 ;; XX the source register will not be valid.
793 (note-next-instruction vop :internal-error)
794 (inst fxch r))))
796 ;; x and r are the same register.
797 ((and (sc-is x single-reg) (location= x r))
798 (cond ((zerop (tn-offset r))
799 (sc-case y
800 (single-reg
801 ;; ST(0) = ST(0) op ST(y)
802 (inst ,fop y))
803 (single-stack
804 ;; ST(0) = ST(0) op Mem
805 (inst ,fop (ea-for-sf-stack y)))
806 (descriptor-reg
807 (inst ,fop (ea-for-sf-desc y)))))
809 ;; y to ST0
810 (sc-case y
811 (single-reg
812 (unless (zerop (tn-offset y))
813 (copy-fp-reg-to-fr0 y)))
814 ((single-stack descriptor-reg)
815 (inst fstp fr0)
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
820 (inst ,fop-sti r)))
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))
825 (sc-case x
826 (single-reg
827 ;; ST(0) = ST(x) op ST(0)
828 (inst ,fopr x))
829 (single-stack
830 ;; ST(0) = Mem op ST(0)
831 (inst ,fopr (ea-for-sf-stack x)))
832 (descriptor-reg
833 (inst ,fopr (ea-for-sf-desc x)))))
835 ;; x to ST0
836 (sc-case x
837 (single-reg
838 (unless (zerop (tn-offset x))
839 (copy-fp-reg-to-fr0 x)))
840 ((single-stack descriptor-reg)
841 (inst fstp fr0)
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)
846 (inst ,fopr-sti r)))
847 (maybe-fp-wait node vop))
848 ;; the default case
850 ;; Get the result to ST0.
852 ;; Special handling is needed if x or y are in ST0, and
853 ;; simpler code is generated.
854 (cond
855 ;; x is in ST0
856 ((and (sc-is x single-reg) (zerop (tn-offset x)))
857 ;; ST0 = ST0 op y
858 (sc-case y
859 (single-reg
860 (inst ,fop y))
861 (single-stack
862 (inst ,fop (ea-for-sf-stack y)))
863 (descriptor-reg
864 (inst ,fop (ea-for-sf-desc y)))))
865 ;; y is in ST0
866 ((and (sc-is y single-reg) (zerop (tn-offset y)))
867 ;; ST0 = x op ST0
868 (sc-case x
869 (single-reg
870 (inst ,fopr x))
871 (single-stack
872 (inst ,fopr (ea-for-sf-stack x)))
873 (descriptor-reg
874 (inst ,fopr (ea-for-sf-desc x)))))
876 ;; x to ST0
877 (sc-case x
878 (single-reg
879 (copy-fp-reg-to-fr0 x))
880 (single-stack
881 (inst fstp fr0)
882 (inst fld (ea-for-sf-stack x)))
883 (descriptor-reg
884 (inst fstp fr0)
885 (inst fld (ea-for-sf-desc x))))
886 ;; ST0 = ST0 op y
887 (sc-case y
888 (single-reg
889 (inst ,fop y))
890 (single-stack
891 (inst ,fop (ea-for-sf-stack y)))
892 (descriptor-reg
893 (inst ,fop (ea-for-sf-desc y))))))
895 (note-next-instruction vop :internal-error)
897 ;; Finally save the result.
898 (sc-case r
899 (single-reg
900 (cond ((zerop (tn-offset r))
901 (maybe-fp-wait node))
903 (inst fst r))))
904 (single-stack
905 (inst fst (ea-for-sf-stack r))))))))
907 (define-vop (,dname)
908 (:translate ,op)
909 (:args (x :scs (double-reg double-stack #+nil descriptor-reg)
910 :to :eval)
911 (y :scs (double-reg double-stack #+nil descriptor-reg)
912 :to :eval))
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)
918 (:policy :fast-safe)
919 (:note "inline float arithmetic")
920 (:vop-var vop)
921 (:save-p :compute-only)
922 (:node-var node)
923 (:generator ,dcost
924 ;; Handle a few special cases.
925 (cond
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))
929 (inst ,fop fr0))
931 (inst fxch x)
932 (inst ,fopd fr0)
933 ;; XX the source register will not be valid.
934 (note-next-instruction vop :internal-error)
935 (inst fxch r))))
937 ;; x and r are the same register.
938 ((and (sc-is x double-reg) (location= x r))
939 (cond ((zerop (tn-offset r))
940 (sc-case y
941 (double-reg
942 ;; ST(0) = ST(0) op ST(y)
943 (inst ,fopd y))
944 (double-stack
945 ;; ST(0) = ST(0) op Mem
946 (inst ,fopd (ea-for-df-stack y)))
947 (descriptor-reg
948 (inst ,fopd (ea-for-df-desc y)))))
950 ;; y to ST0
951 (sc-case y
952 (double-reg
953 (unless (zerop (tn-offset y))
954 (copy-fp-reg-to-fr0 y)))
955 ((double-stack descriptor-reg)
956 (inst fstp fr0)
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
961 (inst ,fop-sti r)))
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))
966 (sc-case x
967 (double-reg
968 ;; ST(0) = ST(x) op ST(0)
969 (inst ,foprd x))
970 (double-stack
971 ;; ST(0) = Mem op ST(0)
972 (inst ,foprd (ea-for-df-stack x)))
973 (descriptor-reg
974 (inst ,foprd (ea-for-df-desc x)))))
976 ;; x to ST0
977 (sc-case x
978 (double-reg
979 (unless (zerop (tn-offset x))
980 (copy-fp-reg-to-fr0 x)))
981 ((double-stack descriptor-reg)
982 (inst fstp fr0)
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)
987 (inst ,fopr-sti r)))
988 (maybe-fp-wait node vop))
989 ;; the default case
991 ;; Get the result to ST0.
993 ;; Special handling is needed if x or y are in ST0, and
994 ;; simpler code is generated.
995 (cond
996 ;; x is in ST0
997 ((and (sc-is x double-reg) (zerop (tn-offset x)))
998 ;; ST0 = ST0 op y
999 (sc-case y
1000 (double-reg
1001 (inst ,fopd y))
1002 (double-stack
1003 (inst ,fopd (ea-for-df-stack y)))
1004 (descriptor-reg
1005 (inst ,fopd (ea-for-df-desc y)))))
1006 ;; y is in ST0
1007 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1008 ;; ST0 = x op ST0
1009 (sc-case x
1010 (double-reg
1011 (inst ,foprd x))
1012 (double-stack
1013 (inst ,foprd (ea-for-df-stack x)))
1014 (descriptor-reg
1015 (inst ,foprd (ea-for-df-desc x)))))
1017 ;; x to ST0
1018 (sc-case x
1019 (double-reg
1020 (copy-fp-reg-to-fr0 x))
1021 (double-stack
1022 (inst fstp fr0)
1023 (inst fldd (ea-for-df-stack x)))
1024 (descriptor-reg
1025 (inst fstp fr0)
1026 (inst fldd (ea-for-df-desc x))))
1027 ;; ST0 = ST0 op y
1028 (sc-case y
1029 (double-reg
1030 (inst ,fopd y))
1031 (double-stack
1032 (inst ,fopd (ea-for-df-stack y)))
1033 (descriptor-reg
1034 (inst ,fopd (ea-for-df-desc y))))))
1036 (note-next-instruction vop :internal-error)
1038 ;; Finally save the result.
1039 (sc-case r
1040 (double-reg
1041 (cond ((zerop (tn-offset r))
1042 (maybe-fp-wait node))
1044 (inst fst r))))
1045 (double-stack
1046 (inst fstd (ea-for-df-stack r))))))))
1048 #!+long-float
1049 (define-vop (,lname)
1050 (:translate ,op)
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")
1060 (:vop-var vop)
1061 (:save-p :compute-only)
1062 (:node-var node)
1063 (:generator ,lcost
1064 ;; Handle a few special cases.
1065 (cond
1066 ;; x, y, and r are the same register.
1067 ((and (location= x r) (location= y r))
1068 (cond ((zerop (tn-offset r))
1069 (inst ,fop fr0))
1071 (inst fxch x)
1072 (inst ,fopd fr0)
1073 ;; XX the source register will not be valid.
1074 (note-next-instruction vop :internal-error)
1075 (inst fxch r))))
1077 ;; x and r are the same register.
1078 ((location= x r)
1079 (cond ((zerop (tn-offset r))
1080 ;; ST(0) = ST(0) op ST(y)
1081 (inst ,fopd y))
1083 ;; y to ST0
1084 (unless (zerop (tn-offset y))
1085 (copy-fp-reg-to-fr0 y))
1086 ;; ST(i) = ST(i) op ST0
1087 (inst ,fop-sti r)))
1088 (maybe-fp-wait node vop))
1089 ;; y and r are the same register.
1090 ((location= y r)
1091 (cond ((zerop (tn-offset r))
1092 ;; ST(0) = ST(x) op ST(0)
1093 (inst ,foprd x))
1095 ;; x to ST0
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))
1101 ;; the default case
1103 ;; Get the result to ST0.
1105 ;; Special handling is needed if x or y are in ST0, and
1106 ;; simpler code is generated.
1107 (cond
1108 ;; x is in ST0.
1109 ((zerop (tn-offset x))
1110 ;; ST0 = ST0 op y
1111 (inst ,fopd y))
1112 ;; y is in ST0
1113 ((zerop (tn-offset y))
1114 ;; ST0 = x op ST0
1115 (inst ,foprd x))
1117 ;; x to ST0
1118 (copy-fp-reg-to-fr0 x)
1119 ;; ST0 = ST0 op y
1120 (inst ,fopd y)))
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
1133 +/long-float 2)
1134 (frob - fsub-sti fsubr-sti
1135 fsub fsubr -/single-float 2
1136 fsubd fsubrd -/double-float 2
1137 -/long-float 2)
1138 (frob * fmul-sti fmul-sti
1139 fmul fmul */single-float 3
1140 fmuld fmuld */double-float 3
1141 */long-float 3)
1142 (frob / fdiv-sti fdivr-sti
1143 fdiv fdivr //single-float 12
1144 fdivd fdivrd //double-float 12
1145 //long-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)
1153 (:arg-types ,type)
1154 (:result-types ,type)
1155 (:temporary (:sc double-reg :offset fr0-offset
1156 :from :argument :to :result) fr0)
1157 (:ignore fr0)
1158 (:note "inline float arithmetic")
1159 (:vop-var vop)
1160 (:save-p :compute-only)
1161 (:generator 1
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))
1169 (inst fst y))))))
1171 (frob abs/single-float fabs abs single-reg single-float)
1172 (frob abs/double-float fabs abs double-reg double-float)
1173 #!+long-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)
1177 #!+long-float
1178 (frob %negate/long-float fchs %negate long-reg long-float))
1180 ;;;; comparison
1182 (define-vop (=/float)
1183 (:args (x) (y))
1184 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1185 (:conditional)
1186 (:info target not-p)
1187 (:policy :fast-safe)
1188 (:vop-var vop)
1189 (:save-p :compute-only)
1190 (:note "inline float comparison")
1191 (:ignore temp)
1192 (:generator 3
1193 (note-this-location vop :internal-error)
1194 (cond
1195 ;; x is in ST0; y is in any reg.
1196 ((zerop (tn-offset x))
1197 (inst fucom y))
1198 ;; y is in ST0; x is in another reg.
1199 ((zerop (tn-offset y))
1200 (inst fucom x))
1201 ;; x and y are the same register, not ST0
1202 ((location= x y)
1203 (inst fxch x)
1204 (inst fucom fr0-tn)
1205 (inst fxch x))
1206 ;; x and y are different registers, neither ST0.
1208 (inst fxch x)
1209 (inst fucom y)
1210 (inst fxch x)))
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)
1217 (:translate =)
1218 (:args (x :scs (single-reg))
1219 (y :scs (single-reg)))
1220 (:arg-types single-float single-float))
1222 (define-vop (=/double-float =/float)
1223 (:translate =)
1224 (:args (x :scs (double-reg))
1225 (y :scs (double-reg)))
1226 (:arg-types double-float double-float))
1228 #!+long-float
1229 (define-vop (=/long-float =/float)
1230 (:translate =)
1231 (:args (x :scs (long-reg))
1232 (y :scs (long-reg)))
1233 (:arg-types long-float long-float))
1235 (define-vop (<single-float)
1236 (:translate <)
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)
1242 (:conditional)
1243 (:info target not-p)
1244 (:policy :fast-safe)
1245 (:note "inline float comparison")
1246 (:ignore temp)
1247 (:generator 3
1248 ;; Handle a few special cases.
1249 (cond
1250 ;; y is ST0.
1251 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1252 (sc-case x
1253 (single-reg
1254 (inst fcom x))
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
1264 ;; x to ST0
1265 (sc-case x
1266 (single-reg
1267 (unless (zerop (tn-offset x))
1268 (copy-fp-reg-to-fr0 x)))
1269 ((single-stack descriptor-reg)
1270 (inst fstp fr0)
1271 (if (sc-is x single-stack)
1272 (inst fld (ea-for-sf-stack x))
1273 (inst fld (ea-for-sf-desc x)))))
1274 (sc-case y
1275 (single-reg
1276 (inst fcom y))
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)
1287 (:translate <)
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)
1293 (:conditional)
1294 (:info target not-p)
1295 (:policy :fast-safe)
1296 (:note "inline float comparison")
1297 (:ignore temp)
1298 (:generator 3
1299 ;; Handle a few special cases
1300 (cond
1301 ;; y is ST0.
1302 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1303 (sc-case x
1304 (double-reg
1305 (inst fcomd x))
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.
1315 ;; x to ST0
1316 (sc-case x
1317 (double-reg
1318 (unless (zerop (tn-offset x))
1319 (copy-fp-reg-to-fr0 x)))
1320 ((double-stack descriptor-reg)
1321 (inst fstp fr0)
1322 (if (sc-is x double-stack)
1323 (inst fldd (ea-for-df-stack x))
1324 (inst fldd (ea-for-df-desc x)))))
1325 (sc-case y
1326 (double-reg
1327 (inst fcomd y))
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)))
1337 #!+long-float
1338 (define-vop (<long-float)
1339 (:translate <)
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)
1344 (:conditional)
1345 (:info target not-p)
1346 (:policy :fast-safe)
1347 (:note "inline float comparison")
1348 (:ignore temp)
1349 (:generator 3
1350 (cond
1351 ;; x is in ST0; y is in any reg.
1352 ((zerop (tn-offset x))
1353 (inst fcomd y)
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))
1359 (inst fcomd x)
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.
1365 (inst fxch y)
1366 (inst fcomd x)
1367 (inst fxch y)
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)
1373 (:translate >)
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)
1379 (:conditional)
1380 (:info target not-p)
1381 (:policy :fast-safe)
1382 (:note "inline float comparison")
1383 (:ignore temp)
1384 (:generator 3
1385 ;; Handle a few special cases.
1386 (cond
1387 ;; y is ST0.
1388 ((and (sc-is y single-reg) (zerop (tn-offset y)))
1389 (sc-case x
1390 (single-reg
1391 (inst fcom x))
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
1402 ;; x to ST0
1403 (sc-case x
1404 (single-reg
1405 (unless (zerop (tn-offset x))
1406 (copy-fp-reg-to-fr0 x)))
1407 ((single-stack descriptor-reg)
1408 (inst fstp fr0)
1409 (if (sc-is x single-stack)
1410 (inst fld (ea-for-sf-stack x))
1411 (inst fld (ea-for-sf-desc x)))))
1412 (sc-case y
1413 (single-reg
1414 (inst fcom y))
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)
1424 (:translate >)
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)
1430 (:conditional)
1431 (:info target not-p)
1432 (:policy :fast-safe)
1433 (:note "inline float comparison")
1434 (:ignore temp)
1435 (:generator 3
1436 ;; Handle a few special cases.
1437 (cond
1438 ;; y is ST0.
1439 ((and (sc-is y double-reg) (zerop (tn-offset y)))
1440 (sc-case x
1441 (double-reg
1442 (inst fcomd x))
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
1453 ;; x to ST0
1454 (sc-case x
1455 (double-reg
1456 (unless (zerop (tn-offset x))
1457 (copy-fp-reg-to-fr0 x)))
1458 ((double-stack descriptor-reg)
1459 (inst fstp fr0)
1460 (if (sc-is x double-stack)
1461 (inst fldd (ea-for-df-stack x))
1462 (inst fldd (ea-for-df-desc x)))))
1463 (sc-case y
1464 (double-reg
1465 (inst fcomd y))
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)))
1474 #!+long-float
1475 (define-vop (>long-float)
1476 (:translate >)
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)
1481 (:conditional)
1482 (:info target not-p)
1483 (:policy :fast-safe)
1484 (:note "inline float comparison")
1485 (:ignore temp)
1486 (:generator 3
1487 (cond
1488 ;; y is in ST0; x is in any reg.
1489 ((zerop (tn-offset y))
1490 (inst fcomd x)
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))
1496 (inst fcomd y)
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.
1502 (inst fxch x)
1503 (inst fcomd y)
1504 (inst fxch x)
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)
1512 (:args (x))
1513 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
1514 (:conditional)
1515 (:info target not-p y)
1516 (:variant-vars code)
1517 (:policy :fast-safe)
1518 (:vop-var vop)
1519 (:save-p :compute-only)
1520 (:note "inline float comparison")
1521 (:ignore temp y)
1522 (:generator 2
1523 (note-this-location vop :internal-error)
1524 (cond
1525 ;; x is in ST0
1526 ((zerop (tn-offset x))
1527 (inst ftst))
1528 ;; x not ST0
1530 (inst fxch x)
1531 (inst ftst)
1532 (inst fxch 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)
1540 (:translate =)
1541 (:args (x :scs (single-reg)))
1542 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1543 (:variant #x40))
1544 (define-vop (=0/double-float float-test)
1545 (:translate =)
1546 (:args (x :scs (double-reg)))
1547 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1548 (:variant #x40))
1549 #!+long-float
1550 (define-vop (=0/long-float float-test)
1551 (:translate =)
1552 (:args (x :scs (long-reg)))
1553 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1554 (:variant #x40))
1556 (define-vop (<0/single-float float-test)
1557 (:translate <)
1558 (:args (x :scs (single-reg)))
1559 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1560 (:variant #x01))
1561 (define-vop (<0/double-float float-test)
1562 (:translate <)
1563 (:args (x :scs (double-reg)))
1564 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1565 (:variant #x01))
1566 #!+long-float
1567 (define-vop (<0/long-float float-test)
1568 (:translate <)
1569 (:args (x :scs (long-reg)))
1570 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1571 (:variant #x01))
1573 (define-vop (>0/single-float float-test)
1574 (:translate >)
1575 (:args (x :scs (single-reg)))
1576 (:arg-types single-float (:constant (single-float 0f0 0f0)))
1577 (:variant #x00))
1578 (define-vop (>0/double-float float-test)
1579 (:translate >)
1580 (:args (x :scs (double-reg)))
1581 (:arg-types double-float (:constant (double-float 0d0 0d0)))
1582 (:variant #x00))
1583 #!+long-float
1584 (define-vop (>0/long-float float-test)
1585 (:translate >)
1586 (:args (x :scs (long-reg)))
1587 (:arg-types long-float (:constant (long-float 0l0 0l0)))
1588 (:variant #x00))
1590 #!+long-float
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))))
1596 ;;;; conversion
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)
1608 (:vop-var vop)
1609 (:save-p :compute-only)
1610 (:generator 5
1611 (sc-case x
1612 (signed-reg
1613 (inst mov temp x)
1614 (with-empty-tn@fp-top(y)
1615 (note-this-location vop :internal-error)
1616 (inst fild temp)))
1617 (signed-stack
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)
1623 #!+long-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)
1635 (:vop-var vop)
1636 (:save-p :compute-only)
1637 (:generator 6
1638 (inst push 0)
1639 (inst push x)
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)
1646 #!+long-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
1650 ;;; things around.
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)
1660 (:vop-var vop)
1661 (:save-p :compute-only)
1662 (:generator 2
1663 (note-this-location vop :internal-error)
1664 (unless (location= x y)
1665 (cond
1666 ((zerop (tn-offset x))
1667 ;; x is in ST0, y is in another reg. not ST0
1668 (inst fst y))
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
1674 ;; the same reg.
1675 (inst fxch x)
1676 (inst fst y)
1677 (inst fxch x))))))))
1679 (frob %single-float/double-float %single-float double-reg
1680 double-float single-reg single-float)
1681 #!+long-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)
1686 #!+long-float
1687 (frob %double-float/long-float %double-float long-reg long-float
1688 double-reg double-float)
1689 #!+long-float
1690 (frob %long-float/single-float %long-float single-reg single-float
1691 long-reg long-float)
1692 #!+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)
1700 ,@(unless round-p
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)
1706 (:translate ,trans)
1707 (:policy :fast-safe)
1708 (:note "inline float truncate")
1709 (:vop-var vop)
1710 (:save-p :compute-only)
1711 (:generator 5
1712 ,@(unless round-p
1713 '((note-this-location vop :internal-error)
1714 ;; Catch any pending FPE exceptions.
1715 (inst wait)))
1716 (,(if round-p 'progn 'pseudo-atomic)
1717 ;; Normal mode (for now) is "round to best".
1718 (with-tn@fp-top (x)
1719 ,@(unless round-p
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)))
1725 (sc-case y
1726 (signed-stack
1727 (inst fist y))
1728 (signed-reg
1729 (inst fist stack-temp)
1730 (inst mov y stack-temp)))
1731 ,@(unless round-p
1732 '((inst fldcw scw)))))))))
1733 (frob %unary-truncate single-reg single-float nil)
1734 (frob %unary-truncate double-reg double-float nil)
1735 #!+long-float
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)
1739 #!+long-float
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)
1747 ,@(unless round-p
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)
1754 (:translate ,trans)
1755 (:policy :fast-safe)
1756 (:note "inline float truncate")
1757 (:vop-var vop)
1758 (:save-p :compute-only)
1759 (:generator 5
1760 ,@(unless round-p
1761 '((note-this-location vop :internal-error)
1762 ;; Catch any pending FPE exceptions.
1763 (inst wait)))
1764 ;; Normal mode (for now) is "round to best".
1765 (unless (zerop (tn-offset x))
1766 (copy-fp-reg-to-fr0 x))
1767 ,@(unless round-p
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)))
1773 (inst sub esp-tn 8)
1774 (inst fistpl (make-ea :dword :base esp-tn))
1775 (inst pop y)
1776 (inst fld fr0) ; copy fr0 to at least restore stack.
1777 (inst add esp-tn 4)
1778 ,@(unless round-p
1779 '((inst fldcw scw)))))))
1780 (frob %unary-truncate single-reg single-float nil)
1781 (frob %unary-truncate double-reg double-float nil)
1782 #!+long-float
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)
1786 #!+long-float
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)
1802 (:vop-var vop)
1803 (:generator 4
1804 (sc-case res
1805 (single-stack
1806 (sc-case bits
1807 (signed-reg
1808 (inst mov res bits))
1809 (signed-stack
1810 (aver (location= bits res)))))
1811 (single-reg
1812 (sc-case bits
1813 (signed-reg
1814 ;; source must be in memory
1815 (inst mov stack-temp bits)
1816 (with-empty-tn@fp-top(res)
1817 (inst fld stack-temp)))
1818 (signed-stack
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)
1831 (:vop-var vop)
1832 (:generator 2
1833 (let ((offset (tn-offset temp)))
1834 (storew hi-bits ebp-tn (frame-word-offset offset))
1835 (storew lo-bits ebp-tn (frame-word-offset (1+ offset)))
1836 (with-empty-tn@fp-top(res)
1837 (inst fldd (make-ea :dword :base ebp-tn
1838 :disp (frame-byte-offset (1+ offset))))))))
1840 #!+long-float
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)
1851 (:vop-var vop)
1852 (:generator 3
1853 (let ((offset (tn-offset temp)))
1854 (storew exp-bits ebp-tn (frame-word-offset offset))
1855 (storew hi-bits ebp-tn (frame-word-offset (1+ offset)))
1856 (storew lo-bits ebp-tn (frame-word-offset (+ offset 2)))
1857 (with-empty-tn@fp-top(res)
1858 (inst fldl (make-ea :dword :base ebp-tn
1859 :disp (frame-byte-offset (+ offset 2))))))))
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)
1870 (:vop-var vop)
1871 (:generator 4
1872 (sc-case bits
1873 (signed-reg
1874 (sc-case float
1875 (single-reg
1876 (with-tn@fp-top(float)
1877 (inst fst stack-temp)
1878 (inst mov bits stack-temp)))
1879 (single-stack
1880 (inst mov bits float))
1881 (descriptor-reg
1882 (loadw
1883 bits float single-float-value-slot
1884 other-pointer-lowtag))))
1885 (signed-stack
1886 (sc-case float
1887 (single-reg
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)
1900 (:vop-var vop)
1901 (:generator 5
1902 (sc-case float
1903 (double-reg
1904 (with-tn@fp-top(float)
1905 (let ((where (make-ea :dword :base ebp-tn
1906 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1907 (inst fstd where)))
1908 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset temp))))
1909 (double-stack
1910 (loadw hi-bits ebp-tn (frame-word-offset (tn-offset float))))
1911 (descriptor-reg
1912 (loadw hi-bits float (1+ double-float-value-slot)
1913 other-pointer-lowtag)))))
1915 (define-vop (double-float-low-bits)
1916 (:args (float :scs (double-reg descriptor-reg)
1917 :load-if (not (sc-is float double-stack))))
1918 (:results (lo-bits :scs (unsigned-reg)))
1919 (:temporary (:sc double-stack) temp)
1920 (:arg-types double-float)
1921 (:result-types unsigned-num)
1922 (:translate double-float-low-bits)
1923 (:policy :fast-safe)
1924 (:vop-var vop)
1925 (:generator 5
1926 (sc-case float
1927 (double-reg
1928 (with-tn@fp-top(float)
1929 (let ((where (make-ea :dword :base ebp-tn
1930 :disp (frame-byte-offset (1+ (tn-offset temp))))))
1931 (inst fstd where)))
1932 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1933 (double-stack
1934 (loadw lo-bits ebp-tn (frame-word-offset (1+ (tn-offset float)))))
1935 (descriptor-reg
1936 (loadw lo-bits float double-float-value-slot
1937 other-pointer-lowtag)))))
1939 #!+long-float
1940 (define-vop (long-float-exp-bits)
1941 (:args (float :scs (long-reg descriptor-reg)
1942 :load-if (not (sc-is float long-stack))))
1943 (:results (exp-bits :scs (signed-reg)))
1944 (:temporary (:sc long-stack) temp)
1945 (:arg-types long-float)
1946 (:result-types signed-num)
1947 (:translate long-float-exp-bits)
1948 (:policy :fast-safe)
1949 (:vop-var vop)
1950 (:generator 5
1951 (sc-case float
1952 (long-reg
1953 (with-tn@fp-top(float)
1954 (let ((where (make-ea :dword :base ebp-tn
1955 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1956 (store-long-float where)))
1957 (inst movsx exp-bits
1958 (make-ea :word :base ebp-tn
1959 :disp (frame-byte-offset (tn-offset temp)))))
1960 (long-stack
1961 (inst movsx exp-bits
1962 (make-ea :word :base ebp-tn
1963 :disp (frame-byte-offset (tn-offset temp)))))
1964 (descriptor-reg
1965 (inst movsx exp-bits
1966 (make-ea-for-object-slot float (+ 2 long-float-value-slot)
1967 other-pointer-lowtag :word))))))
1969 #!+long-float
1970 (define-vop (long-float-high-bits)
1971 (:args (float :scs (long-reg descriptor-reg)
1972 :load-if (not (sc-is float long-stack))))
1973 (:results (hi-bits :scs (unsigned-reg)))
1974 (:temporary (:sc long-stack) temp)
1975 (:arg-types long-float)
1976 (:result-types unsigned-num)
1977 (:translate long-float-high-bits)
1978 (:policy :fast-safe)
1979 (:vop-var vop)
1980 (:generator 5
1981 (sc-case float
1982 (long-reg
1983 (with-tn@fp-top(float)
1984 (let ((where (make-ea :dword :base ebp-tn
1985 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
1986 (store-long-float where)))
1987 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1988 (long-stack
1989 (loadw hi-bits ebp-tn (frame-word-offset (1+ (tn-offset temp)))))
1990 (descriptor-reg
1991 (loadw hi-bits float (1+ long-float-value-slot)
1992 other-pointer-lowtag)))))
1994 #!+long-float
1995 (define-vop (long-float-low-bits)
1996 (:args (float :scs (long-reg descriptor-reg)
1997 :load-if (not (sc-is float long-stack))))
1998 (:results (lo-bits :scs (unsigned-reg)))
1999 (:temporary (:sc long-stack) temp)
2000 (:arg-types long-float)
2001 (:result-types unsigned-num)
2002 (:translate long-float-low-bits)
2003 (:policy :fast-safe)
2004 (:vop-var vop)
2005 (:generator 5
2006 (sc-case float
2007 (long-reg
2008 (with-tn@fp-top(float)
2009 (let ((where (make-ea :dword :base ebp-tn
2010 :disp (frame-byte-offset (+ 2 (tn-offset temp))))))
2011 (store-long-float where)))
2012 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset temp) 2))))
2013 (long-stack
2014 (loadw lo-bits ebp-tn (frame-word-offset (+ (tn-offset float) 2))))
2015 (descriptor-reg
2016 (loadw lo-bits float long-float-value-slot
2017 other-pointer-lowtag)))))
2019 ;;;; float mode hackery
2021 (sb!xc:deftype float-modes () '(unsigned-byte 32)) ; really only 16
2022 (defknown floating-point-modes () float-modes (flushable))
2023 (defknown ((setf floating-point-modes)) (float-modes)
2024 float-modes)
2026 (def!constant npx-env-size (* 7 n-word-bytes))
2027 (def!constant npx-cw-offset 0)
2028 (def!constant npx-sw-offset 4)
2030 (define-vop (floating-point-modes)
2031 (:results (res :scs (unsigned-reg)))
2032 (:result-types unsigned-num)
2033 (:translate floating-point-modes)
2034 (:policy :fast-safe)
2035 (:temporary (:sc unsigned-reg :offset eax-offset :target res
2036 :to :result) eax)
2037 (:generator 8
2038 (inst sub esp-tn npx-env-size) ; Make space on stack.
2039 (inst wait) ; Catch any pending FPE exceptions
2040 (inst fstenv (make-ea :dword :base esp-tn)) ; masks all exceptions
2041 (inst fldenv (make-ea :dword :base esp-tn)) ; Restore previous state.
2042 ;; Move current status to high word.
2043 (inst mov eax (make-ea :dword :base esp-tn :disp (- npx-sw-offset 2)))
2044 ;; Move exception mask to low word.
2045 (inst mov ax-tn (make-ea :word :base esp-tn :disp npx-cw-offset))
2046 (inst add esp-tn npx-env-size) ; Pop stack.
2047 (inst xor eax #x3f) ; Flip exception mask to trap enable bits.
2048 (move res eax)))
2050 (define-vop (set-floating-point-modes)
2051 (:args (new :scs (unsigned-reg) :to :result :target res))
2052 (:results (res :scs (unsigned-reg)))
2053 (:arg-types unsigned-num)
2054 (:result-types unsigned-num)
2055 (:translate (setf floating-point-modes))
2056 (:policy :fast-safe)
2057 (:temporary (:sc unsigned-reg :offset eax-offset
2058 :from :eval :to :result) eax)
2059 (:generator 3
2060 (inst sub esp-tn npx-env-size) ; Make space on stack.
2061 (inst wait) ; Catch any pending FPE exceptions.
2062 (inst fstenv (make-ea :dword :base esp-tn))
2063 (inst mov eax new)
2064 (inst xor eax #x3f) ; Turn trap enable bits into exception mask.
2065 (inst mov (make-ea :word :base esp-tn :disp npx-cw-offset) ax-tn)
2066 (inst shr eax 16) ; position status word
2067 (inst mov (make-ea :word :base esp-tn :disp npx-sw-offset) ax-tn)
2068 (inst fldenv (make-ea :dword :base esp-tn))
2069 (inst add esp-tn npx-env-size) ; Pop stack.
2070 (move res new)))
2072 #!-long-float
2073 (progn
2075 ;;; Let's use some of the 80387 special functions.
2077 ;;; These defs will not take effect unless code/irrat.lisp is modified
2078 ;;; to remove the inlined alien routine def.
2080 (macrolet ((frob (func trans op)
2081 `(define-vop (,func)
2082 (:args (x :scs (double-reg) :target fr0))
2083 (:temporary (:sc double-reg :offset fr0-offset
2084 :from :argument :to :result) fr0)
2085 (:ignore fr0)
2086 (:results (y :scs (double-reg)))
2087 (:arg-types double-float)
2088 (:result-types double-float)
2089 (:translate ,trans)
2090 (:policy :fast-safe)
2091 (:note "inline NPX function")
2092 (:vop-var vop)
2093 (:save-p :compute-only)
2094 (:node-var node)
2095 (:generator 5
2096 (note-this-location vop :internal-error)
2097 (unless (zerop (tn-offset x))
2098 (inst fxch x) ; x to top of stack
2099 (unless (location= x y)
2100 (inst fst x))) ; maybe save it
2101 (inst ,op) ; clobber st0
2102 (cond ((zerop (tn-offset y))
2103 (maybe-fp-wait node))
2105 (inst fst y)))))))
2107 ;; Quick versions of fsin and fcos that require the argument to be
2108 ;; within range 2^63.
2109 (frob fsin-quick %sin-quick fsin)
2110 (frob fcos-quick %cos-quick fcos)
2111 (frob fsqrt %sqrt fsqrt))
2113 ;;; Quick version of ftan that requires the argument to be within
2114 ;;; range 2^63.
2115 (define-vop (ftan-quick)
2116 (:translate %tan-quick)
2117 (:args (x :scs (double-reg) :target fr0))
2118 (:temporary (:sc double-reg :offset fr0-offset
2119 :from :argument :to :result) fr0)
2120 (:temporary (:sc double-reg :offset fr1-offset
2121 :from :argument :to :result) fr1)
2122 (:results (y :scs (double-reg)))
2123 (:arg-types double-float)
2124 (:result-types double-float)
2125 (:policy :fast-safe)
2126 (:note "inline tan function")
2127 (:vop-var vop)
2128 (:save-p :compute-only)
2129 (:generator 5
2130 (note-this-location vop :internal-error)
2131 (case (tn-offset x)
2133 (inst fstp fr1))
2135 (inst fstp fr0))
2137 (inst fstp fr0)
2138 (inst fstp fr0)
2139 (inst fldd (make-random-tn :kind :normal
2140 :sc (sc-or-lose 'double-reg)
2141 :offset (- (tn-offset x) 2)))))
2142 (inst fptan)
2143 ;; Result is in fr1
2144 (case (tn-offset y)
2146 (inst fxch fr1))
2149 (inst fxch fr1)
2150 (inst fstd y)))))
2152 ;;; KLUDGE: these versions of fsin, fcos, and ftan simply load a 0.0
2153 ;;; result if the argument is out of range 2^63 and would thus be
2154 ;;; hopelessly inaccurate.
2155 (macrolet ((frob (func trans op)
2156 `(define-vop (,func)
2157 (:translate ,trans)
2158 (:args (x :scs (double-reg) :target fr0))
2159 (:temporary (:sc double-reg :offset fr0-offset
2160 :from :argument :to :result) fr0)
2161 (:temporary (:sc unsigned-reg :offset eax-offset
2162 :from :argument :to :result) eax)
2163 (:results (y :scs (double-reg)))
2164 (:arg-types double-float)
2165 (:result-types double-float)
2166 (:policy :fast-safe)
2167 (:note "inline sin/cos function")
2168 (:vop-var vop)
2169 (:save-p :compute-only)
2170 (:ignore eax)
2171 (:generator 5
2172 (note-this-location vop :internal-error)
2173 (unless (zerop (tn-offset x))
2174 (inst fxch x) ; x to top of stack
2175 (unless (location= x y)
2176 (inst fst x))) ; maybe save it
2177 (inst ,op)
2178 (inst fnstsw) ; status word to ax
2179 (inst and ah-tn #x04) ; C2
2180 (inst jmp :z DONE)
2181 ;; Else x was out of range so reduce it; ST0 is unchanged.
2182 (inst fstp fr0) ; Load 0.0
2183 (inst fldz)
2184 DONE
2185 (unless (zerop (tn-offset y))
2186 (inst fstd y))))))
2187 (frob fsin %sin fsin)
2188 (frob fcos %cos fcos))
2190 (define-vop (ftan)
2191 (:translate %tan)
2192 (:args (x :scs (double-reg) :target fr0))
2193 (:temporary (:sc double-reg :offset fr0-offset
2194 :from :argument :to :result) fr0)
2195 (:temporary (:sc double-reg :offset fr1-offset
2196 :from :argument :to :result) fr1)
2197 (:temporary (:sc unsigned-reg :offset eax-offset
2198 :from :argument :to :result) eax)
2199 (:results (y :scs (double-reg)))
2200 (:arg-types double-float)
2201 (:result-types double-float)
2202 (:ignore eax)
2203 (:policy :fast-safe)
2204 (:note "inline tan function")
2205 (:vop-var vop)
2206 (:save-p :compute-only)
2207 (:ignore eax)
2208 (:generator 5
2209 (note-this-location vop :internal-error)
2210 (case (tn-offset x)
2212 (inst fstp fr1))
2214 (inst fstp fr0))
2216 (inst fstp fr0)
2217 (inst fstp fr0)
2218 (inst fldd (make-random-tn :kind :normal
2219 :sc (sc-or-lose 'double-reg)
2220 :offset (- (tn-offset x) 2)))))
2221 (inst fptan)
2222 (inst fnstsw) ; status word to ax
2223 (inst and ah-tn #x04) ; C2
2224 (inst jmp :z DONE)
2225 ;; Else x was out of range so load 0.0
2226 (inst fxch fr1)
2227 DONE
2228 ;; Result is in fr1
2229 (case (tn-offset y)
2231 (inst fxch fr1))
2234 (inst fxch fr1)
2235 (inst fstd y)))))
2237 ;;; %exp that handles the following special cases: exp(+Inf) is +Inf;
2238 ;;; exp(-Inf) is 0; exp(NaN) is NaN.
2239 (define-vop (fexp)
2240 (:translate %exp)
2241 (:args (x :scs (double-reg) :target fr0))
2242 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2243 (:temporary (:sc double-reg :offset fr0-offset
2244 :from :argument :to :result) fr0)
2245 (:temporary (:sc double-reg :offset fr1-offset
2246 :from :argument :to :result) fr1)
2247 (:temporary (:sc double-reg :offset fr2-offset
2248 :from :argument :to :result) fr2)
2249 (:results (y :scs (double-reg)))
2250 (:arg-types double-float)
2251 (:result-types double-float)
2252 (:policy :fast-safe)
2253 (:note "inline exp function")
2254 (:vop-var vop)
2255 (:save-p :compute-only)
2256 (:ignore temp)
2257 (:generator 5
2258 (note-this-location vop :internal-error)
2259 (unless (zerop (tn-offset x))
2260 (inst fxch x) ; x to top of stack
2261 (unless (location= x y)
2262 (inst fst x))) ; maybe save it
2263 ;; Check for Inf or NaN
2264 (inst fxam)
2265 (inst fnstsw)
2266 (inst sahf)
2267 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2268 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2269 (inst and ah-tn #x02) ; Test sign of Inf.
2270 (inst jmp :z DONE) ; +Inf gives +Inf.
2271 (inst fstp fr0) ; -Inf gives 0
2272 (inst fldz)
2273 (inst jmp-short DONE)
2274 NOINFNAN
2275 (inst fstp fr1)
2276 (inst fldl2e)
2277 (inst fmul fr1)
2278 ;; Now fr0=x log2(e)
2279 (inst fst fr1)
2280 (inst frndint)
2281 (inst fst fr2)
2282 (inst fsubp-sti fr1)
2283 (inst f2xm1)
2284 (inst fld1)
2285 (inst faddp-sti fr1)
2286 (inst fscale)
2287 (inst fld fr0)
2288 DONE
2289 (unless (zerop (tn-offset y))
2290 (inst fstd y))))
2292 ;;; Expm1 = exp(x) - 1.
2293 ;;; Handles the following special cases:
2294 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
2295 (define-vop (fexpm1)
2296 (:translate %expm1)
2297 (:args (x :scs (double-reg) :target fr0))
2298 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
2299 (:temporary (:sc double-reg :offset fr0-offset
2300 :from :argument :to :result) fr0)
2301 (:temporary (:sc double-reg :offset fr1-offset
2302 :from :argument :to :result) fr1)
2303 (:temporary (:sc double-reg :offset fr2-offset
2304 :from :argument :to :result) fr2)
2305 (:results (y :scs (double-reg)))
2306 (:arg-types double-float)
2307 (:result-types double-float)
2308 (:policy :fast-safe)
2309 (:note "inline expm1 function")
2310 (:vop-var vop)
2311 (:save-p :compute-only)
2312 (:ignore temp)
2313 (:generator 5
2314 (note-this-location vop :internal-error)
2315 (unless (zerop (tn-offset x))
2316 (inst fxch x) ; x to top of stack
2317 (unless (location= x y)
2318 (inst fst x))) ; maybe save it
2319 ;; Check for Inf or NaN
2320 (inst fxam)
2321 (inst fnstsw)
2322 (inst sahf)
2323 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
2324 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
2325 (inst and ah-tn #x02) ; Test sign of Inf.
2326 (inst jmp :z DONE) ; +Inf gives +Inf.
2327 (inst fstp fr0) ; -Inf gives -1.0
2328 (inst fld1)
2329 (inst fchs)
2330 (inst jmp-short DONE)
2331 NOINFNAN
2332 ;; Free two stack slots leaving the argument on top.
2333 (inst fstp fr2)
2334 (inst fstp fr0)
2335 (inst fldl2e)
2336 (inst fmul fr1) ; Now fr0 = x log2(e)
2337 (inst fst fr1)
2338 (inst frndint)
2339 (inst fsub-sti fr1)
2340 (inst fxch fr1)
2341 (inst f2xm1)
2342 (inst fscale)
2343 (inst fxch fr1)
2344 (inst fld1)
2345 (inst fscale)
2346 (inst fstp fr1)
2347 (inst fld1)
2348 (inst fsub fr1)
2349 (inst fsubr fr2)
2350 DONE
2351 (unless (zerop (tn-offset y))
2352 (inst fstd y))))
2354 (define-vop (flog)
2355 (:translate %log)
2356 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2357 (:temporary (:sc double-reg :offset fr0-offset
2358 :from :argument :to :result) fr0)
2359 (:temporary (:sc double-reg :offset fr1-offset
2360 :from :argument :to :result) fr1)
2361 (:results (y :scs (double-reg)))
2362 (:arg-types double-float)
2363 (:result-types double-float)
2364 (:policy :fast-safe)
2365 (:note "inline log function")
2366 (:vop-var vop)
2367 (:save-p :compute-only)
2368 (:generator 5
2369 (note-this-location vop :internal-error)
2370 (sc-case x
2371 (double-reg
2372 (case (tn-offset x)
2374 ;; x is in fr0
2375 (inst fstp fr1)
2376 (inst fldln2)
2377 (inst fxch fr1))
2379 ;; x is in fr1
2380 (inst fstp fr0)
2381 (inst fldln2)
2382 (inst fxch fr1))
2384 ;; x is in a FP reg, not fr0 or fr1
2385 (inst fstp fr0)
2386 (inst fstp fr0)
2387 (inst fldln2)
2388 (inst fldd (make-random-tn :kind :normal
2389 :sc (sc-or-lose 'double-reg)
2390 :offset (1- (tn-offset x))))))
2391 (inst fyl2x))
2392 ((double-stack descriptor-reg)
2393 (inst fstp fr0)
2394 (inst fstp fr0)
2395 (inst fldln2)
2396 (if (sc-is x double-stack)
2397 (inst fldd (ea-for-df-stack x))
2398 (inst fldd (ea-for-df-desc x)))
2399 (inst fyl2x)))
2400 (inst fld fr0)
2401 (case (tn-offset y)
2402 ((0 1))
2403 (t (inst fstd y)))))
2405 (define-vop (flog10)
2406 (:translate %log10)
2407 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2408 (:temporary (:sc double-reg :offset fr0-offset
2409 :from :argument :to :result) fr0)
2410 (:temporary (:sc double-reg :offset fr1-offset
2411 :from :argument :to :result) fr1)
2412 (:results (y :scs (double-reg)))
2413 (:arg-types double-float)
2414 (:result-types double-float)
2415 (:policy :fast-safe)
2416 (:note "inline log10 function")
2417 (:vop-var vop)
2418 (:save-p :compute-only)
2419 (:generator 5
2420 (note-this-location vop :internal-error)
2421 (sc-case x
2422 (double-reg
2423 (case (tn-offset x)
2425 ;; x is in fr0
2426 (inst fstp fr1)
2427 (inst fldlg2)
2428 (inst fxch fr1))
2430 ;; x is in fr1
2431 (inst fstp fr0)
2432 (inst fldlg2)
2433 (inst fxch fr1))
2435 ;; x is in a FP reg, not fr0 or fr1
2436 (inst fstp fr0)
2437 (inst fstp fr0)
2438 (inst fldlg2)
2439 (inst fldd (make-random-tn :kind :normal
2440 :sc (sc-or-lose 'double-reg)
2441 :offset (1- (tn-offset x))))))
2442 (inst fyl2x))
2443 ((double-stack descriptor-reg)
2444 (inst fstp fr0)
2445 (inst fstp fr0)
2446 (inst fldlg2)
2447 (if (sc-is x double-stack)
2448 (inst fldd (ea-for-df-stack x))
2449 (inst fldd (ea-for-df-desc x)))
2450 (inst fyl2x)))
2451 (inst fld fr0)
2452 (case (tn-offset y)
2453 ((0 1))
2454 (t (inst fstd y)))))
2456 (define-vop (fpow)
2457 (:translate %pow)
2458 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2459 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2460 (:temporary (:sc double-reg :offset fr0-offset
2461 :from (:argument 0) :to :result) fr0)
2462 (:temporary (:sc double-reg :offset fr1-offset
2463 :from (:argument 1) :to :result) fr1)
2464 (:temporary (:sc double-reg :offset fr2-offset
2465 :from :load :to :result) fr2)
2466 (:results (r :scs (double-reg)))
2467 (:arg-types double-float double-float)
2468 (:result-types double-float)
2469 (:policy :fast-safe)
2470 (:note "inline pow function")
2471 (:vop-var vop)
2472 (:save-p :compute-only)
2473 (:generator 5
2474 (note-this-location vop :internal-error)
2475 ;; Setup x in fr0 and y in fr1
2476 (cond
2477 ;; x in fr0; y in fr1
2478 ((and (sc-is x double-reg) (zerop (tn-offset x))
2479 (sc-is y double-reg) (= 1 (tn-offset y))))
2480 ;; y in fr1; x not in fr0
2481 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2482 ;; Load x to fr0
2483 (sc-case x
2484 (double-reg
2485 (copy-fp-reg-to-fr0 x))
2486 (double-stack
2487 (inst fstp fr0)
2488 (inst fldd (ea-for-df-stack x)))
2489 (descriptor-reg
2490 (inst fstp fr0)
2491 (inst fldd (ea-for-df-desc x)))))
2492 ;; x in fr0; y not in fr1
2493 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2494 (inst fxch fr1)
2495 ;; Now load y to fr0
2496 (sc-case y
2497 (double-reg
2498 (copy-fp-reg-to-fr0 y))
2499 (double-stack
2500 (inst fstp fr0)
2501 (inst fldd (ea-for-df-stack y)))
2502 (descriptor-reg
2503 (inst fstp fr0)
2504 (inst fldd (ea-for-df-desc y))))
2505 (inst fxch fr1))
2506 ;; x in fr1; y not in fr1
2507 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2508 ;; Load y to fr0
2509 (sc-case y
2510 (double-reg
2511 (copy-fp-reg-to-fr0 y))
2512 (double-stack
2513 (inst fstp fr0)
2514 (inst fldd (ea-for-df-stack y)))
2515 (descriptor-reg
2516 (inst fstp fr0)
2517 (inst fldd (ea-for-df-desc y))))
2518 (inst fxch fr1))
2519 ;; y in fr0;
2520 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2521 (inst fxch fr1)
2522 ;; Now load x to fr0
2523 (sc-case x
2524 (double-reg
2525 (copy-fp-reg-to-fr0 x))
2526 (double-stack
2527 (inst fstp fr0)
2528 (inst fldd (ea-for-df-stack x)))
2529 (descriptor-reg
2530 (inst fstp fr0)
2531 (inst fldd (ea-for-df-desc x)))))
2532 ;; Neither x or y are in either fr0 or fr1
2534 ;; Load y then x
2535 (inst fstp fr0)
2536 (inst fstp fr0)
2537 (sc-case y
2538 (double-reg
2539 (inst fldd (make-random-tn :kind :normal
2540 :sc (sc-or-lose 'double-reg)
2541 :offset (- (tn-offset y) 2))))
2542 (double-stack
2543 (inst fldd (ea-for-df-stack y)))
2544 (descriptor-reg
2545 (inst fldd (ea-for-df-desc y))))
2546 ;; Load x to fr0
2547 (sc-case x
2548 (double-reg
2549 (inst fldd (make-random-tn :kind :normal
2550 :sc (sc-or-lose 'double-reg)
2551 :offset (1- (tn-offset x)))))
2552 (double-stack
2553 (inst fldd (ea-for-df-stack x)))
2554 (descriptor-reg
2555 (inst fldd (ea-for-df-desc x))))))
2557 ;; Now have x at fr0; and y at fr1
2558 (inst fyl2x)
2559 ;; Now fr0=y log2(x)
2560 (inst fld fr0)
2561 (inst frndint)
2562 (inst fst fr2)
2563 (inst fsubp-sti fr1)
2564 (inst f2xm1)
2565 (inst fld1)
2566 (inst faddp-sti fr1)
2567 (inst fscale)
2568 (inst fld fr0)
2569 (case (tn-offset r)
2570 ((0 1))
2571 (t (inst fstd r)))))
2573 (define-vop (fscalen)
2574 (:translate %scalbn)
2575 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2576 (y :scs (signed-stack signed-reg) :target temp))
2577 (:temporary (:sc double-reg :offset fr0-offset
2578 :from (:argument 0) :to :result) fr0)
2579 (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
2580 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
2581 (:results (r :scs (double-reg)))
2582 (:arg-types double-float signed-num)
2583 (:result-types double-float)
2584 (:policy :fast-safe)
2585 (:note "inline scalbn function")
2586 (:generator 5
2587 ;; Setup x in fr0 and y in fr1
2588 (sc-case x
2589 (double-reg
2590 (case (tn-offset x)
2592 (inst fstp fr1)
2593 (sc-case y
2594 (signed-reg
2595 (inst mov temp y)
2596 (inst fild temp))
2597 (signed-stack
2598 (inst fild y)))
2599 (inst fxch fr1))
2601 (inst fstp fr0)
2602 (sc-case y
2603 (signed-reg
2604 (inst mov temp y)
2605 (inst fild temp))
2606 (signed-stack
2607 (inst fild y)))
2608 (inst fxch fr1))
2610 (inst fstp fr0)
2611 (inst fstp fr0)
2612 (sc-case y
2613 (signed-reg
2614 (inst mov temp y)
2615 (inst fild temp))
2616 (signed-stack
2617 (inst fild y)))
2618 (inst fld (make-random-tn :kind :normal
2619 :sc (sc-or-lose 'double-reg)
2620 :offset (1- (tn-offset x)))))))
2621 ((double-stack descriptor-reg)
2622 (inst fstp fr0)
2623 (inst fstp fr0)
2624 (sc-case y
2625 (signed-reg
2626 (inst mov temp y)
2627 (inst fild temp))
2628 (signed-stack
2629 (inst fild y)))
2630 (if (sc-is x double-stack)
2631 (inst fldd (ea-for-df-stack x))
2632 (inst fldd (ea-for-df-desc x)))))
2633 (inst fscale)
2634 (unless (zerop (tn-offset r))
2635 (inst fstd r))))
2637 (define-vop (fscale)
2638 (:translate %scalb)
2639 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
2640 (y :scs (double-reg double-stack descriptor-reg) :target fr1))
2641 (:temporary (:sc double-reg :offset fr0-offset
2642 :from (:argument 0) :to :result) fr0)
2643 (:temporary (:sc double-reg :offset fr1-offset
2644 :from (:argument 1) :to :result) fr1)
2645 (:results (r :scs (double-reg)))
2646 (:arg-types double-float double-float)
2647 (:result-types double-float)
2648 (:policy :fast-safe)
2649 (:note "inline scalb function")
2650 (:vop-var vop)
2651 (:save-p :compute-only)
2652 (:generator 5
2653 (note-this-location vop :internal-error)
2654 ;; Setup x in fr0 and y in fr1
2655 (cond
2656 ;; x in fr0; y in fr1
2657 ((and (sc-is x double-reg) (zerop (tn-offset x))
2658 (sc-is y double-reg) (= 1 (tn-offset y))))
2659 ;; y in fr1; x not in fr0
2660 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2661 ;; Load x to fr0
2662 (sc-case x
2663 (double-reg
2664 (copy-fp-reg-to-fr0 x))
2665 (double-stack
2666 (inst fstp fr0)
2667 (inst fldd (ea-for-df-stack x)))
2668 (descriptor-reg
2669 (inst fstp fr0)
2670 (inst fldd (ea-for-df-desc x)))))
2671 ;; x in fr0; y not in fr1
2672 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2673 (inst fxch fr1)
2674 ;; Now load y to fr0
2675 (sc-case y
2676 (double-reg
2677 (copy-fp-reg-to-fr0 y))
2678 (double-stack
2679 (inst fstp fr0)
2680 (inst fldd (ea-for-df-stack y)))
2681 (descriptor-reg
2682 (inst fstp fr0)
2683 (inst fldd (ea-for-df-desc y))))
2684 (inst fxch fr1))
2685 ;; x in fr1; y not in fr1
2686 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2687 ;; Load y to fr0
2688 (sc-case y
2689 (double-reg
2690 (copy-fp-reg-to-fr0 y))
2691 (double-stack
2692 (inst fstp fr0)
2693 (inst fldd (ea-for-df-stack y)))
2694 (descriptor-reg
2695 (inst fstp fr0)
2696 (inst fldd (ea-for-df-desc y))))
2697 (inst fxch fr1))
2698 ;; y in fr0;
2699 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2700 (inst fxch fr1)
2701 ;; Now load x to fr0
2702 (sc-case x
2703 (double-reg
2704 (copy-fp-reg-to-fr0 x))
2705 (double-stack
2706 (inst fstp fr0)
2707 (inst fldd (ea-for-df-stack x)))
2708 (descriptor-reg
2709 (inst fstp fr0)
2710 (inst fldd (ea-for-df-desc x)))))
2711 ;; Neither x or y are in either fr0 or fr1
2713 ;; Load y then x
2714 (inst fstp fr0)
2715 (inst fstp fr0)
2716 (sc-case y
2717 (double-reg
2718 (inst fldd (make-random-tn :kind :normal
2719 :sc (sc-or-lose 'double-reg)
2720 :offset (- (tn-offset y) 2))))
2721 (double-stack
2722 (inst fldd (ea-for-df-stack y)))
2723 (descriptor-reg
2724 (inst fldd (ea-for-df-desc y))))
2725 ;; Load x to fr0
2726 (sc-case x
2727 (double-reg
2728 (inst fldd (make-random-tn :kind :normal
2729 :sc (sc-or-lose 'double-reg)
2730 :offset (1- (tn-offset x)))))
2731 (double-stack
2732 (inst fldd (ea-for-df-stack x)))
2733 (descriptor-reg
2734 (inst fldd (ea-for-df-desc x))))))
2736 ;; Now have x at fr0; and y at fr1
2737 (inst fscale)
2738 (unless (zerop (tn-offset r))
2739 (inst fstd r))))
2741 (define-vop (flog1p)
2742 (:translate %log1p)
2743 (:args (x :scs (double-reg) :to :result))
2744 (:temporary (:sc double-reg :offset fr0-offset
2745 :from :argument :to :result) fr0)
2746 (:temporary (:sc double-reg :offset fr1-offset
2747 :from :argument :to :result) fr1)
2748 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
2749 (:results (y :scs (double-reg)))
2750 (:arg-types double-float)
2751 (:result-types double-float)
2752 (:policy :fast-safe)
2753 (:note "inline log1p function")
2754 (:ignore temp)
2755 (:generator 5
2756 ;; x is in a FP reg, not fr0, fr1.
2757 (inst fstp fr0)
2758 (inst fstp fr0)
2759 (inst fldd (make-random-tn :kind :normal
2760 :sc (sc-or-lose 'double-reg)
2761 :offset (- (tn-offset x) 2)))
2762 ;; Check the range
2763 (inst push #x3e947ae1) ; Constant 0.29
2764 (inst fabs)
2765 (inst fld (make-ea :dword :base esp-tn))
2766 (inst fcompp)
2767 (inst add esp-tn 4)
2768 (inst fnstsw) ; status word to ax
2769 (inst and ah-tn #x45)
2770 (inst jmp :z WITHIN-RANGE)
2771 ;; Out of range for fyl2xp1.
2772 (inst fld1)
2773 (inst faddd (make-random-tn :kind :normal
2774 :sc (sc-or-lose 'double-reg)
2775 :offset (- (tn-offset x) 1)))
2776 (inst fldln2)
2777 (inst fxch fr1)
2778 (inst fyl2x)
2779 (inst jmp DONE)
2781 WITHIN-RANGE
2782 (inst fldln2)
2783 (inst fldd (make-random-tn :kind :normal
2784 :sc (sc-or-lose 'double-reg)
2785 :offset (- (tn-offset x) 1)))
2786 (inst fyl2xp1)
2787 DONE
2788 (inst fld fr0)
2789 (case (tn-offset y)
2790 ((0 1))
2791 (t (inst fstd y)))))
2793 ;;; The Pentium has a less restricted implementation of the fyl2xp1
2794 ;;; instruction and a range check can be avoided.
2795 (define-vop (flog1p-pentium)
2796 (:translate %log1p)
2797 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2798 (:temporary (:sc double-reg :offset fr0-offset
2799 :from :argument :to :result) fr0)
2800 (:temporary (:sc double-reg :offset fr1-offset
2801 :from :argument :to :result) fr1)
2802 (:results (y :scs (double-reg)))
2803 (:arg-types double-float)
2804 (:result-types double-float)
2805 (:policy :fast-safe)
2806 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
2807 (:note "inline log1p with limited x range function")
2808 (:vop-var vop)
2809 (:save-p :compute-only)
2810 (:generator 4
2811 (note-this-location vop :internal-error)
2812 (sc-case x
2813 (double-reg
2814 (case (tn-offset x)
2816 ;; x is in fr0
2817 (inst fstp fr1)
2818 (inst fldln2)
2819 (inst fxch fr1))
2821 ;; x is in fr1
2822 (inst fstp fr0)
2823 (inst fldln2)
2824 (inst fxch fr1))
2826 ;; x is in a FP reg, not fr0 or fr1
2827 (inst fstp fr0)
2828 (inst fstp fr0)
2829 (inst fldln2)
2830 (inst fldd (make-random-tn :kind :normal
2831 :sc (sc-or-lose 'double-reg)
2832 :offset (1- (tn-offset x)))))))
2833 ((double-stack descriptor-reg)
2834 (inst fstp fr0)
2835 (inst fstp fr0)
2836 (inst fldln2)
2837 (if (sc-is x double-stack)
2838 (inst fldd (ea-for-df-stack x))
2839 (inst fldd (ea-for-df-desc x)))))
2840 (inst fyl2xp1)
2841 (inst fld fr0)
2842 (case (tn-offset y)
2843 ((0 1))
2844 (t (inst fstd y)))))
2846 (define-vop (flogb)
2847 (:translate %logb)
2848 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2849 (:temporary (:sc double-reg :offset fr0-offset
2850 :from :argument :to :result) fr0)
2851 (:temporary (:sc double-reg :offset fr1-offset
2852 :from :argument :to :result) fr1)
2853 (:results (y :scs (double-reg)))
2854 (:arg-types double-float)
2855 (:result-types double-float)
2856 (:policy :fast-safe)
2857 (:note "inline logb function")
2858 (:vop-var vop)
2859 (:save-p :compute-only)
2860 (:generator 5
2861 (note-this-location vop :internal-error)
2862 (sc-case x
2863 (double-reg
2864 (case (tn-offset x)
2866 ;; x is in fr0
2867 (inst fstp fr1))
2869 ;; x is in fr1
2870 (inst fstp fr0))
2872 ;; x is in a FP reg, not fr0 or fr1
2873 (inst fstp fr0)
2874 (inst fstp fr0)
2875 (inst fldd (make-random-tn :kind :normal
2876 :sc (sc-or-lose 'double-reg)
2877 :offset (- (tn-offset x) 2))))))
2878 ((double-stack descriptor-reg)
2879 (inst fstp fr0)
2880 (inst fstp fr0)
2881 (if (sc-is x double-stack)
2882 (inst fldd (ea-for-df-stack x))
2883 (inst fldd (ea-for-df-desc x)))))
2884 (inst fxtract)
2885 (case (tn-offset y)
2887 (inst fxch fr1))
2889 (t (inst fxch fr1)
2890 (inst fstd y)))))
2892 (define-vop (fatan)
2893 (:translate %atan)
2894 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
2895 (:temporary (:sc double-reg :offset fr0-offset
2896 :from (:argument 0) :to :result) fr0)
2897 (:temporary (:sc double-reg :offset fr1-offset
2898 :from (:argument 0) :to :result) fr1)
2899 (:results (r :scs (double-reg)))
2900 (:arg-types double-float)
2901 (:result-types double-float)
2902 (:policy :fast-safe)
2903 (:note "inline atan function")
2904 (:vop-var vop)
2905 (:save-p :compute-only)
2906 (:generator 5
2907 (note-this-location vop :internal-error)
2908 ;; Setup x in fr1 and 1.0 in fr0
2909 (cond
2910 ;; x in fr0
2911 ((and (sc-is x double-reg) (zerop (tn-offset x)))
2912 (inst fstp fr1))
2913 ;; x in fr1
2914 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2915 (inst fstp fr0))
2916 ;; x not in fr0 or fr1
2918 ;; Load x then 1.0
2919 (inst fstp fr0)
2920 (inst fstp fr0)
2921 (sc-case x
2922 (double-reg
2923 (inst fldd (make-random-tn :kind :normal
2924 :sc (sc-or-lose 'double-reg)
2925 :offset (- (tn-offset x) 2))))
2926 (double-stack
2927 (inst fldd (ea-for-df-stack x)))
2928 (descriptor-reg
2929 (inst fldd (ea-for-df-desc x))))))
2930 (inst fld1)
2931 ;; Now have x at fr1; and 1.0 at fr0
2932 (inst fpatan)
2933 (inst fld fr0)
2934 (case (tn-offset r)
2935 ((0 1))
2936 (t (inst fstd r)))))
2938 (define-vop (fatan2)
2939 (:translate %atan2)
2940 (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
2941 (y :scs (double-reg double-stack descriptor-reg) :target fr0))
2942 (:temporary (:sc double-reg :offset fr0-offset
2943 :from (:argument 1) :to :result) fr0)
2944 (:temporary (:sc double-reg :offset fr1-offset
2945 :from (:argument 0) :to :result) fr1)
2946 (:results (r :scs (double-reg)))
2947 (:arg-types double-float double-float)
2948 (:result-types double-float)
2949 (:policy :fast-safe)
2950 (:note "inline atan2 function")
2951 (:vop-var vop)
2952 (:save-p :compute-only)
2953 (:generator 5
2954 (note-this-location vop :internal-error)
2955 ;; Setup x in fr1 and y in fr0
2956 (cond
2957 ;; y in fr0; x in fr1
2958 ((and (sc-is y double-reg) (zerop (tn-offset y))
2959 (sc-is x double-reg) (= 1 (tn-offset x))))
2960 ;; x in fr1; y not in fr0
2961 ((and (sc-is x double-reg) (= 1 (tn-offset x)))
2962 ;; Load y to fr0
2963 (sc-case y
2964 (double-reg
2965 (copy-fp-reg-to-fr0 y))
2966 (double-stack
2967 (inst fstp fr0)
2968 (inst fldd (ea-for-df-stack y)))
2969 (descriptor-reg
2970 (inst fstp fr0)
2971 (inst fldd (ea-for-df-desc y)))))
2972 ((and (sc-is x double-reg) (zerop (tn-offset x))
2973 (sc-is y double-reg) (zerop (tn-offset x)))
2974 ;; copy x to fr1
2975 (inst fst fr1))
2976 ;; y in fr0; x not in fr1
2977 ((and (sc-is y double-reg) (zerop (tn-offset y)))
2978 (inst fxch fr1)
2979 ;; Now load x to fr0
2980 (sc-case x
2981 (double-reg
2982 (copy-fp-reg-to-fr0 x))
2983 (double-stack
2984 (inst fstp fr0)
2985 (inst fldd (ea-for-df-stack x)))
2986 (descriptor-reg
2987 (inst fstp fr0)
2988 (inst fldd (ea-for-df-desc x))))
2989 (inst fxch fr1))
2990 ;; y in fr1; x not in fr1
2991 ((and (sc-is y double-reg) (= 1 (tn-offset y)))
2992 ;; Load x to fr0
2993 (sc-case x
2994 (double-reg
2995 (copy-fp-reg-to-fr0 x))
2996 (double-stack
2997 (inst fstp fr0)
2998 (inst fldd (ea-for-df-stack x)))
2999 (descriptor-reg
3000 (inst fstp fr0)
3001 (inst fldd (ea-for-df-desc x))))
3002 (inst fxch fr1))
3003 ;; x in fr0;
3004 ((and (sc-is x double-reg) (zerop (tn-offset x)))
3005 (inst fxch fr1)
3006 ;; Now load y to fr0
3007 (sc-case y
3008 (double-reg
3009 (copy-fp-reg-to-fr0 y))
3010 (double-stack
3011 (inst fstp fr0)
3012 (inst fldd (ea-for-df-stack y)))
3013 (descriptor-reg
3014 (inst fstp fr0)
3015 (inst fldd (ea-for-df-desc y)))))
3016 ;; Neither y or x are in either fr0 or fr1
3018 ;; Load x then y
3019 (inst fstp fr0)
3020 (inst fstp fr0)
3021 (sc-case x
3022 (double-reg
3023 (inst fldd (make-random-tn :kind :normal
3024 :sc (sc-or-lose 'double-reg)
3025 :offset (- (tn-offset x) 2))))
3026 (double-stack
3027 (inst fldd (ea-for-df-stack x)))
3028 (descriptor-reg
3029 (inst fldd (ea-for-df-desc x))))
3030 ;; Load y to fr0
3031 (sc-case y
3032 (double-reg
3033 (inst fldd (make-random-tn :kind :normal
3034 :sc (sc-or-lose 'double-reg)
3035 :offset (1- (tn-offset y)))))
3036 (double-stack
3037 (inst fldd (ea-for-df-stack y)))
3038 (descriptor-reg
3039 (inst fldd (ea-for-df-desc y))))))
3041 ;; Now have y at fr0; and x at fr1
3042 (inst fpatan)
3043 (inst fld fr0)
3044 (case (tn-offset r)
3045 ((0 1))
3046 (t (inst fstd r)))))
3047 ) ; PROGN #!-LONG-FLOAT
3049 #!+long-float
3050 (progn
3052 ;;; Lets use some of the 80387 special functions.
3054 ;;; These defs will not take effect unless code/irrat.lisp is modified
3055 ;;; to remove the inlined alien routine def.
3057 (macrolet ((frob (func trans op)
3058 `(define-vop (,func)
3059 (:args (x :scs (long-reg) :target fr0))
3060 (:temporary (:sc long-reg :offset fr0-offset
3061 :from :argument :to :result) fr0)
3062 (:ignore fr0)
3063 (:results (y :scs (long-reg)))
3064 (:arg-types long-float)
3065 (:result-types long-float)
3066 (:translate ,trans)
3067 (:policy :fast-safe)
3068 (:note "inline NPX function")
3069 (:vop-var vop)
3070 (:save-p :compute-only)
3071 (:node-var node)
3072 (:generator 5
3073 (note-this-location vop :internal-error)
3074 (unless (zerop (tn-offset x))
3075 (inst fxch x) ; x to top of stack
3076 (unless (location= x y)
3077 (inst fst x))) ; maybe save it
3078 (inst ,op) ; clobber st0
3079 (cond ((zerop (tn-offset y))
3080 (maybe-fp-wait node))
3082 (inst fst y)))))))
3084 ;; Quick versions of FSIN and FCOS that require the argument to be
3085 ;; within range 2^63.
3086 (frob fsin-quick %sin-quick fsin)
3087 (frob fcos-quick %cos-quick fcos)
3088 (frob fsqrt %sqrt fsqrt))
3090 ;;; Quick version of ftan that requires the argument to be within
3091 ;;; range 2^63.
3092 (define-vop (ftan-quick)
3093 (:translate %tan-quick)
3094 (:args (x :scs (long-reg) :target fr0))
3095 (:temporary (:sc long-reg :offset fr0-offset
3096 :from :argument :to :result) fr0)
3097 (:temporary (:sc long-reg :offset fr1-offset
3098 :from :argument :to :result) fr1)
3099 (:results (y :scs (long-reg)))
3100 (:arg-types long-float)
3101 (:result-types long-float)
3102 (:policy :fast-safe)
3103 (:note "inline tan function")
3104 (:vop-var vop)
3105 (:save-p :compute-only)
3106 (:generator 5
3107 (note-this-location vop :internal-error)
3108 (case (tn-offset x)
3110 (inst fstp fr1))
3112 (inst fstp fr0))
3114 (inst fstp fr0)
3115 (inst fstp fr0)
3116 (inst fldd (make-random-tn :kind :normal
3117 :sc (sc-or-lose 'double-reg)
3118 :offset (- (tn-offset x) 2)))))
3119 (inst fptan)
3120 ;; Result is in fr1
3121 (case (tn-offset y)
3123 (inst fxch fr1))
3126 (inst fxch fr1)
3127 (inst fstd y)))))
3129 ;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
3130 ;;; the argument is out of range 2^63 and would thus be hopelessly
3131 ;;; inaccurate.
3132 (macrolet ((frob (func trans op)
3133 `(define-vop (,func)
3134 (:translate ,trans)
3135 (:args (x :scs (long-reg) :target fr0))
3136 (:temporary (:sc long-reg :offset fr0-offset
3137 :from :argument :to :result) fr0)
3138 (:temporary (:sc unsigned-reg :offset eax-offset
3139 :from :argument :to :result) eax)
3140 (:results (y :scs (long-reg)))
3141 (:arg-types long-float)
3142 (:result-types long-float)
3143 (:policy :fast-safe)
3144 (:note "inline sin/cos function")
3145 (:vop-var vop)
3146 (:save-p :compute-only)
3147 (:ignore eax)
3148 (:generator 5
3149 (note-this-location vop :internal-error)
3150 (unless (zerop (tn-offset x))
3151 (inst fxch x) ; x to top of stack
3152 (unless (location= x y)
3153 (inst fst x))) ; maybe save it
3154 (inst ,op)
3155 (inst fnstsw) ; status word to ax
3156 (inst and ah-tn #x04) ; C2
3157 (inst jmp :z DONE)
3158 ;; Else x was out of range so reduce it; ST0 is unchanged.
3159 (inst fstp fr0) ; Load 0.0
3160 (inst fldz)
3161 DONE
3162 (unless (zerop (tn-offset y))
3163 (inst fstd y))))))
3164 (frob fsin %sin fsin)
3165 (frob fcos %cos fcos))
3167 (define-vop (ftan)
3168 (:translate %tan)
3169 (:args (x :scs (long-reg) :target fr0))
3170 (:temporary (:sc long-reg :offset fr0-offset
3171 :from :argument :to :result) fr0)
3172 (:temporary (:sc long-reg :offset fr1-offset
3173 :from :argument :to :result) fr1)
3174 (:temporary (:sc unsigned-reg :offset eax-offset
3175 :from :argument :to :result) eax)
3176 (:results (y :scs (long-reg)))
3177 (:arg-types long-float)
3178 (:result-types long-float)
3179 (:ignore eax)
3180 (:policy :fast-safe)
3181 (:note "inline tan function")
3182 (:vop-var vop)
3183 (:save-p :compute-only)
3184 (:ignore eax)
3185 (:generator 5
3186 (note-this-location vop :internal-error)
3187 (case (tn-offset x)
3189 (inst fstp fr1))
3191 (inst fstp fr0))
3193 (inst fstp fr0)
3194 (inst fstp fr0)
3195 (inst fldd (make-random-tn :kind :normal
3196 :sc (sc-or-lose 'double-reg)
3197 :offset (- (tn-offset x) 2)))))
3198 (inst fptan)
3199 (inst fnstsw) ; status word to ax
3200 (inst and ah-tn #x04) ; C2
3201 (inst jmp :z DONE)
3202 ;; Else x was out of range so reduce it; ST0 is unchanged.
3203 (inst fldz) ; Load 0.0
3204 (inst fxch fr1)
3205 DONE
3206 ;; Result is in fr1
3207 (case (tn-offset y)
3209 (inst fxch fr1))
3212 (inst fxch fr1)
3213 (inst fstd y)))))
3215 ;;; Modified exp that handles the following special cases:
3216 ;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
3217 (define-vop (fexp)
3218 (:translate %exp)
3219 (:args (x :scs (long-reg) :target fr0))
3220 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3221 (:temporary (:sc long-reg :offset fr0-offset
3222 :from :argument :to :result) fr0)
3223 (:temporary (:sc long-reg :offset fr1-offset
3224 :from :argument :to :result) fr1)
3225 (:temporary (:sc long-reg :offset fr2-offset
3226 :from :argument :to :result) fr2)
3227 (:results (y :scs (long-reg)))
3228 (:arg-types long-float)
3229 (:result-types long-float)
3230 (:policy :fast-safe)
3231 (:note "inline exp function")
3232 (:vop-var vop)
3233 (:save-p :compute-only)
3234 (:ignore temp)
3235 (:generator 5
3236 (note-this-location vop :internal-error)
3237 (unless (zerop (tn-offset x))
3238 (inst fxch x) ; x to top of stack
3239 (unless (location= x y)
3240 (inst fst x))) ; maybe save it
3241 ;; Check for Inf or NaN
3242 (inst fxam)
3243 (inst fnstsw)
3244 (inst sahf)
3245 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3246 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3247 (inst and ah-tn #x02) ; Test sign of Inf.
3248 (inst jmp :z DONE) ; +Inf gives +Inf.
3249 (inst fstp fr0) ; -Inf gives 0
3250 (inst fldz)
3251 (inst jmp-short DONE)
3252 NOINFNAN
3253 (inst fstp fr1)
3254 (inst fldl2e)
3255 (inst fmul fr1)
3256 ;; Now fr0=x log2(e)
3257 (inst fst fr1)
3258 (inst frndint)
3259 (inst fst fr2)
3260 (inst fsubp-sti fr1)
3261 (inst f2xm1)
3262 (inst fld1)
3263 (inst faddp-sti fr1)
3264 (inst fscale)
3265 (inst fld fr0)
3266 DONE
3267 (unless (zerop (tn-offset y))
3268 (inst fstd y))))
3270 ;;; Expm1 = exp(x) - 1.
3271 ;;; Handles the following special cases:
3272 ;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
3273 (define-vop (fexpm1)
3274 (:translate %expm1)
3275 (:args (x :scs (long-reg) :target fr0))
3276 (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
3277 (:temporary (:sc long-reg :offset fr0-offset
3278 :from :argument :to :result) fr0)
3279 (:temporary (:sc long-reg :offset fr1-offset
3280 :from :argument :to :result) fr1)
3281 (:temporary (:sc long-reg :offset fr2-offset
3282 :from :argument :to :result) fr2)
3283 (:results (y :scs (long-reg)))
3284 (:arg-types long-float)
3285 (:result-types long-float)
3286 (:policy :fast-safe)
3287 (:note "inline expm1 function")
3288 (:vop-var vop)
3289 (:save-p :compute-only)
3290 (:ignore temp)
3291 (:generator 5
3292 (note-this-location vop :internal-error)
3293 (unless (zerop (tn-offset x))
3294 (inst fxch x) ; x to top of stack
3295 (unless (location= x y)
3296 (inst fst x))) ; maybe save it
3297 ;; Check for Inf or NaN
3298 (inst fxam)
3299 (inst fnstsw)
3300 (inst sahf)
3301 (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
3302 (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
3303 (inst and ah-tn #x02) ; Test sign of Inf.
3304 (inst jmp :z DONE) ; +Inf gives +Inf.
3305 (inst fstp fr0) ; -Inf gives -1.0
3306 (inst fld1)
3307 (inst fchs)
3308 (inst jmp-short DONE)
3309 NOINFNAN
3310 ;; Free two stack slots leaving the argument on top.
3311 (inst fstp fr2)
3312 (inst fstp fr0)
3313 (inst fldl2e)
3314 (inst fmul fr1) ; Now fr0 = x log2(e)
3315 (inst fst fr1)
3316 (inst frndint)
3317 (inst fsub-sti fr1)
3318 (inst fxch fr1)
3319 (inst f2xm1)
3320 (inst fscale)
3321 (inst fxch fr1)
3322 (inst fld1)
3323 (inst fscale)
3324 (inst fstp fr1)
3325 (inst fld1)
3326 (inst fsub fr1)
3327 (inst fsubr fr2)
3328 DONE
3329 (unless (zerop (tn-offset y))
3330 (inst fstd y))))
3332 (define-vop (flog)
3333 (:translate %log)
3334 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3335 (:temporary (:sc long-reg :offset fr0-offset
3336 :from :argument :to :result) fr0)
3337 (:temporary (:sc long-reg :offset fr1-offset
3338 :from :argument :to :result) fr1)
3339 (:results (y :scs (long-reg)))
3340 (:arg-types long-float)
3341 (:result-types long-float)
3342 (:policy :fast-safe)
3343 (:note "inline log function")
3344 (:vop-var vop)
3345 (:save-p :compute-only)
3346 (:generator 5
3347 (note-this-location vop :internal-error)
3348 (sc-case x
3349 (long-reg
3350 (case (tn-offset x)
3352 ;; x is in fr0
3353 (inst fstp fr1)
3354 (inst fldln2)
3355 (inst fxch fr1))
3357 ;; x is in fr1
3358 (inst fstp fr0)
3359 (inst fldln2)
3360 (inst fxch fr1))
3362 ;; x is in a FP reg, not fr0 or fr1
3363 (inst fstp fr0)
3364 (inst fstp fr0)
3365 (inst fldln2)
3366 (inst fldd (make-random-tn :kind :normal
3367 :sc (sc-or-lose 'double-reg)
3368 :offset (1- (tn-offset x))))))
3369 (inst fyl2x))
3370 ((long-stack descriptor-reg)
3371 (inst fstp fr0)
3372 (inst fstp fr0)
3373 (inst fldln2)
3374 (if (sc-is x long-stack)
3375 (inst fldl (ea-for-lf-stack x))
3376 (inst fldl (ea-for-lf-desc x)))
3377 (inst fyl2x)))
3378 (inst fld fr0)
3379 (case (tn-offset y)
3380 ((0 1))
3381 (t (inst fstd y)))))
3383 (define-vop (flog10)
3384 (:translate %log10)
3385 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3386 (:temporary (:sc long-reg :offset fr0-offset
3387 :from :argument :to :result) fr0)
3388 (:temporary (:sc long-reg :offset fr1-offset
3389 :from :argument :to :result) fr1)
3390 (:results (y :scs (long-reg)))
3391 (:arg-types long-float)
3392 (:result-types long-float)
3393 (:policy :fast-safe)
3394 (:note "inline log10 function")
3395 (:vop-var vop)
3396 (:save-p :compute-only)
3397 (:generator 5
3398 (note-this-location vop :internal-error)
3399 (sc-case x
3400 (long-reg
3401 (case (tn-offset x)
3403 ;; x is in fr0
3404 (inst fstp fr1)
3405 (inst fldlg2)
3406 (inst fxch fr1))
3408 ;; x is in fr1
3409 (inst fstp fr0)
3410 (inst fldlg2)
3411 (inst fxch fr1))
3413 ;; x is in a FP reg, not fr0 or fr1
3414 (inst fstp fr0)
3415 (inst fstp fr0)
3416 (inst fldlg2)
3417 (inst fldd (make-random-tn :kind :normal
3418 :sc (sc-or-lose 'double-reg)
3419 :offset (1- (tn-offset x))))))
3420 (inst fyl2x))
3421 ((long-stack descriptor-reg)
3422 (inst fstp fr0)
3423 (inst fstp fr0)
3424 (inst fldlg2)
3425 (if (sc-is x long-stack)
3426 (inst fldl (ea-for-lf-stack x))
3427 (inst fldl (ea-for-lf-desc x)))
3428 (inst fyl2x)))
3429 (inst fld fr0)
3430 (case (tn-offset y)
3431 ((0 1))
3432 (t (inst fstd y)))))
3434 (define-vop (fpow)
3435 (:translate %pow)
3436 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3437 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3438 (:temporary (:sc long-reg :offset fr0-offset
3439 :from (:argument 0) :to :result) fr0)
3440 (:temporary (:sc long-reg :offset fr1-offset
3441 :from (:argument 1) :to :result) fr1)
3442 (:temporary (:sc long-reg :offset fr2-offset
3443 :from :load :to :result) fr2)
3444 (:results (r :scs (long-reg)))
3445 (:arg-types long-float long-float)
3446 (:result-types long-float)
3447 (:policy :fast-safe)
3448 (:note "inline pow function")
3449 (:vop-var vop)
3450 (:save-p :compute-only)
3451 (:generator 5
3452 (note-this-location vop :internal-error)
3453 ;; Setup x in fr0 and y in fr1
3454 (cond
3455 ;; x in fr0; y in fr1
3456 ((and (sc-is x long-reg) (zerop (tn-offset x))
3457 (sc-is y long-reg) (= 1 (tn-offset y))))
3458 ;; y in fr1; x not in fr0
3459 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3460 ;; Load x to fr0
3461 (sc-case x
3462 (long-reg
3463 (copy-fp-reg-to-fr0 x))
3464 (long-stack
3465 (inst fstp fr0)
3466 (inst fldl (ea-for-lf-stack x)))
3467 (descriptor-reg
3468 (inst fstp fr0)
3469 (inst fldl (ea-for-lf-desc x)))))
3470 ;; x in fr0; y not in fr1
3471 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3472 (inst fxch fr1)
3473 ;; Now load y to fr0
3474 (sc-case y
3475 (long-reg
3476 (copy-fp-reg-to-fr0 y))
3477 (long-stack
3478 (inst fstp fr0)
3479 (inst fldl (ea-for-lf-stack y)))
3480 (descriptor-reg
3481 (inst fstp fr0)
3482 (inst fldl (ea-for-lf-desc y))))
3483 (inst fxch fr1))
3484 ;; x in fr1; y not in fr1
3485 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3486 ;; Load y to fr0
3487 (sc-case y
3488 (long-reg
3489 (copy-fp-reg-to-fr0 y))
3490 (long-stack
3491 (inst fstp fr0)
3492 (inst fldl (ea-for-lf-stack y)))
3493 (descriptor-reg
3494 (inst fstp fr0)
3495 (inst fldl (ea-for-lf-desc y))))
3496 (inst fxch fr1))
3497 ;; y in fr0;
3498 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3499 (inst fxch fr1)
3500 ;; Now load x to fr0
3501 (sc-case x
3502 (long-reg
3503 (copy-fp-reg-to-fr0 x))
3504 (long-stack
3505 (inst fstp fr0)
3506 (inst fldl (ea-for-lf-stack x)))
3507 (descriptor-reg
3508 (inst fstp fr0)
3509 (inst fldl (ea-for-lf-desc x)))))
3510 ;; Neither x or y are in either fr0 or fr1
3512 ;; Load y then x
3513 (inst fstp fr0)
3514 (inst fstp fr0)
3515 (sc-case y
3516 (long-reg
3517 (inst fldd (make-random-tn :kind :normal
3518 :sc (sc-or-lose 'double-reg)
3519 :offset (- (tn-offset y) 2))))
3520 (long-stack
3521 (inst fldl (ea-for-lf-stack y)))
3522 (descriptor-reg
3523 (inst fldl (ea-for-lf-desc y))))
3524 ;; Load x to fr0
3525 (sc-case x
3526 (long-reg
3527 (inst fldd (make-random-tn :kind :normal
3528 :sc (sc-or-lose 'double-reg)
3529 :offset (1- (tn-offset x)))))
3530 (long-stack
3531 (inst fldl (ea-for-lf-stack x)))
3532 (descriptor-reg
3533 (inst fldl (ea-for-lf-desc x))))))
3535 ;; Now have x at fr0; and y at fr1
3536 (inst fyl2x)
3537 ;; Now fr0=y log2(x)
3538 (inst fld fr0)
3539 (inst frndint)
3540 (inst fst fr2)
3541 (inst fsubp-sti fr1)
3542 (inst f2xm1)
3543 (inst fld1)
3544 (inst faddp-sti fr1)
3545 (inst fscale)
3546 (inst fld fr0)
3547 (case (tn-offset r)
3548 ((0 1))
3549 (t (inst fstd r)))))
3551 (define-vop (fscalen)
3552 (:translate %scalbn)
3553 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3554 (y :scs (signed-stack signed-reg) :target temp))
3555 (:temporary (:sc long-reg :offset fr0-offset
3556 :from (:argument 0) :to :result) fr0)
3557 (:temporary (:sc long-reg :offset fr1-offset :from :eval :to :result) fr1)
3558 (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
3559 (:results (r :scs (long-reg)))
3560 (:arg-types long-float signed-num)
3561 (:result-types long-float)
3562 (:policy :fast-safe)
3563 (:note "inline scalbn function")
3564 (:generator 5
3565 ;; Setup x in fr0 and y in fr1
3566 (sc-case x
3567 (long-reg
3568 (case (tn-offset x)
3570 (inst fstp fr1)
3571 (sc-case y
3572 (signed-reg
3573 (inst mov temp y)
3574 (inst fild temp))
3575 (signed-stack
3576 (inst fild y)))
3577 (inst fxch fr1))
3579 (inst fstp fr0)
3580 (sc-case y
3581 (signed-reg
3582 (inst mov temp y)
3583 (inst fild temp))
3584 (signed-stack
3585 (inst fild y)))
3586 (inst fxch fr1))
3588 (inst fstp fr0)
3589 (inst fstp fr0)
3590 (sc-case y
3591 (signed-reg
3592 (inst mov temp y)
3593 (inst fild temp))
3594 (signed-stack
3595 (inst fild y)))
3596 (inst fld (make-random-tn :kind :normal
3597 :sc (sc-or-lose 'double-reg)
3598 :offset (1- (tn-offset x)))))))
3599 ((long-stack descriptor-reg)
3600 (inst fstp fr0)
3601 (inst fstp fr0)
3602 (sc-case y
3603 (signed-reg
3604 (inst mov temp y)
3605 (inst fild temp))
3606 (signed-stack
3607 (inst fild y)))
3608 (if (sc-is x long-stack)
3609 (inst fldl (ea-for-lf-stack x))
3610 (inst fldl (ea-for-lf-desc x)))))
3611 (inst fscale)
3612 (unless (zerop (tn-offset r))
3613 (inst fstd r))))
3615 (define-vop (fscale)
3616 (:translate %scalb)
3617 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0)
3618 (y :scs (long-reg long-stack descriptor-reg) :target fr1))
3619 (:temporary (:sc long-reg :offset fr0-offset
3620 :from (:argument 0) :to :result) fr0)
3621 (:temporary (:sc long-reg :offset fr1-offset
3622 :from (:argument 1) :to :result) fr1)
3623 (:results (r :scs (long-reg)))
3624 (:arg-types long-float long-float)
3625 (:result-types long-float)
3626 (:policy :fast-safe)
3627 (:note "inline scalb function")
3628 (:vop-var vop)
3629 (:save-p :compute-only)
3630 (:generator 5
3631 (note-this-location vop :internal-error)
3632 ;; Setup x in fr0 and y in fr1
3633 (cond
3634 ;; x in fr0; y in fr1
3635 ((and (sc-is x long-reg) (zerop (tn-offset x))
3636 (sc-is y long-reg) (= 1 (tn-offset y))))
3637 ;; y in fr1; x not in fr0
3638 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3639 ;; Load x to fr0
3640 (sc-case x
3641 (long-reg
3642 (copy-fp-reg-to-fr0 x))
3643 (long-stack
3644 (inst fstp fr0)
3645 (inst fldl (ea-for-lf-stack x)))
3646 (descriptor-reg
3647 (inst fstp fr0)
3648 (inst fldl (ea-for-lf-desc x)))))
3649 ;; x in fr0; y not in fr1
3650 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3651 (inst fxch fr1)
3652 ;; Now load y to fr0
3653 (sc-case y
3654 (long-reg
3655 (copy-fp-reg-to-fr0 y))
3656 (long-stack
3657 (inst fstp fr0)
3658 (inst fldl (ea-for-lf-stack y)))
3659 (descriptor-reg
3660 (inst fstp fr0)
3661 (inst fldl (ea-for-lf-desc y))))
3662 (inst fxch fr1))
3663 ;; x in fr1; y not in fr1
3664 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3665 ;; Load y to fr0
3666 (sc-case y
3667 (long-reg
3668 (copy-fp-reg-to-fr0 y))
3669 (long-stack
3670 (inst fstp fr0)
3671 (inst fldl (ea-for-lf-stack y)))
3672 (descriptor-reg
3673 (inst fstp fr0)
3674 (inst fldl (ea-for-lf-desc y))))
3675 (inst fxch fr1))
3676 ;; y in fr0;
3677 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3678 (inst fxch fr1)
3679 ;; Now load x to fr0
3680 (sc-case x
3681 (long-reg
3682 (copy-fp-reg-to-fr0 x))
3683 (long-stack
3684 (inst fstp fr0)
3685 (inst fldl (ea-for-lf-stack x)))
3686 (descriptor-reg
3687 (inst fstp fr0)
3688 (inst fldl (ea-for-lf-desc x)))))
3689 ;; Neither x or y are in either fr0 or fr1
3691 ;; Load y then x
3692 (inst fstp fr0)
3693 (inst fstp fr0)
3694 (sc-case y
3695 (long-reg
3696 (inst fldd (make-random-tn :kind :normal
3697 :sc (sc-or-lose 'double-reg)
3698 :offset (- (tn-offset y) 2))))
3699 (long-stack
3700 (inst fldl (ea-for-lf-stack y)))
3701 (descriptor-reg
3702 (inst fldl (ea-for-lf-desc y))))
3703 ;; Load x to fr0
3704 (sc-case x
3705 (long-reg
3706 (inst fldd (make-random-tn :kind :normal
3707 :sc (sc-or-lose 'double-reg)
3708 :offset (1- (tn-offset x)))))
3709 (long-stack
3710 (inst fldl (ea-for-lf-stack x)))
3711 (descriptor-reg
3712 (inst fldl (ea-for-lf-desc x))))))
3714 ;; Now have x at fr0; and y at fr1
3715 (inst fscale)
3716 (unless (zerop (tn-offset r))
3717 (inst fstd r))))
3719 (define-vop (flog1p)
3720 (:translate %log1p)
3721 (:args (x :scs (long-reg) :to :result))
3722 (:temporary (:sc long-reg :offset fr0-offset
3723 :from :argument :to :result) fr0)
3724 (:temporary (:sc long-reg :offset fr1-offset
3725 :from :argument :to :result) fr1)
3726 (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
3727 (:results (y :scs (long-reg)))
3728 (:arg-types long-float)
3729 (:result-types long-float)
3730 (:policy :fast-safe)
3731 ;; FIXME 1: This appears to be the second DEFINE-VOP of FLOG1P.
3732 ;; Perhaps this is OK because of the #!+LONG-FLOAT wrapped around
3733 ;; an enormous PROGN above. Still, it would be probably be good to
3734 ;; add some code to warn about redefining VOPs.
3735 (:note "inline log1p function")
3736 (:ignore temp)
3737 (:generator 5
3738 ;; x is in a FP reg, not fr0, fr1.
3739 (inst fstp fr0)
3740 (inst fstp fr0)
3741 (inst fldd (make-random-tn :kind :normal
3742 :sc (sc-or-lose 'double-reg)
3743 :offset (- (tn-offset x) 2)))
3744 ;; Check the range
3745 (inst push #x3e947ae1) ; Constant 0.29
3746 (inst fabs)
3747 (inst fld (make-ea :dword :base esp-tn))
3748 (inst fcompp)
3749 (inst add esp-tn 4)
3750 (inst fnstsw) ; status word to ax
3751 (inst and ah-tn #x45)
3752 (inst jmp :z WITHIN-RANGE)
3753 ;; Out of range for fyl2xp1.
3754 (inst fld1)
3755 (inst faddd (make-random-tn :kind :normal
3756 :sc (sc-or-lose 'double-reg)
3757 :offset (- (tn-offset x) 1)))
3758 (inst fldln2)
3759 (inst fxch fr1)
3760 (inst fyl2x)
3761 (inst jmp DONE)
3763 WITHIN-RANGE
3764 (inst fldln2)
3765 (inst fldd (make-random-tn :kind :normal
3766 :sc (sc-or-lose 'double-reg)
3767 :offset (- (tn-offset x) 1)))
3768 (inst fyl2xp1)
3769 DONE
3770 (inst fld fr0)
3771 (case (tn-offset y)
3772 ((0 1))
3773 (t (inst fstd y)))))
3775 ;;; The Pentium has a less restricted implementation of the fyl2xp1
3776 ;;; instruction and a range check can be avoided.
3777 (define-vop (flog1p-pentium)
3778 (:translate %log1p)
3779 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3780 (:temporary (:sc long-reg :offset fr0-offset
3781 :from :argument :to :result) fr0)
3782 (:temporary (:sc long-reg :offset fr1-offset
3783 :from :argument :to :result) fr1)
3784 (:results (y :scs (long-reg)))
3785 (:arg-types long-float)
3786 (:result-types long-float)
3787 (:policy :fast-safe)
3788 (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
3789 (:note "inline log1p function")
3790 (:generator 5
3791 (sc-case x
3792 (long-reg
3793 (case (tn-offset x)
3795 ;; x is in fr0
3796 (inst fstp fr1)
3797 (inst fldln2)
3798 (inst fxch fr1))
3800 ;; x is in fr1
3801 (inst fstp fr0)
3802 (inst fldln2)
3803 (inst fxch fr1))
3805 ;; x is in a FP reg, not fr0 or fr1
3806 (inst fstp fr0)
3807 (inst fstp fr0)
3808 (inst fldln2)
3809 (inst fldd (make-random-tn :kind :normal
3810 :sc (sc-or-lose 'double-reg)
3811 :offset (1- (tn-offset x)))))))
3812 ((long-stack descriptor-reg)
3813 (inst fstp fr0)
3814 (inst fstp fr0)
3815 (inst fldln2)
3816 (if (sc-is x long-stack)
3817 (inst fldl (ea-for-lf-stack x))
3818 (inst fldl (ea-for-lf-desc x)))))
3819 (inst fyl2xp1)
3820 (inst fld fr0)
3821 (case (tn-offset y)
3822 ((0 1))
3823 (t (inst fstd y)))))
3825 (define-vop (flogb)
3826 (:translate %logb)
3827 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3828 (:temporary (:sc long-reg :offset fr0-offset
3829 :from :argument :to :result) fr0)
3830 (:temporary (:sc long-reg :offset fr1-offset
3831 :from :argument :to :result) fr1)
3832 (:results (y :scs (long-reg)))
3833 (:arg-types long-float)
3834 (:result-types long-float)
3835 (:policy :fast-safe)
3836 (:note "inline logb function")
3837 (:vop-var vop)
3838 (:save-p :compute-only)
3839 (:generator 5
3840 (note-this-location vop :internal-error)
3841 (sc-case x
3842 (long-reg
3843 (case (tn-offset x)
3845 ;; x is in fr0
3846 (inst fstp fr1))
3848 ;; x is in fr1
3849 (inst fstp fr0))
3851 ;; x is in a FP reg, not fr0 or fr1
3852 (inst fstp fr0)
3853 (inst fstp fr0)
3854 (inst fldd (make-random-tn :kind :normal
3855 :sc (sc-or-lose 'double-reg)
3856 :offset (- (tn-offset x) 2))))))
3857 ((long-stack descriptor-reg)
3858 (inst fstp fr0)
3859 (inst fstp fr0)
3860 (if (sc-is x long-stack)
3861 (inst fldl (ea-for-lf-stack x))
3862 (inst fldl (ea-for-lf-desc x)))))
3863 (inst fxtract)
3864 (case (tn-offset y)
3866 (inst fxch fr1))
3868 (t (inst fxch fr1)
3869 (inst fstd y)))))
3871 (define-vop (fatan)
3872 (:translate %atan)
3873 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr0))
3874 (:temporary (:sc long-reg :offset fr0-offset
3875 :from (:argument 0) :to :result) fr0)
3876 (:temporary (:sc long-reg :offset fr1-offset
3877 :from (:argument 0) :to :result) fr1)
3878 (:results (r :scs (long-reg)))
3879 (:arg-types long-float)
3880 (:result-types long-float)
3881 (:policy :fast-safe)
3882 (:note "inline atan function")
3883 (:vop-var vop)
3884 (:save-p :compute-only)
3885 (:generator 5
3886 (note-this-location vop :internal-error)
3887 ;; Setup x in fr1 and 1.0 in fr0
3888 (cond
3889 ;; x in fr0
3890 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3891 (inst fstp fr1))
3892 ;; x in fr1
3893 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3894 (inst fstp fr0))
3895 ;; x not in fr0 or fr1
3897 ;; Load x then 1.0
3898 (inst fstp fr0)
3899 (inst fstp fr0)
3900 (sc-case x
3901 (long-reg
3902 (inst fldd (make-random-tn :kind :normal
3903 :sc (sc-or-lose 'double-reg)
3904 :offset (- (tn-offset x) 2))))
3905 (long-stack
3906 (inst fldl (ea-for-lf-stack x)))
3907 (descriptor-reg
3908 (inst fldl (ea-for-lf-desc x))))))
3909 (inst fld1)
3910 ;; Now have x at fr1; and 1.0 at fr0
3911 (inst fpatan)
3912 (inst fld fr0)
3913 (case (tn-offset r)
3914 ((0 1))
3915 (t (inst fstd r)))))
3917 (define-vop (fatan2)
3918 (:translate %atan2)
3919 (:args (x :scs (long-reg long-stack descriptor-reg) :target fr1)
3920 (y :scs (long-reg long-stack descriptor-reg) :target fr0))
3921 (:temporary (:sc long-reg :offset fr0-offset
3922 :from (:argument 1) :to :result) fr0)
3923 (:temporary (:sc long-reg :offset fr1-offset
3924 :from (:argument 0) :to :result) fr1)
3925 (:results (r :scs (long-reg)))
3926 (:arg-types long-float long-float)
3927 (:result-types long-float)
3928 (:policy :fast-safe)
3929 (:note "inline atan2 function")
3930 (:vop-var vop)
3931 (:save-p :compute-only)
3932 (:generator 5
3933 (note-this-location vop :internal-error)
3934 ;; Setup x in fr1 and y in fr0
3935 (cond
3936 ;; y in fr0; x in fr1
3937 ((and (sc-is y long-reg) (zerop (tn-offset y))
3938 (sc-is x long-reg) (= 1 (tn-offset x))))
3939 ;; x in fr1; y not in fr0
3940 ((and (sc-is x long-reg) (= 1 (tn-offset x)))
3941 ;; Load y to fr0
3942 (sc-case y
3943 (long-reg
3944 (copy-fp-reg-to-fr0 y))
3945 (long-stack
3946 (inst fstp fr0)
3947 (inst fldl (ea-for-lf-stack y)))
3948 (descriptor-reg
3949 (inst fstp fr0)
3950 (inst fldl (ea-for-lf-desc y)))))
3951 ;; y in fr0; x not in fr1
3952 ((and (sc-is y long-reg) (zerop (tn-offset y)))
3953 (inst fxch fr1)
3954 ;; Now load x to fr0
3955 (sc-case x
3956 (long-reg
3957 (copy-fp-reg-to-fr0 x))
3958 (long-stack
3959 (inst fstp fr0)
3960 (inst fldl (ea-for-lf-stack x)))
3961 (descriptor-reg
3962 (inst fstp fr0)
3963 (inst fldl (ea-for-lf-desc x))))
3964 (inst fxch fr1))
3965 ;; y in fr1; x not in fr1
3966 ((and (sc-is y long-reg) (= 1 (tn-offset y)))
3967 ;; Load x to fr0
3968 (sc-case x
3969 (long-reg
3970 (copy-fp-reg-to-fr0 x))
3971 (long-stack
3972 (inst fstp fr0)
3973 (inst fldl (ea-for-lf-stack x)))
3974 (descriptor-reg
3975 (inst fstp fr0)
3976 (inst fldl (ea-for-lf-desc x))))
3977 (inst fxch fr1))
3978 ;; x in fr0;
3979 ((and (sc-is x long-reg) (zerop (tn-offset x)))
3980 (inst fxch fr1)
3981 ;; Now load y to fr0
3982 (sc-case y
3983 (long-reg
3984 (copy-fp-reg-to-fr0 y))
3985 (long-stack
3986 (inst fstp fr0)
3987 (inst fldl (ea-for-lf-stack y)))
3988 (descriptor-reg
3989 (inst fstp fr0)
3990 (inst fldl (ea-for-lf-desc y)))))
3991 ;; Neither y or x are in either fr0 or fr1
3993 ;; Load x then y
3994 (inst fstp fr0)
3995 (inst fstp fr0)
3996 (sc-case x
3997 (long-reg
3998 (inst fldd (make-random-tn :kind :normal
3999 :sc (sc-or-lose 'double-reg)
4000 :offset (- (tn-offset x) 2))))
4001 (long-stack
4002 (inst fldl (ea-for-lf-stack x)))
4003 (descriptor-reg
4004 (inst fldl (ea-for-lf-desc x))))
4005 ;; Load y to fr0
4006 (sc-case y
4007 (long-reg
4008 (inst fldd (make-random-tn :kind :normal
4009 :sc (sc-or-lose 'double-reg)
4010 :offset (1- (tn-offset y)))))
4011 (long-stack
4012 (inst fldl (ea-for-lf-stack y)))
4013 (descriptor-reg
4014 (inst fldl (ea-for-lf-desc y))))))
4016 ;; Now have y at fr0; and x at fr1
4017 (inst fpatan)
4018 (inst fld fr0)
4019 (case (tn-offset r)
4020 ((0 1))
4021 (t (inst fstd r)))))
4023 ) ; PROGN #!+LONG-FLOAT
4025 ;;;; complex float VOPs
4027 (define-vop (make-complex-single-float)
4028 (:translate complex)
4029 (:args (real :scs (single-reg) :to :result :target r
4030 :load-if (not (location= real r)))
4031 (imag :scs (single-reg) :to :save))
4032 (:arg-types single-float single-float)
4033 (:results (r :scs (complex-single-reg) :from (:argument 0)
4034 :load-if (not (sc-is r complex-single-stack))))
4035 (:result-types complex-single-float)
4036 (:note "inline complex single-float creation")
4037 (:policy :fast-safe)
4038 (:generator 5
4039 (sc-case r
4040 (complex-single-reg
4041 (let ((r-real (complex-double-reg-real-tn r)))
4042 (unless (location= real r-real)
4043 (cond ((zerop (tn-offset r-real))
4044 (copy-fp-reg-to-fr0 real))
4045 ((zerop (tn-offset real))
4046 (inst fstd r-real))
4048 (inst fxch real)
4049 (inst fstd r-real)
4050 (inst fxch real)))))
4051 (let ((r-imag (complex-double-reg-imag-tn r)))
4052 (unless (location= imag r-imag)
4053 (cond ((zerop (tn-offset imag))
4054 (inst fstd r-imag))
4056 (inst fxch imag)
4057 (inst fstd r-imag)
4058 (inst fxch imag))))))
4059 (complex-single-stack
4060 (unless (location= real r)
4061 (cond ((zerop (tn-offset real))
4062 (inst fst (ea-for-csf-real-stack r)))
4064 (inst fxch real)
4065 (inst fst (ea-for-csf-real-stack r))
4066 (inst fxch real))))
4067 (inst fxch imag)
4068 (inst fst (ea-for-csf-imag-stack r))
4069 (inst fxch imag)))))
4071 (define-vop (make-complex-double-float)
4072 (:translate complex)
4073 (:args (real :scs (double-reg) :target r
4074 :load-if (not (location= real r)))
4075 (imag :scs (double-reg) :to :save))
4076 (:arg-types double-float double-float)
4077 (:results (r :scs (complex-double-reg) :from (:argument 0)
4078 :load-if (not (sc-is r complex-double-stack))))
4079 (:result-types complex-double-float)
4080 (:note "inline complex double-float creation")
4081 (:policy :fast-safe)
4082 (:generator 5
4083 (sc-case r
4084 (complex-double-reg
4085 (let ((r-real (complex-double-reg-real-tn r)))
4086 (unless (location= real r-real)
4087 (cond ((zerop (tn-offset r-real))
4088 (copy-fp-reg-to-fr0 real))
4089 ((zerop (tn-offset real))
4090 (inst fstd r-real))
4092 (inst fxch real)
4093 (inst fstd r-real)
4094 (inst fxch real)))))
4095 (let ((r-imag (complex-double-reg-imag-tn r)))
4096 (unless (location= imag r-imag)
4097 (cond ((zerop (tn-offset imag))
4098 (inst fstd r-imag))
4100 (inst fxch imag)
4101 (inst fstd r-imag)
4102 (inst fxch imag))))))
4103 (complex-double-stack
4104 (unless (location= real r)
4105 (cond ((zerop (tn-offset real))
4106 (inst fstd (ea-for-cdf-real-stack r)))
4108 (inst fxch real)
4109 (inst fstd (ea-for-cdf-real-stack r))
4110 (inst fxch real))))
4111 (inst fxch imag)
4112 (inst fstd (ea-for-cdf-imag-stack r))
4113 (inst fxch imag)))))
4115 #!+long-float
4116 (define-vop (make-complex-long-float)
4117 (:translate complex)
4118 (:args (real :scs (long-reg) :target r
4119 :load-if (not (location= real r)))
4120 (imag :scs (long-reg) :to :save))
4121 (:arg-types long-float long-float)
4122 (:results (r :scs (complex-long-reg) :from (:argument 0)
4123 :load-if (not (sc-is r complex-long-stack))))
4124 (:result-types complex-long-float)
4125 (:note "inline complex long-float creation")
4126 (:policy :fast-safe)
4127 (:generator 5
4128 (sc-case r
4129 (complex-long-reg
4130 (let ((r-real (complex-double-reg-real-tn r)))
4131 (unless (location= real r-real)
4132 (cond ((zerop (tn-offset r-real))
4133 (copy-fp-reg-to-fr0 real))
4134 ((zerop (tn-offset real))
4135 (inst fstd r-real))
4137 (inst fxch real)
4138 (inst fstd r-real)
4139 (inst fxch real)))))
4140 (let ((r-imag (complex-double-reg-imag-tn r)))
4141 (unless (location= imag r-imag)
4142 (cond ((zerop (tn-offset imag))
4143 (inst fstd r-imag))
4145 (inst fxch imag)
4146 (inst fstd r-imag)
4147 (inst fxch imag))))))
4148 (complex-long-stack
4149 (unless (location= real r)
4150 (cond ((zerop (tn-offset real))
4151 (store-long-float (ea-for-clf-real-stack r)))
4153 (inst fxch real)
4154 (store-long-float (ea-for-clf-real-stack r))
4155 (inst fxch real))))
4156 (inst fxch imag)
4157 (store-long-float (ea-for-clf-imag-stack r))
4158 (inst fxch imag)))))
4161 (define-vop (complex-float-value)
4162 (:args (x :target r))
4163 (:results (r))
4164 (:variant-vars offset)
4165 (:policy :fast-safe)
4166 (:generator 3
4167 (cond ((sc-is x complex-single-reg complex-double-reg
4168 #!+long-float complex-long-reg)
4169 (let ((value-tn
4170 (make-random-tn :kind :normal
4171 :sc (sc-or-lose 'double-reg)
4172 :offset (+ offset (tn-offset x)))))
4173 (unless (location= value-tn r)
4174 (cond ((zerop (tn-offset r))
4175 (copy-fp-reg-to-fr0 value-tn))
4176 ((zerop (tn-offset value-tn))
4177 (inst fstd r))
4179 (inst fxch value-tn)
4180 (inst fstd r)
4181 (inst fxch value-tn))))))
4182 ((sc-is r single-reg)
4183 (let ((ea (sc-case x
4184 (complex-single-stack
4185 (ecase offset
4186 (0 (ea-for-csf-real-stack x))
4187 (1 (ea-for-csf-imag-stack x))))
4188 (descriptor-reg
4189 (ecase offset
4190 (0 (ea-for-csf-real-desc x))
4191 (1 (ea-for-csf-imag-desc x)))))))
4192 (with-empty-tn@fp-top(r)
4193 (inst fld ea))))
4194 ((sc-is r double-reg)
4195 (let ((ea (sc-case x
4196 (complex-double-stack
4197 (ecase offset
4198 (0 (ea-for-cdf-real-stack x))
4199 (1 (ea-for-cdf-imag-stack x))))
4200 (descriptor-reg
4201 (ecase offset
4202 (0 (ea-for-cdf-real-desc x))
4203 (1 (ea-for-cdf-imag-desc x)))))))
4204 (with-empty-tn@fp-top(r)
4205 (inst fldd ea))))
4206 #!+long-float
4207 ((sc-is r long-reg)
4208 (let ((ea (sc-case x
4209 (complex-long-stack
4210 (ecase offset
4211 (0 (ea-for-clf-real-stack x))
4212 (1 (ea-for-clf-imag-stack x))))
4213 (descriptor-reg
4214 (ecase offset
4215 (0 (ea-for-clf-real-desc x))
4216 (1 (ea-for-clf-imag-desc x)))))))
4217 (with-empty-tn@fp-top(r)
4218 (inst fldl ea))))
4219 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
4221 (define-vop (realpart/complex-single-float complex-float-value)
4222 (:translate realpart)
4223 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4224 :target r))
4225 (:arg-types complex-single-float)
4226 (:results (r :scs (single-reg)))
4227 (:result-types single-float)
4228 (:note "complex float realpart")
4229 (:variant 0))
4231 (define-vop (realpart/complex-double-float complex-float-value)
4232 (:translate realpart)
4233 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4234 :target r))
4235 (:arg-types complex-double-float)
4236 (:results (r :scs (double-reg)))
4237 (:result-types double-float)
4238 (:note "complex float realpart")
4239 (:variant 0))
4241 #!+long-float
4242 (define-vop (realpart/complex-long-float complex-float-value)
4243 (:translate realpart)
4244 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4245 :target r))
4246 (:arg-types complex-long-float)
4247 (:results (r :scs (long-reg)))
4248 (:result-types long-float)
4249 (:note "complex float realpart")
4250 (:variant 0))
4252 (define-vop (imagpart/complex-single-float complex-float-value)
4253 (:translate imagpart)
4254 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
4255 :target r))
4256 (:arg-types complex-single-float)
4257 (:results (r :scs (single-reg)))
4258 (:result-types single-float)
4259 (:note "complex float imagpart")
4260 (:variant 1))
4262 (define-vop (imagpart/complex-double-float complex-float-value)
4263 (:translate imagpart)
4264 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
4265 :target r))
4266 (:arg-types complex-double-float)
4267 (:results (r :scs (double-reg)))
4268 (:result-types double-float)
4269 (:note "complex float imagpart")
4270 (:variant 1))
4272 #!+long-float
4273 (define-vop (imagpart/complex-long-float complex-float-value)
4274 (:translate imagpart)
4275 (:args (x :scs (complex-long-reg complex-long-stack descriptor-reg)
4276 :target r))
4277 (:arg-types complex-long-float)
4278 (:results (r :scs (long-reg)))
4279 (:result-types long-float)
4280 (:note "complex float imagpart")
4281 (:variant 1))
4283 ;;; hack dummy VOPs to bias the representation selection of their
4284 ;;; arguments towards a FP register, which can help avoid consing at
4285 ;;; inappropriate locations
4286 (defknown double-float-reg-bias (double-float) (values))
4287 (define-vop (double-float-reg-bias)
4288 (:translate double-float-reg-bias)
4289 (:args (x :scs (double-reg double-stack) :load-if nil))
4290 (:arg-types double-float)
4291 (:policy :fast-safe)
4292 (:note "inline dummy FP register bias")
4293 (:ignore x)
4294 (:generator 0))
4295 (defknown single-float-reg-bias (single-float) (values))
4296 (define-vop (single-float-reg-bias)
4297 (:translate single-float-reg-bias)
4298 (:args (x :scs (single-reg single-stack) :load-if nil))
4299 (:arg-types single-float)
4300 (:policy :fast-safe)
4301 (:note "inline dummy FP register bias")
4302 (:ignore x)
4303 (:generator 0))
4306 ;; XMM Moves
4309 (defun ea-for-xmm-desc (tn)
4310 (make-ea :xmmword :base tn
4311 :disp (- (* xmm-value-slot n-word-bytes) other-pointer-lowtag)))
4313 (defun ea-for-xmm-stack (tn)
4314 (make-ea :xmmword :base ebp-tn
4315 :disp (- (* (+ (tn-offset tn)
4317 n-word-bytes))))
4319 (define-move-fun (load-xmm 2) (vop x y)
4320 ((xmm-stack) (xmm-reg))
4321 (inst movdqu y (ea-for-xmm-stack x)))
4323 (define-move-fun (store-xmm 2) (vop x y)
4324 ((xmm-reg) (xmm-stack))
4325 (inst movdqu (ea-for-xmm-stack y) x))
4327 (define-move-fun (load-xmm-single 2) (vop x y)
4328 ((single-stack) (xmm-reg))
4329 (inst movss y (ea-for-sf-stack x)))
4331 (define-move-fun (store-xmm-single 2) (vop x y)
4332 ((xmm-reg) (single-stack))
4333 (inst movss (ea-for-sf-stack y) x))
4336 (define-vop (%load-xmm-from-array/single-float)
4337 (:policy :fast-safe)
4338 (:args (src :scs (descriptor-reg))
4339 (index :scs (unsigned-reg)))
4340 (:ARG-TYPES SIMPLE-ARRAY-SINGLE-FLOAT fixnum)
4341 (:results (dest :scs (xmm-reg)))
4342 (:result-types xmm)
4343 (:generator 1
4344 (inst shl index 2)
4345 (inst movdqu dest (make-ea :xmmword :base src :index index
4346 :disp (- (* VECTOR-DATA-OFFSET N-WORD-BYTES) OTHER-POINTER-LOWTAG)))))
4349 (define-vop (%store-xmm-to-array/single-float)
4350 (:policy :fast-safe)
4351 (:args (dest :scs (descriptor-reg))
4352 (index :scs (unsigned-reg))
4353 (src :scs (xmm-reg)))
4354 (:ARG-TYPES SIMPLE-ARRAY-SINGLE-FLOAT fixnum XMM)
4355 (:generator 1
4356 (inst shl index 2)
4357 (inst movdqu (make-ea :xmmword :base dest :index index
4358 :disp (- (* VECTOR-DATA-OFFSET N-WORD-BYTES) OTHER-POINTER-LOWTAG))
4359 src)))
4362 (define-vop (xmm-move)
4363 (:args (x :scs (xmm-reg) :target y :load-if (not (location= x y))))
4364 (:results (y :scs (xmm-reg) :load-if (not (location= x y))))
4365 (:note "xmm move")
4366 (:generator 0
4367 (unless (location= x y)
4368 (inst movdqa y x))))
4370 (define-move-vop xmm-move :move (xmm-reg) (xmm-reg))
4372 (define-vop (move-from-xmm)
4373 (:args (x :scs (xmm-reg) :to :save))
4374 (:results (y :scs (descriptor-reg)))
4375 (:node-var node)
4376 (:note "xmm to pointer coercion")
4377 (:generator 13
4378 (with-fixed-allocation (y
4379 xmm-widetag
4380 xmm-size node)
4381 (inst movdqu (ea-for-xmm-desc y) x))))
4383 (define-move-vop move-from-xmm :move (xmm-reg) (descriptor-reg))
4385 (define-vop (move-to-xmm)
4386 (:args (x :scs (descriptor-reg)))
4387 (:results (y :scs (xmm-reg)))
4388 (:note "pointer to xmm coercion")
4389 (:generator 2
4390 (inst movdqu y (ea-for-xmm-desc x))))
4392 (define-move-vop move-to-xmm :move (descriptor-reg) (xmm-reg))
4395 (define-vop (move-xmm-arg)
4396 (:args (x :scs (xmm-reg) :target y)
4397 (fp :scs (any-reg)
4398 :load-if (not (sc-is y xmm-reg))))
4399 (:results (y))
4400 (:note "xmm argument move")
4401 (:generator 6
4402 (sc-case y
4403 (xmm-reg
4404 (unless (location= x y)
4405 (inst movdqa y x)))
4407 (xmm-stack
4408 (if (= (tn-offset fp) esp-offset)
4409 (let* ((offset (* (tn-offset y) n-word-bytes))
4410 (ea (make-ea :xmmword :base fp :disp offset)))
4411 (inst movdqu ea x))
4413 (let ((ea (make-ea :xmmword :base fp
4414 :disp (- (* (+ (tn-offset y) 4)
4415 n-word-bytes)))))
4416 (inst movdqu ea x)))))))
4418 (define-move-vop move-xmm-arg :move-arg (xmm-reg descriptor-reg) (xmm-reg))
4420 (define-move-vop move-arg :move-arg (xmm-reg) (descriptor-reg))