Author Topic: X64 ABI, REAL8 passed in xmmreg?  (Read 302 times)

jj2007

  • Member
  • *****
  • Posts: 11317
  • Assembler is fun ;-)
    • MasmBasic
X64 ABI, REAL8 passed in xmmreg?
« on: April 08, 2021, 11:23:32 AM »
I am testing the Masm64 SDK (including the May 2020 update), and wanted to see how ML64 passes REAL8 (double) arguments in the XMM registers. Here is my code (it assembles fine, and even runs but obviously throws an error, because the arguments have no meaningful values):
Code: [Select]
include \masm32\include64\masm64rt.inc
include \masm32\include64\glu32.inc
includelib \masm32\lib64\glu32.lib

.code
txTitle db "Title", 0
txText db "Text", 0

entry_point proc
LOCAL rval :QWORD
LOCAL qobj:QWORD, innerRadius:REAL8, outerRadius:REAL8, slices:DWORD, loops:DWORD, startAngle:REAL8, sweepAngle:REAL8

; C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\gl\GLU.h
; void APIENTRY gluPartialDisk (
;     GLUquadric          *qobj,
;     GLdouble            innerRadius,
;     GLdouble            outerRadius,
;     GLint               slices,
;     GLint               loops,
;     GLdouble            startAngle,
;     GLdouble            sweepAngle);
  int 3   ; for testing
  invoke gluPartialDisk, addr qobj, innerRadius, outerRadius, slices, loops, startAngle, sweepAngle
  invoke MessageBox, 0, addr txText, addr txTitle, MB_OK
  invoke ExitProcess, 0
  ret
entry_point endp

end

However, when launching the exe (only 1536 bytes!) with the debugger, there are no xmm regs passed:
Code: [Select]
lea rcx,[rbp-78]           |
mov rdx,[rbp-80]           |
mov r8,[rbp-88]            |
mov r9d,[rbp-8C]           |
mov eax,[rbp-90]           |
mov [rsp+20],eax           |
mov rax,[rbp-98]           |
mov [rsp+28],rax           |
mov rax,[rbp-A0]           |
mov [rsp+30],rax           |
call [<&gluPartialDisk>]   |

What am I making wrong?

P.S.: Interesting that gluPartialDisk does lots of pushing:
Code: [Select]
000007FEEADFAF20  | 48:8BC4                      | mov rax,rsp                |
000007FEEADFAF23  | 48:8958 08                   | mov [rax+8],rbx            |
000007FEEADFAF27  | 48:8968 10                   | mov [rax+10],rbp           |
000007FEEADFAF2B  | 56                           | push rsi                   |
000007FEEADFAF2C  | 57                           | push rdi                   |
000007FEEADFAF2D  | 41:54                        | push r12                   |
000007FEEADFAF2F  | 41:55                        | push r13                   |
000007FEEADFAF31  | 41:56                        | push r14                   |

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8239
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #1 on: April 08, 2021, 12:38:54 PM »
Load an XMM register with a floating point REAL8 value with "movsd" then read whatever you need in the proc. The REAL8 value must be a memory operand. I use a macro "loadsd" but it just a wrapper around a data section entry and loading its address with LEA.

NOSTACKFRAME

XmmTest proc

    addsd xmm0, xmm1
    addsd xmm0, xmm2
    addsd xmm0, xmm3
    addsd xmm0, xmm4
    addsd xmm0, xmm5
    addsd xmm0, xmm6
    addsd xmm0, xmm7

    ret

XmmTest endp

STACKFRAME

hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

HSE

  • Member
  • *****
  • Posts: 1618
  • <AMD>< 7-32>
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #2 on: April 09, 2021, 03:48:18 AM »
Some macros64 modifications:
Code: (procedure_call) [Select]
  ;; **************************
    ;; first 4 register arguments
    ;; **************************
      IFNB <a1>
        REGISTER a1,cl,cx,ecx,rcx,xmm0
      ENDIF

      IFNB <a2>
        REGISTER a2,dl,dx,edx,rdx,xmm1
      ENDIF

      IFNB <a3>
        REGISTER a3,r8b,r8w,r8d,r8,xmm2
      ENDIF

      IFNB <a4>
        REGISTER a4,r9b,r9w,r9d,r9,xmm3
      ENDIF

