Log in

View Full Version : How do I move inline assembly to external file?


bassquake
6th November 2019, 11:43
I'm currently recompiling virtualdub plugins and need to move the inline assembly code to an external asm file but I dont know how to call it in the cpp.

As an example, here's a very simple bit of inline code:

void LUT_iSSE (Pixel32 *dst,int *LUT,int psize)
{
__asm {
mov edi, [dst]
mov esi, [LUT]
mov ecx, [psize]

align 16
GLoop: mov eax, [edi]
xor ebx, ebx
mov edx, eax
mov bl, ah
and edx, 0xff0000
and eax, 0xff
shr edx, 16
movd mm0, [esi + eax * 4 + (512 * 4)]
prefetchnta[edi + 512]
por mm0, [esi + ebx * 4 + (256 * 4)]
por mm0, [esi + edx * 4]
movd[edi], mm0
add edi, 4
dec ecx
jnz GLoop
emms
}
}

Can someone post what I would put there instead and what the asm file should have in it or point me in the right direction online? I'm guessing Extern "C" is involved somewhere!

Greatly appreciated!

StainlessS
6th November 2019, 13:37
I am very rusty on this stuff and not an intel assmebler guy, but maybe something like this

myheader.h

#ifndef __MYHEADER_H__ // Avoid multiple inclusions
#define __MYHEADER_H__

#include <windows.h> // and whatever else
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h> // etc

// Other stuff ...

extern "C" {
void __stdcall LUT_iSSE (Pixel32 *dst,int *LUT,int psize);
}

#endif // __MYHEADER_H__


asm.c

#include myHeader.h

void __stdcall LUT_iSSE (Pixel32 *dst,int *LUT,int psize)
{
__asm {
mov edi, [dst]
mov esi, [LUT]
mov ecx, [psize]

align 16
GLoop: mov eax, [edi]
xor ebx, ebx
mov edx, eax
mov bl, ah
and edx, 0xff0000
and eax, 0xff
shr edx, 16
movd mm0, [esi + eax * 4 + (512 * 4)]
prefetchnta[edi + 512]
por mm0, [esi + ebx * 4 + (256 * 4)]
por mm0, [esi + edx * 4]
movd[edi], mm0
add edi, 4
dec ecx
jnz GLoop
emms
}
}


I think that the asm file should b using __stdcall, but not sure.
Perhaps others will give better advice.

EDIT: One of the headers should define what Pixel32 is.

Groucho2004
6th November 2019, 13:45
He wants to move it to a asm file. There is no inline in asm files. I recommend googling, there's tons of info on the subject. I think there's even a section on avisynth.nl.

Edit1: Here (http://avisynth.nl/index.php/Filter_SDK/Assembler_optimizing) is the page on the wiki.
Edit2: Also, look at the code of plugins with external ASM modules.

Groucho2004
6th November 2019, 13:51
I am very rusty on this stuffIn my case, MASM 5.1 was the last Assembler I worked with, very early 90's. :)

StainlessS
6th November 2019, 13:51
Thanks G2K4, here on Wiki, Separate assembly modules :- http://avisynth.nl/index.php/Filter_SDK/Assembler_optimizing

EDIT:
In my case, MASM 5.1 was the last Assembler I worked with, very early 90's. :)

well I have not done any intel at all, I am aware that there are different calling conventions (I think Pascal is one of them apart from __stdcall),
but have little knowledge other than that.

Perhaps I might one day get into the intrinsics thing, but am put off by the whole menagerie of different CPU instruction requirements.

EDIT: Well, I did do a teensy-weensy bit of 8080 back in 1981 [Zlilog Z80A was better].

StainlessS
6th November 2019, 14:02
G2K4, is the posted header part of use as is, though ?
[of interest to both me and the bassquake]

EDIT: I've never had to use extern "C", being only a C programmer, I think that its a CPP thing.

Also, look at the code of plugins with external ASM modules.
I nearly suggested same, code of VirtualDub plugins with external ASM modules, there is bound to be quite a few.

Groucho2004
6th November 2019, 14:06
Perhaps I might one day get into the intrinsics thing, but am put off by the whole menagerie of different CPU instruction requirements.Intrinsics seem to be the way to go for time critical applications but for what I'm writing nowadays, plain C/C++ is sufficient.

Groucho2004
6th November 2019, 14:10
G2K4, is the posted header part of use as is, though ?
[of interest to both me and the bassquake]
Dunno.

StainlessS
6th November 2019, 14:14
Good, we can Dunno together then :)

Bassquake, post how you get on please.

Groucho2004
6th November 2019, 14:15
Good, we can Dunno together then :)Yep, as usual.

StainlessS
6th November 2019, 16:01
VirtualDub2 on sourceforge, hqdn3d, has asm, no idea if of use:- https://sourceforge.net/projects/vdfiltermod/files/plugins/

EDIT: It uses YASM assembler (which I think most/all VD stuff uses).

jpsdr
6th November 2019, 17:40
My plugins use external asm, and the asm provided with Visual Studio, no need to install any another stuff, just VS is enough.
You can check in my github to see exemples of code, for both x86 and x64 versions.

