Sign in to follow this  
Kwak

inline asm: move signed chars

Recommended Posts

I tried to convert a little function to assembler: I keep having errors
char _fPlaceFallthrough[64];

MoveMessage putPion(char move)
{
    __asm
    {
        xor eax, eax                        //eax = 0
        movs al, move                       //al = move
        movs bl, 4                          //bl=4
        imul bl                             //ax = move*4           // now is   eax = move*4

        add eax, offset _fPlaceFallthrough  //eax = &_fPlaceFallthrough[move*4]
        movs bl,[eax]                       //bl = _fPlaceFallthrough[move*4]
        cmp bl,-3                           //if (getFallthrough(move*4)!=-3)
        jnz validMove                       //      goto validMove
        mov message, INVALID_MOVE
        jmp endAsm

    validMove:  
        dec [eax]                           // _fPlaceFallthrough[move*4]--;
        dec [eax +1]                        // _fPlaceFallthrough[move*4 + 1]--;
        dec [eax +2]                        // _fPlaceFallthrough[move*4 + 2]--;
        dec [eax +3]                        // _fPlaceFallthrough[move*4 + 3]--;
    }
    if (message==INVALID_MOVE)
        return INVALID_MOVE;
    else
        return VALID_MOVE;
}




should be the same as
MoveMessage putPion(char move)
{
    char place = move*4;
    if (getFallthrough(place)==-3)
        return INVALID_MOVE;

    _fPlaceFallthrough[place]--;
    _fPlaceFallthrough[place + 1]--;
    _fPlaceFallthrough[place + 2]--;
    _fPlaceFallthrough[place + 3]--;
        return VALID_MOVE;
}







I know the problem must be something with the sign of a char, but i don't know when a char is interpreted signed or unsigned. I think that after asm line 4 (imul bl //ax=move*4): ax is a signed 2 byte value. I guess i have to make it an unsigned 4 byte value? I've also read that to return a value you can do: asm mov eax, RETURN_VALUE asm ret Because eax is used for returning data. But how is the difference made between a pointer and a value? if a function gets a value, it must know what type it is. and I guess asm xor eax, eax asm movs al, INVALID_MOVE asm ret is wrong again (trying to load signed byte into unsigned 4-byte var [Edited by - Kwak on August 17, 2006 7:11:54 AM]

Share this post


Link to post
Share on other sites
honestly, the function is so simple, unless you wanted to try to convert the last 4 lines to an sse instruction,
I doubt that your code is any faster than what the compiler generates. You should look at the output of the
compiler, and profile the code to be sure this is your bottleneck.

Share this post


Link to post
Share on other sites
This is actually only a part of the function. I only posted this because i know there is going something wrong in that piece of code, and I don't want to dump all the code. (function is about 50 lines of code in c++)

And i know speed optimization must be done here. This function is called over a million times each time i decide where to put my pion.
I have a recursive function that keeps calling this code. Besides calling putPion() and comparing the returned value (INVALID_MOVE/WIN/LOSE/FORCE/DOUBLE_FORCE) it does nothing.

I have an idea how i could guess when it is not necessary to check that much possibilities, but i would probably be wrong 1% of the time. I want to keep this AI routine correct.

I made this code already 3! times faster by changing value getValue() functions into #define getValue() (value)

If the asm would make it another 5 times faster i would be happy :)
and after all its only 2 functions that must be converted (putPion() and undoPutPion() for a total of 60 lines

[Edited by - Kwak on August 16, 2006 5:44:20 PM]

Share this post


Link to post
Share on other sites
MOVS: Move with Sign Extension; Intel 80x86; moves data from a register or memory to a register, with a sign extension (conversion to larger binary integer: byte to word, byte to doubleword, or word to doubleword); does not affect flags

Share this post


Link to post
Share on other sites
I've checked my code. I've used mov instead of moves. moves generates an error: invalid combination of opcode and operands. I thougt i could use it to convert signed 1 byte integers (chars) to two byte integers (shorts)

Share this post


Link to post
Share on other sites
Well written C(++) is worth more than any lame attempt at assembly that you can make. For example:
Quote:
I made this code already 3! times faster by changing value getValue() functions into #define getValue() (value)
You could've gotten the same result by marking the method inline, or just asking the compiler to consider all functions for inlining.

In any case, making your crude assembly work won't make it any faster. It might even make it slower. Try to make algorithmic improvements, code level improvements, and compile setting tweaks.


In unrelated news, don't prefix your variable names with an underscore. Really bad idea. (Technically your identifiers are legal, as only __identifer and _Identifier are reserved, not _identifier, but it's still a bad idea. Use m_ or something instead.)

