;;; The ABI specifies that signed short/int's are returned as 32-bit
;;; values. Negative values need to be sign-extended to 64-bits (done
;;; in a :NATURALIZE-GEN alien-type-method).
-(defknown sign-extend (fixnum) fixnum (foldable flushable movable))
+(defknown sign-extend ((signed-byte 32)) fixnum
+ (foldable flushable movable))
(define-vop (sign-extend)
(:translate sign-extend)
(:policy :fast-safe)
- (:args (val :scs (any-reg)))
+ (:args (val :scs (signed-reg)))
(:arg-types fixnum)
- (:results (res :scs (any-reg)))
+ (:results (res :scs (signed-reg)))
(:result-types fixnum)
(:generator 1
(inst movsxd res
:offset (tn-offset val)))))
(defun sign-extend (x)
- (if (logbitp 31 x)
- (dpb x (byte 32 0) -1)
- (ldb (byte 32 0) x)))
+ (declare (type (signed-byte 32) x))
+ (sign-extend x))
(define-vop (foreign-symbol-sap)
(:translate foreign-symbol-sap)
(:vop-var vop)
(:save-p t)
(:generator 0
+ ;; ABI: Direction flag must be clear on function entry. -- JES, 2006-01-20
+ (inst cld)
;; ABI: AL contains amount of arguments passed in XMM registers
;; for vararg calls.
(move-immediate rax
'float-registers)))
(inst call function)
;; To give the debugger a clue. XX not really internal-error?
- (note-this-location vop :internal-error)
- ;; FLOAT15 needs to contain FP zero in Lispland
- (let ((float15 (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset float15-offset)))
- (inst xorpd float15 float15))))
+ (note-this-location vop :internal-error)))
(define-vop (alloc-number-stack-space)
(:info amount)
(let ((delta (logandc2 (+ amount 7) 7)))
(inst sub rsp-tn delta)))
;; C stack must be 16 byte aligned
- (inst and rsp-tn #xfffffff0)
+ (inst and rsp-tn -16)
(move result rsp-tn)))
(define-vop (dealloc-number-stack-space)
(:generator 2
(inst add rsp-tn (fixnumize number))))
+;;; Callbacks
+
+#-sb-xc-host
+(defun alien-callback-accessor-form (type sp offset)
+ `(deref (sap-alien (sap+ ,sp ,offset) (* ,type))))
+
+#-sb-xc-host
+(defun alien-callback-assembler-wrapper (index result-type argument-types)
+ (labels ((make-tn-maker (sc-name)
+ (lambda (offset)
+ (make-random-tn :kind :normal
+ :sc (sc-or-lose sc-name)
+ :offset offset)))
+ (out-of-registers-error ()
+ (error "Too many arguments in callback")))
+ (let* ((segment (make-segment))
+ (rax rax-tn)
+ (rcx rcx-tn)
+ (rdi rdi-tn)
+ (rsi rsi-tn)
+ (rdx rdx-tn)
+ (rbp rbp-tn)
+ (rsp rsp-tn)
+ (xmm0 float0-tn)
+ ([rsp] (make-ea :qword :base rsp :disp 0))
+ ;; How many arguments have been copied
+ (arg-count 0)
+ ;; How many arguments have been copied from the stack
+ (stack-argument-count 0)
+ (gprs (mapcar (make-tn-maker 'any-reg) *c-call-register-arg-offsets*))
+ (fprs (mapcar (make-tn-maker 'double-reg)
+ ;; Only 8 first XMM registers are used for
+ ;; passing arguments
+ (subseq *float-regs* 0 8))))
+ (assemble (segment)
+ ;; Make room on the stack for arguments.
+ (inst sub rsp (* n-word-bytes (length argument-types)))
+ ;; Copy arguments from registers to stack
+ (dolist (type argument-types)
+ (let ((integerp (not (alien-float-type-p type)))
+ ;; A TN pointing to the stack location where the
+ ;; current argument should be stored for the purposes
+ ;; of ENTER-ALIEN-CALLBACK.
+ (target-tn (make-ea :qword :base rsp
+ :disp (* arg-count
+ n-word-bytes)))
+ ;; A TN pointing to the stack location that contains
+ ;; the next argument passed on the stack.
+ (stack-arg-tn (make-ea :qword :base rsp
+ :disp (* (+ 1
+ (length argument-types)
+ stack-argument-count)
+ n-word-bytes))))
+ (incf arg-count)
+ (cond (integerp
+ (let ((gpr (pop gprs)))
+ ;; Argument not in register, copy it from the old
+ ;; stack location to a temporary register.
+ (unless gpr
+ (incf stack-argument-count)
+ (setf gpr temp-reg-tn)
+ (inst mov gpr stack-arg-tn))
+ ;; Copy from either argument register or temporary
+ ;; register to target.
+ (inst mov target-tn gpr)))
+ ((or (alien-single-float-type-p type)
+ (alien-double-float-type-p type))
+ (let ((fpr (pop fprs)))
+ (cond (fpr
+ ;; Copy from float register to target location.
+ (inst movq target-tn fpr))
+ (t
+ ;; Not in float register. Copy from stack to
+ ;; temporary (general purpose) register, and
+ ;; from there to the target location.
+ (incf stack-argument-count)
+ (inst mov temp-reg-tn stack-arg-tn)
+ (inst mov target-tn temp-reg-tn)))))
+ (t
+ (bug "Unknown alien floating point type: ~S" type)))))
+
+ ;; arg0 to FUNCALL3 (function)
+ ;;
+ ;; Indirect the access to ENTER-ALIEN-CALLBACK through
+ ;; the symbol-value slot of SB-ALIEN::*ENTER-ALIEN-CALLBACK*
+ ;; to ensure it'll work even if the GC moves ENTER-ALIEN-CALLBACK.
+ ;; Skip any SB-THREAD TLS magic, since we don't expect anyone
+ ;; to rebind the variable. -- JES, 2006-01-01
+ (inst mov rdi (+ nil-value (static-symbol-offset
+ 'sb!alien::*enter-alien-callback*)))
+ (loadw rdi rdi symbol-value-slot other-pointer-lowtag)
+ ;; arg0 to ENTER-ALIEN-CALLBACK (trampoline index)
+ (inst mov rsi (fixnumize index))
+ ;; arg1 to ENTER-ALIEN-CALLBACK (pointer to argument vector)
+ (inst mov rdx rsp)
+ ;; add room on stack for return value
+ (inst sub rsp 8)
+ ;; arg2 to ENTER-ALIEN-CALLBACK (pointer to return value)
+ (inst mov rcx rsp)
+
+ ;; Make new frame
+ (inst push rbp)
+ (inst mov rbp rsp)
+
+ ;; Call
+ (inst mov rax (foreign-symbol-address "funcall3"))
+ (inst call rax)
+
+ ;; Back! Restore frame
+ (inst mov rsp rbp)
+ (inst pop rbp)
+
+ ;; Result now on top of stack, put it in the right register
+ (cond
+ ((or (alien-integer-type-p result-type)
+ (alien-pointer-type-p result-type)
+ (alien-type-= #.(parse-alien-type 'system-area-pointer nil)
+ result-type))
+ (inst mov rax [rsp]))
+ ((or (alien-single-float-type-p result-type)
+ (alien-double-float-type-p result-type))
+ (inst movq xmm0 [rsp]))
+ ((alien-void-type-p result-type))
+ (t
+ (error "unrecognized alien type: ~A" result-type)))
+
+ ;; Pop the arguments and the return value from the stack to get
+ ;; the return address at top of stack.
+ (inst add rsp (* (1+ (length argument-types)) n-word-bytes))
+ ;; Return
+ (inst ret))
+ (finalize-segment segment)
+ ;; Now that the segment is done, convert it to a static
+ ;; vector we can point foreign code to.
+ (let ((buffer (sb!assem::segment-buffer segment)))
+ (make-static-vector (length buffer)
+ :element-type '(unsigned-byte 8)
+ :initial-contents buffer)))))