Invoke with SIMD operands

Problems which concern EuroAssembler
User avatar
vitsoft
Site Admin
Posts: 49
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Invoke with SIMD operands

Unread postby vitsoft » 29 Aug 2018 22:45

ar18 wrote: 29 Aug 2018 13:38 Sometimes a bit of pseudocode will help better than any explanation ...
api %MACRO Function, Argument1, Argument2,,,Lib=
____%i %SETA %#
____j %FOR %i..1
________%IF %i=4
____________%IF TYPE# %j = 'real4'
________________movss xmm3,%j
____________%ELSEIF TYPE# %j = 'real8'
________________movsd xmm3,%j
____________%ELSE
________________mov r9,%j
________________%ENDIF
...
Yes I understand your idea. BTW %j is assigned with ordinal integer number, TYPE# %j returns 'N'. You probably meant TYPE# %*{%j}.
Unfortunately, operator TYPE# doesn't distinguish register families, it returns 'R' for GPR, XMM, MMX, SEGREG...
I would have to implement another operator REGTYPE#. What if the operand is provided as an immediate number, e.g. Function 0x8040, how should the poor assembler know whether it is integer number 32832 or real4 number 4.0?
€ASM fastcall implementation expects all operands of Invoke to be qword-pushable, i.e. r64, imm, [mem]. That would require some new mechanism how to tell the Invoke macro, if the operand should be preloaded to GPR or to SIMD register. I'm afraid automatic detection with TYPE# is not capable of this.
And I'm not sure if it's worth the effort - I didn't found any WinAPI function which requires SIMD, and with user-defined functions we are not obeyed with fastcall convention, we may contract arbitrary register calling convention, right?
ar18
Posts: 29
Joined: 27 Aug 2018 13:38

Re: Invoke with SIMD operands

Unread postby ar18 » 30 Aug 2018 00:34

vitsoft wrote: 29 Aug 2018 22:45
ar18 wrote: 29 Aug 2018 13:38 Sometimes a bit of pseudocode will help better than any explanation ...
api %MACRO Function, Argument1, Argument2,,,Lib=
____%i %SETA %#
____j %FOR %i..1
________%IF %i=4
____________%IF TYPE# %j = 'real4'
________________movss xmm3,%j
____________%ELSEIF TYPE# %j = 'real8'
________________movsd xmm3,%j
____________%ELSE
________________mov r9,%j
________________%ENDIF
...
Yes I understand your idea. BTW %j is assigned with ordinal integer number, TYPE# %j returns 'N'. You probably meant TYPE# %*{%j}.
I'm not sure what I meant because I am not familiar with the MACRO system of €ASM yet.
vitsoft wrote: 29 Aug 2018 22:45Unfortunately, operator TYPE# doesn't distinguish register families, it returns 'R' for GPR, XMM, MMX, SEGREG...
I would have to implement another operator REGTYPE#.
You only need to flag xmm registers as different. You don't even need to distinguish between FLOAT and DOUBLE because both will get pushed on the stack (or moved into a register) as a little-endian QWORD anyways.
vitsoft wrote: 29 Aug 2018 22:45What if the operand is provided as an immediate number, e.g. Function 0x8040, how should the poor assembler know whether it is integer number 32832 or real4 number 4.0? €ASM fastcall implementation expects all operands of Invoke to be qword-pushable, i.e. r64, imm, [mem]. That would require some new mechanism how to tell the Invoke macro, if the operand should be preloaded to GPR or to SIMD register. I'm afraid automatic detection with TYPE# is not capable of this.
I worked with the author of GoASM regarding this and his approach was to prefix those particular parameters with a Q or a D to indicate if it was a float or double, e.g. -- invoke fnTest,Q [dblVar], D [fltVar],,,and so on . While GoASM supports immediate floating point using this system (e.g. -- invoke fnTest,Q 1.234,D 1.234,,,and so on), I've never used it because I prefer to just to create a constant and pass the value of that constant instead.
vitsoft wrote: 29 Aug 2018 22:45And I'm not sure if it's worth the effort - I didn't found any WinAPI function which requires SIMD,
You mean like AngleArc(), RectF(), or htonf()? The C-Runtime library has a slew of functions that require it. Any math/graphics intensive programs would also be off-limits with €ASM as a result, even if they don't use the C-Runtime libary. My Paint program uses many of these functions, like floor(), fsin(), sin(), etc., as well as custom calculations (like resizing an image) in separate function calls.

