views:

253

answers:

7

Not that I'm in that situation currently, but I'm just interested in the answer...

Assuming you have some code written in C/C++ and you want to manually optimize it by modifying it in ASM.

What happens if you alter the code in C/C++ and recompile from source. Sure, the optimization on the just compiled file is lost. How do you avoid that these optimizations need to be redone each time the project is compiled? Do you create separate source files for the parts that need to be optimized to make it less complex? Or is there some kind of automatic tool to do this...? Guess you cannot use diff/patch for this...

Please share your experiences, thanks

+7  A: 

You write some functions in a separate ASM file and call those functions from your C/C++ code. Or you write inline assembly directly in your C/C++ code.

In other words, you could start with some C/C++ code to get some basic ASM code, but after you start tweaking it, you delete the original C/C++ code and replace it with your ASM code, using one of these 2 methods.

Tarydon
well, euh, you put them under ifdef to be used for validating if issues arrive, or suddenly have to port to a different arch
Marco van de Voort
+6  A: 

Instead of modifying the output, why don't you rewrite the critical sections of code in inlined assembler? The method how to do that varies between compilers -- check your compilers documentation.

In MSVC:

// asm_overview.cpp
// processor: x86
void __declspec(naked) main()
{
    // Naked functions must provide their own prolog...
    __asm {
        push ebp
        mov ebp, esp
        sub esp, __LOCAL_SIZE
    }

    // ... and epilog
    __asm {
        pop ebp
        ret
    }
}

In GCC:

 __asm__ ("movl %eax, %ebx\n\t"
          "movl $56, %esi\n\t"
          "movl %ecx, $label(%edx,%ebx,$4)\n\t"
          "movb %ah, (%ebx)");

Note also, that doing ASM changes AFTER compilation and optimization is something only for those that know EXACTLY what they are doing. Not only does the compiler optimize the structure in a way a human couldn't (at least not one without lighting calculator abilities), it also performs a much more complex analisys of the code that we could ever do.

Trust in your compiler. It's the greatest tool you'll ever work with ;).

Kornel Kisielewicz
And for MSVC, does that code compile in 64-bit mode? :)
Dmitry
That's a copy paste from MSDN -- only to provide an overview of the embedding syntax, personally I used asm only in GCC ;>
Kornel Kisielewicz
Do you really have to do that hideous string wrapping in GCC?!
BlueRaja - Danny Pflughoeft
@Dmitry - no, as far as I know, MSVC only allows inline assembly in 32-bit code. For 64-bit code, you can still use ML64.
PhiS
+1  A: 

You either link with modules explicitly written in assembler, or use inline asm.

Nikolai N Fetissov
+3  A: 

If your compiler supports it, perhaps you are looking for something like inline assembly?

Nick Meyer
+2  A: 

Sorry, not strictly an answer to your question, but I believe that people making compiler are a lot better in asm, than most of us. Thus I'd more rely on compiler doing "the right thing", rather than writing some asm code in the midst of c++ source.

Another argument for me for not using at least inline asm (yet sometimes I like to put an __asm int 3; in code) is that MS Visual Studio compiler doesn't support inline asm for 64 bit builds.

And one last thing, have you tried using a different algorithm for optimization, rather than assuming that say gcc (that can use SSE_whatever_is_the_current_version optimizations) produces asm code worse than you can write.

Dmitry
Dmitry has a point. Modern processors are very difficult to write optimized assembly code for, what with all the pipelining, register re-assignments, preventing stalls, keeping code caches filled etc. Compiler generated code sometimes *looks* inefficient, but do some benchmarking before you assume your handwritten code will perform better. You may be surprised how difficult it is to beat a good compiler with all optimizations turned on.
Tarydon
@Tarydon: this leads me to another question: Does compiling with all optimizations turned on (assuming GCC) *always* produce a "working" result? Or are there options to take a very careful look at before turning them on? regards
Atmocreations
@Atmocreations: Some optimizations like rearranging instructions to account for latency should always be safe (unless of course there's a bug in the compiler). Sometimes rearranging floating point operations can change the output of the resulting code because of finite-precision arithmetic. In GCC, you can turn on some of these unsafe math optimizations with -ffast-math. The most "dangerous" one that I know of is turning on strict aliasing (-fstrict-aliasing), which can break code that e.g. tries to access the bits of a float by casting it's address to an int*.
celion
++ It's funny how much attention micro-optimization gets, when macro-optimization is so easy (http://stackoverflow.com/questions/406760/whats-your-most-controversial-programming-opinion/1562802#1562802). I think optimizing code is like building a race car starting from a normal car. First you have to get rid of the *big* stuff before you start shaving parts to save a few ounces, but we programmers act as if there is no big stuff, and we start in with the shaving.
Mike Dunlavey
+4  A: 

Do not modify the assembly code generated by your compiler. Modifying it, like modifying any auto-generated code is a very bad idea precisely for the reason you've discovered yourself.

If there is a particular portion of code you'd like to manually optimize by implementing it in ASM, you have two options:

  1. Write the code as ASM code in the first place, and link an assembled ASM file into your executable. You can first let the compiler generate assembly from C/C++ and then modify it, if this saves you time. But from this moment on manage this code at the ASM level.
  2. Use inline assembly in your C/C++ code. Since hand-optimized ASM portions of code are usually small, this is often the best idea. Using inline ASM is very simple in most compilers. Below is a simple snippet for GCC:

int main(void)
{
        int foo = 10, bar = 15;
        __asm__ __volatile__("addl  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo+bar=%d\n", foo);
        return 0;
}

It demonstrates nicely how to combine C code with ASM, sharing variables.

Eli Bendersky
+2  A: 

Another good reason for using inline assembly: gcc style inline assembly gives the code generator a bunch of information (clobbers, volatile, etc.) that the code generator can use to make your assembly fit nicely (and inline!) into your C/C++ code without losing opportunities for optimization.


Edit:

For example, the C code from another answer:

int main(void)
{
    int foo = 10, bar = 15;
    __asm__ __volatile__("addl  %%ebx,%%eax"
                         :"=a"(foo)
                         :"a"(foo), "b"(bar)
                         );
    printf("foo+bar=%d\n", foo);
    return 0;
}

produces:

....
movl    $15, %ebx
movl    $10, %eax
#APP
addl  %ebx,%eax
#NO_APP
movl    %eax, 8(%esp)
movl    $.str, (%esp)
movl    %eax, 4(%esp)
call    printf
....

The variables foo and bar are kept in registers and never even stored on the stack.

Richard Pennington