Changeset 5776


Ignore:
Timestamp:
Jan 23, 2007, 5:59:23 AM (18 years ago)
Author:
Gary Byers
Message:

Define (common) x8664 ffi stuff here.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ccl/compiler/X86/X8664/x8664-backend.lisp

    r5752 r5776  
    296296(pushnew *x8664-backend* *known-backends* :key #'backend-name)
    297297
     298;;; FFI stuff.  Seems to be shared by Darwin/Linux/FreeBSD.
     299
     300;;; A returned structure is passed as an invisible first argument if
     301;;; it's more than 2 doublewords long or if it contains unaligned fields.
     302;;; Not clear how the latter case can happen, so this just checks for
     303;;; the first.
     304(defun x8664::record-type-returns-structure-as-first-arg (rtype)
     305  (when (and rtype
     306             (not (typep rtype 'unsigned-byte))
     307             (not (member rtype *foreign-representation-type-keywords*
     308                          :test #'eq)))
     309    (let* ((ftype (if (typep rtype 'foreign-type)
     310                    rtype
     311                    (parse-foreign-type rtype))))
     312      (> (ensure-foreign-type-bits ftype) 128))))
     313
     314;;; On x8664, structures can be passed by value:
     315;;;  a) in memory, if they're more than 128 bits in size or if there aren't
     316;;;     enough of the right kind of register to pass them entirely in registers.
     317;;;  b) as a series of 64-bit chunks, passed in GPRs if any component of the
     318;;;     chunk is a non FLOAT or in FPRs otherwise.
     319;;; Note that this means that a chunk consisting of two SINGLE-FLOATs would
     320;;; be passed in the low 64 bit of an SSE (xmm) register.
     321
     322(defun x8664::field-is-of-class-integer (field)
     323  ;; Return true if field is of "class" integer or if it's a record
     324  ;; type of class integer.  (See the System V AMD64 ABI document for
     325  ;; a convoluted definition of field "classes".)
     326  (let* ((ftype (foreign-record-field-type field)))
     327    (typecase ftype
     328      ((or foreign-integer-type foreign-pointer-type) t)
     329      (foreign-record-type (dolist (f (foreign-record-type-fields ftype))
     330                             (when (x8664::field-is-of-class-integer f)
     331                               (return t))))
     332      (otherwise nil))))
     333
     334(defun x8664::classify-8byte (field-list bit-limit)
     335  ;; CDR down the fields in FIELD-LIST until we find a field of class integer,
     336  ;; hit the end of the list, or find a field whose offset is >= BIT-LIMIT.
     337  ;; In the first case, return :INTEGER.  In other cases, return :FLOAT.
     338  (dolist (field field-list :float)
     339    (if (<= bit-limit (foreign-record-field-offset field))
     340      (return :float)
     341      (if (x8664::field-is-of-class-integer field)
     342        (return :integer)))))
     343
     344;;; Return a first value :memory, :integer, or::float and a second
     345;;; value of NIL, :integer, or :float according to how the structure
     346;;; RTYPE should ideally be passed or returned.  Note that the caller
     347;;; may decide to turn this to :memory if there aren't enough
     348;;; available registers of the right class when passing an instance of
     349;;; this structure type.
     350(defun x8664::classify-record-type (rtype)
     351  (let* ((nbits (ensure-foreign-type-bits rtype))
     352         (fields (foreign-record-type-fields rtype)))
     353    (cond ((> nbits 128) (values :memory nil))
     354          ((<= nbits 64) (values (x8664::classify-8byte fields 64) nil))
     355          (t (values (x8664::classify-8byte fields 64)
     356               (do* ()
     357                    ((>= (foreign-record-field-offset (car fields)) 64)
     358                     (x8664::classify-8byte fields 128))
     359                 (setq fields (cdr fields))))))))
     360
     361(defun x8664::struct-from-regbuf-values (r rtype regbuf)
     362  (multiple-value-bind (first second)
     363      (x8664::classify-record-type rtype)
     364    (let* ((gpr-offset 0)
     365           (fpr-offset 16))
     366      (collect ((forms))
     367        (case first
     368          (:integer (forms `(setf (%%get-unsigned-longlong ,r 0)
     369                             (%%get-unsigned-longlong ,regbuf 0)))
     370                    (setq gpr-offset 8))
     371          (:float (forms `(setf (%%get-unsigned-longlong ,r 0)
     372                             (%%get-unsigned-longlong ,regbuf 16)))
     373                  (setf fpr-offset 24)))
     374        (case second
     375          (:integer (forms `(setf (%%get-unsigned-longlong ,r 8)
     376                             (%%get-unsigned-longlong ,regbuf ,gpr-offset))))
     377          (:float (forms `(setf (%%get-unsigned-longlong ,r 8)
     378                             (%%get-unsigned-longlong ,regbuf ,fpr-offset)))))
     379        `(progn ,@(forms))))))
     380
     381(defun x8664::expand-ff-call (callform args &key (arg-coerce #'null-coerce-foreign-arg) (result-coerce #'null-coerce-foreign-result))
     382  (let* ((result-type-spec (or (car (last args)) :void))
     383         (regbuf nil)
     384         (result-temp nil)
     385         (result-form nil)
     386         (struct-result-type nil)
     387         (structure-arg-temp nil))
     388    (multiple-value-bind (result-type error)
     389        (parse-foreign-type result-type-spec)
     390      (if error
     391        (setq result-type-spec :void result-type *void-foreign-type*)
     392        (setq args (butlast args)))
     393      (collect ((argforms))
     394        (when (eq (car args) :monitor-exception-ports)
     395          (argforms (pop args)))
     396        (when (typep result-type 'foreign-record-type)
     397          (setq result-form (pop args)
     398                struct-result-type result-type
     399                result-type *void-foreign-type*
     400                result-type-spec :void)
     401          (if (x8664::record-type-returns-structure-as-first-arg struct-result-type)
     402            (progn
     403              (argforms :address)
     404              (argforms result-form))
     405            (progn
     406              (setq regbuf (gensym)
     407                    result-temp (gensym))
     408              (argforms :registers)
     409              (argforms regbuf))))
     410        (let* ((valform nil))
     411                      (unless (evenp (length args))
     412              (error "~s should be an even-length list of alternating foreign types and values" args))
     413            (do* ((args args (cddr args))
     414                  (remaining-gprs 6)
     415                  (remaining-fprs 8))
     416                 ((null args))
     417              (let* ((arg-type-spec (car args))
     418                     (arg-value-form (cadr args)))
     419                (if (or (member arg-type-spec *foreign-representation-type-keywords*
     420                                :test #'eq)
     421                        (typep arg-type-spec 'unsigned-byte))
     422                  (progn
     423                    (argforms arg-type-spec)
     424                    (argforms arg-value-form))
     425                  (let* ((ftype (parse-foreign-type arg-type-spec)))
     426                    (if (typep ftype 'foreign-record-type)
     427                      (multiple-value-bind (first8 second8)
     428                          (x8664::classify-record-type ftype)
     429                        (let* ((gprs remaining-gprs)
     430                               (fprs remaining-fprs))
     431                          (case first8
     432                            (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
     433                            (:float (if (< (decf fprs) 0) (setq first8 :memory))))
     434                          (case second8
     435                            (:integer (if (< (decf gprs) 0) (setq first8 :memory)))
     436                            (:float (if (< (decf fprs) 0) (setq first8 :memory)))))
     437                        (if (eq first8 :memory)
     438                          (progn
     439                            (argforms (ceiling (foreign-record-type-bits ftype) 64))
     440                            (argforms arg-value-form))
     441                          (progn
     442                            (if second8
     443                              (progn
     444                                (unless structure-arg-temp
     445                                  (setq structure-arg-temp (gensym)))
     446                                (setq valform `(%setf-macptr ,structure-arg-temp ,arg-value-form)))
     447                              (setq valform arg-value-form))
     448                            (if (eq first8 :float)
     449                              (progn
     450                                (decf remaining-fprs)
     451                                (argforms :double-float)
     452                                (argforms `(%get-double-float ,valform 0)))
     453                              (progn
     454                                (decf remaining-gprs)
     455                                (argforms :unsigned-doubleword)
     456                                (argforms `(%%get-unsigned-longlong ,valform 0))))
     457                            (when second8
     458                              (if (eq second8 :float)
     459                                (progn
     460                                (decf remaining-fprs)
     461                                (argforms :double-float)
     462                                (argforms `(%get-double-float ,valform 8)))
     463                              (progn
     464                                (decf remaining-gprs)
     465                                (argforms :unsigned-doubleword)
     466                                (argforms `(%%get-unsigned-longlong ,valform 8))))))))
     467                      (let* ((rtype (foreign-type-to-representation-type ftype)))
     468                        (if (or (eq rtype :singlefloat) (eq rtype :double-float))
     469                          (decf remaining-fprs)
     470                          (decf remaining-gprs))
     471                        (argforms rtype)
     472                        (argforms (funcall arg-coerce arg-type-spec arg-value-form))))))))
     473            (argforms (foreign-type-to-representation-type result-type))
     474            (let* ((call (funcall result-coerce result-type-spec `(,@callform ,@(argforms)))))
     475              (when structure-arg-temp
     476                (setq call `(let* ((,structure-arg-temp (%null-ptr)))
     477                             (declare (dynamic-extent ,structure-arg-temp)
     478                                      (type macptr ,structure-arg-temp))
     479                             ,call)))
     480              (if regbuf
     481                `(let* ((,result-temp (%null-ptr)))
     482                  (declare (dynamic-extent ,result-temp)
     483                           (type macptr ,result-temp))
     484                  (%setf-macptr ,result-temp ,result-form)
     485                  (%stack-block ((,regbuf (+ (* 2 8) (* 2 8))))
     486                    ,call
     487                    ,(x8664::struct-from-regbuf-values result-temp struct-result-type regbuf)))
     488                call)))))))
     489
     490
    298491#+x8664-target
    299492(require "X8664-VINSNS")
Note: See TracChangeset for help on using the changeset viewer.