Search code examples
compilationlanguage-agnostic

Will compiler optimize away called-once functions


I've been reading "Clean Code" by Robert C Martin, and one of the pieces of advice is to use more but smaller functions; i.e. instead of

int main(){

    // do one thing
    // ... 10 lines of code

    // do another thing
    // ... another 10 lines of code

    // one last thing
    // ... another 10 lines

    return 0;
}

you ought to

int main(){
    doOneThing();
    doAnotherThing();
    oneLastThing();
}

void doOneThing(){
    ... 10 lines of code
}

// ... you get the idea

However, from my understanding of low level langauges, I know that when a function is called, variables are pushed onto the stack and the stack pointer is incremented, etc, whereas for the continuous code, there is no need to do this.

On the other hand, compiler optimisations can do cool things like inline class methods. Assuming doOneThing is called exactly once, could a compiler this code, deduce that the code can be unrolled into main(), and elimiate the function call and associated runtime overhead altogether?


Solution

  • A previous version of the question was about C++ or C. I am convinced that it needs the context of a language to discuss this topic in a meaningful way, so I chose to stay with C++.

    C++ is not really "low level". Code you write is not instructions for your CPU. Between your code and what actually happens during runtime there is one of the most sophisticated pieces of software: Your compiler. When you turn on optimizations then your compiler will analyze your code and try to produce the most efficient executable that behaves at runtime as your code would if it was taken literally (i.e. no optimizations).

    This is governed by the so-called as-if rule. Calling a function is not observable behavior. If the function is small, the compiler will inline the call to the function.

    On the other hand, of course calling a function has a cost, but that cost is comparatively small. You need to start worry about this overhead, when the function is very small, like only 1 or 2 lines, and (and this is important!) for some reason the compiler cannot inline the call. This can be due the function being virtual for example.

    You are asking if a compiler can optimize it, so I pick just one example. Gcc with -O3 will produce following output for following code:

    int foo() { return 42;}
    int bar() { return 0;}
    int moo() { return 1;}
    
    
    int main() {
        return foo() + bar() + moo();
    }
    

    output:

    foo():
            mov     eax, 42
            ret
    bar():
            xor     eax, eax
            ret
    moo():
            mov     eax, 1
            ret
    main:
            mov     eax, 43
            ret
    

    You can see hat in main no function is called. THe compiler examind the expression foo() + bar() + moo() and realized it always equals 43. No function has to be called to return 43.

    This is a silly example, though for the general case, if you do want to see what the compiler did you need to do the same: look at the compilers output.

    And to do that you need to write the code first. It is of no use to first speculate which code would be more efficient or less efficient. You first need to write the code. And because you need to do that anyhow, you can write clean simple human comprehensible code. That's the code your compiler understands best and knows how to optimize, because thats also what other programmers write.