1 ;;;; the VOPs and other necessary machine specific support
2 ;;;; routines for call-out to C
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
15 ;; The MOVE-ARG vop is going to store args on the stack for
16 ;; call-out. These tn's will be used for that. move-arg is normally
17 ;; used for things going down the stack but C wants to have args
18 ;; indexed in the positive direction.
20 (defun my-make-wired-tn (prim-type-name sc-name offset
)
21 (make-wired-tn (primitive-type-or-lose prim-type-name
)
22 (sc-number-or-lose sc-name
)
25 (defstruct (arg-state (:copier nil
))
30 (defun int-arg (state prim-type reg-sc stack-sc
)
31 (let ((reg-args (arg-state-register-args state
)))
33 (setf (arg-state-register-args state
) (1+ reg-args
))
34 (my-make-wired-tn prim-type reg-sc
35 (nth reg-args
*c-call-register-arg-offsets
*)))
37 (let ((frame-size (arg-state-stack-frame-size state
)))
38 (setf (arg-state-stack-frame-size state
) (1+ frame-size
))
39 (my-make-wired-tn prim-type stack-sc frame-size
))))))
41 (define-alien-type-method (integer :arg-tn
) (type state
)
42 (if (alien-integer-type-signed type
)
43 (int-arg state
'signed-byte-64
'signed-reg
'signed-stack
)
44 (int-arg state
'unsigned-byte-64
'unsigned-reg
'unsigned-stack
)))
46 (define-alien-type-method (system-area-pointer :arg-tn
) (type state
)
47 (declare (ignore type
))
48 (int-arg state
'system-area-pointer
'sap-reg
'sap-stack
))
50 (defun float-arg (state prim-type reg-sc stack-sc
)
51 (let ((xmm-args (arg-state-xmm-args state
)))
53 (setf (arg-state-xmm-args state
) (1+ xmm-args
))
54 (my-make-wired-tn prim-type reg-sc
55 (nth xmm-args
*float-regs
*)))
57 (let ((frame-size (arg-state-stack-frame-size state
)))
58 (setf (arg-state-stack-frame-size state
) (1+ frame-size
))
59 (my-make-wired-tn prim-type stack-sc frame-size
))))))
61 (define-alien-type-method (double-float :arg-tn
) (type state
)
62 (declare (ignore type
))
63 (float-arg state
'double-float
'double-reg
'double-stack
))
65 (define-alien-type-method (single-float :arg-tn
) (type state
)
66 (declare (ignore type
))
67 (float-arg state
'single-float
'single-reg
'single-stack
))
69 (defstruct (result-state (:copier nil
))
72 (defun result-reg-offset (slot)
77 ;; XXX The return handling probably doesn't conform to the ABI
79 (define-alien-type-method (integer :result-tn
) (type state
)
80 (let ((num-results (result-state-num-results state
)))
81 (setf (result-state-num-results state
) (1+ num-results
))
82 (multiple-value-bind (ptype reg-sc
)
83 (if (alien-integer-type-signed type
)
84 (values 'signed-byte-64
'signed-reg
)
85 (values 'unsigned-byte-64
'unsigned-reg
))
86 (my-make-wired-tn ptype reg-sc
(result-reg-offset num-results
)))))
88 (define-alien-type-method (integer :naturalize-gen
) (type alien
)
89 (if (and (alien-integer-type-signed type
)
90 (<= (alien-type-bits type
) 32))
94 (define-alien-type-method (system-area-pointer :result-tn
) (type state
)
95 (declare (ignore type
))
96 (let ((num-results (result-state-num-results state
)))
97 (setf (result-state-num-results state
) (1+ num-results
))
98 (my-make-wired-tn 'system-area-pointer
'sap-reg
99 (result-reg-offset num-results
))))
101 (define-alien-type-method (double-float :result-tn
) (type state
)
102 (declare (ignore type
))
103 (let ((num-results (result-state-num-results state
)))
104 (setf (result-state-num-results state
) (1+ num-results
))
105 (my-make-wired-tn 'double-float
'double-reg num-results
)))
107 (define-alien-type-method (single-float :result-tn
) (type state
)
108 (declare (ignore type
))
109 (let ((num-results (result-state-num-results state
)))
110 (setf (result-state-num-results state
) (1+ num-results
))
111 (my-make-wired-tn 'single-float
'single-reg num-results
)))
113 (define-alien-type-method (values :result-tn
) (type state
)
114 (let ((values (alien-values-type-values type
)))
115 (when (> (length values
) 2)
116 (error "Too many result values from c-call."))
117 (mapcar (lambda (type)
118 (invoke-alien-type-method :result-tn type state
))
121 (!def-vm-support-routine make-call-out-tns
(type)
122 (let ((arg-state (make-arg-state)))
124 (dolist (arg-type (alien-fun-type-arg-types type
))
125 (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state
)))
126 (values (my-make-wired-tn 'positive-fixnum
'any-reg esp-offset
)
127 (* (arg-state-stack-frame-size arg-state
) n-word-bytes
)
129 (invoke-alien-type-method :result-tn
130 (alien-fun-type-result-type type
)
131 (make-result-state))))))
134 (deftransform %alien-funcall
((function type
&rest args
) * * :node node
)
135 (aver (sb!c
::constant-lvar-p type
))
136 (let* ((type (sb!c
::lvar-value type
))
137 (env (sb!c
::node-lexenv node
))
138 (arg-types (alien-fun-type-arg-types type
))
139 (result-type (alien-fun-type-result-type type
)))
140 (aver (= (length arg-types
) (length args
)))
141 (if (or (some #'(lambda (type)
142 (and (alien-integer-type-p type
)
143 (> (sb!alien
::alien-integer-type-bits type
) 64)))
145 (and (alien-integer-type-p result-type
)
146 (> (sb!alien
::alien-integer-type-bits result-type
) 64)))
147 (collect ((new-args) (lambda-vars) (new-arg-types))
148 (dolist (type arg-types
)
149 (let ((arg (gensym)))
151 (cond ((and (alien-integer-type-p type
)
152 (> (sb!alien
::alien-integer-type-bits type
) 64))
153 (new-args `(logand ,arg
#xffffffff
))
154 (new-args `(ash ,arg -
64))
155 (new-arg-types (parse-alien-type '(unsigned 64) env
))
156 (if (alien-integer-type-signed type
)
157 (new-arg-types (parse-alien-type '(signed 64) env
))
158 (new-arg-types (parse-alien-type '(unsigned 64) env
))))
161 (new-arg-types type
)))))
162 (cond ((and (alien-integer-type-p result-type
)
163 (> (sb!alien
::alien-integer-type-bits result-type
) 64))
164 (let ((new-result-type
165 (let ((sb!alien
::*values-type-okay
* t
))
167 (if (alien-integer-type-signed result-type
)
168 '(values (unsigned 64) (signed 64))
169 '(values (unsigned 64) (unsigned 64)))
171 `(lambda (function type
,@(lambda-vars))
172 (declare (ignore type
))
173 (multiple-value-bind (low high
)
174 (%alien-funcall function
175 ',(make-alien-fun-type
176 :arg-types
(new-arg-types)
177 :result-type new-result-type
)
179 (logior low
(ash high
64))))))
181 `(lambda (function type
,@(lambda-vars))
182 (declare (ignore type
))
183 (%alien-funcall function
184 ',(make-alien-fun-type
185 :arg-types
(new-arg-types)
186 :result-type result-type
)
188 (sb!c
::give-up-ir1-transform
))))
190 ;;; The ABI specifies that signed short/int's are returned as 32-bit
191 ;;; values. Negative values need to be sign-extended to 64-bits (done
192 ;;; in a :NATURALIZE-GEN alien-type-method).
193 (defknown sign-extend
(fixnum) fixnum
(foldable flushable movable
))
195 (define-vop (sign-extend)
196 (:translate sign-extend
)
198 (:args
(val :scs
(any-reg)))
200 (:results
(res :scs
(any-reg)))
201 (:result-types fixnum
)
204 (make-random-tn :kind
:normal
205 :sc
(sc-or-lose 'dword-reg
)
206 :offset
(tn-offset val
)))))
208 (defun sign-extend (x)
210 (dpb x
(byte 32 0) -
1)
211 (ldb (byte 32 0) x
)))
213 (define-vop (foreign-symbol-sap)
214 (:translate foreign-symbol-sap
)
217 (:arg-types
(:constant simple-string
))
218 (:info foreign-symbol
)
219 (:results
(res :scs
(sap-reg)))
220 (:result-types system-area-pointer
)
222 (inst lea res
(make-fixup foreign-symbol
:foreign
))))
225 (define-vop (foreign-symbol-dataref-sap)
226 (:translate foreign-symbol-dataref-sap
)
229 (:arg-types
(:constant simple-string
))
230 (:info foreign-symbol
)
231 (:results
(res :scs
(sap-reg)))
232 (:result-types system-area-pointer
)
234 (inst mov res
(make-fixup foreign-symbol
:foreign-dataref
))))
236 (define-vop (call-out)
237 (:args
(function :scs
(sap-reg))
239 (:results
(results :more t
))
240 (:temporary
(:sc unsigned-reg
:offset rax-offset
:to
:result
) rax
)
245 ;; ABI: AL contains amount of arguments passed in XMM registers
248 (loop for tn-ref
= args then
(tn-ref-across tn-ref
)
250 count
(eq (sb-name (sc-sb (tn-sc (tn-ref-tn tn-ref
))))
253 ;; To give the debugger a clue. XX not really internal-error?
254 (note-this-location vop
:internal-error
)
255 ;; FLOAT15 needs to contain FP zero in Lispland
256 (let ((float15 (make-random-tn :kind
:normal
257 :sc
(sc-or-lose 'double-reg
)
258 :offset float15-offset
)))
259 (inst xorpd float15 float15
))))
261 (define-vop (alloc-number-stack-space)
263 (:results
(result :scs
(sap-reg any-reg
)))
265 (aver (location= result rsp-tn
))
266 (unless (zerop amount
)
267 (let ((delta (logandc2 (+ amount
7) 7)))
268 (inst sub rsp-tn delta
)))
269 ;; C stack must be 16 byte aligned
270 (inst and rsp-tn
#xfffffff0
)
271 (move result rsp-tn
)))
273 (define-vop (dealloc-number-stack-space)
276 (unless (zerop amount
)
277 (let ((delta (logandc2 (+ amount
7) 7)))
278 (inst add rsp-tn delta
)))))
280 (define-vop (alloc-alien-stack-space)
282 #!+sb-thread
(:temporary
(:sc unsigned-reg
) temp
)
283 (:results
(result :scs
(sap-reg any-reg
)))
286 (aver (not (location= result rsp-tn
)))
287 (unless (zerop amount
)
288 (let ((delta (logandc2 (+ amount
7) 7)))
292 (static-symbol-offset '*alien-stack
*)
293 (ash symbol-tls-index-slot word-shift
)
294 (- other-pointer-lowtag
))))
295 (inst sub
(make-ea :qword
:base thread-base-tn
296 :scale
1 :index temp
) delta
)))
297 (load-tl-symbol-value result
*alien-stack
*))
300 (aver (not (location= result rsp-tn
)))
301 (unless (zerop amount
)
302 (let ((delta (logandc2 (+ amount
7) 7)))
303 (inst sub
(make-ea :qword
305 (static-symbol-offset '*alien-stack
*)
306 (ash symbol-value-slot word-shift
)
307 (- other-pointer-lowtag
)))
309 (load-symbol-value result
*alien-stack
*)))
311 (define-vop (dealloc-alien-stack-space)
313 #!+sb-thread
(:temporary
(:sc unsigned-reg
) temp
)
316 (unless (zerop amount
)
317 (let ((delta (logandc2 (+ amount
7) 7)))
321 (static-symbol-offset '*alien-stack
*)
322 (ash symbol-tls-index-slot word-shift
)
323 (- other-pointer-lowtag
))))
324 (inst add
(make-ea :qword
:base thread-base-tn
:scale
1 :index temp
)
328 (unless (zerop amount
)
329 (let ((delta (logandc2 (+ amount
7) 7)))
330 (inst add
(make-ea :qword
332 (static-symbol-offset '*alien-stack
*)
333 (ash symbol-value-slot word-shift
)
334 (- other-pointer-lowtag
)))
337 ;;; these are not strictly part of the c-call convention, but are
338 ;;; needed for the WITH-PRESERVED-POINTERS macro used for "locking
339 ;;; down" lisp objects so that GC won't move them while foreign
340 ;;; functions go to work.
342 (define-vop (push-word-on-c-stack)
343 (:translate push-word-on-c-stack
)
344 (:args
(val :scs
(sap-reg)))
346 (:arg-types system-area-pointer
)
350 (define-vop (pop-words-from-c-stack)
351 (:translate pop-words-from-c-stack
)
353 (:arg-types
(:constant
(unsigned-byte 60)))
357 (inst add rsp-tn
(fixnumize number
))))