rubinius/rubinius

View on GitHub
build/libraries/libffi/src/x86/win64.S

Summary

Maintainability
Test Coverage
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>

/* Constants for ffi_call_win64 */
#define STACK 0
#define PREP_ARGS_FN 32
#define ECIF 40
#define CIF_BYTES 48
#define CIF_FLAGS 56
#define RVALUE 64
#define FN 72

/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
           extended_cif *ecif, unsigned bytes, unsigned flags,
           unsigned *rvalue, void (*fn)());
 */

#ifdef _MSC_VER
PUBLIC    ffi_call_win64

EXTRN    __chkstk:NEAR
EXTRN    ffi_closure_win64_inner:NEAR

_TEXT    SEGMENT

;;; ffi_closure_win64 will be called with these registers set:
;;;    rax points to 'closure'
;;;    r11 contains a bit mask that specifies which of the
;;;    first four parameters are float or double
;;;
;;; It must move the parameters passed in registers to their stack location,
;;; call ffi_closure_win64_inner for the actual work, then return the result.
;;;
ffi_closure_win64 PROC FRAME
    ;; copy register arguments onto stack
    test    r11, 1
    jne    first_is_float
    mov    QWORD PTR [rsp+8], rcx
    jmp    second
first_is_float:
    movlpd    QWORD PTR [rsp+8], xmm0

second:
    test    r11, 2
    jne    second_is_float
    mov    QWORD PTR [rsp+16], rdx
    jmp    third
second_is_float:
    movlpd    QWORD PTR [rsp+16], xmm1

third:
    test    r11, 4
    jne    third_is_float
    mov    QWORD PTR [rsp+24], r8
    jmp    fourth
third_is_float:
    movlpd    QWORD PTR [rsp+24], xmm2

fourth:
    test    r11, 8
    jne    fourth_is_float
    mov    QWORD PTR [rsp+32], r9
    jmp    done
fourth_is_float:
    movlpd    QWORD PTR [rsp+32], xmm3

done:
    .ALLOCSTACK 40
    sub    rsp, 40
    .ENDPROLOG
    mov    rcx, rax    ; context is first parameter
    mov    rdx, rsp    ; stack is second parameter
    add    rdx, 48        ; point to start of arguments
    mov    rax, ffi_closure_win64_inner
    call    rax        ; call the real closure function
    add    rsp, 40
    movd    xmm0, rax    ; If the closure returned a float,
                ; ffi_closure_win64_inner wrote it to rax
    ret    0
ffi_closure_win64 ENDP

ffi_call_win64 PROC FRAME
    ;; copy registers onto stack
    mov    QWORD PTR [rsp+32], r9
    mov    QWORD PTR [rsp+24], r8
    mov    QWORD PTR [rsp+16], rdx
    mov    QWORD PTR [rsp+8], rcx
    .PUSHREG rbp
    push    rbp
    .ALLOCSTACK 48
    sub    rsp, 48                    ; 00000030H
    .SETFRAME rbp, 32
    lea    rbp, QWORD PTR [rsp+32]
    .ENDPROLOG

    mov    eax, DWORD PTR CIF_BYTES[rbp]
    add    rax, 15
    and    rax, -16
    call    __chkstk
    sub    rsp, rax
    lea    rax, QWORD PTR [rsp+32]
    mov    QWORD PTR STACK[rbp], rax

    mov    rdx, QWORD PTR ECIF[rbp]
    mov    rcx, QWORD PTR STACK[rbp]
    call    QWORD PTR PREP_ARGS_FN[rbp]

    mov    rsp, QWORD PTR STACK[rbp]

    movlpd    xmm3, QWORD PTR [rsp+24]
    movd    r9, xmm3

    movlpd    xmm2, QWORD PTR [rsp+16]
    movd    r8, xmm2

    movlpd    xmm1, QWORD PTR [rsp+8]
    movd    rdx, xmm1

    movlpd    xmm0, QWORD PTR [rsp]
    movd    rcx, xmm0

    call    QWORD PTR FN[rbp]
ret_struct4b$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
     jne    ret_struct2b$

    mov    rcx, QWORD PTR RVALUE[rbp]
    mov    DWORD PTR [rcx], eax
    jmp    ret_void$

ret_struct2b$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
     jne    ret_struct1b$

    mov    rcx, QWORD PTR RVALUE[rbp]
    mov    WORD PTR [rcx], ax
    jmp    ret_void$

ret_struct1b$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
     jne    ret_uint8$

    mov    rcx, QWORD PTR RVALUE[rbp]
    mov    BYTE PTR [rcx], al
    jmp    ret_void$

ret_uint8$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
     jne    ret_sint8$

    mov    rcx, QWORD PTR RVALUE[rbp]
    movzx   rax, al
    mov    QWORD PTR [rcx], rax
    jmp    ret_void$

ret_sint8$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
     jne    ret_uint16$

    mov    rcx, QWORD PTR RVALUE[rbp]
    movsx   rax, al
    mov    QWORD PTR [rcx], rax
    jmp    ret_void$