You don't have to support every possible use case like you did with Win32 INVOKE. All you need is minimal support like adding three more TYPES: real4, real8, and the xmm register -- just like I showed in the pseudocode I submitted. That approach works perfectly fine for me in GoASM.

This wouldn't be in the Win64 ABI if it wasn't important, so iIf you decide to not support this, then make it clear in your documentation that €ASM only partially supports the Win64 ABI.
vitsoft wrote: 29 Aug 2018 22:45and with user-defined functions we are not obeyed with fastcall convention, we may contract arbitrary register calling convention, right?
No, not if you are writing a DLL or you are going to EXPORT a function.

PS -- If you decided to support vector calls per the Win64 ABI, that would be an additional two extra data types and a MACRO.
ar18
Posts: 29
Joined: 27 Aug 2018 13:38

Re: Invoke with SIMD operands

Unread postby ar18 » 30 Aug 2018 18:34

vitsoft wrote: 29 Aug 2018 22:45What if the operand is provided as an immediate number, e.g. Function 0x8040, how should the poor assembler know whether it is integer number 32832 or real4 number 4.0?
That is the purpose of having a PROTO in the vast majority of all other assemblers. Personally I don't like protos. They make the language verboose, less readable, and bloat the code.
vitsoft wrote: 29 Aug 2018 22:45€ASM fastcall implementation expects all operands of Invoke to be qword-pushable, i.e. r64, imm, [mem]. That would require some new mechanism how to tell the Invoke macro, if the operand should be preloaded to GPR or to SIMD register. I'm afraid automatic detection with TYPE# is not capable of this.
You only need to check for the xmm register type because that is the only SIMD type the ABI specifies, and even then it is specified as a QWORD value instead of the default 128-bit value of the xmm registers.

For preloading, most assemblers reserve r11 for this purpose, so a simple ...

movq r11,xmm
push r11


... would suffice for pushing any xmm register parameter, whether single- or double-precision.

I would just skip support for imm because it is not an ABI requirement and the Intel processor doesn't support it.
User avatar
vitsoft
Site Admin
Posts: 49
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: Invoke with SIMD operands

Unread postby vitsoft » 30 Aug 2018 21:25

ar18 wrote: 30 Aug 2018 00:34 if you decide to not support this, then make it clear in your documentation that €ASM only partially supports the Win64 ABI.
Actually it's not €ASM's job to support various ABI invokations (Win64, SystemV, Delphi etc), they are implemented as external macros, totally in the hands of €ASM users. So let's make them more compliant.
Current version (20180804) of macros WinAPI and Invoke push all arguments (at least four) on stack, which reserves the shadow space, too, and allows to use scratch registers as macro operands in arbitrary order. Then are RCX,RDX,R8,R9 loaded from the shadow space and function is called. The function now has all its arguments available on stack frame:
%1 is in [RBP+16] and RCX
%2 is in [RBP+24] and RDX
%3 is in [RBP+32] and R8
%4 is in [RBP+40] and R9
%5 is in [RBP+48]
%6 is in [RBP+56]
and so on.

If any of the first four argument is declared as float, the function expects it in the lower half of XMM0,XMM1.XMM2,XMM3 instead of RCX,RDX,R8,R9. Lets load those XMM registers from RCX,RDX,R8,R9 immediately after they have been loaded from the shadow space, regardless if their arguments were declared as float or not. XMM0..XMM5 as well as RCX,RDX,R8..R11 are caller-save, so nobody will miss their original contents.
%1 is in [RBP+16] and RCX and XMM0
%2 is in [RBP+24] and RDX and XMM1
%3 is in [RBP+32] and R8 and XMM2
%4 is in [RBP+40] and R9 and XMM3
%5 is in [RBP+48]
%6 is in [RBP+56]
and so on.
This solution requires four instructions (MOVQ XMM0,RCX etc) which would bloat every Invoke, so they should be emitted on demand only, when the function uses floating-point argument(s). I'm considering boolean keyword operand SIMD=No|Yes added to macros Invoke and WinAPI. This would be backward compatible with their current version, which is already used in sample programs.
ar18 wrote: 30 Aug 2018 18:34 That is the purpose of having a PROTO in the vast majority of all other assemblers. Personally I don't like protos. They make the language verboose, less readable, and bloat the code.