Code: (REGISTER) [Select]

    REGISTER MACRO anum,breg,wreg,dreg,qreg,xreg

      ·······

     IF ssize GT 9                             ;; handle REAL4 PTR
        lead SUBSTR <anum>,1,9
        IFIDNI lead,<REAL4 PTR>
          mov qreg, anum
          cvtss2sd xreg, DWORD PTR anum
          goto elbl
        ENDIF
      ENDIF

      IF ssize GT 9                             ;; handle REAL8 PTR
        lead SUBSTR <anum>,1,9
        IFIDNI lead,<REAL8 PTR>
          mov qreg, anum
          movsd xreg, qword ptr anum
          goto elbl
        ENDIF
      ENDIF

Attached macros64B.inc

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8239
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #3 on: April 09, 2021, 08:20:20 AM »
Hi Hector,

Sorry if I have been a bit slow, I have been ploughing through a mountain of work and got a bit snowed under. I like the idea in the first one, will have to have a play with it to make sure there are no unintended side effects but it looks like a good idea. I have not digested the second one yet.

I am inclined to keep 32 and 64 bit SSE2 separate

This is a test piece I was working on recently, so far it will sequence load as many 64 bit pseudo immediated as you point at it but I ran out of time to finish it off.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

    xmm_reg_call MACRO pname, args:VARARG
      LOCAL buff, var
      buff equ <>
      cnt = 0
        for arg, <args>
          buff CATSTR <loadsd >,<xmm>,num2str(cnt),<, >,<arg>   ;; join all strings
          % buff                                                ;; output as string
          cnt = cnt + 1                                         ;; increment register counter
        ENDM
      call pname                                                ;; call the procedure
    ENDM

    xrv MACRO pname, args :VARARG
      xmm_reg_call pname, args
      EXITM < xmm0>
    ENDM

    xinvoke MACRO pname, args :VARARG
      xmm_reg_call pname, args
    ENDM

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

 entry_point proc

    LOCAL fvar :REAL8
    LOCAL tvar :REAL8
    LOCAL pbuf :QWORD
    LOCAL buff[64] :BYTE

    mov pbuf, ptr$(buff)
    movsd fvar, xrv(XmmTest,1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)
    rcall fptoa,fvar,pbuf
    conout "  Result = ",pbuf,lf

    xinvoke XmmTest,1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
    movsd fvar, xmm0
    rcall fptoa,fvar,pbuf
    conout "  Result = ",pbuf,lf

    waitkey
    .exit

 entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

NOSTACKFRAME

XmmTest proc

    addsd xmm0, xmm1
    addsd xmm0, xmm2
    addsd xmm0, xmm3
    addsd xmm0, xmm4
    addsd xmm0, xmm5
    addsd xmm0, xmm6
    addsd xmm0, xmm7

    ret

XmmTest endp

STACKFRAME

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

HSE

  • Member
  • *****
  • Posts: 1618
  • <AMD>< 7-32>
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #4 on: April 09, 2021, 09:20:29 AM »
Hi Hutch!

No hurry at all  :biggrin:

Line can be shorter using expansión instead of num2str:
Code: [Select]
        buff CATSTR <loadsd >,<xmm>,%cnt,<, >,<arg>   ;; join all strings

