1 ;;;; VOPs and other machine-specific support routines for call-out to C
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 (defconstant +number-stack-alignment-mask
+ 7)
16 (defconstant +max-register-args
+ 4)
24 (defstruct (result-state (:copier nil
))
27 (defun result-reg-offset (slot)
32 (defun register-args-offset (index)
33 (elt '(#.ocfp-offset
#.nargs-offset
#.nl2-offset
#.nl3-offset
)
36 (defun int-arg (state prim-type reg-sc stack-sc
)
37 (let ((reg-args (arg-state-num-register-args state
)))
38 (cond ((< reg-args
+max-register-args
+)
39 (setf (arg-state-num-register-args state
) (1+ reg-args
))
40 (make-wired-tn* prim-type reg-sc
(register-args-offset reg-args
)))
42 (let ((frame-size (arg-state-stack-frame-size state
)))
43 (setf (arg-state-stack-frame-size state
) (1+ frame-size
))
44 (make-wired-tn* prim-type stack-sc frame-size
))))))
46 (define-alien-type-method (integer :arg-tn
) (type state
)
47 (if (alien-integer-type-signed type
)
48 (int-arg state
'signed-byte-32 signed-reg-sc-number signed-stack-sc-number
)
49 (int-arg state
'unsigned-byte-32 unsigned-reg-sc-number unsigned-stack-sc-number
)))
51 (define-alien-type-method (system-area-pointer :arg-tn
) (type state
)
52 (declare (ignore type
))
53 (int-arg state
'system-area-pointer sap-reg-sc-number sap-stack-sc-number
))
56 (define-alien-type-method (single-float :arg-tn
) (type state
)
57 (declare (ignore type
))
58 (int-arg state
'single-float unsigned-reg-sc-number single-stack-sc-number
))
61 (define-alien-type-method (single-float :arg-tn
) (type state
)
62 (declare (ignore type
))
63 (let ((register (arg-state-fp-registers state
)))
64 (cond ((> register
15)
65 (let ((frame-size (arg-state-stack-frame-size state
)))
66 (setf (arg-state-stack-frame-size state
) (1+ frame-size
))
67 (make-wired-tn* 'single-float single-stack-sc-number frame-size
)))
69 (incf (arg-state-fp-registers state
))
70 (make-wired-tn* 'single-float single-reg-sc-number register
)))))
73 (define-alien-type-method (double-float :arg-tn
) (type state
)
74 (declare (ignore type
))
75 (let* ((register (arg-state-num-register-args state
))
76 ;; The registers used are aligned, only r0-r1 and r2-r3 pairs
78 (register (+ register
(logand register
1))))
79 (cond ((> (+ register
2) +max-register-args
+)
80 (setf (arg-state-num-register-args state
) +max-register-args
+)
81 (let ((frame-size (arg-state-stack-frame-size state
)))
82 (setf (arg-state-stack-frame-size state
) (+ frame-size
2))
83 (make-wired-tn* 'double-float double-stack-sc-number frame-size
)))
85 (setf (arg-state-num-register-args state
) (+ register
2))
87 (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number
88 (register-args-offset register
))
89 (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number
90 (register-args-offset (1+ register
)))
91 'move-double-to-int-args
)))))
94 (define-alien-type-method (double-float :arg-tn
) (type state
)
95 (declare (ignore type
))
96 (let ((register (setf (arg-state-fp-registers state
)
97 (logandc2 (+ (arg-state-fp-registers state
) 1) 1))))
98 (cond ((> register
15)
101 (setf (arg-state-stack-frame-size state
)
102 (logandc2 (+ (arg-state-stack-frame-size state
) 1) 1))))
103 (setf (arg-state-stack-frame-size state
) (+ frame-size
2))
104 (make-wired-tn* 'double-float double-stack-sc-number frame-size
)))
106 (incf (arg-state-fp-registers state
) 2)
107 (make-wired-tn* 'double-float double-reg-sc-number register
)))))
109 (define-alien-type-method (integer :result-tn
) (type state
)
110 (let ((num-results (result-state-num-results state
)))
111 (setf (result-state-num-results state
) (1+ num-results
))
112 (multiple-value-bind (ptype reg-sc
)
113 (if (alien-integer-type-signed type
)
114 (values 'signed-byte-32 signed-reg-sc-number
)
115 (values 'unsigned-byte-32 unsigned-reg-sc-number
))
116 (make-wired-tn* ptype reg-sc
117 (result-reg-offset num-results
)))))
119 (define-alien-type-method (system-area-pointer :result-tn
) (type state
)
120 (declare (ignore type state
))
121 (make-wired-tn* 'system-area-pointer sap-reg-sc-number nargs-offset
))
124 (define-alien-type-method (single-float :result-tn
) (type state
)
125 (declare (ignore type state
))
126 (make-wired-tn* 'single-float unsigned-reg-sc-number nargs-offset
))
129 (define-alien-type-method (single-float :result-tn
) (type state
)
130 (declare (ignore type state
))
131 (make-wired-tn* 'single-float single-reg-sc-number
0))
134 (define-alien-type-method (double-float :result-tn
) (type state
)
135 (declare (ignore type state
))
136 (list (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number nargs-offset
)
137 (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number nl3-offset
)
138 'move-int-args-to-double
))
141 (define-alien-type-method (double-float :result-tn
) (type state
)
142 (declare (ignore type state
))
143 (make-wired-tn* 'double-float double-reg-sc-number
0))
145 (define-alien-type-method (values :result-tn
) (type state
)
146 (let ((values (alien-values-type-values type
)))
147 (when (> (length values
) 2)
148 (error "Too many result values from c-call."))
149 (mapcar (lambda (type)
150 (invoke-alien-type-method :result-tn type state
))
153 (defun make-call-out-tns (type)
154 (let ((arg-state (make-arg-state)))
156 (dolist (arg-type (alien-fun-type-arg-types type
))
157 (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state
)))
158 (values (make-normal-tn *fixnum-primitive-type
*)
159 (* (arg-state-stack-frame-size arg-state
) n-word-bytes
)
161 (invoke-alien-type-method :result-tn
162 (alien-fun-type-result-type type
)
163 (make-result-state))))))
165 (define-vop (foreign-symbol-sap)
166 (:translate foreign-symbol-sap
)
169 (:arg-types
(:constant simple-string
))
170 (:info foreign-symbol
)
171 (:temporary
(:sc interior-reg
) lip
)
172 (:results
(res :scs
(sap-reg)))
173 (:result-types system-area-pointer
)
175 (let ((fixup-label (gen-label)))
176 (inst load-from-label res lip fixup-label
)
177 (assemble (*elsewhere
*)
178 (emit-label fixup-label
)
179 (inst word
(make-fixup foreign-symbol
:foreign
))))))
182 (define-vop (foreign-symbol-dataref-sap)
183 (:translate foreign-symbol-dataref-sap
)
186 (:arg-types
(:constant simple-string
))
187 (:info foreign-symbol
)
188 (:temporary
(:sc interior-reg
) lip
)
189 (:results
(res :scs
(sap-reg)))
190 (:result-types system-area-pointer
)
192 (let ((fixup-label (gen-label)))
193 (inst load-from-label res lip fixup-label
)
194 (inst ldr res
(@ res
))
195 (assemble (*elsewhere
*)
196 (emit-label fixup-label
)
197 (inst word
(make-fixup foreign-symbol
:foreign-dataref
))))))
199 (define-vop (call-out)
200 (:args
(function :scs
(sap-reg sap-stack
))
202 (:results
(results :more t
))
203 (:ignore args results
)
205 (:temporary
(:sc any-reg
:offset r8-offset
206 :from
(:argument
0) :to
(:result
0)) cfunc
)
207 (:temporary
(:sc control-stack
:offset nfp-save-offset
) nfp-save
)
208 (:temporary
(:sc any-reg
) temp
)
209 (:temporary
(:sc interior-reg
) lip
)
212 (let ((call-into-c-fixup (gen-label))
213 (cur-nfp (current-nfp-tn vop
)))
214 (assemble (*elsewhere
*)
215 (emit-label call-into-c-fixup
)
216 (inst word
(make-fixup "call_into_c" :foreign
)))
218 (store-stack-tn nfp-save cur-nfp
))
219 (inst load-from-label temp lip call-into-c-fixup
)
221 (sap-reg (move cfunc function
))
223 (load-stack-offset cfunc cur-nfp function
)))
226 (load-stack-tn cur-nfp nfp-save
)))))
228 (define-vop (alloc-number-stack-space)
230 (:result-types system-area-pointer
)
231 (:results
(result :scs
(sap-reg any-reg
)))
233 (unless (zerop amount
)
234 (let ((delta (logandc2 (+ amount
+number-stack-alignment-mask
+)
235 +number-stack-alignment-mask
+)))
236 (composite-immediate-instruction sub nsp-tn nsp-tn delta
)
237 (move result nsp-tn
)))))
239 (define-vop (dealloc-number-stack-space)
243 (unless (zerop amount
)
244 (let ((delta (logandc2 (+ amount
+number-stack-alignment-mask
+)
245 +number-stack-alignment-mask
+)))
246 (composite-immediate-instruction add nsp-tn nsp-tn delta
)))))
250 (define-vop (move-double-to-int-args)
251 (:args
(double :scs
(double-reg)))
252 (:results
(lo-bits :scs
(unsigned-reg))
253 (hi-bits :scs
(unsigned-reg)))
254 (:arg-types double-float
)
255 (:result-types unsigned-num unsigned-num
)
258 (inst fmrrd lo-bits hi-bits double
)))
261 (define-vop (move-int-args-to-double)
262 (:args
(lo-bits :scs
(unsigned-reg))
263 (hi-bits :scs
(unsigned-reg)))
264 (:results
(double :scs
(double-reg)))
265 (:arg-types unsigned-num unsigned-num
)
266 (:result-types double-float
)
269 (inst fmdrr double lo-bits hi-bits
)))
271 ;;; long-long support
272 (deftransform %alien-funcall
((function type
&rest args
) * * :node node
)
273 (aver (sb!c
::constant-lvar-p type
))
274 (let* ((type (sb!c
::lvar-value type
))
275 (env (sb!c
::node-lexenv node
))
276 (arg-types (alien-fun-type-arg-types type
))
277 (result-type (alien-fun-type-result-type type
)))
278 (aver (= (length arg-types
) (length args
)))
279 (if (or (some (lambda (type)
280 (and (alien-integer-type-p type
)
281 (> (sb!alien
::alien-integer-type-bits type
) 32)))
283 (and (alien-integer-type-p result-type
)
284 (> (sb!alien
::alien-integer-type-bits result-type
) 32)))
285 (collect ((new-args) (lambda-vars) (new-arg-types))
287 for type in arg-types
291 (cond ((and (alien-integer-type-p type
)
292 (> (sb!alien
::alien-integer-type-bits type
) 32))
294 ;; long-long is only passed in pairs of r0-r1 and r2-r3,
295 ;; and the stack is double-word aligned
298 (new-arg-types (parse-alien-type '(signed 8) env
)))
300 (new-args `(logand ,arg
#xffffffff
))
301 (new-args `(ash ,arg -
32))
302 (new-arg-types (parse-alien-type '(unsigned 32) env
))
303 (if (alien-integer-type-signed type
)
304 (new-arg-types (parse-alien-type '(signed 32) env
))
305 (new-arg-types (parse-alien-type '(unsigned 32) env
))))
307 (incf i
(cond ((or (alien-double-float-type-p type
)
308 #!-arm-softfp
(alien-single-float-type-p type
))
314 (new-arg-types type
))))
315 (cond ((and (alien-integer-type-p result-type
)
316 (> (sb!alien
::alien-integer-type-bits result-type
) 32))
317 (let ((new-result-type
318 (let ((sb!alien
::*values-type-okay
* t
))
320 (if (alien-integer-type-signed result-type
)
321 '(values (unsigned 32) (signed 32))
322 '(values (unsigned 32) (unsigned 32)))
324 `(lambda (function type
,@(lambda-vars))
325 (declare (ignore type
))
326 (multiple-value-bind (low high
)
327 (%alien-funcall function
328 ',(make-alien-fun-type
329 :arg-types
(new-arg-types)
330 :result-type new-result-type
)
332 (logior low
(ash high
32))))))
334 `(lambda (function type
,@(lambda-vars))
335 (declare (ignore type
))
336 (%alien-funcall function
337 ',(make-alien-fun-type
338 :arg-types
(new-arg-types)
339 :result-type result-type
)
341 (sb!c
::give-up-ir1-transform
))))
345 (defun alien-callback-accessor-form (type sap offset
)
346 (let ((parsed-type type
))
347 (if (alien-integer-type-p parsed-type
)
348 (let ((bits (sb!alien
::alien-integer-type-bits parsed-type
)))
350 (cond ((< bits n-word-bits
)
352 (ceiling bits n-byte-bits
)))
354 `(deref (sap-alien (sap+ ,sap
355 ,(+ byte-offset offset
))
357 `(deref (sap-alien (sap+ ,sap
,offset
) (* ,type
))))))
360 (defun alien-callback-assembler-wrapper (index result-type argument-types
)
361 (flet ((make-tn (offset &optional
(sc-name 'any-reg
))
362 (make-random-tn :kind
:normal
363 :sc
(sc-or-lose sc-name
)
365 (let* ((segment (make-segment))
366 ;; How many arguments have been copied
368 ;; How many arguments have been copied from the stack
369 (stack-argument-count 0)
375 (temp-tn (make-tn 5))
376 (nsp-save-tn (make-tn 6))
379 (gprs (list r0-tn r1-tn r2-tn r3-tn
))
381 (loop for type in argument-types
383 (if (or (alien-double-float-type-p type
)
384 (and (alien-integer-type-p type
)
385 (eql (alien-type-bits type
) 64)))
388 (setf frame-size
(logandc2 (+ frame-size
+number-stack-alignment-mask
+)
389 +number-stack-alignment-mask
+))
391 (emit-word segment
#xe92d4ff8
) ;; stmfd sp!, {r3-r11, lr}
392 (move nsp-save-tn nsp-tn
)
394 ;; Make room on the stack for arguments.
395 (when (plusp frame-size
)
396 (inst sub nsp-tn nsp-tn frame-size
))
398 (dolist (type argument-types
)
399 (let ((target-tn (@ nsp-tn
(* arg-count n-word-bytes
)))
400 ;; A TN pointing to the stack location that contains
401 ;; the next argument passed on the stack.
402 ;; 10 is the amount of registers saved by stmfd above.
403 (stack-arg-tn (@ nsp-save-tn
(* (+ 10 stack-argument-count
)
405 (cond ((or (and (alien-integer-type-p type
)
406 (not (eql (alien-type-bits type
) 64)))
407 (alien-pointer-type-p type
)
408 (alien-type-= #.
(parse-alien-type 'system-area-pointer nil
)
411 (alien-single-float-type-p type
))
412 (let ((gpr (pop gprs
)))
414 (inst str gpr target-tn
))
416 (incf stack-argument-count
)
417 (inst ldr temp-tn stack-arg-tn
)
418 (inst str temp-tn target-tn
))))
421 (alien-double-float-type-p type
)
423 (alien-integer-type-p type
))
424 (let ((left (length gprs
)))
429 (inst str
(pop gprs
) (@ nsp-tn
(* arg-count n-word-bytes
)))
431 (inst str
(pop gprs
) (@ nsp-tn
(* arg-count n-word-bytes
)))
436 (setf stack-argument-count
437 (logandc2 (+ stack-argument-count
1) 1))
438 (inst ldr temp-tn
(@ nsp-save-tn
(* (+ 10 stack-argument-count
)
440 (inst str temp-tn
(@ nsp-tn
(* arg-count n-word-bytes
)))
442 (inst ldr temp-tn
(@ nsp-save-tn
(* (+ 11 stack-argument-count
)
444 (inst str temp-tn
(@ nsp-tn
(* arg-count n-word-bytes
)))
445 (incf stack-argument-count
2)
448 ((alien-double-float-type-p type
)
449 (setf fp-registers
(logandc2 (+ fp-registers
1) 1))
453 (setf stack-argument-count
454 (logandc2 (+ stack-argument-count
1) 1))
455 (inst ldr temp-tn
(@ nsp-save-tn
(* (+ 10 stack-argument-count
)
457 (inst str temp-tn
(@ nsp-tn
(* arg-count n-word-bytes
)))
459 (inst ldr temp-tn
(@ nsp-save-tn
(* (+ 11 stack-argument-count
)
461 (inst str temp-tn
(@ nsp-tn
(* arg-count n-word-bytes
)))
462 (incf stack-argument-count
2)
465 (inst fstd
(make-tn fp-registers
'double-reg
) target-tn
)
466 (incf fp-registers
2)
467 (incf arg-count
2))))
469 ((alien-single-float-type-p type
)
470 (cond ((> fp-registers
15)
471 (incf stack-argument-count
)
472 (inst ldr temp-tn stack-arg-tn
)
473 (inst str temp-tn target-tn
))
475 (inst fsts
(make-tn fp-registers
'single-reg
) target-tn
)
476 (incf fp-registers
1)))
479 (bug "Unknown alien floating point type: ~S" type
)))))
480 ;; arg0 to FUNCALL3 (function)
481 (load-immediate-word r0-tn
(static-fdefn-fun-addr 'enter-alien-callback
))
483 ;; arg0 to ENTER-ALIEN-CALLBACK (trampoline index)
484 (inst mov r1-tn
(fixnumize index
))
485 ;; arg1 to ENTER-ALIEN-CALLBACK (pointer to argument vector)
486 (inst mov r2-tn nsp-tn
)
487 ;; add room on stack for return value
488 (inst sub nsp-tn nsp-tn
8)
489 ;; arg2 to ENTER-ALIEN-CALLBACK (pointer to return value)
490 (inst mov r3-tn nsp-tn
)
493 (load-immediate-word r4-tn
(foreign-symbol-address "funcall3"))
496 ;; Result now on top of stack, put it in the right register
498 ((or (and (alien-integer-type-p result-type
)
499 (not (eql (alien-type-bits result-type
) 64)))
500 (alien-pointer-type-p result-type
)
501 (alien-type-= #.
(parse-alien-type 'system-area-pointer nil
)
504 (alien-single-float-type-p result-type
))
505 (loadw r0-tn nsp-tn
))
506 ((or #!+arm-softfp
(alien-double-float-type-p result-type
)
508 (alien-integer-type-p result-type
))
510 (loadw r1-tn nsp-tn
1))
512 ((alien-single-float-type-p result-type
)
513 (inst flds
(make-tn 0 'single-reg
) (@ nsp-tn
)))
515 ((alien-double-float-type-p result-type
)
516 (inst fldd
(make-tn 0 'double-reg
) (@ nsp-tn
)))
517 ((alien-void-type-p result-type
))
519 (error "Unrecognized alien type: ~A" result-type
)))
520 (move nsp-tn nsp-save-tn
)
521 (emit-word segment
#xe8bd4ff8
) ;; ldmfd sp!, {r3-r11, lr}
523 (finalize-segment segment
)
524 ;; Now that the segment is done, convert it to a static
525 ;; vector we can point foreign code to.
526 (let* ((buffer (sb!assem
::segment-buffer segment
))
527 (vector (make-static-vector (length buffer
)
528 :element-type
'(unsigned-byte 8)
529 :initial-contents buffer
))
530 (sap (vector-sap vector
)))
532 (extern-alien "os_flush_icache"