close Warning: Can't use blame annotator:
No changeset 2948 in the repository

source: branches/lscan/source/compiler/X86/X8664/x8664-backend.lisp

Last change on this file was 16444, checked in by Gary Byers, 9 years ago

still in progress.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.3 KB
RevLine 
1;;;-*- Mode: Lisp; Package: CCL -*-
2;;;
3;;; Copyright (C) 2005-2009 Clozure Associates
4;;; This file is part of Clozure CL.
5;;;
6;;; Clozure CL is licensed under the terms of the Lisp Lesser GNU Public
7;;; License , known as the LLGPL and distributed with Clozure CL as the
8;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL,
9;;; which is distributed with Clozure CL as the file "LGPL". Where these
10;;; conflict, the preamble takes precedence.
11;;;
12;;; Clozure CL is referenced in the preamble as the "LIBRARY."
13;;;
14;;; The LLGPL is also available online at
15;;; http://opensource.franz.com/preamble.html
16
17(in-package "CCL")
18(eval-when (:compile-toplevel :load-toplevel :execute)
19 (require "BACKEND"))
20
21(eval-when (:compile-toplevel :execute)
22 (require "NXENV")
23 (require "X8664ENV"))
24
25
26(defvar *x8664-vinsn-templates* (make-hash-table :test #'eq))
27
28
29
30(defvar *known-x8664-backends* ())
31
32
33#+(or linuxx86-target (not x86-target))
34(defvar *linuxx8664-backend*
35 (make-backend :lookup-opcode 'lookup-x86-opcode
36 :lookup-macro #'false
37 :lap-opcodes x86::*x86-opcode-templates*
38 :define-vinsn 'define-x86-vinsn
39 :platform-syscall-mask (logior platform-os-linux platform-cpu-x86 platform-word-size-64)
40 :p2-dispatch *x862-specials*
41 :p2-vinsn-templates *x8664-vinsn-templates*
42 :p2-template-hash-name '*x8664-vinsn-templates*
43 :p2-compile 'x862-compile
44 :target-specific-features
45 '(:x8664 :x86-target :linux-target :linuxx86-target :x8664-target
46 :linuxx8664-target
47 :little-endian-target
48 :64-bit-target)
49 :target-fasl-pathname (make-pathname :type "lx64fsl")
50 :target-platform (logior platform-cpu-x86
51 platform-os-linux
52 platform-word-size-64)
53 :target-os :linuxx86
54 :name :linuxx8664
55 :target-arch-name :x8664
56 :target-foreign-type-data nil
57
58
59 :target-arch x8664::*x8664-target-arch*
60 :lisp-context-register x8664::gs
61 ))
62
63
64(defvar *linuxx8664-dev-backend*
65 (make-backend :lookup-opcode 'lookup-x86-opcode
66 :lookup-macro #'false
67 :lap-opcodes x86::*x86-opcode-templates*
68 :define-vinsn 'define-x86-vinsn
69 :platform-syscall-mask (logior platform-os-linux platform-cpu-x86 platform-word-size-64)
70 :p2-dispatch *x862-specials*
71 :p2-vinsn-templates *x8664-vinsn-templates*
72 :p2-template-hash-name '*x8664-vinsn-templates*
73 :p2-compile 'x862-compile
74 :target-specific-features
75 '(:x8664 :x86-target :linux-target :linuxx86-target :x8664-target
76 :linuxx8664-target :linear-scan
77 :little-endian-target
78 :64-bit-target)
79 :target-fasl-pathname (make-pathname :type "ls64fsl")
80 :target-platform (logior platform-cpu-x86
81 platform-os-linux
82 platform-word-size-64)
83 :target-os :linuxx86
84 :name :linuxx8664-dev
85 :target-arch-name :x8664
86 :target-foreign-type-data nil
87
88
89 :target-arch x8664::*x8664-target-arch*
90 :lisp-context-register x8664::gs
91 ))
92
93
94#+darwinx86-target
95(defvar *darwinx8664-backend*
96 (make-backend :lookup-opcode 'lookup-x86-opcode
97 :lookup-macro #'false
98 :lap-opcodes x86::*x86-opcode-templates*
99 :define-vinsn 'define-x86-vinsn
100 :p2-dispatch *x862-specials*
101 :p2-vinsn-templates *x8664-vinsn-templates*
102 :p2-template-hash-name '*x8664-vinsn-templates*
103 :p2-compile 'x862-compile
104 :platform-syscall-mask (logior platform-os-darwin platform-cpu-x86 platform-word-size-64)
105 :target-specific-features
106 '(:x8664 :x86-target :darwin-target :darwinx86-target :x8664-target
107 :darwinx8664-target
108 :little-endian-target
109 :64-bit-target)
110 :target-fasl-pathname (make-pathname :type "dx64fsl")
111 :target-platform (logior platform-cpu-x86
112 platform-os-darwin
113 platform-word-size-64)
114 :target-os :darwinx86
115 :name :darwinx8664
116 :target-arch-name :x8664
117 :target-foreign-type-data nil
118 :target-arch x8664::*x8664-target-arch*
119 ;; Overload %gs until Apple straightens things out.
120 ;; Whoops; they never did.
121 :lisp-context-register x8664::r11
122 ))
123
124#+freebsdx86-target
125(defvar *freebsdx8664-backend*
126 (make-backend :lookup-opcode 'lookup-x86-opcode
127 :lookup-macro #'false
128 :lap-opcodes x86::*x86-opcode-templates*
129 :define-vinsn 'define-x86-vinsn
130 :p2-dispatch *x862-specials*
131 :p2-vinsn-templates *x8664-vinsn-templates*
132 :p2-template-hash-name '*x8664-vinsn-templates*
133 :p2-compile 'x862-compile
134 :target-specific-features
135 '(:x8664 :x86-target :freebsd-target :freebsdx86-target :x8664-target
136 :freebsdx8664-target
137 :little-endian-target
138 :64-bit-target)
139 :target-fasl-pathname (make-pathname :type "fx64fsl")
140 :target-platform (logior platform-cpu-x86
141 platform-os-freebsd
142 platform-word-size-64)
143 :target-os :freebsdx86
144 :name :freebsdx8664
145 :target-arch-name :x8664
146 :target-foreign-type-data nil
147 :target-arch x8664::*x8664-target-arch*
148 :platform-syscall-mask (logior platform-os-freebsd platform-cpu-x86 platform-word-size-64)
149 :lisp-context-register x8664::gs
150 ))
151
152#+solarisx86-target
153(defvar *solarisx8664-backend*
154 (make-backend :lookup-opcode 'lookup-x86-opcode
155 :lookup-macro #'false
156 :lap-opcodes x86::*x86-opcode-templates*
157 :define-vinsn 'define-x86-vinsn
158 :p2-dispatch *x862-specials*
159 :p2-vinsn-templates *x8664-vinsn-templates*
160 :p2-template-hash-name '*x8664-vinsn-templates*
161 :p2-compile 'x862-compile
162 :target-specific-features
163 '(:x8664 :x86-target :solaris-target :solarisx86-target :x8664-target
164 :solarisx8664-target
165 :solarisx64-target
166 :little-endian-target
167 :64-bit-target)
168 :target-fasl-pathname (make-pathname :type "sx64fsl")
169 :target-platform (logior platform-cpu-x86
170 platform-os-solaris
171 platform-word-size-64)
172 :target-os :solarisx86
173 :name :solarisx8664
174 :target-arch-name :x8664
175 :target-foreign-type-data nil
176 :target-arch x8664::*x8664-target-arch*
177 :platform-syscall-mask (logior platform-os-solaris platform-cpu-x86 platform-word-size-64)
178 :lisp-context-register x8664::gs
179 ))
180
181#+win64-target
182(defvar *win64-backend*
183 (make-backend :lookup-opcode 'lookup-x86-opcode
184 :lookup-macro #'false
185 :lap-opcodes x86::*x86-opcode-templates*
186 :define-vinsn 'define-x86-vinsn
187 :p2-dispatch *x862-specials*
188 :p2-vinsn-templates *x8664-vinsn-templates*
189 :p2-template-hash-name '*x8664-vinsn-templates*
190 :p2-compile 'x862-compile
191 :target-specific-features
192 '(:x8664 :x86-target :win64-target :windows-target :x8664-target
193 :winx64-target
194 :little-endian-target
195 :64-bit-target)
196 :target-fasl-pathname (make-pathname :type "wx64fsl")
197 :target-platform (logior platform-cpu-x86
198 platform-os-windows
199 platform-word-size-64)
200 :target-os :win64
201 :name :win64
202 :target-arch-name :x8664
203 :target-foreign-type-data nil
204 :target-arch x8664::*x8664-target-arch*
205 :platform-syscall-mask (logior platform-os-windows platform-cpu-x86 platform-word-size-64)
206 :lisp-context-register x8664::r11
207 ))
208
209#+(or linuxx86-target (not x86-target))
210(pushnew *linuxx8664-backend* *known-x8664-backends* :key #'backend-name)
211
212
213#+darwinx86-target
214(pushnew *darwinx8664-backend* *known-x8664-backends* :key #'backend-name)
215
216#+freebsdx86-target
217(pushnew *freebsdx8664-backend* *known-x8664-backends* :key #'backend-name)
218
219#+solarisx86-target
220(pushnew *solarisx8664-backend* *known-x8664-backends* :key #'backend-name)
221
222#+win64-target
223(pushnew *win64-backend* *known-x8664-backends* :key #'backend-name)
224
225(defvar *x8664-backend* (car *known-x8664-backends*))
226
227(defun fixup-x8664-backend ()
228 (dolist (b *known-x8664-backends*)
229 (setf #| (backend-lap-opcodes b) x86::*x86-opcodes* |#
230 (backend-p2-dispatch b) *x862-specials*
231 (backend-p2-vinsn-templates b) *x8664-vinsn-templates*)
232 (or (backend-lap-macros b) (setf (backend-lap-macros b)
233 (make-hash-table :test #'equalp)))))
234
235
236
237(fixup-x8664-backend)
238
239#+x8664-target
240(setq *host-backend* *x8664-backend* *target-backend* *x8664-backend*)
241
242(defun setup-x8664-ftd (backend)
243 (or (backend-target-foreign-type-data backend)
244 (let* ((name (backend-name backend))
245 (ftd
246 (case name
247 ((:linuxx8664 :linuxx8664-dev)
248 (make-ftd :interface-db-directory
249 (if (eq backend *host-backend*)
250 "ccl:x86-headers64;"
251 "ccl:cross-x86-headers64;")
252 :interface-package-name "X86-LINUX64"
253 :attributes '(:bits-per-word 64
254 :struct-by-value t)
255 :ff-call-expand-function
256 (intern "EXPAND-FF-CALL" "X86-LINUX64")
257 :ff-call-struct-return-by-implicit-arg-function
258 (intern "RECORD-TYPE-RETURNS-STRUCTURE-AS-FIRST-ARG"
259 "X86-LINUX64")
260 :callback-bindings-function
261 (intern "GENERATE-CALLBACK-BINDINGS" "X86-LINUX64")
262 :callback-return-value-function
263 (intern "GENERATE-CALLBACK-RETURN-VALUE" "X86-LINUX64")))
264 (:darwinx8664
265 (make-ftd :interface-db-directory
266 (if (eq backend *host-backend*)
267 "ccl:darwin-x86-headers64;"
268 "ccl:cross-darwin-x86-headers64;")
269 :interface-package-name "X86-DARWIN64"
270 :attributes '(:bits-per-word 64
271 :signed-char t
272 :struct-by-value t
273 :prepend-underscore t)
274 :ff-call-expand-function
275 (intern "EXPAND-FF-CALL" "X86-DARWIN64")
276 :ff-call-struct-return-by-implicit-arg-function
277 (intern "RECORD-TYPE-RETURNS-STRUCTURE-AS-FIRST-ARG"
278 "X86-DARWIN64")
279 :callback-bindings-function
280 (intern "GENERATE-CALLBACK-BINDINGS" "X86-DARWIN64")
281 :callback-return-value-function
282 (intern "GENERATE-CALLBACK-RETURN-VALUE" "X86-DARWIN64")))
283 (:freebsdx8664
284 (make-ftd :interface-db-directory
285 (if (eq backend *host-backend*)
286 "ccl:freebsd-headers64;"
287 "ccl:cross-freebsd-headers64;")
288 :interface-package-name "X86-FREEBSD64"
289 :attributes '(:bits-per-word 64
290 :struct-by-value t)
291 :ff-call-expand-function
292 (intern "EXPAND-FF-CALL" "X86-FREEBSD64")
293 :ff-call-struct-return-by-implicit-arg-function
294 (intern "RECORD-TYPE-RETURNS-STRUCTURE-AS-FIRST-ARG"
295 "X86-FREEBSD64")
296 :callback-bindings-function
297 (intern "GENERATE-CALLBACK-BINDINGS" "X86-FREEBSD64")
298 :callback-return-value-function
299 (intern "GENERATE-CALLBACK-RETURN-VALUE" "X86-FREEBSD64")))
300 (:solarisx8664
301 (make-ftd :interface-db-directory
302 (if (eq backend *host-backend*)
303 "ccl:solarisx64-headers;"
304 "ccl:cross-solarisx64-headers;")
305 :interface-package-name "X86-SOLARIS64"
306 :attributes '(:bits-per-word 64
307 :struct-by-value t)
308 :ff-call-expand-function
309 (intern "EXPAND-FF-CALL" "X86-SOLARIS64")
310 :ff-call-struct-return-by-implicit-arg-function
311 (intern "RECORD-TYPE-RETURNS-STRUCTURE-AS-FIRST-ARG"
312 "X86-SOLARIS64")
313 :callback-bindings-function
314 (intern "GENERATE-CALLBACK-BINDINGS" "X86-SOLARIS64")
315 :callback-return-value-function
316 (intern "GENERATE-CALLBACK-RETURN-VALUE" "X86-SOLARIS64")))
317 (:win64
318 (make-ftd :interface-db-directory
319 (if (eq backend *host-backend*)
320 "ccl:win64-headers;"
321 "ccl:cross-win64-headers;")
322 :interface-package-name "WIN64"
323 :attributes '(:bits-per-word 64
324 :struct-by-value t
325 :bits-per-long 32)
326 :ff-call-expand-function
327 (intern "EXPAND-FF-CALL" "WIN64")
328 :ff-call-struct-return-by-implicit-arg-function
329 (intern "RECORD-TYPE-RETURNS-STRUCTURE-AS-FIRST-ARG"
330 "WIN64")
331 :callback-bindings-function
332 (intern "GENERATE-CALLBACK-BINDINGS" "WIN64")
333 :callback-return-value-function
334 (intern "GENERATE-CALLBACK-RETURN-VALUE" "WIN64"))))))
335 (install-standard-foreign-types ftd)
336 (use-interface-dir :libc ftd)
337 (setf (backend-target-foreign-type-data backend) ftd))))
338
339#-x8664-target
340(setup-x8664-ftd *x8664-backend*)
341
342(pushnew *x8664-backend* *known-backends* :key #'backend-name)
343#+linuxxx8664-target
344(pushnew *linuxx8664-dev-backend* *known-backends* :key #'backend-name)
345
346
347;;; FFI stuff. Seems to be shared by Darwin/Linux/FreeBSD.
348
349;;; A returned structure is passed as an invisible first argument if
350;;; it's more than 2 doublewords long or if it contains unaligned fields.
351;;; Not clear how the latter case can happen, so this just checks for
352;;; the first.
353(defun x8664::record-type-returns-structure-as-first-arg (rtype)
354 (when (and rtype
355 (not (typep rtype 'unsigned-byte))
356 (not (member rtype *foreign-representation-type-keywords*
357 :test #'eq)))
358 (let* ((ftype (if (typep rtype 'foreign-type)
359 rtype
360 (parse-foreign-type rtype))))
361 (> (ensure-foreign-type-bits ftype) 128))))
362
363;;; On x8664, structures can be passed by value:
364;;; a) in memory, if they're more than 128 bits in size or if there aren't
365;;; enough of the right kind of register to pass them entirely in registers.
366;;; b) as a series of 64-bit chunks, passed in GPRs if any component of the
367;;; chunk is a non FLOAT or in FPRs otherwise.
368;;; Note that this means that a chunk consisting of two SINGLE-FLOATs would
369;;; be passed in the low 64 bit of an SSE (xmm) register.
370
371(defun x8664::field-is-of-class-integer (field)
372 ;; Return true if field is of "class" integer or if it's a record
373 ;; type of class integer. (See the System V AMD64 ABI document for
374 ;; a convoluted definition of field "classes".)
375 (let* ((ftype (foreign-record-field-type field)))
376 (typecase ftype
377 ((or foreign-integer-type foreign-pointer-type) t)
378 (foreign-record-type (dolist (f (foreign-record-type-fields ftype))
379 (when (x8664::field-is-of-class-integer f)
380 (return t))))
381 (otherwise nil))))
382
383(defun x8664::classify-8byte (field-list bit-limit)
384 ;; CDR down the fields in FIELD-LIST until we find a field of class integer,
385 ;; hit the end of the list, or find a field whose offset is >= BIT-LIMIT.
386 ;; In the first case, return :INTEGER. In other cases, return :FLOAT.
387 (dolist (field field-list :float)
388 (if (<= bit-limit (foreign-record-field-offset field))
389 (return :float)
390 (if (x8664::field-is-of-class-integer field)
391 (return :integer)))))
392
393;;; Return a first value :memory, :integer, or::float and a second
394;;; value of NIL, :integer, or :float according to how the structure
395;;; RTYPE should ideally be passed or returned. Note that the caller
396;;; may decide to turn this to :memory if there aren't enough
397;;; available registers of the right class when passing an instance of
398;;; this structure type.
399(defun x8664::classify-record-type (rtype)
400 (let* ((nbits (ensure-foreign-type-bits rtype))
401 (fields (foreign-record-type-fields rtype)))
402 (cond ((> nbits 128) (values :memory nil))
403 ((<= nbits 64) (values (x8664::classify-8byte fields 64) nil))
404 (t (values (x8664::classify-8byte fields 64)
405 (do* ()
406 ((>= (foreign-record-field-offset (car fields)) 64)
407 (x8664::classify-8byte fields 128))
408 (setq fields (cdr fields))))))))
409
410(defun x8664::struct-from-regbuf-values (r rtype regbuf)
411 (multiple-value-bind (first second)
412 (x8664::classify-record-type rtype)
413 (let* ((gpr-offset 0)
414 (fpr-offset 16))
415 ;; Do this 32 bits at a time, to avoid consing.
416 (collect ((forms))
417 (case first
418 (:integer (forms `(setf (%get-unsigned-long ,r 0)
419 (%get-unsigned-long ,regbuf 0)))
420 (forms `(setf (%get-unsigned-long ,r 4)
421 (%get-unsigned-long ,regbuf 4)))
422 (setq gpr-offset 8))
423 (:float (forms `(setf (%get-unsigned-long ,r 0)
424 (%get-unsigned-long ,regbuf 16)))
425 (forms `(setf (%get-unsigned-long ,r 4)
426 (%get-unsigned-long ,regbuf 20)))
427 (setf fpr-offset 24)))
428 (case second
429 (:integer (forms `(setf (%get-unsigned-long ,r 8)
430 (%get-unsigned-long ,regbuf ,gpr-offset)))
431 (forms `(setf (%get-unsigned-long ,r 12)
432 (%get-unsigned-long ,regbuf ,(+ gpr-offset 4)))))
433 (:float (forms `(setf (%get-unsigned-long ,r 8)
434 (%get-unsigned-long ,regbuf ,fpr-offset)))
435 (forms `(setf (%get-unsigned-long ,r 12)
436 (%get-unsigned-long ,regbuf ,(+ fpr-offset 4))))))
437 `(progn ,@(forms))))))
438
439(defun x8664::expand-ff-call (callform args &key (arg-coerce #'null-coerce-foreign-arg) (result-coerce #'null-coerce-foreign-result))
440 (let* ((result-type-spec (or (car (last args)) :void))
441 (regbuf nil)
442 (result-temp nil)
443 (result-form nil)
444 (struct-result-type nil)
445 (structure-arg-temp nil))
446 (multiple-value-bind (result-type error)
447 (ignore-errors (parse-foreign-type result-type-spec))
448 (if error
449 (setq result-type-spec :void result-type *void-foreign-type*)
450 (setq args (butlast args)))
451 (collect ((argforms))
452 (when (eq (car args) :monitor-exception-ports)
453 (argforms (pop args)))
454 (when (typep result-type 'foreign-record-type)
455 (setq result-form (pop args)
456 struct-result-type result-type
457 result-type *void-foreign-type*
458 result-type-spec :void)
459 (if (x8664::record-type-returns-structure-as-first-arg struct-result-type)
460 (progn
461 (argforms :address)
462 (argforms result-form))
463 (progn
464 (setq regbuf (gensym)
465 result-temp (gensym))
466 (argforms :registers)
467 (argforms regbuf))))
468 (let* ((valform nil))
469 (unless (evenp (length args))
470 (error "~s should be an even-length list of alternating foreign types and values" args))
471 (do* ((args args (cddr args))
472 (remaining-gprs 6)
473 (remaining-fprs 8))
474 ((null args))
475 (let* ((arg-type-spec (car args))
476 (arg-value-form (cadr args)))
477 (if (or (member arg-type-spec *foreign-representation-type-keywords*
478 :test #'eq)
479 (typep arg-type-spec 'unsigned-byte))
480 (progn
481 (if (or (eq arg-type-spec :double-float)
482 (eq arg-type-spec :single-float))
483 (decf remaining-fprs)
484 (unless (typep arg-type-spec 'unsigned-byte)
485 (decf remaining-gprs)))
486 (argforms arg-type-spec)
487 (argforms arg-value-form))
488 (let* ((ftype (parse-foreign-type arg-type-spec)))
489 (when (and (typep ftype 'foreign-record-type)
490 (eq (foreign-record-type-kind ftype) :transparent-union))
491 (ensure-foreign-type-bits ftype)
492 (setq ftype (foreign-record-field-type
493 (car (foreign-record-type-fields ftype)))
494 arg-type-spec (foreign-type-to-representation-type ftype)))
495 (if (typep ftype 'foreign-record-type)
496 (multiple-value-bind (first8 second8)
497 (x8664::classify-record-type ftype)
498 (let* ((gprs remaining-gprs)
499 (fprs remaining-fprs))
500 (case first8
501 (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
502 (:float (if (< (decf fprs) 0) (setq first8 :memory))))
503 (case second8
504 (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
505 (:float (if (< (decf fprs) 0) (setq first8 :memory)))))
506 (if (eq first8 :memory)
507 (progn
508 (argforms (ceiling (foreign-record-type-bits ftype) 64))
509 (argforms arg-value-form))
510 (progn
511 (if second8
512 (progn
513 (unless structure-arg-temp
514 (setq structure-arg-temp (gensym)))
515 (setq valform `(%setf-macptr ,structure-arg-temp ,arg-value-form)))
516 (setq valform arg-value-form))
517 (if (eq first8 :float)
518 (progn
519 (decf remaining-fprs)
520 (argforms :double-float)
521 (argforms `(%get-double-float ,valform 0)))
522 (progn
523 (decf remaining-gprs)
524 (argforms :unsigned-doubleword)
525 (argforms `(%%get-unsigned-longlong ,valform 0))))
526 (when second8
527 (setq valform structure-arg-temp)
528 (if (eq second8 :float)
529 (progn
530 (decf remaining-fprs)
531 (argforms :double-float)
532 (argforms `(%get-double-float ,valform 8)))
533 (progn
534 (decf remaining-gprs)
535 (argforms :unsigned-doubleword)
536 (argforms `(%%get-unsigned-longlong ,valform 8))))))))
537 (let* ((rtype (foreign-type-to-representation-type ftype)))
538 (if (or (eq rtype :singlefloat) (eq rtype :double-float))
539 (decf remaining-fprs)
540 (decf remaining-gprs))
541 (argforms rtype)
542 (argforms (funcall arg-coerce arg-type-spec arg-value-form))))))))
543 (argforms (foreign-type-to-representation-type result-type))
544 (let* ((call (funcall result-coerce result-type-spec `(,@callform ,@(argforms)))))
545 (when structure-arg-temp
546 (setq call `(let* ((,structure-arg-temp (%null-ptr)))
547 (declare (dynamic-extent ,structure-arg-temp)
548 (type macptr ,structure-arg-temp))
549 ,call)))
550 (if regbuf
551 `(let* ((,result-temp (%null-ptr)))
552 (declare (dynamic-extent ,result-temp)
553 (type macptr ,result-temp))
554 (%setf-macptr ,result-temp ,result-form)
555 (%stack-block ((,regbuf (+ (* 2 8) (* 2 8))))
556 ,call
557 ,(x8664::struct-from-regbuf-values result-temp struct-result-type regbuf)))
558 call)))))))
559
560
561;;; Return 7 values:
562;;; A list of RLET bindings
563;;; A list of LET* bindings
564;;; A list of DYNAMIC-EXTENT declarations for the LET* bindings
565;;; A list of initializaton forms for (some) structure args
566;;; A FOREIGN-TYPE representing the "actual" return type.
567;;; A form which can be used to initialize FP-ARGS-PTR, relative
568;;; to STACK-PTR. (This is unused on linuxppc32.)
569;;; The byte offset of the foreign return address, relative to STACK-PTR
570
571(defun x8664::generate-callback-bindings (stack-ptr fp-args-ptr argvars argspecs result-spec struct-result-name)
572 (declare (ignore fp-args-ptr))
573 (collect ((lets)
574 (rlets)
575 (inits)
576 (dynamic-extent-names))
577 (let* ((rtype (parse-foreign-type result-spec)))
578 (when (typep rtype 'foreign-record-type)
579 (if (x8664::record-type-returns-structure-as-first-arg rtype)
580 (setq argvars (cons struct-result-name argvars)
581 argspecs (cons :address argspecs)
582 rtype *void-foreign-type*)
583 (rlets (list struct-result-name (foreign-record-type-name rtype)))))
584 (do* ((argvars argvars (cdr argvars))
585 (argspecs argspecs (cdr argspecs))
586 (gpr-arg-num 0)
587 (gpr-arg-offset -8)
588 (fpr-arg-num 0)
589 (fpr-arg-offset -56)
590 (memory-arg-offset 16)
591 (fp nil nil))
592 ((null argvars)
593 (values (rlets) (lets) (dynamic-extent-names) (inits) rtype nil 8))
594 (flet ((next-gpr ()
595 (if (<= (incf gpr-arg-num) 6)
596 (prog1
597 gpr-arg-offset
598 (decf gpr-arg-offset 8))
599 (prog1
600 memory-arg-offset
601 (incf memory-arg-offset 8))))
602 (next-fpr ()
603 (if (<= (incf fpr-arg-num) 8)
604 (prog1
605 fpr-arg-offset
606 (decf fpr-arg-offset 8))
607 (prog1
608 memory-arg-offset
609 (incf memory-arg-offset 8)))))
610 (let* ((name (car argvars))
611 (spec (car argspecs))
612 (argtype (parse-foreign-type spec))
613 (bits (require-foreign-type-bits argtype)))
614 (if (typep argtype 'foreign-record-type)
615 (multiple-value-bind (first8 second8)
616 (x8664::classify-record-type argtype)
617 (let* ((gprs (- 6 gpr-arg-num))
618 (fprs (- 8 fpr-arg-num)))
619 (case first8
620 (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
621 (:float (if (< (decf fprs) 0) (setq first8 :memory))))
622 (case second8
623 (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
624 (:float (if (< (decf fprs) 0) (setq first8 :memory)))))
625 (if (eq first8 :memory)
626 (let* ((form `(%inc-ptr ,stack-ptr ,(prog1 memory-arg-offset
627 (incf memory-arg-offset (* 8 (ceiling bits 64)))))))
628 (when name
629 (lets (list name form))
630 (dynamic-extent-names name)))
631 (progn
632 (when name (rlets (list name (foreign-record-type-name argtype))))
633 (let* ((init1 `(setf (%%get-unsigned-longlong ,name 0)
634 (%%get-unsigned-longlong ,stack-ptr ,(if (eq first8 :integer) (next-gpr) (next-fpr))))))
635 (when name (inits init1)))
636 (if second8
637 (let* ((init2 `(setf (%%get-unsigned-longlong ,name 8)
638 (%%get-unsigned-longlong ,stack-ptr ,(if (eq second8 :integer) (next-gpr) (next-fpr))))))
639 (when name (inits init2 )))))))
640 (let* ((form`(,
641 (ecase (foreign-type-to-representation-type argtype)
642 (:single-float (setq fp t) '%get-single-float)
643 (:double-float (setq fp t) '%get-double-float)
644 (:signed-doubleword '%%get-signed-longlong)
645 (:signed-fullword '%get-signed-long)
646 (:signed-halfword '%get-signed-word)
647 (:signed-byte '%get-signed-byte)
648 (:unsigned-doubleword '%%get-unsigned-longlong)
649 (:unsigned-fullword '%get-unsigned-long)
650 (:unsigned-halfword '%get-unsigned-word)
651 (:unsigned-byte '%get-unsigned-byte)
652 (:address
653 #+nil
654 (when name (dynamic-extent-names name))
655 '%get-ptr))
656 ,stack-ptr
657 ,(if fp (next-fpr) (next-gpr)))))
658 (if name (lets (list name form )))))))))))
659
660(defun x8664::generate-callback-return-value (stack-ptr fp-args-ptr result return-type struct-return-arg)
661 (declare (ignore fp-args-ptr))
662 (unless (eq return-type *void-foreign-type*)
663 (let* ((gpr-offset -8)
664 (fpr-offset -24))
665 (if (typep return-type 'foreign-record-type)
666 ;;; Would have been mapped to :VOID unless record-type was <= 128 bits.
667 (collect ((forms))
668 (multiple-value-bind (first8 second8)
669 (x8664::classify-record-type return-type)
670 (forms `(setf (%%get-signed-longlong ,stack-ptr ,(if (eq first8 :integer) gpr-offset fpr-offset))
671 (%%get-signed-longlong ,struct-return-arg 0)))
672 (when second8
673 (if (eq first8 :integer) (decf gpr-offset 8) (decf fpr-offset 8))
674 (forms `(setf (%%get-signed-longlong ,stack-ptr ,(if (eq first8 :integer) gpr-offset fpr-offset))
675 (%%get-signed-longlong ,struct-return-arg 8))))
676 `(progn ,@(forms))))
677 (let* ((return-type-keyword (foreign-type-to-representation-type return-type))
678 (offset (case return-type-keyword
679 ((:single-float :double-float) fpr-offset)
680 (t gpr-offset))))
681 `(setf (,
682 (case return-type-keyword
683 (:address '%get-ptr)
684 (:signed-doubleword '%%get-signed-longlong)
685 (:unsigned-doubleword '%%get-unsigned-longlong)
686 (:double-float '%get-double-float)
687 (:single-float '%get-single-float)
688 (:unsigned-fullword '%get-unsigned-long)
689 (t '%%get-signed-longlong )
690 ) ,stack-ptr ,offset) ,result))))))
691
692
693
694#+x8664-target
695(require "X8664-VINSNS")
696
697(provide "X8664-BACKEND")
Note: See TracBrowser for help on using the repository browser.