ret_uint16$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
     jne    ret_sint16$

    mov    rcx, QWORD PTR RVALUE[rbp]
    movzx   rax, ax
    mov    QWORD PTR [rcx], rax
    jmp    SHORT ret_void$

ret_sint16$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
     jne    ret_uint32$

    mov    rcx, QWORD PTR RVALUE[rbp]
    movsx   rax, ax
    mov    QWORD PTR [rcx], rax
    jmp    SHORT ret_void$

ret_uint32$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
     jne    ret_sint32$

    mov    rcx, QWORD PTR RVALUE[rbp]
    mov     eax, eax
    mov    QWORD PTR [rcx], rax
    jmp    SHORT ret_void$

ret_sint32$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
     jne    ret_float$

    mov    rcx, QWORD PTR RVALUE[rbp]
    cdqe
    mov    QWORD PTR [rcx], rax
    jmp    SHORT ret_void$

ret_float$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
     jne    SHORT ret_double$

     mov    rax, QWORD PTR RVALUE[rbp]
     movss    DWORD PTR [rax], xmm0
     jmp    SHORT ret_void$

ret_double$:
     cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
     jne    SHORT ret_uint64$

     mov    rax, QWORD PTR RVALUE[rbp]
     movlpd    QWORD PTR [rax], xmm0
     jmp    SHORT ret_void$

ret_uint64$:
      cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT64
      jne    SHORT ret_sint64$

     mov    rcx, QWORD PTR RVALUE[rbp]
     mov    QWORD PTR [rcx], rax
     jmp    SHORT ret_void$

ret_sint64$:
      cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
      jne    SHORT ret_pointer$

     mov    rcx, QWORD PTR RVALUE[rbp]
     mov    QWORD PTR [rcx], rax
     jmp    SHORT ret_void$

ret_pointer$:
      cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_POINTER
      jne    SHORT ret_int$

     mov    rcx, QWORD PTR RVALUE[rbp]
     mov    QWORD PTR [rcx], rax
     jmp    SHORT ret_void$

ret_int$:
      cmp    DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_INT
      jne    SHORT ret_void$

    mov    rcx, QWORD PTR RVALUE[rbp]
    cdqe
    mov    QWORD PTR [rcx], rax
     jmp    SHORT ret_void$

ret_void$:
    xor    rax, rax

    lea    rsp, QWORD PTR [rbp+16]
    pop    rbp
    ret    0
ffi_call_win64 ENDP
_TEXT    ENDS
END

#else

#ifdef SYMBOL_UNDERSCORE
#define SYMBOL_NAME(name) _##name
#else
#define SYMBOL_NAME(name) name
#endif

.text

.extern SYMBOL_NAME(ffi_closure_win64_inner)

# ffi_closure_win64 will be called with these registers set:
#    rax points to 'closure'
#    r11 contains a bit mask that specifies which of the
#    first four parameters are float or double
#
# It must move the parameters passed in registers to their stack location,
# call ffi_closure_win64_inner for the actual work, then return the result.
#
    .balign 16
    .globl SYMBOL_NAME(ffi_closure_win64)
    .seh_proc SYMBOL_NAME(ffi_closure_win64)
SYMBOL_NAME(ffi_closure_win64):
    # copy register arguments onto stack
    test    $1,%r11
    jne    .Lfirst_is_float
    mov    %rcx, 8(%rsp)
    jmp    .Lsecond
.Lfirst_is_float:
    movlpd    %xmm0, 8(%rsp)

.Lsecond:
    test    $2, %r11
    jne    .Lsecond_is_float
    mov    %rdx, 16(%rsp)
    jmp    .Lthird
.Lsecond_is_float:
    movlpd    %xmm1, 16(%rsp)

.Lthird:
    test    $4, %r11
    jne    .Lthird_is_float
    mov    %r8,24(%rsp)
    jmp    .Lfourth
.Lthird_is_float:
    movlpd    %xmm2, 24(%rsp)

.Lfourth:
    test    $8, %r11
    jne    .Lfourth_is_float
    mov    %r9, 32(%rsp)
    jmp    .Ldone
.Lfourth_is_float:
    movlpd    %xmm3, 32(%rsp)

.Ldone:
    .seh_stackalloc 40
    sub    $40, %rsp
    .seh_endprologue
    mov    %rax, %rcx    # context is first parameter
    mov    %rsp, %rdx    # stack is second parameter
    add    $48, %rdx    # point to start of arguments
    leaq    SYMBOL_NAME(ffi_closure_win64_inner)(%rip), %rax
    callq    *%rax        # call the real closure function
    add    $40, %rsp
    movq    %rax, %xmm0    # If the closure returned a float,
                # ffi_closure_win64_inner wrote it to rax
    retq
    .seh_endproc

    .balign 16
    .globl    SYMBOL_NAME(ffi_call_win64)
    .seh_proc SYMBOL_NAME(ffi_call_win64)
SYMBOL_NAME(ffi_call_win64):
    # copy registers onto stack
    mov    %r9,32(%rsp)
    mov    %r8,24(%rsp)
    mov    %rdx,16(%rsp)
    mov    %rcx,8(%rsp)
    .seh_pushreg rbp
    push    %rbp
    .seh_stackalloc 48
    sub    $48,%rsp
    .seh_setframe rbp, 32
    lea    32(%rsp),%rbp
    .seh_endprologue

    mov    CIF_BYTES(%rbp),%eax
    add    $15, %rax
    and    $-16, %rax
    cmpq    $0x1000, %rax
    jb    Lch_done
Lch_probe:
    subq    $0x1000,%rsp
    orl    $0x0, (%rsp)
    subq    $0x1000,%rax
    cmpq    $0x1000,%rax
    ja    Lch_probe
Lch_done:
    subq    %rax, %rsp
    orl    $0x0, (%rsp)
    lea    32(%rsp), %rax
    mov    %rax, STACK(%rbp)

    mov    ECIF(%rbp), %rdx
    mov    STACK(%rbp), %rcx
    callq    *PREP_ARGS_FN(%rbp)

    mov    STACK(%rbp), %rsp

    movlpd    24(%rsp), %xmm3
    movd    %xmm3, %r9

    movlpd    16(%rsp), %xmm2
    movd    %xmm2, %r8

    movlpd    8(%rsp), %xmm1
    movd    %xmm1, %rdx

    movlpd    (%rsp), %xmm0
    movd    %xmm0, %rcx

    callq    *FN(%rbp)
.Lret_struct4b:
     cmpl    $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
     jne .Lret_struct2b

    mov    RVALUE(%rbp), %rcx
    mov    %eax, (%rcx)
    jmp    .Lret_void

.Lret_struct2b:
    cmpl    $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
    jne .Lret_struct1b

    mov    RVALUE(%rbp), %rcx
    mov    %ax, (%rcx)
    jmp .Lret_void

.Lret_struct1b:
    cmpl    $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
    jne .Lret_uint8

    mov    RVALUE(%rbp), %rcx
    mov    %al, (%rcx)
    jmp .Lret_void

.Lret_uint8:
    cmpl    $FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
    jne .Lret_sint8

    mov     RVALUE(%rbp), %rcx
    movzbq  %al, %rax
    movq    %rax, (%rcx)
    jmp .Lret_void

.Lret_sint8:
    cmpl    $FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
    jne .Lret_uint16

    mov     RVALUE(%rbp), %rcx
    movsbq  %al, %rax
    movq    %rax, (%rcx)
    jmp .Lret_void

.Lret_uint16:
    cmpl    $FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
    jne .Lret_sint16

    mov     RVALUE(%rbp), %rcx
    movzwq  %ax, %rax
    movq    %rax, (%rcx)
    jmp .Lret_void

.Lret_sint16:
    cmpl    $FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
    jne .Lret_uint32

    mov     RVALUE(%rbp), %rcx
    movswq  %ax, %rax
    movq    %rax, (%rcx)
    jmp .Lret_void

.Lret_uint32:
    cmpl    $FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
    jne .Lret_sint32

    mov     RVALUE(%rbp), %rcx
    movl    %eax, %eax
    movq    %rax, (%rcx)
    jmp .Lret_void

.Lret_sint32:
     cmpl    $FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
     jne    .Lret_float

    mov    RVALUE(%rbp), %rcx
    cltq
    movq    %rax, (%rcx)
    jmp    .Lret_void

.Lret_float:
     cmpl    $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
     jne    .Lret_double

     mov    RVALUE(%rbp), %rax
     movss    %xmm0, (%rax)
     jmp    .Lret_void

.Lret_double:
     cmpl    $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
     jne    .Lret_uint64

     mov    RVALUE(%rbp), %rax
     movlpd    %xmm0, (%rax)
     jmp    .Lret_void

.Lret_uint64:
      cmpl    $FFI_TYPE_UINT64, CIF_FLAGS(%rbp)
     jne    .Lret_sint64

     mov    RVALUE(%rbp), %rcx
     mov    %rax, (%rcx)
     jmp    .Lret_void

.Lret_sint64:
      cmpl    $FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
      jne    .Lret_pointer

     mov    RVALUE(%rbp), %rcx
     mov    %rax, (%rcx)
     jmp    .Lret_void

.Lret_pointer:
      cmpl    $FFI_TYPE_POINTER, CIF_FLAGS(%rbp)
      jne    .Lret_int

     mov    RVALUE(%rbp), %rcx
     mov    %rax, (%rcx)
     jmp    .Lret_void

.Lret_int:
      cmpl    $FFI_TYPE_INT, CIF_FLAGS(%rbp)
      jne    .Lret_void

    mov    RVALUE(%rbp), %rcx
    cltq
    movq    %rax, (%rcx)
    jmp    .Lret_void

.Lret_void:
    xor    %rax, %rax

    lea    16(%rbp), %rsp
    pop    %rbp
    retq
    .seh_endproc
#endif /* !_MSC_VER */