1 ;;;; the HPPA VM definition of floating point operations
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
15 (define-move-fun (load-fp-zero 1) (vop x y
)
16 ((fp-single-zero) (single-reg)
17 (fp-double-zero) (double-reg))
18 (inst funop
:copy x y
))
20 (defun ld-float (offset base r
)
21 (cond ((< offset
(ash 1 4))
22 (inst flds offset base r
))
23 ((and (< offset
(ash 1 13))
25 (inst ldo offset zero-tn lip-tn
)
26 (inst fldx lip-tn base r
))
28 (error "ld-float: bad offset: ~s~%" offset
))))
30 (define-move-fun (load-float 1) (vop x y
)
31 ((single-stack) (single-reg)
32 (double-stack) (double-reg))
33 (let ((offset (* (tn-offset x
) n-word-bytes
)))
34 (ld-float offset
(current-nfp-tn vop
) y
)))
36 (defun str-float (x offset base
)
37 (cond ((< offset
(ash 1 4))
38 ;(note-next-instruction vop :internal-error)
39 (inst fsts x offset base
))
40 ((and (< offset
(ash 1 13))
42 ;; FIXME-lav, ok with GC to use lip-tn for arbitrary offsets ?
43 (inst ldo offset zero-tn lip-tn
)
44 ;(note-next-instruction vop :internal-error)
45 (inst fstx x lip-tn base
))
47 (error "str-float: bad offset: ~s~%" offset
))))
49 (define-move-fun (store-float 1) (vop x y
)
50 ((single-reg) (single-stack)
51 (double-reg) (double-stack))
52 (let ((offset (* (tn-offset y
) n-word-bytes
)))
53 (str-float x offset
(current-nfp-tn vop
))))
56 (define-vop (move-float)
57 (:args
(x :scs
(single-reg double-reg
)
59 :load-if
(not (location= x y
))))
60 (:results
(y :scs
(single-reg double-reg
)
61 :load-if
(not (location= x y
))))
64 (unless (location= y x
)
65 (inst funop
:copy x y
))))
66 (define-move-vop move-float
:move
(single-reg) (single-reg))
67 (define-move-vop move-float
:move
(double-reg) (double-reg))
69 (define-vop (move-from-float)
71 (:results
(y :scs
(descriptor-reg)))
72 (:temporary
(:scs
(non-descriptor-reg)) ndescr
)
73 (:variant-vars size type data
)
74 (:note
"float to pointer coercion")
76 (with-fixed-allocation (y nil ndescr type size nil
)
78 (inst fsts x
(- (* data n-word-bytes
) other-pointer-lowtag
) y
)))
80 (macrolet ((frob (name sc
&rest args
)
82 (define-vop (,name move-from-float
)
83 (:args
(x :scs
(,sc
) :to
:save
))
85 (define-move-vop ,name
:move
(,sc
) (descriptor-reg)))))
86 (frob move-from-single single-reg
87 single-float-size single-float-widetag single-float-value-slot
)
88 (frob move-from-double double-reg
89 double-float-size double-float-widetag double-float-value-slot
))
91 (define-vop (move-to-float)
92 (:args
(x :scs
(descriptor-reg)))
94 (:variant-vars offset
)
95 (:note
"pointer to float coercion")
97 (inst flds
(- (* offset n-word-bytes
) other-pointer-lowtag
) x y
)))
99 (macrolet ((frob (name sc offset
)
101 (define-vop (,name move-to-float
)
102 (:results
(y :scs
(,sc
)))
104 (define-move-vop ,name
:move
(descriptor-reg) (,sc
)))))
105 (frob move-to-single single-reg single-float-value-slot
)
106 (frob move-to-double double-reg double-float-value-slot
))
108 (define-vop (move-float-arg)
109 (:args
(x :scs
(single-reg double-reg
) :target y
)
111 :load-if
(not (sc-is y single-reg double-reg
))))
113 (:note
"float argument move")
116 ((single-reg double-reg
)
117 (unless (location= x y
)
118 (inst funop
:copy x y
)))
119 ((single-stack double-stack
)
120 (let ((offset (* (tn-offset y
) n-word-bytes
)))
121 (str-float x offset nfp
))))))
122 (define-move-vop move-float-arg
:move-arg
123 (single-reg descriptor-reg
) (single-reg))
124 (define-move-vop move-float-arg
:move-arg
125 (double-reg descriptor-reg
) (double-reg))
127 ;;;; Complex float move functions
128 (defun complex-single-reg-real-tn (x)
129 (make-random-tn :kind
:normal
:sc
(sc-or-lose 'single-reg
)
130 :offset
(tn-offset x
)))
131 (defun complex-single-reg-imag-tn (x)
132 (make-random-tn :kind
:normal
:sc
(sc-or-lose 'single-reg
)
133 :offset
(1+ (tn-offset x
))))
135 (defun complex-double-reg-real-tn (x)
136 (make-random-tn :kind
:normal
:sc
(sc-or-lose 'complex-double-reg
)
137 :offset
(tn-offset x
)))
138 (defun complex-double-reg-imag-tn (x)
139 (make-random-tn :kind
:normal
:sc
(sc-or-lose 'complex-double-reg
)
140 :offset
(1+ (tn-offset x
))))
143 ((def-move-fun (dir type size from to
)
144 `(define-move-fun (,(symbolicate dir
"-" type
) ,size
) (vop x y
)
145 ((,(symbolicate type
"-" from
)) (,(symbolicate type
"-" to
)))
146 (let ((nfp (current-nfp-tn vop
))
147 (offset (* (tn-offset ,(if (eq dir
'load
) 'x
'y
)) n-word-bytes
)))
149 `((let ((real-tn (,(symbolicate type
"-REG-REAL-TN") y
)))
150 (ld-float offset nfp real-tn
))
151 (let ((imag-tn (,(symbolicate type
"-REG-IMAG-TN") y
)))
152 (ld-float (+ offset
(* ,(/ size
2) n-word-bytes
)) nfp imag-tn
)))
153 `((let ((real-tn (,(symbolicate type
"-REG-REAL-TN") x
)))
154 (str-float real-tn offset nfp
))
155 (let ((imag-tn (,(symbolicate type
"-REG-IMAG-TN") x
)))
157 (+ offset
(* ,(/ size
2) n-word-bytes
))
159 (def-move-fun load complex-single
2 stack reg
)
160 (def-move-fun store complex-single
2 reg stack
)
161 (def-move-fun load complex-double
4 stack reg
)
162 (def-move-fun store complex-double
4 reg stack
))
164 ;;; Complex float register to register moves.
165 (define-vop (complex-single-move)
166 (:args
(x :scs
(complex-single-reg) :target y
167 :load-if
(not (location= x y
))))
168 (:results
(y :scs
(complex-single-reg) :load-if
(not (location= x y
))))
169 (:note
"complex single float move")
171 (unless (location= x y
)
172 ;; Note the complex-float-regs are aligned to every second
173 ;; float register so there is not need to worry about overlap.
174 (let ((x-real (complex-single-reg-real-tn x
))
175 (y-real (complex-single-reg-real-tn y
)))
176 (inst funop
:copy x-real y-real
))
177 (let ((x-imag (complex-single-reg-imag-tn x
))
178 (y-imag (complex-single-reg-imag-tn y
)))
179 (inst funop
:copy x-imag y-imag
)))))
180 (define-move-vop complex-single-move
:move
181 (complex-single-reg) (complex-single-reg))
183 (define-vop (complex-double-move)
184 (:args
(x :scs
(complex-double-reg)
185 :target y
:load-if
(not (location= x y
))))
186 (:results
(y :scs
(complex-double-reg) :load-if
(not (location= x y
))))
187 (:note
"complex double float move")
189 (unless (location= x y
)
190 ;; Note the complex-float-regs are aligned to every second
191 ;; float register so there is not need to worry about overlap.
192 (let ((x-real (complex-double-reg-real-tn x
))
193 (y-real (complex-double-reg-real-tn y
)))
194 (inst funop
:copy x-real y-real
))
195 (let ((x-imag (complex-double-reg-imag-tn x
))
196 (y-imag (complex-double-reg-imag-tn y
)))
197 (inst funop
:copy x-imag y-imag
)))))
198 (define-move-vop complex-double-move
:move
199 (complex-double-reg) (complex-double-reg))
201 ;;; Move from a complex float to a descriptor register allocating a
202 ;;; new complex float object in the process.
203 (define-vop (move-from-complex-single)
204 (:args
(x :scs
(complex-single-reg) :to
:save
))
205 (:results
(y :scs
(descriptor-reg)))
206 (:temporary
(:scs
(non-descriptor-reg)) ndescr
)
207 (:note
"complex single float to pointer coercion")
209 (with-fixed-allocation (y nil ndescr complex-single-float-widetag
210 complex-single-float-size nil
)
212 (let ((real-tn (complex-single-reg-real-tn x
)))
213 (inst fsts real-tn
(- (* complex-single-float-real-slot n-word-bytes
)
214 other-pointer-lowtag
) y
))
215 (let ((imag-tn (complex-single-reg-imag-tn x
)))
216 (inst fsts imag-tn
(- (* complex-single-float-imag-slot n-word-bytes
)
217 other-pointer-lowtag
) y
))))
218 (define-move-vop move-from-complex-single
:move
219 (complex-single-reg) (descriptor-reg))
221 (define-vop (move-from-complex-double)
222 (:args
(x :scs
(complex-double-reg) :to
:save
))
223 (:results
(y :scs
(descriptor-reg)))
224 (:temporary
(:scs
(non-descriptor-reg)) ndescr
)
225 (:note
"complex double float to pointer coercion")
227 (with-fixed-allocation (y nil ndescr complex-double-float-widetag
228 complex-double-float-size nil
)
230 (let ((real-tn (complex-double-reg-real-tn x
)))
231 (inst fsts real-tn
(- (* complex-double-float-real-slot n-word-bytes
)
232 other-pointer-lowtag
) y
))
233 (let ((imag-tn (complex-double-reg-imag-tn x
)))
234 (inst fsts imag-tn
(- (* complex-double-float-imag-slot n-word-bytes
)
235 other-pointer-lowtag
) y
))))
236 (define-move-vop move-from-complex-double
:move
237 (complex-double-reg) (descriptor-reg))
239 ;;; Move from a descriptor to a complex float register
240 (define-vop (move-to-complex-single)
241 (:args
(x :scs
(descriptor-reg)))
242 (:results
(y :scs
(complex-single-reg)))
243 (:note
"pointer to complex float coercion")
245 (let ((real-tn (complex-single-reg-real-tn y
)))
246 (inst flds
(- (* complex-single-float-real-slot n-word-bytes
)
247 other-pointer-lowtag
)
249 (let ((imag-tn (complex-single-reg-imag-tn y
)))
250 (inst flds
(- (* complex-single-float-imag-slot n-word-bytes
)
251 other-pointer-lowtag
)
253 (define-move-vop move-to-complex-single
:move
254 (descriptor-reg) (complex-single-reg))
256 (define-vop (move-to-complex-double)
257 (:args
(x :scs
(descriptor-reg)))
258 (:results
(y :scs
(complex-double-reg)))
259 (:note
"pointer to complex float coercion")
261 (let ((real-tn (complex-double-reg-real-tn y
)))
262 (inst flds
(- (* complex-double-float-real-slot n-word-bytes
)
263 other-pointer-lowtag
)
265 (let ((imag-tn (complex-double-reg-imag-tn y
)))
266 (inst flds
(- (* complex-double-float-imag-slot n-word-bytes
)
267 other-pointer-lowtag
)
269 (define-move-vop move-to-complex-double
:move
270 (descriptor-reg) (complex-double-reg))
272 ;;; Complex float move-arg vop
273 (define-vop (move-complex-single-float-arg)
274 (:args
(x :scs
(complex-single-reg) :target y
)
275 (nfp :scs
(any-reg) :load-if
(not (sc-is y complex-single-reg
))))
277 (:note
"float argument move")
281 (unless (location= x y
)
282 (let ((x-real (complex-single-reg-real-tn x
))
283 (y-real (complex-single-reg-real-tn y
)))
284 (inst funop
:copy x-real y-real
))
285 (let ((x-imag (complex-single-reg-imag-tn x
))
286 (y-imag (complex-single-reg-imag-tn y
)))
287 (inst funop
:copy x-imag y-imag
))))
288 (complex-single-stack
289 (let ((offset (* (tn-offset y
) n-word-bytes
)))
290 (let ((real-tn (complex-single-reg-real-tn x
)))
291 (str-float real-tn offset nfp
))
292 (let ((imag-tn (complex-single-reg-imag-tn x
)))
293 (str-float imag-tn
(+ offset n-word-bytes
) nfp
)))))))
294 (define-move-vop move-complex-single-float-arg
:move-arg
295 (complex-single-reg descriptor-reg
) (complex-single-reg))
297 (define-vop (move-complex-double-float-arg)
298 (:args
(x :scs
(complex-double-reg) :target y
)
299 (nfp :scs
(any-reg) :load-if
(not (sc-is y complex-double-reg
))))
301 (:note
"float argument move")
305 (unless (location= x y
)
306 (let ((x-real (complex-double-reg-real-tn x
))
307 (y-real (complex-double-reg-real-tn y
)))
308 (inst funop
:copy x-real y-real
))
309 (let ((x-imag (complex-double-reg-imag-tn x
))
310 (y-imag (complex-double-reg-imag-tn y
)))
311 (inst funop
:copy x-imag y-imag
))))
312 (complex-double-stack
313 (let ((offset (* (tn-offset y
) n-word-bytes
)))
314 (let ((real-tn (complex-double-reg-real-tn x
)))
315 (str-float real-tn offset nfp
))
316 (let ((imag-tn (complex-double-reg-imag-tn x
)))
317 (str-float imag-tn
(+ offset
(* 2 n-word-bytes
)) nfp
)))))))
318 (define-move-vop move-complex-double-float-arg
:move-arg
319 (complex-double-reg descriptor-reg
) (complex-double-reg))
321 (define-move-vop move-arg
:move-arg
322 (single-reg double-reg complex-single-reg complex-double-reg
)
325 ;;;; stuff for c-call float-in-int-register arguments
326 (define-vop (move-to-single-int-reg)
327 (:note
"pointer to float-in-int coercion")
328 (:args
(x :scs
(single-reg descriptor-reg
)))
329 (:results
(y :scs
(single-int-carg-reg) :load-if nil
))
333 (inst funop
:copy x y
))
335 (inst ldw
(- (* single-float-value-slot n-word-bytes
)
336 other-pointer-lowtag
) x y
)))))
337 (define-move-vop move-to-single-int-reg
338 :move
(single-reg descriptor-reg
) (single-int-carg-reg))
340 (define-vop (move-single-int-reg)
341 (:args
(x :target y
:scs
(single-int-carg-reg) :load-if nil
)
342 (fp :scs
(any-reg) :load-if
(not (sc-is y single-int-carg-reg
))))
343 (:results
(y :scs
(single-int-carg-reg) :load-if nil
))
345 (unless (location= x y
)
346 (error "Huh? why did it do that?"))))
347 (define-move-vop move-single-int-reg
:move-arg
348 (single-int-carg-reg) (single-int-carg-reg))
350 ; move contents of float register x to register y
351 (define-vop (move-to-double-int-reg)
352 (:note
"pointer to float-in-int coercion")
353 (:args
(x :scs
(double-reg descriptor-reg
)))
354 (:results
(y :scs
(double-int-carg-reg) :load-if nil
))
355 (:temporary
(:scs
(signed-stack) :to
(:result
0)) temp
)
356 (:temporary
(:scs
(signed-reg) :to
(:result
0) :target y
) old1
)
357 (:temporary
(:scs
(signed-reg) :to
(:result
0) :target y
) old2
)
359 (:save-p
:compute-only
)
363 (let* ((nfp (current-nfp-tn vop
))
366 (double-int-carg-reg temp
)))
367 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
368 ;; save 8 bytes of stack to two register,
369 ;; write down float in stack and load it back
370 ;; into result register. Notice the result hack,
371 ;; we are writing to one extra register.
372 ;; Double float argument convention uses two registers,
373 ;; but we only know about one (thanks to c-call).
374 (inst ldw offset nfp old1
)
375 (inst ldw
(+ offset n-word-bytes
) nfp old2
)
376 (str-float x offset nfp
) ; writes 8 bytes
377 (inst ldw offset nfp y
)
378 (inst ldw
(+ offset n-word-bytes
) nfp
379 (make-wired-tn (primitive-type-or-lose 'unsigned-byte-32
)
380 (sc-number-or-lose 'unsigned-reg
)
381 (+ 1 (tn-offset y
))))
382 (inst stw old1 offset nfp
)
383 (inst stw old2
(+ offset n-word-bytes
) nfp
)))
385 (inst ldw
(- (* double-float-value-slot n-word-bytes
)
386 other-pointer-lowtag
) x y
)
387 (inst ldw
(- (* (1+ double-float-value-slot
) n-word-bytes
)
388 other-pointer-lowtag
) x
389 (make-wired-tn (primitive-type-or-lose 'unsigned-byte-32
)
390 (sc-number-or-lose 'unsigned-reg
)
391 (+ 1 (tn-offset y
))))))))
392 (define-move-vop move-to-double-int-reg
393 :move
(double-reg descriptor-reg
) (double-int-carg-reg))
395 (define-vop (move-double-int-reg)
396 (:args
(x :target y
:scs
(double-int-carg-reg) :load-if nil
)
397 (fp :scs
(any-reg) :load-if
(not (sc-is y double-int-carg-reg
))))
398 (:results
(y :scs
(double-int-carg-reg) :load-if nil
))
400 (unless (location= x y
)
401 (error "Huh? why did it do that?"))))
402 (define-move-vop move-double-int-reg
:move-arg
403 (double-int-carg-reg) (double-int-carg-reg))
405 ;;;; Arithmetic VOPs.
407 (define-vop (float-op)
410 (:variant-vars operation
)
412 (:note
"inline float arithmetic")
414 (:save-p
:compute-only
)
416 (note-this-location vop
:internal-error
)
417 (inst fbinop operation x y r
)))
419 (macrolet ((frob (name sc zero-sc ptype
)
420 `(define-vop (,name float-op
)
421 (:args
(x :scs
(,sc
,zero-sc
))
422 (y :scs
(,sc
,zero-sc
)))
423 (:results
(r :scs
(,sc
)))
424 (:arg-types
,ptype
,ptype
)
425 (:result-types
,ptype
))))
426 (frob single-float-op single-reg fp-single-zero single-float
)
427 (frob double-float-op double-reg fp-double-zero double-float
))
429 (macrolet ((frob (translate op sname scost dname dcost
)
431 (define-vop (,sname single-float-op
)
432 (:translate
,translate
)
434 (:variant-cost
,scost
))
435 (define-vop (,dname double-float-op
)
436 (:translate
,translate
)
438 (:variant-cost
,dcost
)))))
439 (frob + :add
+/single-float
2 +/double-float
2)
440 (frob -
:sub -
/single-float
2 -
/double-float
2)
441 (frob * :mpy
*/single-float
4 */double-float
5)
442 (frob / :div
//single-float
12 //double-float
19))
444 (macrolet ((frob (name translate sc type inst
)
446 (:args
(x :scs
(,sc
)))
447 (:results
(y :scs
(,sc
)))
448 (:translate
,translate
)
451 (:result-types
,type
)
452 (:note
"inline float arithmetic")
454 (:save-p
:compute-only
)
456 (note-this-location vop
:internal-error
)
458 (frob abs
/single-float abs single-reg single-float
459 (inst funop
:abs x y
))
460 (frob abs
/double-float abs double-reg double-float
461 (inst funop
:abs x y
)))
463 (macrolet ((frob (name translate sc type zero-tn
)
465 (:args
(x :scs
(,sc
)))
466 (:results
(y :scs
(,sc
)))
467 (:temporary
(:scs
(,sc
)) float-temp
)
468 (:temporary
(:scs
(signed-reg)) reg-temp
)
469 (:temporary
(:scs
(signed-stack)) stack-temp
)
470 (:translate
,translate
)
473 (:result-types
,type
)
474 (:note
"inline float arithmetic")
476 (:save-p
:compute-only
)
478 (note-this-location vop
:internal-error
)
479 ;; KLUDGE: Subtracting the input from zero fails to
480 ;; produce negative zero from positive zero.
481 ;; Multiplying by -1 causes overflow conditions on
482 ;; some inputs. The FNEG instruction is available
483 ;; in PA-RISC 2.0 only, and we're supposed to be
484 ;; PA-RISC 1.1 compatible. To do the negation as an
485 ;; integer operation requires writing out the value
486 ;; (or its high bits) to memory, reading them up
487 ;; into a non-descriptor-reg, flipping the sign bit
488 ;; (most likely requiring another unsigned-reg to
489 ;; hold a constant to XOR with), then getting the
490 ;; result back to the FPU via memory again. So
491 ;; instead we test for zeroness explicitly and
492 ;; decide which of the two FPU-based strategies to
493 ;; use. I feel unclean for having implemented this,
494 ;; but it seems to be the least dreadful option.
495 ;; Help? -- AB, 2015-11-26
496 (inst fcmp
#b00111 x
,zero-tn
)
498 (inst b SUBTRACT-FROM-ZERO
:nullify t
)
500 MULTIPLY-BY-NEGATIVE-ONE
501 (let ((nfp (current-nfp-tn vop
))
502 (short-float-temp (make-random-tn :kind
:normal
503 :sc
(sc-or-lose 'single-reg
)
504 :offset
(tn-offset reg-temp
))))
505 (inst li -
1 reg-temp
)
506 (storew reg-temp nfp
(tn-offset stack-temp
))
507 (ld-float (* (tn-offset stack-temp
) n-word-bytes
) nfp short-float-temp
)
508 (inst fcnvxf short-float-temp float-temp
)
509 (inst fbinop
:mpy x float-temp y
))
510 (inst b DONE
:nullify t
)
513 (inst fbinop
:sub
,zero-tn x y
)
516 (frob %negate
/single-float %negate single-reg single-float fp-single-zero-tn
)
517 (frob %negate
/double-float %negate double-reg double-float fp-double-zero-tn
))
521 (define-vop (float-compare)
525 (:variant-vars condition complement
)
527 (:note
"inline float comparison")
529 (:save-p
:compute-only
)
531 (note-this-location vop
:internal-error
)
532 ;; This is the condition to nullify the branch, so it is inverted.
533 (inst fcmp
(if not-p condition complement
) x y
)
535 (inst b target
:nullify t
)))
537 (macrolet ((frob (name sc zero-sc ptype
)
538 `(define-vop (,name float-compare
)
539 (:args
(x :scs
(,sc
,zero-sc
))
540 (y :scs
(,sc
,zero-sc
)))
541 (:arg-types
,ptype
,ptype
))))
542 (frob single-float-compare single-reg fp-single-zero single-float
)
543 (frob double-float-compare double-reg fp-double-zero double-float
))
545 (macrolet ((frob (translate condition complement sname dname
)
547 (define-vop (,sname single-float-compare
)
548 (:translate
,translate
)
549 (:variant
,condition
,complement
))
550 (define-vop (,dname double-float-compare
)
551 (:translate
,translate
)
552 (:variant
,condition
,complement
)))))
553 ;; FIXME-lav: let 'inst cmp' translate keywords into raw binary instead of giving it here
554 (frob < #b01001
#b10101
</single-float
</double-float
)
555 (frob > #b10001
#b01101
>/single-float
>/double-float
)
556 (frob = #b00101
#b11001 eql
/single-float eql
/double-float
))
561 (macrolet ((frob (name translate from-sc from-type to-sc to-type
)
563 (:args
(x :scs
(,from-sc
)))
564 (:results
(y :scs
(,to-sc
)))
565 (:arg-types
,from-type
)
566 (:result-types
,to-type
)
568 (:note
"inline float coercion")
569 (:translate
,translate
)
571 (:save-p
:compute-only
)
573 (note-this-location vop
:internal-error
)
574 (inst fcnvff x y
)))))
575 (frob %single-float
/double-float %single-float
576 double-reg double-float
577 single-reg single-float
)
578 (frob %double-float
/single-float %double-float
579 single-reg single-float
580 double-reg double-float
))
582 ; convert register-integer to registersingle/double by
583 ; putting it on single-float-stack and then float-loading it into
584 ; an float register, and finally convert the float-register and
585 ; storing the result into y
586 (macrolet ((frob (name translate to-sc to-type
)
588 (:args
(x :scs
(signed-reg)
589 :load-if
(not (sc-is x signed-stack
))
591 (:arg-types signed-num
)
592 (:results
(y :scs
(,to-sc
)))
593 (:result-types
,to-type
)
595 (:note
"inline float coercion")
596 (:translate
,translate
)
598 (:save-p
:compute-only
)
599 (:temporary
(:scs
(signed-stack) :from
(:argument
0))
601 (:temporary
(:scs
(single-reg) :to
(:result
0) :target y
)
603 (:temporary
(:scs
(any-reg) :from
(:argument
0)
604 :to
(:result
0)) index
)
606 (let* ((nfp (current-nfp-tn vop
))
612 (storew x nfp
(tn-offset stack-temp
))
614 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
615 (cond ((< offset
(ash 1 4))
616 (inst flds offset nfp fp-temp
))
617 ((and (< offset
(ash 1 13))
619 (inst ldo offset zero-tn index
)
620 (inst fldx index nfp fp-temp
))
622 (error "in vop ~s offset ~s is out-of-range" ',name offset
)))
623 (note-this-location vop
:internal-error
)
624 (inst fcnvxf fp-temp y
))))))
625 (frob %single-float
/signed %single-float
626 single-reg single-float
)
627 (frob %double-float
/signed %double-float
628 double-reg double-float
))
630 (macrolet ((frob (trans from-sc from-type inst note
)
631 `(define-vop (,(symbolicate trans
"/" from-type
))
632 (:args
(x :scs
(,from-sc
)
634 (:results
(y :scs
(signed-reg)
635 :load-if
(not (sc-is y signed-stack
))))
636 (:arg-types
,from-type
)
637 (:result-types signed-num
)
642 (:save-p
:compute-only
)
643 (:temporary
(:scs
(single-reg) :from
(:argument
0)) fp-temp
)
644 (:temporary
(:scs
(signed-stack) :to
(:result
0) :target y
)
646 (:temporary
(:scs
(any-reg) :from
(:argument
0)
647 :to
(:result
0)) index
)
649 (let* ((nfp (current-nfp-tn vop
))
653 (signed-reg stack-temp
)))
654 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
655 (inst ,inst x fp-temp
)
656 (cond ((< offset
(ash 1 4))
657 (note-next-instruction vop
:internal-error
)
658 (inst fsts fp-temp offset nfp
))
659 ((and (< offset
(ash 1 13))
661 (inst ldo offset zero-tn index
)
662 (note-next-instruction vop
:internal-error
)
663 (inst fstx fp-temp index nfp
))
665 (error "unary error, ldo offset too high")))
666 (unless (eq y stack-tn
)
667 (loadw y nfp
(tn-offset stack-tn
))))))))
668 (frob %unary-round single-reg single-float fcnvfx
"inline float round")
669 (frob %unary-round double-reg double-float fcnvfx
"inline float round")
670 (frob %unary-truncate
/single-float single-reg single-float fcnvfxt
671 "inline float truncate")
672 (frob %unary-truncate
/double-float double-reg double-float fcnvfxt
673 "inline float truncate"))
675 (define-vop (make-single-float)
676 (:args
(bits :scs
(signed-reg)
677 :load-if
(or (not (sc-is bits signed-stack
))
678 (sc-is res single-stack
))
680 (:results
(res :scs
(single-reg)
681 :load-if
(not (sc-is bits single-stack
))))
682 (:arg-types signed-num
)
683 (:result-types single-float
)
684 (:translate make-single-float
)
687 (:temporary
(:scs
(single-stack) :from
(:argument
0) :to
(:result
0)) temp
)
688 (:temporary
(:scs
(any-reg) :from
(:argument
0) :to
(:result
0)) index
)
690 (let ((nfp (current-nfp-tn vop
)))
695 (let ((offset (* (tn-offset temp
) n-word-bytes
)))
696 (inst stw bits offset nfp
)
697 (cond ((< offset
(ash 1 4))
698 (inst flds offset nfp res
))
699 ((and (< offset
(ash 1 13))
701 (inst ldo offset zero-tn index
)
702 (inst fldx index nfp res
))
704 (error "make-single-float error, ldo offset too large")))))
706 (inst stw bits
(* (tn-offset res
) n-word-bytes
) nfp
))))
710 (let ((offset (* (tn-offset bits
) n-word-bytes
)))
711 (cond ((< offset
(ash 1 4))
712 (inst flds offset nfp res
))
713 ((and (< offset
(ash 1 13))
715 (inst ldo offset zero-tn index
)
716 (inst fldx index nfp res
))
718 (error "make-single-float error, ldo offset too large")))))))))))
720 (define-vop (make-double-float)
721 (:args
(hi-bits :scs
(signed-reg))
722 (lo-bits :scs
(unsigned-reg)))
723 (:results
(res :scs
(double-reg)
724 :load-if
(not (sc-is res double-stack
))))
725 (:arg-types signed-num unsigned-num
)
726 (:result-types double-float
)
727 (:translate make-double-float
)
729 (:temporary
(:scs
(double-stack) :to
(:result
0)) temp
)
730 (:temporary
(:scs
(any-reg) :from
(:argument
0) :to
(:result
0)) index
)
733 (let* ((nfp (current-nfp-tn vop
))
734 (stack-tn (sc-case res
737 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
738 (inst stw hi-bits offset nfp
)
739 (inst stw lo-bits
(+ offset n-word-bytes
) nfp
)
740 (cond ((eq stack-tn res
))
741 ((< offset
(ash 1 4))
742 (inst flds offset nfp res
))
743 ((and (< offset
(ash 1 13))
745 (inst ldo offset zero-tn index
)
746 (inst fldx index nfp res
))
748 (error "make-single-float error, ldo offset too large"))))))
751 ((float-bits (name reg rreg stack rstack atype anum side offset
)
753 (:args
(float :scs
(,reg
)
754 :load-if
(not (sc-is float
,stack
))))
755 (:results
(bits :scs
(,rreg
)
756 :load-if
(or (not (sc-is bits
,rstack
))
757 (sc-is float
,stack
))))
759 (:result-types
,anum
)
763 (:temporary
(:scs
(signed-stack) :from
(:argument
0) :to
(:result
0)) temp
)
764 (:temporary
(:scs
(any-reg) :from
(:argument
0) :to
(:result
0)) index
)
766 (let ((nfp (current-nfp-tn vop
)))
771 (let ((offset (* (tn-offset temp
) n-word-bytes
)))
772 (cond ((< offset
(ash 1 4))
774 `((inst fsts float offset nfp
:side
,side
))
775 `((inst fsts float offset nfp
))))
776 ((and (< offset
(ash 1 13))
778 (inst ldo offset zero-tn index
)
780 `((inst fstx float index nfp
:side
,side
))
781 `((inst fstx float index nfp
))))
783 (error ,(format nil
"~s,~s: inst-LDO offset too large"
785 (inst ldw offset nfp bits
)))
787 (let ((offset (* (tn-offset bits
) n-word-bytes
)))
788 (cond ((< offset
(ash 1 4))
790 `((inst fsts float offset nfp
:side
,side
))
791 `((inst fsts float offset nfp
))))
792 ((and (< offset
(ash 1 13))
794 (inst ldo offset zero-tn index
)
796 `((inst fstx float index nfp
:side
,side
))
797 `((inst fstx float index nfp
))))
799 (error ,(format nil
"~s,~s: inst-LDO offset too large"
804 (inst ldw
(* (+ (tn-offset float
) ,offset
) n-word-bytes
)
806 (float-bits single-float-bits single-reg signed-reg single-stack
807 signed-stack single-float signed-num nil
0)
808 (float-bits double-float-high-bits double-reg signed-reg
809 double-stack signed-stack double-float signed-num
0 0)
810 (float-bits double-float-low-bits double-reg unsigned-reg
811 double-stack unsigned-stack double-float unsigned-num
1 1))
813 ;;;; Float mode hackery:
815 (sb!xc
:deftype float-modes
() '(unsigned-byte 32))
816 (defknown floating-point-modes
() float-modes
(flushable))
817 (defknown ((setf floating-point-modes
)) (float-modes)
820 (define-vop (floating-point-modes)
821 (:results
(res :scs
(unsigned-reg)))
822 (:result-types unsigned-num
)
823 (:translate floating-point-modes
)
825 (:temporary
(:scs
(double-stack)) temp
)
826 (:temporary
(:scs
(any-reg) :to
(:result
0)) index
)
829 (let* ((nfp (current-nfp-tn vop
))
830 (stack-tn (sc-case res
832 (unsigned-reg temp
)))
833 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
834 (cond ((< offset
(ash 1 4))
835 (inst fsts fp-double-zero-tn offset nfp
))
836 ((and (< offset
(ash 1 13))
838 (inst ldo offset zero-tn index
)
839 (inst fstx fp-double-zero-tn index nfp
))
841 (error "floating-point-modes error, ldo offset too large")))
842 (ecase *backend-byte-order
*
844 (inst ldw offset nfp res
))
846 (inst ldw
(+ offset
4) nfp res
))))))
848 (define-vop (set-floating-point-modes)
849 (:args
(new :scs
(unsigned-reg) :target res
))
850 (:results
(res :scs
(unsigned-reg)))
851 (:arg-types unsigned-num
)
852 (:result-types unsigned-num
)
853 (:translate
(setf floating-point-modes
))
855 (:temporary
(:scs
(double-stack)) stack-tn
)
856 (:temporary
(:scs
(any-reg)) index
)
859 (let* ((nfp (current-nfp-tn vop
))
860 (offset (* (tn-offset stack-tn
) n-word-bytes
)))
861 (ecase *backend-byte-order
*
863 (inst stw new offset nfp
)
864 (inst stw zero-tn
(+ offset
4) nfp
))
866 (inst stw zero-tn offset nfp
)
867 (inst stw new
(+ offset
4) nfp
)))
868 (cond ((< offset
(ash 1 4))
869 (inst flds offset nfp fp-double-zero-tn
))
870 ((and (< offset
(ash 1 13))
872 (inst ldo offset zero-tn index
)
873 (inst fldx index nfp fp-double-zero-tn
))
875 (error "set-floating-point-modes error, ldo offset too large")))
878 ;;;; Complex float VOPs
880 (define-vop (make-complex-single-float)
882 (:args
(real :scs
(single-reg) :target r
)
883 (imag :scs
(single-reg) :to
:save
))
884 (:arg-types single-float single-float
)
885 (:results
(r :scs
(complex-single-reg) :from
(:argument
0)
886 :load-if
(not (sc-is r complex-single-stack
))))
887 (:result-types complex-single-float
)
888 (:note
"inline complex single-float creation")
894 (let ((r-real (complex-single-reg-real-tn r
)))
895 (unless (location= real r-real
)
896 (inst funop
:copy real r-real
)))
897 (let ((r-imag (complex-single-reg-imag-tn r
)))
898 (unless (location= imag r-imag
)
899 (inst funop
:copy imag r-imag
))))
900 (complex-single-stack
901 (let ((nfp (current-nfp-tn vop
))
902 (offset (* (tn-offset r
) n-word-bytes
)))
903 (str-float real offset nfp
)
904 (str-float imag
(+ offset n-word-bytes
) nfp
))))))
906 (define-vop (make-complex-double-float)
908 (:args
(real :scs
(double-reg) :target r
)
909 (imag :scs
(double-reg) :to
:save
))
910 (:arg-types double-float double-float
)
911 (:results
(r :scs
(complex-double-reg) :from
(:argument
0)
912 :load-if
(not (sc-is r complex-double-stack
))))
913 (:result-types complex-double-float
)
914 (:note
"inline complex double-float creation")
920 (let ((r-real (complex-double-reg-real-tn r
)))
921 (unless (location= real r-real
)
922 (inst funop
:copy real r-real
)))
923 (let ((r-imag (complex-double-reg-imag-tn r
)))
924 (unless (location= imag r-imag
)
925 (inst funop
:copy imag r-imag
))))
926 (complex-double-stack
927 (let ((nfp (current-nfp-tn vop
))
928 (offset (* (tn-offset r
) n-word-bytes
)))
929 (str-float real offset nfp
)
930 (str-float imag
(+ offset
(* 2 n-word-bytes
)) nfp
))))))
932 (define-vop (complex-single-float-value)
933 (:args
(x :scs
(complex-single-reg) :target r
934 :load-if
(not (sc-is x complex-single-stack
))))
935 (:arg-types complex-single-float
)
936 (:results
(r :scs
(single-reg)))
937 (:result-types single-float
)
944 (let ((value-tn (ecase slot
945 (:real
(complex-single-reg-real-tn x
))
946 (:imag
(complex-single-reg-imag-tn x
)))))
947 (unless (location= value-tn r
)
948 (inst funop
:copy value-tn r
))))
949 (complex-single-stack
950 (ld-float (* (+ (ecase slot
(:real
0) (:imag
1)) (tn-offset x
))
952 (current-nfp-tn vop
) r
)))))
954 (define-vop (realpart/complex-single-float complex-single-float-value
)
955 (:translate realpart
)
956 (:note
"complex single float realpart")
959 (define-vop (imagpart/complex-single-float complex-single-float-value
)
960 (:translate imagpart
)
961 (:note
"complex single float imagpart")
964 (define-vop (complex-double-float-value)
965 (:args
(x :scs
(complex-double-reg) :target r
966 :load-if
(not (sc-is x complex-double-stack
))))
967 (:arg-types complex-double-float
)
968 (:results
(r :scs
(double-reg)))
969 (:result-types double-float
)
976 (let ((value-tn (ecase slot
977 (:real
(complex-double-reg-real-tn x
))
978 (:imag
(complex-double-reg-imag-tn x
)))))
979 (unless (location= value-tn r
)
980 (inst funop
:copy value-tn r
))))
981 (complex-double-stack
982 (ld-float (* (+ (ecase slot
(:real
0) (:imag
2)) (tn-offset x
))
984 (current-nfp-tn vop
) r
)))))
986 (define-vop (realpart/complex-double-float complex-double-float-value
)
987 (:translate realpart
)
988 (:note
"complex double float realpart")
991 (define-vop (imagpart/complex-double-float complex-double-float-value
)
992 (:translate imagpart
)
993 (:note
"complex double float imagpart")