Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Bitscan

Author: Dann Corbit

Date: 14:26:38 02/12/03

Go up one level in this thread


On February 12, 2003 at 17:08:34, Matt Taylor wrote:
>On February 12, 2003 at 14:14:58, Gerd Isenberg wrote:
[snip]
>>You have some explicite loads and stores:
>>Why not leaving the return value directly in eax?
>>
>>Cheers,
>>Gerd
>
>I do, but I was assuming that leaving it in eax is not technically legal for VC.
>The VC docs on inline assembly are extremely vague about everything besides
>syntax. Alternatively one can use __declspec(naked), but then inlining is
>problematic.
>
>I can try this...I am hesitant, though it's probably true that it will always
>work.

From the VC++ help files:

 C++ Language Reference

Writing Functions with Inline AssemblySee Also
Using C or C++ in __asm Blocks
Microsoft Specific

If you write a function with inline assembly code, it's easy to pass arguments
to the function and return a value from it. The following examples compare a
function first written for a separate assembler and then rewritten for the
inline assembler. The function, called power2, receives two parameters,
multiplying the first parameter by 2 to the power of the second parameter.
Written for a separate assembler, the function might look like this:

; POWER.ASM
; Compute the power of an integer
;
       PUBLIC _power2
_TEXT SEGMENT WORD PUBLIC 'CODE'
_power2 PROC

        push ebp        ; Save EBP
        mov ebp, esp    ; Move ESP into EBP so we can refer
                        ;   to arguments on the stack
        mov eax, [ebp+4] ; Get first argument
        mov ecx, [ebp+6] ; Get second argument
        shl eax, cl     ; EAX = EAX * ( 2 ^ CL )
        pop ebp         ; Restore EBP
        ret             ; Return with sum in EAX

_power2 ENDP
_TEXT   ENDS
        END
Since it's written for a separate assembler, the function requires a separate
source file and assembly and link steps. C and C++ function arguments are
usually passed on the stack, so this version of the power2 function accesses its
arguments by their positions on the stack. (Note that the MODEL directive,
available in MASM and some other assemblers, also allows you to access stack
arguments and local stack variables by name.)

The POWER2.C program writes the power2 function with inline assembly code:

/* POWER2.C */
// Power2.c
// compile with: /EHsc
#include <stdio.h>

int power2( int num, int power );

void main( void )
{
   printf( "3 times 2 to the power of 5 is %d\n", \
           power2( 3, 5) );
}
int power2( int num, int power )
{
   __asm
   {
      mov eax, num    ; Get first argument
      mov ecx, power  ; Get second argument
      shl eax, cl     ; EAX = EAX * ( 2 to the power of CL )
   }
   /* Return with result in EAX */
}
The inline version of the power2 function refers to its arguments by name and
appears in the same source file as the rest of the program. This version also
requires fewer assembly instructions.

Because the inline version of power2 doesn't execute a C return statement, it
causes a harmless warning if you compile at warning level 2 or higher. The
function does return a value, but the compiler cannot tell that in the absence
of a return statement. You can use #pragma warning to disable the generation of
this warning.

END Microsoft Specific

See Also
Using C or C++ in __asm Blocks

Using and Preserving Registers in Inline Assembly
Home |  Overview |  How Do I

In general, you should not assume that a register will have a given value when
an __asm block begins. Register values are not guaranteed to be preserved across
separate __asm blocks. If you end a block of inline code and begin another, you
cannot rely on the registers in the second block to retain their values from the
first block. An __asm block inherits whatever register values result from the
normal flow of control.

If you use the __fastcall calling convention, the compiler passes function
arguments in registers instead of on the stack. This can create problems in
functions with __asm blocks because a function has no way to tell which
parameter is in which register. If the function happens to receive a parameter
in EAX and immediately stores something else in EAX, the original parameter is
lost. In addition, you must preserve the ECX register in any function declared
with __fastcall.

To avoid such register conflicts, don’t use the __fastcall convention for
functions that contain an __asm block. If you specify the __fastcall convention
globally with the /Gr compiler option, declare every function containing an
__asm block with __cdecl or __stdcall. (The __cdecl attribute tells the compiler
to use the C calling convention for that function.) If you are not compiling
with /Gr, avoid declaring the function with the __fastcall attribute.

When using __asm to write assembly language in C/C++ functions, you don't need
to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers. For example, in the
POWER2.C example in Writing Functions with Inline Assembly, the power2 function
doesn't preserve the value in the EAX register. However, using these registers
will affect code quality because the register allocator cannot use them to store
values across __asm blocks. In addition, by using EBX, ESI or EDI in inline
assembly code, you force the compiler to save and restore those registers in the
function prologue and epilogue.

You should preserve other registers you use (such as DS, SS, SP, BP, and flags
registers) for the scope of the __asm block. You should preserve the ESP and EBP
registers unless you have some reason to change them (to switch stacks, for
example). Also see Optimizing Inline Assembly.

Note   If your inline assembly code changes the direction flag using the STD or
CLD instructions, you must restore the flag to its original value.




This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.