Merged sbcl-1.0.14 with the sb-simd 1.3 patches
[sbcl/simd.git] / src / compiler / x86-64 / float.lisp
blobf1b7f4175178bf78762be487d66b6f6dba6d6006
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
16 :qword :base ,tn
17 :disp (- (* ,slot n-word-bytes)
18 other-pointer-lowtag))))
19 (defun ea-for-df-desc (tn)
20 (ea-for-xf-desc tn double-float-value-slot))
21 ;; complex floats
22 (defun ea-for-csf-real-desc (tn)
23 (ea-for-xf-desc tn complex-single-float-real-slot))
24 (defun ea-for-csf-imag-desc (tn)
25 (ea-for-xf-desc tn complex-single-float-imag-slot))
26 (defun ea-for-cdf-real-desc (tn)
27 (ea-for-xf-desc tn complex-double-float-real-slot))
28 (defun ea-for-cdf-imag-desc (tn)
29 (ea-for-xf-desc tn complex-double-float-imag-slot)))
31 (macrolet ((ea-for-xf-stack (tn kind)
32 (declare (ignore kind))
33 `(make-ea
34 :qword :base rbp-tn
35 :disp (- (* (+ (tn-offset ,tn) 1)
36 n-word-bytes)))))
37 (defun ea-for-sf-stack (tn)
38 (ea-for-xf-stack tn :single))
39 (defun ea-for-df-stack (tn)
40 (ea-for-xf-stack tn :double)))
42 ;;; complex float stack EAs
43 (macrolet ((ea-for-cxf-stack (tn kind slot &optional base)
44 (declare (ignore kind))
45 `(make-ea
46 :qword :base ,base
47 :disp (- (* (+ (tn-offset ,tn)
48 (* 1 (ecase ,slot (:real 1) (:imag 2))))
49 n-word-bytes)))))
50 (defun ea-for-csf-real-stack (tn &optional (base rbp-tn))
51 (ea-for-cxf-stack tn :single :real base))
52 (defun ea-for-csf-imag-stack (tn &optional (base rbp-tn))
53 (ea-for-cxf-stack tn :single :imag base))
54 (defun ea-for-cdf-real-stack (tn &optional (base rbp-tn))
55 (ea-for-cxf-stack tn :double :real base))
56 (defun ea-for-cdf-imag-stack (tn &optional (base rbp-tn))
57 (ea-for-cxf-stack tn :double :imag base)))
60 ;;;; move functions
62 ;;; X is source, Y is destination.
64 (define-move-fun (load-fp-zero 1) (vop x y)
65 ((fp-single-zero) (single-reg)
66 (fp-double-zero) (double-reg))
67 (identity x)
68 (sc-case y
69 (single-reg (inst xorps y y))
70 (double-reg (inst xorpd y y))))
72 (define-move-fun (load-single 2) (vop x y)
73 ((single-stack) (single-reg))
74 (inst movss y (ea-for-sf-stack x)))
76 (define-move-fun (store-single 2) (vop x y)
77 ((single-reg) (single-stack))
78 (inst movss (ea-for-sf-stack y) x))
80 (define-move-fun (load-double 2) (vop x y)
81 ((double-stack) (double-reg))
82 (inst movsd y (ea-for-df-stack x)))
84 (define-move-fun (store-double 2) (vop x y)
85 ((double-reg) (double-stack))
86 (inst movsd (ea-for-df-stack y) x))
88 (eval-when (:compile-toplevel :execute)
89 (setf *read-default-float-format* 'single-float))
91 ;;;; complex float move functions
93 (defun complex-single-reg-real-tn (x)
94 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
95 :offset (tn-offset x)))
96 (defun complex-single-reg-imag-tn (x)
97 (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg)
98 :offset (1+ (tn-offset x))))
100 (defun complex-double-reg-real-tn (x)
101 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
102 :offset (tn-offset x)))
103 (defun complex-double-reg-imag-tn (x)
104 (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg)
105 :offset (1+ (tn-offset x))))
107 ;;; X is source, Y is destination.
108 (define-move-fun (load-complex-single 2) (vop x y)
109 ((complex-single-stack) (complex-single-reg))
110 (let ((real-tn (complex-single-reg-real-tn y)))
111 (inst movss real-tn (ea-for-csf-real-stack x)))
112 (let ((imag-tn (complex-single-reg-imag-tn y)))
113 (inst movss imag-tn (ea-for-csf-imag-stack x))))
115 (define-move-fun (store-complex-single 2) (vop x y)
116 ((complex-single-reg) (complex-single-stack))
117 (let ((real-tn (complex-single-reg-real-tn x))
118 (imag-tn (complex-single-reg-imag-tn x)))
119 (inst movss (ea-for-csf-real-stack y) real-tn)
120 (inst movss (ea-for-csf-imag-stack y) imag-tn)))
122 (define-move-fun (load-complex-double 2) (vop x y)
123 ((complex-double-stack) (complex-double-reg))
124 (let ((real-tn (complex-double-reg-real-tn y)))
125 (inst movsd real-tn (ea-for-cdf-real-stack x)))
126 (let ((imag-tn (complex-double-reg-imag-tn y)))
127 (inst movsd imag-tn (ea-for-cdf-imag-stack x))))
129 (define-move-fun (store-complex-double 2) (vop x y)
130 ((complex-double-reg) (complex-double-stack))
131 (let ((real-tn (complex-double-reg-real-tn x))
132 (imag-tn (complex-double-reg-imag-tn x)))
133 (inst movsd (ea-for-cdf-real-stack y) real-tn)
134 (inst movsd (ea-for-cdf-imag-stack y) imag-tn)))
137 ;;;; move VOPs
139 ;;; float register to register moves
140 (macrolet ((frob (vop sc)
141 `(progn
142 (define-vop (,vop)
143 (:args (x :scs (,sc)
144 :target y
145 :load-if (not (location= x y))))
146 (:results (y :scs (,sc)
147 :load-if (not (location= x y))))
148 (:note "float move")
149 (:generator 0
150 (unless (location= y x)
151 (inst movq y x))))
152 (define-move-vop ,vop :move (,sc) (,sc)))))
153 (frob single-move single-reg)
154 (frob double-move double-reg))
156 ;;; complex float register to register moves
157 (define-vop (complex-float-move)
158 (:args (x :target y :load-if (not (location= x y))))
159 (:results (y :load-if (not (location= x y))))
160 (:note "complex float move")
161 (:generator 0
162 (unless (location= x y)
163 ;; Note the complex-float-regs are aligned to every second
164 ;; float register so there is not need to worry about overlap.
165 ;; (It would be better to put the imagpart in the top half of the
166 ;; register, or something, but let's worry about that later)
167 (let ((x-real (complex-single-reg-real-tn x))
168 (y-real (complex-single-reg-real-tn y)))
169 (inst movq y-real x-real))
170 (let ((x-imag (complex-single-reg-imag-tn x))
171 (y-imag (complex-single-reg-imag-tn y)))
172 (inst movq y-imag x-imag)))))
174 (define-vop (complex-single-move complex-float-move)
175 (:args (x :scs (complex-single-reg) :target y
176 :load-if (not (location= x y))))
177 (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))))
178 (define-move-vop complex-single-move :move
179 (complex-single-reg) (complex-single-reg))
181 (define-vop (complex-double-move complex-float-move)
182 (:args (x :scs (complex-double-reg)
183 :target y :load-if (not (location= x y))))
184 (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))))
185 (define-move-vop complex-double-move :move
186 (complex-double-reg) (complex-double-reg))
189 ;;; Move from float to a descriptor reg. allocating a new float
190 ;;; object in the process.
191 (define-vop (move-from-single)
192 (:args (x :scs (single-reg) :to :save))
193 (:results (y :scs (descriptor-reg)))
194 (:note "float to pointer coercion")
195 (:generator 4
196 (inst movd y x)
197 (inst shl y 32)
198 (inst or y single-float-widetag)))
200 (define-move-vop move-from-single :move
201 (single-reg) (descriptor-reg))
203 (define-vop (move-from-double)
204 (:args (x :scs (double-reg) :to :save))
205 (:results (y :scs (descriptor-reg)))
206 (:node-var node)
207 (:note "float to pointer coercion")
208 (:generator 13
209 (with-fixed-allocation (y
210 double-float-widetag
211 double-float-size
212 node)
213 (inst movsd (ea-for-df-desc y) x))))
214 (define-move-vop move-from-double :move
215 (double-reg) (descriptor-reg))
217 ;;; Move from a descriptor to a float register.
218 (define-vop (move-to-single)
219 (:args (x :scs (descriptor-reg) :target tmp))
220 (:temporary (:sc unsigned-reg) tmp)
221 (:results (y :scs (single-reg)))
222 (:note "pointer to float coercion")
223 (:generator 2
224 (move tmp x)
225 (inst shr tmp 32)
226 (inst movd y tmp)))
228 (define-move-vop move-to-single :move (descriptor-reg) (single-reg))
230 (define-vop (move-to-double)
231 (:args (x :scs (descriptor-reg)))
232 (:results (y :scs (double-reg)))
233 (:note "pointer to float coercion")
234 (:generator 2
235 (inst movsd y (ea-for-df-desc x))))
236 (define-move-vop move-to-double :move (descriptor-reg) (double-reg))
239 ;;; Move from complex float to a descriptor reg. allocating a new
240 ;;; complex float object in the process.
241 (define-vop (move-from-complex-single)
242 (:args (x :scs (complex-single-reg) :to :save))
243 (:results (y :scs (descriptor-reg)))
244 (:node-var node)
245 (:note "complex float to pointer coercion")
246 (:generator 13
247 (with-fixed-allocation (y
248 complex-single-float-widetag
249 complex-single-float-size
250 node)
251 (let ((real-tn (complex-single-reg-real-tn x)))
252 (inst movss (ea-for-csf-real-desc y) real-tn))
253 (let ((imag-tn (complex-single-reg-imag-tn x)))
254 (inst movss (ea-for-csf-imag-desc y) imag-tn)))))
255 (define-move-vop move-from-complex-single :move
256 (complex-single-reg) (descriptor-reg))
258 (define-vop (move-from-complex-double)
259 (:args (x :scs (complex-double-reg) :to :save))
260 (:results (y :scs (descriptor-reg)))
261 (:node-var node)
262 (:note "complex float to pointer coercion")
263 (:generator 13
264 (with-fixed-allocation (y
265 complex-double-float-widetag
266 complex-double-float-size
267 node)
268 (let ((real-tn (complex-double-reg-real-tn x)))
269 (inst movsd (ea-for-cdf-real-desc y) real-tn))
270 (let ((imag-tn (complex-double-reg-imag-tn x)))
271 (inst movsd (ea-for-cdf-imag-desc y) imag-tn)))))
272 (define-move-vop move-from-complex-double :move
273 (complex-double-reg) (descriptor-reg))
275 ;;; Move from a descriptor to a complex float register.
276 (macrolet ((frob (name sc format)
277 `(progn
278 (define-vop (,name)
279 (:args (x :scs (descriptor-reg)))
280 (:results (y :scs (,sc)))
281 (:note "pointer to complex float coercion")
282 (:generator 2
283 (let ((real-tn (complex-double-reg-real-tn y)))
284 ,@(ecase
285 format
286 (:single
287 '((inst movss real-tn (ea-for-csf-real-desc x))))
288 (:double
289 '((inst movsd real-tn (ea-for-cdf-real-desc x))))))
290 (let ((imag-tn (complex-double-reg-imag-tn y)))
291 ,@(ecase
292 format
293 (:single
294 '((inst movss imag-tn (ea-for-csf-imag-desc x))))
295 (:double
296 '((inst movsd imag-tn (ea-for-cdf-imag-desc x))))))))
297 (define-move-vop ,name :move (descriptor-reg) (,sc)))))
298 (frob move-to-complex-single complex-single-reg :single)
299 (frob move-to-complex-double complex-double-reg :double))
301 ;;;; the move argument vops
302 ;;;;
303 ;;;; Note these are also used to stuff fp numbers onto the c-call
304 ;;;; stack so the order is different than the lisp-stack.
306 ;;; the general MOVE-ARG VOP
307 (macrolet ((frob (name sc stack-sc format)
308 `(progn
309 (define-vop (,name)
310 (:args (x :scs (,sc) :target y)
311 (fp :scs (any-reg)
312 :load-if (not (sc-is y ,sc))))
313 (:results (y))
314 (:note "float argument move")
315 (:generator ,(case format (:single 2) (:double 3) )
316 (sc-case y
317 (,sc
318 (unless (location= x y)
319 (inst movq y x)))
320 (,stack-sc
321 (if (= (tn-offset fp) esp-offset)
322 (let* ((offset (* (tn-offset y) n-word-bytes))
323 (ea (make-ea :dword :base fp :disp offset)))
324 ,@(ecase format
325 (:single '((inst movss ea x)))
326 (:double '((inst movsd ea x)))))
327 (let ((ea (make-ea
328 :dword :base fp
329 :disp (- (* (1+ (tn-offset y))
330 n-word-bytes)))))
331 ,@(ecase format
332 (:single '((inst movss ea x)))
333 (:double '((inst movsd ea x))))))))))
334 (define-move-vop ,name :move-arg
335 (,sc descriptor-reg) (,sc)))))
336 (frob move-single-float-arg single-reg single-stack :single)
337 (frob move-double-float-arg double-reg double-stack :double))
339 ;;;; complex float MOVE-ARG VOP
340 (macrolet ((frob (name sc stack-sc format)
341 `(progn
342 (define-vop (,name)
343 (:args (x :scs (,sc) :target y)
344 (fp :scs (any-reg)
345 :load-if (not (sc-is y ,sc))))
346 (:results (y))
347 (:note "complex float argument move")
348 (:generator ,(ecase format (:single 2) (:double 3))
349 (sc-case y
350 (,sc
351 (unless (location= x y)
352 (let ((x-real (complex-double-reg-real-tn x))
353 (y-real (complex-double-reg-real-tn y)))
354 (inst movsd y-real x-real))
355 (let ((x-imag (complex-double-reg-imag-tn x))
356 (y-imag (complex-double-reg-imag-tn y)))
357 (inst movsd y-imag x-imag))))
358 (,stack-sc
359 (let ((real-tn (complex-double-reg-real-tn x)))
360 ,@(ecase format
361 (:single
362 '((inst movss
363 (ea-for-csf-real-stack y fp)
364 real-tn)))
365 (:double
366 '((inst movsd
367 (ea-for-cdf-real-stack y fp)
368 real-tn)))))
369 (let ((imag-tn (complex-double-reg-imag-tn x)))
370 ,@(ecase format
371 (:single
372 '((inst movss
373 (ea-for-csf-imag-stack y fp) imag-tn)))
374 (:double
375 '((inst movsd
376 (ea-for-cdf-imag-stack y fp) imag-tn)))))))))
377 (define-move-vop ,name :move-arg
378 (,sc descriptor-reg) (,sc)))))
379 (frob move-complex-single-float-arg
380 complex-single-reg complex-single-stack :single)
381 (frob move-complex-double-float-arg
382 complex-double-reg complex-double-stack :double))
384 (define-move-vop move-arg :move-arg
385 (single-reg double-reg
386 complex-single-reg complex-double-reg)
387 (descriptor-reg))
390 ;;;; arithmetic VOPs
392 (define-vop (float-op)
393 (:args (x) (y))
394 (:results (r))
395 (:policy :fast-safe)
396 (:note "inline float arithmetic")
397 (:vop-var vop)
398 (:save-p :compute-only))
400 (macrolet ((frob (name sc ptype)
401 `(define-vop (,name float-op)
402 (:args (x :scs (,sc) :target r)
403 (y :scs (,sc)))
404 (:results (r :scs (,sc)))
405 (:arg-types ,ptype ,ptype)
406 (:result-types ,ptype))))
407 (frob single-float-op single-reg single-float)
408 (frob double-float-op double-reg double-float))
410 (macrolet ((generate (movinst opinst commutative)
411 `(progn
412 (cond
413 ((location= x r)
414 (inst ,opinst x y))
415 ((and ,commutative (location= y r))
416 (inst ,opinst y x))
417 ((not (location= r y))
418 (inst ,movinst r x)
419 (inst ,opinst r y))
421 (inst ,movinst tmp x)
422 (inst ,opinst tmp y)
423 (inst ,movinst r tmp)))))
424 (frob (op sinst sname scost dinst dname dcost commutative)
425 `(progn
426 (define-vop (,sname single-float-op)
427 (:translate ,op)
428 (:temporary (:sc single-reg) tmp)
429 (:generator ,scost
430 (generate movss ,sinst ,commutative)))
431 (define-vop (,dname double-float-op)
432 (:translate ,op)
433 (:temporary (:sc single-reg) tmp)
434 (:generator ,dcost
435 (generate movsd ,dinst ,commutative))))))
436 (frob + addss +/single-float 2 addsd +/double-float 2 t)
437 (frob - subss -/single-float 2 subsd -/double-float 2 nil)
438 (frob * mulss */single-float 4 mulsd */double-float 5 t)
439 (frob / divss //single-float 12 divsd //double-float 19 nil))
441 (define-vop (fsqrt)
442 (:args (x :scs (double-reg)))
443 (:results (y :scs (double-reg)))
444 (:translate %sqrt)
445 (:policy :fast-safe)
446 (:arg-types double-float)
447 (:result-types double-float)
448 (:note "inline float arithmetic")
449 (:vop-var vop)
450 (:save-p :compute-only)
451 (:generator 1
452 (note-this-location vop :internal-error)
453 (inst sqrtsd y x)))
455 (macrolet ((frob ((name translate sc type) &body body)
456 `(define-vop (,name)
457 (:args (x :scs (,sc)))
458 (:results (y :scs (,sc)))
459 (:translate ,translate)
460 (:policy :fast-safe)
461 (:arg-types ,type)
462 (:result-types ,type)
463 (:temporary (:sc any-reg) hex8)
464 (:temporary
465 (:sc ,sc) xmm)
466 (:note "inline float arithmetic")
467 (:vop-var vop)
468 (:save-p :compute-only)
469 (:generator 1
470 (note-this-location vop :internal-error)
471 ;; we should be able to do this better. what we
472 ;; really would like to do is use the target as the
473 ;; temp whenever it's not also the source
474 (unless (location= x y)
475 (inst movq y x))
476 ,@body))))
477 (frob (%negate/double-float %negate double-reg double-float)
478 (inst lea hex8 (make-ea :qword :disp 1))
479 (inst ror hex8 1) ; #x8000000000000000
480 (inst movd xmm hex8)
481 (inst xorpd y xmm))
482 (frob (%negate/single-float %negate single-reg single-float)
483 (inst lea hex8 (make-ea :qword :disp 1))
484 (inst rol hex8 31)
485 (inst movd xmm hex8)
486 (inst xorps y xmm))
487 (frob (abs/double-float abs double-reg double-float)
488 (inst mov hex8 -1)
489 (inst shr hex8 1)
490 (inst movd xmm hex8)
491 (inst andpd y xmm))
492 (frob (abs/single-float abs single-reg single-float)
493 (inst mov hex8 -1)
494 (inst shr hex8 33)
495 (inst movd xmm hex8)
496 (inst andps y xmm)))
498 ;;;; comparison
500 (define-vop (float-compare)
501 (:conditional)
502 (:info target not-p)
503 (:policy :fast-safe)
504 (:vop-var vop)
505 (:save-p :compute-only)
506 (:note "inline float comparison"))
508 ;;; comiss and comisd can cope with one or other arg in memory: we
509 ;;; could (should, indeed) extend these to cope with descriptor args
510 ;;; and stack args
512 (define-vop (single-float-compare float-compare)
513 (:args (x :scs (single-reg)) (y :scs (single-reg)))
514 (:conditional)
515 (:arg-types single-float single-float))
516 (define-vop (double-float-compare float-compare)
517 (:args (x :scs (double-reg)) (y :scs (double-reg)))
518 (:conditional)
519 (:arg-types double-float double-float))
521 (define-vop (=/single-float single-float-compare)
522 (:translate =)
523 (:info target not-p)
524 (:vop-var vop)
525 (:generator 3
526 (note-this-location vop :internal-error)
527 (inst comiss x y)
528 ;; if PF&CF, there was a NaN involved => not equal
529 ;; otherwise, ZF => equal
530 (cond (not-p
531 (inst jmp :p target)
532 (inst jmp :ne target))
534 (let ((not-lab (gen-label)))
535 (inst jmp :p not-lab)
536 (inst jmp :e target)
537 (emit-label not-lab))))))
539 (define-vop (=/double-float double-float-compare)
540 (:translate =)
541 (:info target not-p)
542 (:vop-var vop)
543 (:generator 3
544 (note-this-location vop :internal-error)
545 (inst comisd x y)
546 (cond (not-p
547 (inst jmp :p target)
548 (inst jmp :ne target))
550 (let ((not-lab (gen-label)))
551 (inst jmp :p not-lab)
552 (inst jmp :e target)
553 (emit-label not-lab))))))
555 (define-vop (<double-float double-float-compare)
556 (:translate <)
557 (:info target not-p)
558 (:generator 3
559 (inst comisd x y)
560 (cond (not-p
561 (inst jmp :p target)
562 (inst jmp :nc target))
564 (let ((not-lab (gen-label)))
565 (inst jmp :p not-lab)
566 (inst jmp :c target)
567 (emit-label not-lab))))))
569 (define-vop (<single-float single-float-compare)
570 (:translate <)
571 (:info target not-p)
572 (:generator 3
573 (inst comiss x y)
574 (cond (not-p
575 (inst jmp :p target)
576 (inst jmp :nc target))
578 (let ((not-lab (gen-label)))
579 (inst jmp :p not-lab)
580 (inst jmp :c target)
581 (emit-label not-lab))))))
583 (define-vop (>double-float double-float-compare)
584 (:translate >)
585 (:info target not-p)
586 (:generator 3
587 (inst comisd x y)
588 (cond (not-p
589 (inst jmp :p target)
590 (inst jmp :na target))
592 (let ((not-lab (gen-label)))
593 (inst jmp :p not-lab)
594 (inst jmp :a target)
595 (emit-label not-lab))))))
597 (define-vop (>single-float single-float-compare)
598 (:translate >)
599 (:info target not-p)
600 (:generator 3
601 (inst comiss x y)
602 (cond (not-p
603 (inst jmp :p target)
604 (inst jmp :na target))
606 (let ((not-lab (gen-label)))
607 (inst jmp :p not-lab)
608 (inst jmp :a target)
609 (emit-label not-lab))))))
613 ;;;; conversion
615 (macrolet ((frob (name translate inst to-sc to-type)
616 `(define-vop (,name)
617 (:args (x :scs (signed-stack signed-reg) :target temp))
618 (:temporary (:sc signed-stack) temp)
619 (:results (y :scs (,to-sc)))
620 (:arg-types signed-num)
621 (:result-types ,to-type)
622 (:policy :fast-safe)
623 (:note "inline float coercion")
624 (:translate ,translate)
625 (:vop-var vop)
626 (:save-p :compute-only)
627 (:generator 5
628 (sc-case x
629 (signed-reg
630 (inst mov temp x)
631 (note-this-location vop :internal-error)
632 (inst ,inst y temp))
633 (signed-stack
634 (note-this-location vop :internal-error)
635 (inst ,inst y x)))))))
636 (frob %single-float/signed %single-float cvtsi2ss single-reg single-float)
637 (frob %double-float/signed %double-float cvtsi2sd double-reg double-float))
639 (macrolet ((frob (name translate inst from-sc from-type to-sc to-type)
640 `(define-vop (,name)
641 (:args (x :scs (,from-sc) :target y))
642 (:results (y :scs (,to-sc)))
643 (:arg-types ,from-type)
644 (:result-types ,to-type)
645 (:policy :fast-safe)
646 (:note "inline float coercion")
647 (:translate ,translate)
648 (:vop-var vop)
649 (:save-p :compute-only)
650 (:generator 2
651 (note-this-location vop :internal-error)
652 (inst ,inst y x)))))
653 (frob %single-float/double-float %single-float cvtsd2ss double-reg
654 double-float single-reg single-float)
656 (frob %double-float/single-float %double-float cvtss2sd
657 single-reg single-float double-reg double-float))
659 (macrolet ((frob (trans inst from-sc from-type round-p)
660 (declare (ignore round-p))
661 `(define-vop (,(symbolicate trans "/" from-type))
662 (:args (x :scs (,from-sc)))
663 (:temporary (:sc any-reg) temp-reg)
664 (:results (y :scs (signed-reg)))
665 (:arg-types ,from-type)
666 (:result-types signed-num)
667 (:translate ,trans)
668 (:policy :fast-safe)
669 (:note "inline float truncate")
670 (:vop-var vop)
671 (:save-p :compute-only)
672 (:generator 5
673 (sc-case y
674 (signed-stack
675 (inst ,inst temp-reg x)
676 (move y temp-reg))
677 (signed-reg
678 (inst ,inst y x)
679 ))))))
680 (frob %unary-truncate cvttss2si single-reg single-float nil)
681 (frob %unary-truncate cvttsd2si double-reg double-float nil)
683 (frob %unary-round cvtss2si single-reg single-float t)
684 (frob %unary-round cvtsd2si double-reg double-float t))
686 (define-vop (make-single-float)
687 (:args (bits :scs (signed-reg) :target res
688 :load-if (not (or (and (sc-is bits signed-stack)
689 (sc-is res single-reg))
690 (and (sc-is bits signed-stack)
691 (sc-is res single-stack)
692 (location= bits res))))))
693 (:results (res :scs (single-reg single-stack)))
694 (:arg-types signed-num)
695 (:result-types single-float)
696 (:translate make-single-float)
697 (:policy :fast-safe)
698 (:vop-var vop)
699 (:generator 4
700 (sc-case res
701 (single-stack
702 (sc-case bits
703 (signed-reg
704 (inst mov res bits))
705 (signed-stack
706 (aver (location= bits res)))))
707 (single-reg
708 (sc-case bits
709 (signed-reg
710 (inst movd res bits))
711 (signed-stack
712 (inst movd res bits)))))))
714 (define-vop (make-double-float)
715 (:args (hi-bits :scs (signed-reg))
716 (lo-bits :scs (unsigned-reg)))
717 (:results (res :scs (double-reg)))
718 (:temporary (:sc unsigned-reg) temp)
719 (:arg-types signed-num unsigned-num)
720 (:result-types double-float)
721 (:translate make-double-float)
722 (:policy :fast-safe)
723 (:vop-var vop)
724 (:generator 2
725 (move temp hi-bits)
726 (inst shl temp 32)
727 (inst or temp lo-bits)
728 (inst movd res temp)))
730 (define-vop (single-float-bits)
731 (:args (float :scs (single-reg descriptor-reg)
732 :load-if (not (sc-is float single-stack))))
733 (:results (bits :scs (signed-reg)))
734 (:temporary (:sc signed-stack :from :argument :to :result) stack-temp)
735 (:arg-types single-float)
736 (:result-types signed-num)
737 (:translate single-float-bits)
738 (:policy :fast-safe)
739 (:vop-var vop)
740 (:generator 4
741 (sc-case bits
742 (signed-reg
743 (sc-case float
744 (single-reg
745 (inst movss stack-temp float)
746 (move bits stack-temp))
747 (single-stack
748 (move bits float))
749 (descriptor-reg
750 (move bits float)
751 (inst shr bits 32))))
752 (signed-stack
753 (sc-case float
754 (single-reg
755 (inst movss bits float)))))
756 ;; Sign-extend
757 (inst shl bits 32)
758 (inst sar bits 32)))
760 (define-vop (double-float-high-bits)
761 (:args (float :scs (double-reg descriptor-reg)
762 :load-if (not (sc-is float double-stack))))
763 (:results (hi-bits :scs (signed-reg)))
764 (:temporary (:sc signed-stack :from :argument :to :result) temp)
765 (:arg-types double-float)
766 (:result-types signed-num)
767 (:translate double-float-high-bits)
768 (:policy :fast-safe)
769 (:vop-var vop)
770 (:generator 5
771 (sc-case float
772 (double-reg
773 (inst movsd temp float)
774 (move hi-bits temp))
775 (double-stack
776 (loadw hi-bits ebp-tn (- (1+ (tn-offset float)))))
777 (descriptor-reg
778 (loadw hi-bits float double-float-value-slot
779 other-pointer-lowtag)))
780 (inst sar hi-bits 32)))
782 (define-vop (double-float-low-bits)
783 (:args (float :scs (double-reg descriptor-reg)
784 :load-if (not (sc-is float double-stack))))
785 (:results (lo-bits :scs (unsigned-reg)))
786 (:temporary (:sc signed-stack :from :argument :to :result) temp)
787 (:arg-types double-float)
788 (:result-types unsigned-num)
789 (:translate double-float-low-bits)
790 (:policy :fast-safe)
791 (:vop-var vop)
792 (:generator 5
793 (sc-case float
794 (double-reg
795 (inst movsd temp float)
796 (move lo-bits temp))
797 (double-stack
798 (loadw lo-bits ebp-tn (- (1+ (tn-offset float)))))
799 (descriptor-reg
800 (loadw lo-bits float double-float-value-slot
801 other-pointer-lowtag)))
802 (inst shl lo-bits 32)
803 (inst shr lo-bits 32)))
807 ;;;; complex float VOPs
809 (define-vop (make-complex-single-float)
810 (:translate complex)
811 (:args (real :scs (single-reg) :to :result :target r
812 :load-if (not (location= real r)))
813 (imag :scs (single-reg) :to :save))
814 (:arg-types single-float single-float)
815 (:results (r :scs (complex-single-reg) :from (:argument 0)
816 :load-if (not (sc-is r complex-single-stack))))
817 (:result-types complex-single-float)
818 (:note "inline complex single-float creation")
819 (:policy :fast-safe)
820 (:generator 5
821 (sc-case r
822 (complex-single-reg
823 (let ((r-real (complex-single-reg-real-tn r)))
824 (unless (location= real r-real)
825 (inst movss r-real real)))
826 (let ((r-imag (complex-single-reg-imag-tn r)))
827 (unless (location= imag r-imag)
828 (inst movss r-imag imag))))
829 (complex-single-stack
830 (unless (location= real r)
831 (inst movss (ea-for-csf-real-stack r) real))
832 (inst movss (ea-for-csf-imag-stack r) imag)))))
834 (define-vop (make-complex-double-float)
835 (:translate complex)
836 (:args (real :scs (double-reg) :target r
837 :load-if (not (location= real r)))
838 (imag :scs (double-reg) :to :save))
839 (:arg-types double-float double-float)
840 (:results (r :scs (complex-double-reg) :from (:argument 0)
841 :load-if (not (sc-is r complex-double-stack))))
842 (:result-types complex-double-float)
843 (:note "inline complex double-float creation")
844 (:policy :fast-safe)
845 (:generator 5
846 (sc-case r
847 (complex-double-reg
848 (let ((r-real (complex-double-reg-real-tn r)))
849 (unless (location= real r-real)
850 (inst movsd r-real real)))
851 (let ((r-imag (complex-double-reg-imag-tn r)))
852 (unless (location= imag r-imag)
853 (inst movsd r-imag imag))))
854 (complex-double-stack
855 (unless (location= real r)
856 (inst movsd (ea-for-cdf-real-stack r) real))
857 (inst movsd (ea-for-cdf-imag-stack r) imag)))))
859 (define-vop (complex-float-value)
860 (:args (x :target r))
861 (:results (r))
862 (:variant-vars offset)
863 (:policy :fast-safe)
864 (:generator 3
865 (cond ((sc-is x complex-single-reg complex-double-reg)
866 (let ((value-tn
867 (make-random-tn :kind :normal
868 :sc (sc-or-lose 'double-reg)
869 :offset (+ offset (tn-offset x)))))
870 (unless (location= value-tn r)
871 (if (sc-is x complex-single-reg)
872 (inst movss r value-tn)
873 (inst movsd r value-tn)))))
874 ((sc-is r single-reg)
875 (let ((ea (sc-case x
876 (complex-single-stack
877 (ecase offset
878 (0 (ea-for-csf-real-stack x))
879 (1 (ea-for-csf-imag-stack x))))
880 (descriptor-reg
881 (ecase offset
882 (0 (ea-for-csf-real-desc x))
883 (1 (ea-for-csf-imag-desc x)))))))
884 (inst movss r ea)))
885 ((sc-is r double-reg)
886 (let ((ea (sc-case x
887 (complex-double-stack
888 (ecase offset
889 (0 (ea-for-cdf-real-stack x))
890 (1 (ea-for-cdf-imag-stack x))))
891 (descriptor-reg
892 (ecase offset
893 (0 (ea-for-cdf-real-desc x))
894 (1 (ea-for-cdf-imag-desc x)))))))
895 (inst movsd r ea)))
896 (t (error "COMPLEX-FLOAT-VALUE VOP failure")))))
898 (define-vop (realpart/complex-single-float complex-float-value)
899 (:translate realpart)
900 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
901 :target r))
902 (:arg-types complex-single-float)
903 (:results (r :scs (single-reg)))
904 (:result-types single-float)
905 (:note "complex float realpart")
906 (:variant 0))
908 (define-vop (realpart/complex-double-float complex-float-value)
909 (:translate realpart)
910 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
911 :target r))
912 (:arg-types complex-double-float)
913 (:results (r :scs (double-reg)))
914 (:result-types double-float)
915 (:note "complex float realpart")
916 (:variant 0))
918 (define-vop (imagpart/complex-single-float complex-float-value)
919 (:translate imagpart)
920 (:args (x :scs (complex-single-reg complex-single-stack descriptor-reg)
921 :target r))
922 (:arg-types complex-single-float)
923 (:results (r :scs (single-reg)))
924 (:result-types single-float)
925 (:note "complex float imagpart")
926 (:variant 1))
928 (define-vop (imagpart/complex-double-float complex-float-value)
929 (:translate imagpart)
930 (:args (x :scs (complex-double-reg complex-double-stack descriptor-reg)
931 :target r))
932 (:arg-types complex-double-float)
933 (:results (r :scs (double-reg)))
934 (:result-types double-float)
935 (:note "complex float imagpart")
936 (:variant 1))
939 ;;; hack dummy VOPs to bias the representation selection of their
940 ;;; arguments towards a FP register, which can help avoid consing at
941 ;;; inappropriate locations
942 (defknown double-float-reg-bias (double-float) (values))
943 (define-vop (double-float-reg-bias)
944 (:translate double-float-reg-bias)
945 (:args (x :scs (double-reg double-stack) :load-if nil))
946 (:arg-types double-float)
947 (:policy :fast-safe)
948 (:note "inline dummy FP register bias")
949 (:ignore x)
950 (:generator 0))
951 (defknown single-float-reg-bias (single-float) (values))
952 (define-vop (single-float-reg-bias)
953 (:translate single-float-reg-bias)
954 (:args (x :scs (single-reg single-stack) :load-if nil))
955 (:arg-types single-float)
956 (:policy :fast-safe)
957 (:note "inline dummy FP register bias")
958 (:ignore x)
959 (:generator 0))