Ditto.
ar18 wrote:
You only need to check for the xmm register type because that is the only SIMD type the ABI specifies, and even then it is specified as a QWORD value instead of the default 128-bit value of the xmm registers.

movq r11,xmm
push r11
Now, when the first four argument values are correctly passed in registers, let's look at the possibility to use XMM as ordinal operands in Invoke and WinAPI.
Presence of XMM register in operands can be checked with

%IF "%1[1..3]" == "XMM"
MOVQ R11,%1
PUSH R11
%ELSE
PUSHQ %1
%ENDIF

but it's not much reliable. User could pass a symbolic value defined as XmmIsGood EQU 1234 and this would throw false positive.
You can enhance macro Invoke if you need this for your Paint functions, but somehow I should solve the asm-time register recognition anyway, which will take some time. Anyway, thank you for testing, Andy.
ar18
Posts: 29
Joined: 27 Aug 2018 13:38

Re: Invoke with SIMD operands

Unread postby ar18 » 31 Aug 2018 16:18

vitsoft wrote: 30 Aug 2018 21:25 Actually it's not €ASM's job to support various ABI invokations (Win64, SystemV, Delphi etc), they are implemented as external macros, totally in the hands of €ASM users. So let's make them more compliant.
Don't call the macro "WinAPI" then for 64-bit code, since that is a misnomer. Call it BasicAPICall.
vitsoft wrote: 30 Aug 2018 21:25 Current version (20180804) of macros WinAPI and Invoke push all arguments (at least four) on stack, which reserves the shadow space, too, and allows to use scratch registers as macro operands in arbitrary order. Then are RCX,RDX,R8,R9 loaded from the shadow space and function is called. The function now has all its arguments available on stack frame:
%1 is in [RBP+16] and RCX
%2 is in [RBP+24] and RDX
%3 is in [RBP+32] and R8
%4 is in [RBP+40] and R9
%5 is in [RBP+48]
%6 is in [RBP+56]
and so on.
That is incorrect code. The registers are never put on the shadow space stack by the caller, but always by the callee. Seems I remember someone telling me to RTFM, in this case it should be the Win64 ABI manual :) . This is one of the problems with the WinAPI macro in 64-bit mode. It is the function that moves the registers to the stack, not the call/invoke code.
vitsoft wrote: 30 Aug 2018 21:25 If any of the first four argument is declared as float, the function expects it in the lower half of XMM0,XMM1.XMM2,XMM3 instead of RCX,RDX,R8,R9.
Actually the function expects it to be in the lower 4 or 8 bytes of the xmm registers. Half an XMM register is 16 DWORDS or 8 QWORDS. That is why all 64-bit programs use movq or movd to set SIMD values for function calls (where q means "8 bytes" and d means "4 bytes). Vector calls do actually use whole entire SIMD registers, but that is another issue for another time.
vitsoft wrote: 30 Aug 2018 21:25 Lets load those XMM registers from RCX,RDX,R8,R9 immediately after they have been loaded from the shadow space, regardless if their arguments were declared as float or not. XMM0..XMM5 as well as RCX,RDX,R8..R11 are caller-save, so nobody will miss their original contents.
%1 is in [RBP+16] and RCX and XMM0
%2 is in [RBP+24] and RDX and XMM1
%3 is in [RBP+32] and R8 and XMM2
%4 is in [RBP+40] and R9 and XMM3
%5 is in [RBP+48]
%6 is in [RBP+56]
and so on.

This solution requires four instructions (MOVQ XMM0,RCX etc) which would bloat every Invoke,
Actually that "bloat" belongs in the function being called, not in the WinAPI. And it isn't referred to as "bloat" if it is a requirement of the operating system or library that conforms to the Win64 ABI.
vitsoft wrote: 30 Aug 2018 21:25 so they should be emitted on demand only, when the function uses floating-point argument(s). I'm considering boolean keyword operand SIMD=No|Yes added to macros Invoke and WinAPI. This would be backward compatible with their current version, which is already used in sample programs.
For the invoke macro, only the first four args identified as being xmm, real4, and real8 need special processing. Everything else just needs a simple mov reg,%var. For args beyond the first four, only args identified as being xmm need special processing.

For the function being called, only the first four parameters identified as being xmm, real4, or real8 need special processing (to move rcx, rdx, r8, and r9 into the shadow space). Everything else within the first four args just needs a simple mov [rsp+nn],%var. For args beyond the first four, that is up to the programmer to determine how to process them.

That is what the Win64 ABI manual tells us to do
vitsoft wrote: 30 Aug 2018 21:25 You only need to check for the xmm register type because that is the only SIMD type the ABI specifies, and even then it is specified as a QWORD value instead of the default 128-bit value of the xmm registers.
My exact point this whole entire time.
vitsoft wrote: 30 Aug 2018 21:25 Now, when the first four argument values are correctly passed in registers, let's look at the possibility to use XMM as ordinal operands in Invoke and WinAPI.
Presence of XMM register in operands can be checked with

%IF "%1[1..3]" == "XMM"
MOVQ R11,%1
PUSH R11
%ELSE
PUSHQ %1
%ENDIF

but it's not much reliable. User could pass a symbolic value defined as XmmIsGood EQU 1234 and this would throw false positive.
Better fix that hole in your application then :D, but I wouldn't worry about it in real life. That wouldn't be a problem of the assembler for a properly constructed Win64 ABI compliant program because...

invoke fnTest,1234

fnTest param1
____movsd xmm1,[dbl_1234]
____mulsd %param1,xmm1
____ret


...is valid code. It might not be what the programmer intended but that would only make it a valid programmer mistake :lol:, not a hole in the assembler that needs to be fixed.
vitsoft wrote: 30 Aug 2018 21:25 You can enhance macro Invoke if you need this for your Paint functions, but somehow I should solve the asm-time register recognition anyway, which will take some time. Anyway, thank you for testing, Andy.
Actually that isn't possible with €ASM without adding at least two new data types: real4 and real8 (or whatever you decide on to call single-precision and double-precision floating-point data types).
User avatar
vitsoft
Site Admin
Posts: 49
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: Invoke with SIMD operands

Unread postby vitsoft » 01 Sep 2018 22:37

ar18 wrote: 31 Aug 2018 16:18 That is incorrect code. The registers are never put on the shadow space stack by the caller, but always by the callee. Seems I remember someone telling me to RTFM, in this case it should be the Win64 ABI manual :) . This is one of the problems with the WinAPI macro in 64-bit mode. It is the function that moves the registers to the stack, not the call/invoke code.
I don't think that current implementation of WinAPI violates MS 64bit ABI specification.
If I'd reserved the shadow space by SUB RSP,32, as you suggest, Microsoft gets undefined garbage in it.
When I use four PUSHQ instead, MS gets shadow space with first 4 argument already preinitialized, but nobody obstructs Microsoft
from populating the shadow space with whatever they want, as soon as their function is called.
Yes, it is slower but I'm getting two advantages: 1.any GRP can be used as WinAPI operand in arbitrary order, including RCX,RDX,R8,R9,
and 2. if I use the same WinAPI convention for invocation of my own private function (not MS API), I'm getting all arguments on stack addresses
[RBP+16], [RSP+24] etc., where they can be processed in a loop consistently, without exceptions concerning the first four arguments.
I don't care bloating of code at this moment. My favourite approach is
  1. make the code robust and working, though slow
  2. use it in some real programs for some time
  3. think about code refactoring and optimization, and whether it's worth at all
  4. use those real programs in the role of canary in a coal mine
ar18 wrote: Actually that isn't possible with €ASM without adding at least two new data types:
real4 and real8 (or whatever you decide on to call single-precision and double-precision floating-point data types).
Actually, those data types are with us all the time.
I would recommend you to clone winabi library with something like copy winabi.htm winabi.ar.htm,
include winabi.ar.htm in your program and try to enhance WinAPI with other possible format of macro arguments.

In order to enable XMM as argument, e.g. WinAPI RectF,XMM1,XMM3,XMM5,XMM7, Lib=D2d1.dll you can use something like
%IF REGTYPE# %1 = 'X' ; If it is XMM register.
MOVD XMM0, %1
%ELSE
MOV RCX, %1
%ENDIF


I didn't manage to add this to September release of winabi library but the attribute REGTYPE# built in €ASM 20180901 is already working.
If you need to tell WinAPI macro about datatypes of some of its arguments, you might add a new keyword, e.g.
DataType1=D or DataType1=Q to signalize that WinAPI should treat argument %1 as real4 or real8,
and test it in your cloned macro with something like
%IF "%DataType1" == "D"
MOVSD XMM0,[=D %1]
%ENDIF
%IF "%DataType1" == "Q"
MOVSQ XMM0,[=Q %1]
%ENDIF
%IF "%DataType1" == ""
MOV RCX,%1
%ENDIF
ar18
Posts: 29
Joined: 27 Aug 2018 13:38

