CS253: Software Development with C++

Fall 2022

Inlining

Show Lecture.Inlining as a slide show.

CS253 Inlining

Split Interface and Implementation

The Problem

Simple Class

main.cc:

#include "Numbers.h"
int main() {
    return Numbers::two() + Numbers::three();
}

Numbers.h:

class Numbers {
  public:
    static int two(), three();
};

Numbers.cc:

#include "Numbers.h"
int Numbers::two() {
    return 2;
}
int Numbers::three() {
    return 3;
}

Compile with no optimization

% cp ~cs253/Example/Inline/* .
% g++ -Wall -c main.cc
% g++ -Wall -c Numbers.cc
% g++ -Wall main.o Numbers.o
% objdump --no-show-raw-insn --demangle --disassemble | sed '/<main>/,/^$/!d'
0000000000400556 <main>:
  400556:	push   %rbp
  400557:	mov    %rsp,%rbp
  40055a:	push   %rbx
  40055b:	sub    $0x8,%rsp
  40055f:	callq  400574 <Numbers::two()>
  400564:	mov    %eax,%ebx
  400566:	callq  400580 <Numbers::three()>
  40056b:	add    %ebx,%eax
  40056d:	add    $0x8,%rsp
  400571:	pop    %rbx
  400572:	pop    %rbp
  400573:	retq   

main() called Numbers::two() & Numbers::two(), and added the results. Sure.

Optimization

There are several optimization arguments to g++:

Compile with -O3 optimization

% cp ~cs253/Example/Inline/* .
% g++ -Wall -O3 -c main.cc
% g++ -Wall -O3 -c Numbers.cc
% g++ -Wall -O3 main.o Numbers.o
% objdump --no-show-raw-insn --demangle --disassemble | sed '/<main>/,/^$/!d'
0000000000400470 <main>:
  400470:	push   %rbx
  400471:	callq  400580 <Numbers::two()>
  400476:	mov    %eax,%ebx
  400478:	callq  400590 <Numbers::three()>
  40047d:	add    %ebx,%eax
  40047f:	pop    %rbx
  400480:	retq   

A bit better, but not much. Really, we can’t expect more. How is it supposed to know, when compiling main.cc, what the functions two() and three() do?

Link-Time Optimization

This tells the linker to perform optimization between the individual *.o object files.

Link-time optimization

% cp ~cs253/Example/Inline/* .
% g++ -Wall -O3 -flto -c main.cc
% g++ -Wall -O3 -flto -c Numbers.cc
% g++ -Wall -O3 -flto main.o Numbers.o
% objdump --no-show-raw-insn --demangle --disassemble | sed '/<main>/,/^$/!d'
0000000000400470 <main>:
  400470:	mov    $0x5,%eax
  400475:	retq   

Holy smokes! 😲 The code from Numbers.cc, which was in a completely separate file, got integrated into main(), and the addition got done at compile time! You could not produce smaller or faster code if you wrote the assembly language yourself! Nice work, compiler!

Conclusion