Share this post


Link to post
Share on other sites
Although the argument to the function is a char, it gets pushed as a dword in order to maintain stack alignment. Also note that on 32 bit systems, 32 bit registers are faster. So, you'll be better off using them rather than just the low byte parts of them.

xor eax, eax //eax = 0
mov eax, move //al = move
mov ebx, 4 //bl=4
imul ebx

There is likely an addressing mode that would simplify decrementing those array values, but I'd have to dig out my notes and think about it a bit to comment.

Share this post


Link to post
Share on other sites
Quote:
Original post by NisseBosseLasse
When I look in my big-ol'-book-of-asm, I read out this:

*** Source Snippet Removed ***

Isn't movs a string function (like "rep movs")?


Yes, if I recall correctly, MOVS moves DS:SI to ES:DI. It shouldn't take an operand, and uses the direction flag, and CX stores the length of the memory to copy. He's trying to move an immediate into a register, which is what MOV is for, not MOVS. (Unless for some reason he's not using the X86 instruction set, but that's what it appears to be).

*Edit*

As for the sign extention, mov doesn't care. That's what the Sign Flag is for, and you're not going be manipulating that.

Take the following binary

10101011

What does this equal should you put it in an unsigned char vs a char? And if you MOV that value to a register, you're not going to chop off the significant bit.

Even more edit:

Alright, I dug out my ASM books. IBM PC Assembly Language and Programming by Peter Abel

MOVSX: Move with Sign Extend (80386+)
Copies an 8 or 16 bit source operand into a larger 16 or 32 bit destination operand. MOVSX fills the sign bit into the leftmost bits.

Share this post


Link to post
Share on other sites
give this a shot:



movzx eax, BYTE PTR [move] //Do you want char as unsigned? Use 'movsx' otherwise
mov ebx,offset _fPlaceFallthrough //eax = _fPlaceFallthrough
cmp DWORD PTR [ebx+eax*4],3 //if _fPlaceFallthrough[move*4]!= 3)
...
...
...


Share this post


Link to post
Share on other sites
thx tachikoma
I tried this:

__asm
{
movzx eax, BYTE PTR [move] // eax = content of move
mov ebx, offset _fPlaceFallthrough //eax = _fPlaceFallthrough
cmp BYTE PTR [ebx+eax*4],-3 //if _fPlaceFallthrough[move*4]!= -3)

jnz validMove // goto validMove
mov message, INVALID_MOVE
jmp endAsm

validMove:
dec BYTE PTR [ebx+eax*4] // decFallthrough(move*4);
dec BYTE PTR [ebx+eax*4 +1] // decFallthrough(move*4 + 1);
dec BYTE PTR [ebx+eax*4 +2] // decFallthrough(move*4 + 2);
dec BYTE PTR [ebx+eax*4 +3] // decFallthrough(move*4 + 3);
endAsm:
}



but as soon as the program starts, i get a stack overflow error.

Quote:
by Lessbread
Although the argument to the function is a char, it gets pushed as a dword in order to maintain stack alignment. Also note that on 32 bit systems, 32 bit registers are faster.

should i do pop eax first?
pop move from the stack

movzx eax, BYTE PTR [move]
[] means get the value at address... so shouldn't it be
movzx eax, BYTE PTR [&move]

cmp BYTE PTR [ebx+eax*4],-3
I'm stunned this is possible. I thought ebx+eax*4 should be calculated with add and mult commands first.

to promit: never thought of inline (never used it too), I'll certainly get rid of those defines. Like you say, i'd better not mess around with assembler in my code, but i'd like to test the inline asm commands.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this