Re: Invoke with SIMD operands

Unread postby ar18 » 02 Sep 2018 03:26

vitsoft wrote: 01 Sep 2018 22:37
ar18 wrote: 31 Aug 2018 16:18 That is incorrect code. The registers are never put on the shadow space stack by the caller, but always by the callee. Seems I remember someone telling me to RTFM, in this case it should be the Win64 ABI manual :) . This is one of the problems with the WinAPI macro in 64-bit mode. It is the function that moves the registers to the stack, not the call/invoke code.
I don't think that current implementation of WinAPI violates MS 64bit ABI specification.
From https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx:

"The callee has the responsibility of dumping the register parameters into their shadow space if needed."

And if you don't believe Microsoft, than how about the creators of GCC? I can show you a screen dump of their source code that shows how they interpret what Microsoft said. How many credible programmers in the world do what you do? I would like to see their source code because all the valid source code I see on the Internet does it differently from you.
vitsoft wrote: 01 Sep 2018 22:37 If I'd reserved the shadow space by SUB RSP,32, as you suggest, Microsoft gets undefined garbage in it ...
What you really need to do right now, is get out your debugger or disassembler, and take a look at a 64-bit C-program and see how they do it. They all do it like Microsoft says to do it and not how you do it. It is a trivial thing to do and it will save 4 bytes/cycles per invoke.
vitsoft wrote: 01 Sep 2018 22:37 I don't care bloating of code at this moment. My favourite approach is
  1. make the code robust and working, though slow
  2. use it in some real programs for some time
  3. think about code refactoring and optimization, and whether it's worth at all
  4. use those real programs in the role of canary in a coal mine
What are the milestones for that? €ASM is certainly past the alpha and beta stage.
vitsoft wrote: 01 Sep 2018 22:37
ar18 wrote: Actually that isn't possible with €ASM without adding at least two new data types:
real4 and real8 (or whatever you decide on to call single-precision and double-precision floating-point data types).
Actually, those data types are with us all the time.
I'm not seeing it. A QWORD is not the same thing as a REAL8 or double-precision float. They are the same size in bytes, but they are not interpreted in the same way or in the way that a Win64 compliant needs it to be interpreted. Most of the functions I encounter have many arguments, and most of those arguments are pointers, which is a QWORD and not a REAL8. They must be treated differently and not the same.
vitsoft wrote: 01 Sep 2018 22:37 I would recommend you to clone winabi library with something like copy winabi.htm winabi.ar.htm,
include winabi.ar.htm in your program and try to enhance WinAPI with other possible format of macro arguments.
I will use a custom file to include in my projects.
vitsoft wrote: 01 Sep 2018 22:37 In order to enable XMM as argument, e.g. WinAPI RectF,XMM1,XMM3,XMM5,XMM7, Lib=D2d1.dll you can use something like
%IF REGTYPE# %1 = 'X' ; If it is XMM register.
MOVD XMM0, %1
%ELSE
MOV RCX, %1
%ENDIF


I didn't manage to add this to September release of winabi library but the attribute REGTYPE# built in €ASM 20180901 is already working.
I already like that just the way it is now.
vitsoft wrote: 01 Sep 2018 22:37 If you need to tell WinAPI macro about datatypes of some of its arguments, you might add a new keyword, e.g.
DataType1=D or DataType1=Q to signalize that WinAPI should treat argument %1 as real4 or real8,
and test it in your cloned macro with something like
%IF "%DataType1" == "D"
MOVSD XMM0,[=D %1]
%ENDIF
%IF "%DataType1" == "Q"
MOVSQ XMM0,[=Q %1]
%ENDIF
%IF "%DataType1" == ""
MOV RCX,%1
%ENDIF
Yeah, I've done that before and it really clutters up the invoke statements. I'll only do that if I have no other choice but I'd much rather see it as a real data type like int (DWORD) or long (QWORD). I think the code to change that sits in the sym.htm file but I still need to familiarize myself with your program first, especially the macro scripting, before doing anything with the code.

Now that I think of it, I might just use the macro you suggested instead. Let me think about it.
User avatar
vitsoft
Site Admin
Posts: 49
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: Invoke with SIMD operands

Unread postby vitsoft » 02 Sep 2018 17:25

ar18 wrote: 02 Sep 2018 03:26 Actually, those data types are with us all the time.
I'm not seeing it. A QWORD is not the same thing as a REAL8 or double-precision float. They are the same size in bytes,
but they are not interpreted in the same way or in the way that a Win64 compliant needs it to be interpreted.
Most of the functions I encounter have many arguments, and most of those arguments are pointers, which is a QWORD and not a REAL8.
They must be treated differently and not the same.
And a DWORD is not the same thing as a single-precision float, as an signed integer, unsigned integer, pointer, pointer to float, pointer to int...
that's certainly true in the world of high-level languages. Runtime multiplication in HLL is prescribed with universal operator *
and the compiler needs to know the datatype of factor to choose relevant instruction.
But in assembly language it is the programmer who decides if the multiplication will be performed by MUL, IMUL, MULSS, MULSD.
It is the selected machine instruction which determines whether the actual multiplied DWORD will be treated as integer or float,
and not any metainformation given to assembler when the DWORD was defined in data section. That's why I do not think that €ASM
should distinguish datatypes in addition to those usual fundamental types.

Of course, when some macroinstruction accepts arguments in either integer or floating format, it is useful to know the type of data automatically,
just to tell the macro whether it should use MUL or MULSD or to tell it whether the argument should be loaded to RCX or to XMM0.
You probably want something like
WinAPI %MACRO Arg1
%IF ISFLOAT# %Arg1
MOVD XMM0, %Arg1
%ELSE
MOV RCX,%Arg1
%ENDIF


This could work if Arg1 were provided as a datasymbol, but what if its someting like [RSI] or [RBP+16]?
You would need some backup method anyway, and I think keyword macro operands are the most appropriate tool.
ar18 wrote: Yeah, I've done that before and it really clutters up the invoke statements.
It's true, unfortunately, all those %IF, %ELSE, %ENDIF, each per line.
But once you've set it to work, you can put the macrolibrary aside and your main program
can invoke 3rd party functions with just one neat statement.
ar18
Posts: 29
Joined: 27 Aug 2018 13:38

Re: Invoke with SIMD operands

Unread postby ar18 » 02 Sep 2018 19:49