bassquake
7th November 2019, 11:52
My plugins use external asm, and the asm provided with Visual Studio, no need to install any another stuff, just VS is enough.
You can check in my github to see exemples of code, for both x86 and x64 versions.

Thanks for the pointer. I tried using your code to work off. I think I'm close but I get these 4 errors in the asm.

The code in the cpp is:

extern "C" void lut_isse(Pixel32 *dst,int *LUT,int psize);

and the asm file is:

.586
.mmx
.xmm
.model flat, c
.code

lut_isse proc dst:dword,LUT:dword,psize:dword

public lut_isse

mov edi,[dst]
mov esi,[LUT]
mov ecx,[psize]

align 16
GLoop: mov eax,[edi]
xor ebx,ebx
mov edx,eax
mov bl,ah
and edx,0xff0000 ;A2206 missing operator in expression
and eax,0xff ;A2206 missing operator in expression
shr edx,16
movd mm0,[esi+eax*4+(512*4)] ;A2070 invalid instruction operands
prefetchnta [edi+512]
por mm0,[esi+ebx*4+(256*4)]
por mm0,[esi+edx*4 ]
movd [edi],mm0 ;A2070 invalid instruction operands
add edi,4
dec ecx
jnz GLoop
emms

ret
lut_isse endp

END

I've marked where and what the 4 errors are.

I don't know assembly and was hoping wouldn't have to rewrite any of it.

jpsdr
7th November 2019, 14:54
You're not in C... ;)

and edx,0ff0000h
and eax,0ffh

Also, i think it always needs to begin with a number. If i remember properly, this doesn't work :

and eax,ffh

but this will :

and eax,0ffh



Try this :

movd mm0,dword ptr[esi+eax*4+(512*4)]
....
movd dword ptr[edi],mm0

I think transfert default size is the operand, so, not specifying ptr size may probably result as if you've written this :

movd qword ptr[edi],mm0

Which is inconsistant of course, movd with qword...

Also, i would write the begining like this (but maybe it will produce the same result).

mov edi,dst
mov esi,LUT
mov ecx,psize


Your code is 32 bit only, so i will just state the 32 bits rules.

The only registers you can alter without saving them are : eax, ecx, edx and all the mm* and xmm* registers.
If you change esi, edi, ebx, ebp or esp, you'll need to backup and restore them.

Note that if you change ebp, after you'll not be able anymore to do things like this :

mov edi,dst

I think the compiler add implicit save/restore code of ebp at the begining and end of function, and use it afterward when you acces to the stack parameters.
This is what all the .model flat, c and lut_isse proc ... are for.

So, the start of your function should be :

public lut_isse

push esi
push edi
push ebx

mov edi,dst
...

and the end :

....
emms

pop ebx
pop edi
pop esi

ret


Also :

dec ecx
jnz GLoop

can be shorten to :

loop GLoop


I personnaly avoid the use of "int", as it's something with to much variation size possibility and no real "spec".
I always use data i'm sure of the size, like uint32_t for fixed size in both 32/64 bits, or size_t for 32 bits in 32 bits, 64 bits in 64 bits (unsigned), and ptrdiff_t for pointer offset, as it also adapt the size for 32/64 bits, but it's signed.

bassquake
7th November 2019, 17:29
Cool thanks. I got it working with the following:

.586
.mmx
.xmm
.model flat, c
.code

lut_isse proc dst:dword,LUT:dword,psize:dword

public lut_isse

push esi
push edi
push ebx

mov edi,dst
mov esi,LUT
mov ecx,psize

align 16
GLoop: mov eax,[edi]
xor ebx,ebx
mov edx,eax
mov bl,ah
and edx,0ff0000h ;A2206 missing operator in expression
and eax,0ffh ;A2206 missing operator in expression
shr edx,16
movd mm0,dword ptr[esi+eax*4+(512*4)] ;A2070 invalid instruction operands
prefetchnta [edi+512]
por mm0,[esi+ebx*4+(256*4)]
por mm0,[esi+edx*4 ]
movd dword ptr[edi],mm0 ;A2070 invalid instruction operands
add edi,4
loop GLoop
emms

pop ebx
pop edi
pop esi

ret
lut_isse endp

END

Now need to see if can convert to 64 bit! A project for another time.

shekh
7th November 2019, 19:17
Probably better to convert this to plain c++ (btw maybe you already have it), this asm is not doing anything special.
What is the plugin?

bassquake
8th November 2019, 10:10
Its the Color Balance 1.1 plugin from here:

https://emiliano.deepabyss.org/

shekh
8th November 2019, 13:23
You can get rid of asm by removing the lines

if ((CPUF_SUPPORTS_INTEGER_SSE & ff->getCPUFlags()))
LUT_iSSE (dst,mfd->Lut,psize);
else

Wondering if there is performance difference.
Notes for x64:
SetWindowLong -> SetWindowLongPtr
GetWindowLong -> GetWindowLongPtr