MASM Macros to EuroAssembler

Problems which concern EuroAssembler
AndreyDmitriev
Posts: 6
Joined: 01 Jun 2023 09:11

MASM Macros to EuroAssembler

Unread postby AndreyDmitriev » 01 Jun 2023 09:30

Hello!

Currently I learning asm with AVX and lost a little bit with Macros. Especially with this one: https://github.com/Apress/modern-x86-as ... 4-AVX.asmh
(used in this example https://github.com/Apress/modern-x86-as ... 07_06_.asm)
The goal is to create DLL in EuroAssembler with exactly same functionality. Is there elegant way to port the macros like _CreateFrame and _Save/RestoreXmmRegs to EuroAssembler?
Thank you in advance,
Andrey.
User avatar
vitsoft
Site Admin
Posts: 51
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: MASM Macros to EuroAssembler

Unread postby vitsoft » 03 Jun 2023 19:45

Hello Andrey, there is a way but not much elegant and I had to omit MASM directives for SEH (Structured Exception Handling) which are not supported by €ASM:

;-------------------------------------------------------------------------
; Description:  The following macro generates code that creates a stack
;               frame for x86-64 functions.
; Macro Parameters: %1 Prefix          Macro symbolic name prefix
;                   %2 StkSizeLocal1   Size in bytes for local1 vars
;                   %3 StkSizeLocal2   Size in bytes for XMM reg save area
;                   %4..%10 Rnv1 - Rnv7     Non-volatile registers to save
_CreateFrame %MACRO Prefix,StkSizeLocal1,StkSizeLocal2,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7
%IF %StkSizeLocal1 \ 16   ; Make sure stack sizes are valid
   %ERROR Macro parameter %StkSizeLocal1 must be evenly divisible by 16.
%ENDIF
%IF %StkSizeLocal2 \ 16
   %ERROR Macro parameter %StkSizeLocal2 must be evenly divisible by 16.
%ENDIF
%IF %StkSizeLocal2 > 240
   %ERROR Macro parameter %StkSizeLocal2 must be less than or equal to 240.
%ENDIF
           PUSH RBP       ; Push previous frame pointer.
%GPRtoPush %SET           ; Make the list of GPR-to-save empty.
%GPRtoPop  %SET           ; Make the list of GPR-to-restore empty.
ArgNr  %FOR 4..10         ; FOR-loop thru 4-th and further macro argument.
         %GPR %SET2 %%Rnv%ArgNr
         %IF %GPR                          ; If ArgNr-th argument is specified.
           %GPRtoPush %SET %GPRtoPush,%GPR ; Populate the list of registers to save.
           %GPRtoPop  %SET %GPR,%GPRtoPop  ; Populate the list in inversed order.
         %ENDIF
        %ENDFOR ArgNr
%NumPushReg %SETL %GPRtoPop
%NumPushReg %SETA %NumPushReg + 1  ; Increment because RBP was already pushed.
%IF %NumPushReg > 1
        PUSH %GPRtoPush   ; Push all specified non-volatile registers specified on the list.
%ENDIF
%StackPad       %SETA ((%NumPushReg & 1) ^ 1) * 8 ; Zero when there are no other GPR than RBP.
%StackSizeTotal %SETA %StkSizeLocal1+%StkSizeLocal2+%StackPad
        SUB RSP,%StackSizeTotal
%IF     %StkSizeLocal2 > 0
         LEA RBP,[RSP+%StkSizeLocal2]
%ELSE
         MOV RBP,RSP
%ENDIF
; Create the symbols for current function
        %Prefix{}StackSizeTotal    EQU %StackSizeTotal
        %Prefix{}StackSizeLocal1   EQU %StkSizeLocal1
        %Prefix{}StackSizeLocal2   EQU %StkSizeLocal2
        %Prefix{}OffsetHomeRCX     EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+8
        %Prefix{}OffsetHomeRDX     EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+16
        %Prefix{}OffsetHomeR8      EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+24
        %Prefix{}OffsetHomeR9      EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+32
        %Prefix{}OffsetStaclArgs   EQU %StkSizeLocal1+%NumPushReg*8+%StackPad+40
        %ValNameOffsetSaveXmmRegs  %SET %Prefix{}OffsetSaveXmmRegs
        %Prefix{}OffsetSaveXmmRegs EQU %StkSizeLocal2
        %ValNameOffsetDeleteFrame  %SET %Prefix{}OffsetDeleteFrame
        %Prefix{}OffsetDeleteFrame EQU %StkSizeLocal1+%StackPad
    %ENDMACRO _CreateFrame


;-------------------------------------------------------------------------
; Description:  The following macro generates code that de-allocate a
;               stack frame previously created using _CreateFrame.
; Macro Parameters: Rnv1 - Rnv7     Non-volatile registers to restore
_DeleteFrame %MACRO Rnv1,Rnv2,,,
%IF (%ValNameOffsetDeleteFrame > 0)
        LEA RSP,[RBP+%ValNameOffsetDeleteFrame]
%ELSE
        MOV RSP,RBP
%ENDIF
%IF %GPRtoPop                ; List of Rnv7..Rnv1, if any.
        POP %GPRtoPop        ; Restore all pushed registers at once.
%ENDIF
        POP RBP
      %ENDMACRO _DeleteFrame

;-------------------------------------------------------------------------
; Description:  The following macro generates code that saves the
;               specified non-volatile registers to the local save area.
; Macro Parameters: Rnv1 - Rnv7     Non-volatile XMM registers to save.
_SaveXmmRegs %MACRO Rnv0,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7,Rnv8,Rnv9
%position %SETA 0       ; Position of XMM register stored in Local2  (0,16,32..)
reg %FOR %*             ; Repeat the %FOR block with all arguments.
      VMOVDQA [RBP-%ValNameOffsetSaveXmmRegs+%position],%reg
      %position %SETA %position+16
    %ENDFOR reg
   %ENDMACRO _SaveXmmRegs

;-------------------------------------------------------------------------
; Description:  The following macro generates code that restores the
;               specified non-volatile registers from the local save area.
; Macro Parameters: Rnv1 - Rnv7     Non-volatile XMM registers to restore.
;-------------------------------------------------------------------------
_RestoreXmmRegs %MACRO Rnv0,Rnv1,Rnv2,Rnv3,Rnv4,Rnv5,Rnv6,Rnv7,Rnv8,Rnv9
%position %SETA 0        ; Position of XMM register stored in Local2  (0,8,16,24..)
reg %FOR %*             ; Repeat the %FOR block with all arguments.
      VMOVDQA %reg,[RBP-%ValNameOffsetSaveXmmRegs+%position]
      %position %SETA %position+16
    %ENDFOR reg
   %ENDMACRO _RestoreXmmRegs


;-------------------------------------------------------------------------
; A simple program to test the macros defined above.
       EUROASM CPU=X64,SIMD=AVX, NoWarn=2101
    ;  EUROASM ListRepeat=yes,ListMacro=yes,ListVar=yes ; Only if you want to debug the listing.

Andrey PROGRAM Format=DLL,Width=64
       EXPORT ConvertImgU8ToF32_
ConvertImgU8ToF32_ PROC
        _CreateFrame U2F_,0,160
        _SaveXmmRegs xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15

        NOP ; Here should be inserted instructions from the procedure ConvertImgU8ToF32_
        NOP ; https://github.com/Apress/modern-x86-as ... 07_06_.asm

Done:   _RestoreXmmRegs xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15
        _DeleteFrame
        RET
      ENDP ConvertImgU8ToF32_
      ; %Display UserVariables, Symbols      ; Only if you want to debug the listing.
    ENDPROGRAM

If you want it more elegant, use macros from https://euroassembler.eu/maclib/fastcall.htm
Uses saves and restores the enumerated GPR and XMM registers (unfortunately only the low half of XMM)
However, you can reserve space on stack for save/restore XMMs with LocalVar and you won't need the complex MASM frame machinery. Something like

      EUROASM CPU=X64,SIMD=AVX, NoWarn=2101
    ;  EUROASM ListRepeat=yes,ListMacro=yes,ListVar=yes ; Only if you want to debug the listing.

Elegant PROGRAM Format=DLL,Width=64
         INCLUDE "fastcall.htm"
         EXPORT ConvertImgU8ToF32_

ConvertImgU8ToF32_ Procedure des, src, num_pixels
       Uses RSI,RDI         ; GPR which shouldn't be clobbered in the procedure.
 ; The number of enumerated GPRs should be even to keep 16byte alignment of the following local stack variables.
SavedXMM10 LocalVar Size=16
SavedXMM11 LocalVar Size=16
SavedXMM12 LocalVar Size=16  ; etc.
       VMOVDQA [%SavedXMM10],XMM10  ; Manually store XMMs which should't be clobbered.
       VMOVDQA [%SavedXMM11],XMM11
       VMOVDQA [%SavedXMM12],XMM12  ; etc.

; Make sure num_pixels is valid and pixel buffers are properly aligned
        xor eax,eax                         ;set error return code
        ; Here should be instructions from the original procedure ConvertImgU8ToF32_
        mov eax,1                           ;set success return code
Done:
        VMOVDQA XMM12,[%SavedXMM12] ; Manually restore XMMs which should't be clobbered.
        VMOVDQA XMM11,[%SavedXMM11]
        VMOVDQA XMM10,[%SavedXMM10] ; etc.
       EndProcedure ConvertImgU8ToF32_
      ENDPROGRAM
AndreyDmitriev
Posts: 6
Joined: 01 Jun 2023 09:11

Re: MASM Macros to EuroAssembler

Unread postby AndreyDmitriev » 06 Jun 2023 08:33

Wow, thank you so much, Pavel, it works after some minor changes like
vmovdqa xmm0, xmmword ptr [rdx] > vmovdqa xmm0, [rdx]
and
Uint8ToFloat real4 255.0, 255.0, 255.0, 255.0 > Uint8ToFloat: DD 255.0, 255.0, 255.0, 255.0
(tried Uint8ToFloat: DO..., but euroasm told me that the Oword memory variable cannot be statically initialized.)
Anyway got both ConvertImgU8ToF32 and ConvertImgF32ToU8 running. AVX rocks, they're fast.
Last week I've created simple DLL in MASM, NASM, FASM and YASM, but I like EuroAssembler, really. Now can continue my exercises.
The next step is to call some functions from third-party DLL directly from asm, but I'll get this myself, for sure.
Thanks again for your time and help!
Andrey.
User avatar
vitsoft
Site Admin
Posts: 51
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: MASM Macros to EuroAssembler

Unread postby vitsoft » 06 Jun 2023 09:10

Hi, nice to read this.
AndreyDmitriev wrote: 06 Jun 2023 08:33 Uint8ToFloat real4 255.0, 255.0, 255.0, 255.0 > Uint8ToFloat: DD 255.0, 255.0, 255.0, 255.0
(tried Uint8ToFloat: DO..., but euroasm told me that the Oword memory variable cannot be statically initialized.)
Actually not directly with one value but this can be bypassed with specifying the type of each element. Here is an example of three variants how to define a vector of four real4 numbers (32bit DWORDs) and setting the vector type to OWORD:
|[.data]                   ::::Section changed.
|00000000:00007F4300007F43~|Uint8ToFloat1 DD 255.0, 255.0, 255.0, 255.0
|00000010:00007F4300007F43~|Uint8ToFloat2 DO D 255.0, D 255.0, D 255.0, D 255.0
|00000020:00007F4300007F43~|Uint8ToFloat3 DO 4*DWORD 255.0
|                          |       %Display Symbols=Uint8*
|# D1400 **** %DISPLAY Symbols=Uint8*
|# D1450 Uint8ToFloat1,[.data]:00000000h,type='D',size=16,scope='S',ref='N',fix=Y,src="Andrey.asm"{143}
|# D1450 Uint8ToFloat2,[.data]:00000010h,type='O',size=16,scope='S',ref='N',fix=Y,src="Andrey.asm"{144}
|# D1450 Uint8ToFloat3,[.data]:00000020h,type='O',size=16,scope='S',ref='N',fix=Y,src="Andrey.asm"{145}
|# D1790 **** End of %DISPLAY

Who is online

Users browsing this forum: No registered users and 2 guests