vitsoft wrote: 02 Sep 2018 17:25
ar18 wrote: 02 Sep 2018 03:26 Actually, those data types are with us all the time.
I'm not seeing it. A QWORD is not the same thing as a REAL8 or double-precision float. They are the same size in bytes,
but they are not interpreted in the same way or in the way that a Win64 compliant needs it to be interpreted.
Most of the functions I encounter have many arguments, and most of those arguments are pointers, which is a QWORD and not a REAL8. They must be treated differently and not the same.
It is the selected machine instruction which determines whether the actual multiplied DWORD will be treated as integer or float, and not any metainformation given to assembler when the DWORD was defined in data section. That's why I do not think that €ASM should distinguish datatypes in addition to those usual fundamental types. Of course, when some macroinstruction accepts arguments in either integer or floating format, it is useful to know the type of data automatically,
just to tell the macro whether it should use MUL or MULSD or to tell it whether the argument should be loaded to RCX or to XMM0.
The "selected machine instruction" is "push arg". If arg is a DWORD integer, then push it to a GP register. If the arg is a DWORD float, push it to an xmm register. How can a simple, plain "push arg" determine whether to push to a GP register or XMM register? And I only need to worry about this with the first four arguments -- after that I can treat it like I used to with Win32.

ASM is a typed language, just not the same types as the C-language. Until the Win64 ABI, float/double wasn't an ASM data type you had to worry about. But if the Operating System now says that you need to treat float point data type arguments differently from everything else, you had better flag that arg so you can know when to treat it differently from everything else.
vitsoft wrote: 02 Sep 2018 17:25 You probably want something like
WinAPI %MACRO Arg1
%IF ISFLOAT# %Arg1
MOVD XMM0, %Arg1
%ELSE
MOV RCX,%Arg1
%ENDIF


This could work if Arg1 were provided as a datasymbol, but what if its someting like [RSI] or [RBP+16]?
My point exactly, hence the reason for the need to flag an arg within the INVOKE or WinAPI statement as being floating point or not floating point.
vitsoft wrote: 02 Sep 2018 17:25 You would need some backup method anyway, and I think keyword macro operands are the most appropriate tool.
ar18 wrote: Yeah, I've done that before and it really clutters up the invoke statements.
It's true, unfortunately, all those %IF, %ELSE, %ENDIF, each per line.
I wasn't talking about that, I was talking about the INVOKE statement with those extra variables mixed in along with the arguments. MACROS should be transparent to the programmer so it doesn't matter how verboose they can get.
vitsoft wrote: 02 Sep 2018 17:25 But once you've set it to work, you can put the macrolibrary aside and your main program
can invoke 3rd party functions with just one neat statement.
Oh it will work just fine, as evidenced by GoAsm, seeing that is exactly how they did it. I just don't believe that is the most elegant or optimal solution, and it doesn't hurt to ask, does it? What's the worse anyone could say? No?
User avatar
vitsoft
Site Admin
Posts: 49
Joined: 04 Nov 2017 20:08
Location: Vítkov, The Czech Republic
Contact:

Re: Invoke with SIMD operands

Unread postby vitsoft » 02 Sep 2018 20:47

ar18 wrote: 30 Aug 2018 00:34 I worked with the author of GoASM regarding this and his approach was to prefix those particular parameters with a Q or a D to indicate if it was a float or double, e.g. -- invoke fnTest,Q [dblVar], D [fltVar],,,and so on .
If you'll satisfy with something like
invoke fnTest, Q:dblVar, D:fltVar,,,and so on .
you can choose a similar approach and parse the type-prefix in macro body, without even consulting the assembler's author:
invoke %MACRO fnTest, Arg1, Arg2,,,
%IF "%Arg1[1..2]" == "Q:" || "%Arg1[1..2]" == "D:" ; Let float arguments start with typeid and some special character (e.g.colon).
MOVD XMM0,%Arg1[3..] ; Get rid of the first two characters.
%ELSE ; Otherwise it's an ordinary argument - integer, pointer; copy it to GPR as is.
MOV RCX, %Arg1
%ENDIF
%IF "%Arg2[1..2]" == "Q:" || "%Arg2[1..2]" == "D:"
MOVD XMM1,%Arg2[3..]
%ELSE
MOV RDX, %Arg2
%ENDIF
and so on

Who is online

Users browsing this forum: No registered users and 3 guests