num2str is good for:
Code: [Select]
       %echo num2str(cnt) 
 :thumbsup:

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8239
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #5 on: April 09, 2021, 09:31:59 PM »
I have got the earlier macro to work on different data notations and it seems to be working OK. I got a notation to work in an invoke call if it is used as the last argument.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

  ; *************************************************************

    load_xmm_regs MACRO args:VARARG
      LOCAL buff,aattr
      buff equ <>
      cnt = 0

     ;; ---------------------------------------------------------

      for arg, <args>
        aattr = getattr(arg)                                    ;; get the argument attribute
        IF aattr EQ 36                                          ;; INT immediate, exit on error
          .err <   ---{ notation error, missing floating point }--->
            %echo ------------------------------------------------------------------
            %echo ERROR => arg : x86-64 does not support loading immediate integers
            %echo          in an XMM register. Use FP format value instead => arg.0
            %echo          Assembly is TERMINATED at this point
            %echo ------------------------------------------------------------------
          EXITM <>                                              ;; stop the macro here on error
          END                                                   ;; terminate the assembly
        ENDIF
        IF aattr EQ 0
          buff CATSTR <loadsd >,<xmm>,%cnt,<, >,<arg>           ;; pseudo immediate
          goto writeit
        ENDIF
        IF aattr EQ 98
          buff CATSTR <movsd >,<xmm>,%cnt,<, >,<arg>            ;; LOCAL var
          goto writeit
        ENDIF
        IF aattr EQ 42
          buff CATSTR <movsd >,<xmm>,%cnt,<, >,<arg>            ;; GLOBAL var
          goto writeit
        ENDIF
        IF aattr EQ 48
          buff CATSTR <movsd >,<xmm>,%cnt,<, >,<arg>            ;; XMM register
          goto writeit
        ENDIF
      :writeit
        % buff                                                  ;; output as string
        cnt = cnt + 1                                           ;; increment register counter
      ENDM

     ;; ---------------------------------------------------------

    ENDM

  ; *************************************************************

    xrv MACRO pname:REQ, args :VARARG                           ;; function form
      load_xmm_regs args
      call pname                                                ;; call the procedure
      EXITM < xmm0>
    ENDM

    xinvoke MACRO pname:REQ, args :VARARG                       ;; statement form
      load_xmm_regs args
      call pname                                                ;; call the procedure
    ENDM

    xload MACRO args:VARARG
      load_xmm_regs args                                        ;; load XMM regs only
    ENDM

    xloadrv MACRO args:VARARG
      load_xmm_regs args                                        ;; load XMM regs only
      EXITM <>                                                  ;; allow empty function form
    ENDM

  ; *************************************************************

    .data?
      gvar REAL8 ?                      ; global for testing

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

 entry_point proc

    LOCAL lvar :REAL8
    LOCAL tvar :REAL8
    LOCAL pbuf :QWORD
    LOCAL buff[64] :BYTE


    mov pbuf, ptr$(buff)
    movsd lvar, xrv(XmmTest,1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)
    rcall fptoa,lvar,pbuf
    conout "  Result = ",pbuf,lf

    xinvoke XmmTest,1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
    movsd lvar, xmm0
    rcall fptoa,lvar,pbuf
    conout "  Result = ",pbuf,lf,lf

  ; -------------------------------------------------------------------
  ; with invoke, the integer args must come first. FP load must be last
  ; -------------------------------------------------------------------
    invoke LoadTest,1111,2222,3333,4444, xloadrv(1234.1234, 5678.5678)

    waitkey
    .exit

 entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

NOSTACKFRAME

XmmTest proc

    addsd xmm0, xmm1
    addsd xmm0, xmm2
    addsd xmm0, xmm3
    addsd xmm0, xmm4
    addsd xmm0, xmm5
    addsd xmm0, xmm6
    addsd xmm0, xmm7

    ret

XmmTest endp

STACKFRAME

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

LoadTest proc

    USING r12,r13,r14,r15

    LOCAL var1 :REAL8
    LOCAL var2 :REAL8
    LOCAL ptxt :QWORD
    LOCAL text[64]:BYTE

    SaveRegs

    movsd var1, xmm0            ; copy to REAL8 first
    movsd var2, xmm1            ; something in fptoa over writes at least one XMM register

    mov ptxt, ptr$(text)

    mov r12, rcx
    mov r13, rdx
    mov r14, r8
    mov r15, r9

    conout "  Integer  ",str$(r12),lf
    conout "  Integer  ",str$(r13),lf
    conout "  Integer  ",str$(r14),lf
    conout "  Integer  ",str$(r15),lf,lf

    invoke fptoa,var1,ptxt
    conout "  SD Float ",ptxt,lf

    invoke fptoa,var2,ptxt
    conout "  SD Float ",ptxt,lf

    RestoreRegs

    ret

LoadTest endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8239
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: X64 ABI, REAL8 passed in xmmreg?
« Reply #6 on: April 12, 2021, 06:21:56 AM »
I have split this topic where it shifted from the 64 bit MASM project into wider and different topics. It can be found in the 64 bit assembler forum for any who wish to contribute to that discussion.

This subforum is reserved for 64 bit MASM and I will move anything that is different.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy: