Delete all but 2 versions of MY-MAKE-WIRED-TN
[sbcl.git] / src / compiler / arm / c-call.lisp
blobd5143df8f22e14564be03f5ee9506f58465c34e1
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
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 (defconstant +number-stack-alignment-mask+ 7)
16 (defconstant +max-register-args+ 4)
18 (defstruct arg-state
19 (num-register-args 0)
20 #!-arm-softfp
21 (fp-registers 0)
22 (stack-frame-size 0))
24 (defstruct (result-state (:copier nil))
25 (num-results 0))
27 (defun result-reg-offset (slot)
28 (ecase slot
29 (0 nargs-offset)
30 (1 nl3-offset)))
32 (defun register-args-offset (index)
33 (elt '(#.ocfp-offset #.nargs-offset #.nl2-offset #.nl3-offset)
34 index))
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))
55 #!+arm-softfp
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))
60 #!-arm-softfp
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)))))
72 #!+arm-softfp
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
77 ;; can be used.
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))
86 (list
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)))))
93 #!-arm-softfp
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)
99 (let ((frame-size
100 ;; align
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))
123 #!+arm-softfp
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))
128 #!-arm-softfp
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))
133 #!+arm-softfp
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))
140 #!-arm-softfp
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))
151 values)))
153 (defun make-call-out-tns (type)
154 (let ((arg-state (make-arg-state)))
155 (collect ((arg-tns))
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)
160 (arg-tns)
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)
167 (:policy :fast-safe)
168 (:args)
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)
174 (:generator 2
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))))))
181 #!+linkage-table
182 (define-vop (foreign-symbol-dataref-sap)
183 (:translate foreign-symbol-dataref-sap)
184 (:policy :fast-safe)
185 (:args)
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)
191 (:generator 2
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))
201 (args :more t))
202 (:results (results :more t))
203 (:ignore args results)
204 (:save-p t)
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)
210 (:vop-var vop)
211 (:generator 0
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)))
217 (when cur-nfp
218 (store-stack-tn nfp-save cur-nfp))
219 (inst load-from-label temp lip call-into-c-fixup)
220 (sc-case function
221 (sap-reg (move cfunc function))
222 (sap-stack
223 (load-stack-offset cfunc cur-nfp function)))
224 (inst blx temp)
225 (when cur-nfp
226 (load-stack-tn cur-nfp nfp-save)))))
228 (define-vop (alloc-number-stack-space)
229 (:info amount)
230 (:result-types system-area-pointer)
231 (:results (result :scs (sap-reg any-reg)))
232 (:generator 0
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)
240 (:info amount)
241 (:policy :fast-safe)
242 (:generator 0
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)))))
249 #!+arm-softfp
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)
256 (:policy :fast-safe)
257 (:generator 1
258 (inst fmrrd lo-bits hi-bits double)))
260 #!+arm-softfp
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)
267 (:policy :fast-safe)
268 (:generator 1
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)))
282 arg-types)
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))
286 (loop with i = 0
287 for type in arg-types
288 for arg = (gensym)
290 (lambda-vars arg)
291 (cond ((and (alien-integer-type-p type)
292 (> (sb!alien::alien-integer-type-bits type) 32))
293 (when (oddp i)
294 ;; long-long is only passed in pairs of r0-r1 and r2-r3,
295 ;; and the stack is double-word aligned
296 (incf i)
297 (new-args 0)
298 (new-arg-types (parse-alien-type '(signed 8) env)))
299 (incf i 2)
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))
309 #!+arm-softfp 2
310 #!-arm-softfp 0)
312 1)))
313 (new-args arg)
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))
319 (parse-alien-type
320 (if (alien-integer-type-signed result-type)
321 '(values (unsigned 32) (signed 32))
322 '(values (unsigned 32) (unsigned 32)))
323 env))))
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)
331 ,@(new-args))
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)
340 ,@(new-args))))))
341 (sb!c::give-up-ir1-transform))))
343 ;;; Callback
344 #-sb-xc-host
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)))
349 (let ((byte-offset
350 (cond ((< bits n-word-bits)
351 (- n-word-bytes
352 (ceiling bits n-byte-bits)))
353 (t 0))))
354 `(deref (sap-alien (sap+ ,sap
355 ,(+ byte-offset offset))
356 (* ,type)))))
357 `(deref (sap-alien (sap+ ,sap ,offset) (* ,type))))))
359 #-sb-xc-host
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)
364 :offset offset)))
365 (let* ((segment (make-segment))
366 ;; How many arguments have been copied
367 (arg-count 0)
368 ;; How many arguments have been copied from the stack
369 (stack-argument-count 0)
370 (r0-tn (make-tn 0))
371 (r1-tn (make-tn 1))
372 (r2-tn (make-tn 2))
373 (r3-tn (make-tn 3))
374 (r4-tn (make-tn 4))
375 (temp-tn (make-tn 5))
376 (nsp-save-tn (make-tn 6))
377 #!-arm-softfp
378 (fp-registers 0)
379 (gprs (list r0-tn r1-tn r2-tn r3-tn))
380 (frame-size
381 (loop for type in argument-types
382 sum (* n-word-bytes
383 (if (or (alien-double-float-type-p type)
384 (and (alien-integer-type-p type)
385 (eql (alien-type-bits type) 64)))
387 1)))))
388 (setf frame-size (logandc2 (+ frame-size +number-stack-alignment-mask+)
389 +number-stack-alignment-mask+))
390 (assemble (segment)
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))
397 ;; Copy arguments
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)
404 n-word-bytes))))
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)
409 type)
410 #!+arm-softfp
411 (alien-single-float-type-p type))
412 (let ((gpr (pop gprs)))
413 (cond (gpr
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))))
419 (incf arg-count))
420 ((or #!+arm-softfp
421 (alien-double-float-type-p type)
422 ;; long-long
423 (alien-integer-type-p type))
424 (let ((left (length gprs)))
425 (case left
426 ((2 3 4)
427 (when (= left 3)
428 (pop gprs))
429 (inst str (pop gprs) (@ nsp-tn (* arg-count n-word-bytes)))
430 (incf arg-count)
431 (inst str (pop gprs) (@ nsp-tn (* arg-count n-word-bytes)))
432 (incf arg-count))
434 (pop gprs)
435 ;; two-word aligned
436 (setf stack-argument-count
437 (logandc2 (+ stack-argument-count 1) 1))
438 (inst ldr temp-tn (@ nsp-save-tn (* (+ 10 stack-argument-count)
439 n-word-bytes)))
440 (inst str temp-tn (@ nsp-tn (* arg-count n-word-bytes)))
441 (incf arg-count)
442 (inst ldr temp-tn (@ nsp-save-tn (* (+ 11 stack-argument-count)
443 n-word-bytes)))
444 (inst str temp-tn (@ nsp-tn (* arg-count n-word-bytes)))
445 (incf stack-argument-count 2)
446 (incf arg-count)))))
447 #!-arm-softfp
448 ((alien-double-float-type-p type)
449 (setf fp-registers (logandc2 (+ fp-registers 1) 1))
450 (cond
451 ((> fp-registers 15)
452 ;; align
453 (setf stack-argument-count
454 (logandc2 (+ stack-argument-count 1) 1))
455 (inst ldr temp-tn (@ nsp-save-tn (* (+ 10 stack-argument-count)
456 n-word-bytes)))
457 (inst str temp-tn (@ nsp-tn (* arg-count n-word-bytes)))
458 (incf arg-count)
459 (inst ldr temp-tn (@ nsp-save-tn (* (+ 11 stack-argument-count)
460 n-word-bytes)))
461 (inst str temp-tn (@ nsp-tn (* arg-count n-word-bytes)))
462 (incf stack-argument-count 2)
463 (incf arg-count))
465 (inst fstd (make-tn fp-registers 'double-reg) target-tn)
466 (incf fp-registers 2)
467 (incf arg-count 2))))
468 #!-arm-softfp
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)))
477 (incf arg-count 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))
482 (loadw r0-tn r0-tn)
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)
492 ;; Call
493 (load-immediate-word r4-tn (foreign-symbol-address "funcall3"))
494 (inst blx r4-tn)
496 ;; Result now on top of stack, put it in the right register
497 (cond
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)
502 result-type)
503 #!+arm-softfp
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)
507 ;; long-long
508 (alien-integer-type-p result-type))
509 (loadw r0-tn nsp-tn)
510 (loadw r1-tn nsp-tn 1))
511 #!-arm-softfp
512 ((alien-single-float-type-p result-type)
513 (inst flds (make-tn 0 'single-reg) (@ nsp-tn)))
514 #!-arm-softfp
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}
522 (inst bx lr-tn))
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)))
531 (alien-funcall
532 (extern-alien "os_flush_icache"
533 (function void
534 system-area-pointer
535 unsigned-long))
536 sap (length buffer))
537 vector))))