ファイルfile1.c
には、ファイルfile2.c
に実装されている関数の呼び出しがあります。 file1.o
とfile2.o
を実行可能ファイルにリンクするとき、file2
の関数が非常に小さい場合、リンカーは関数が小さいことを自動的に検出し、その呼び出しをインライン化しますか?
Jame McNellisが言及したリンクタイムコード生成(LTCG)のサポートに加えて、GCCツールチェーンはリンクタイムの最適化もサポートします。バージョン4.5以降、GCCは-flto
スイッチをサポートします。これにより、リンク時間最適化(LTO)が有効になります。これは、プログラム全体の最適化の形式であり、個別のオブジェクトファイルから関数をインライン化できます(コンパイラがコンパイル中に実行できるその他の最適化)。すべてのオブジェクトファイルは、単一のCソースファイルからのものであるかのように)。
簡単な例を次に示します。
test.c:
void print_int(int x);
int main(){
print_int(1);
print_int(42);
print_int(-1);
return 0;
}
print_int.c:
#include <stdio.h>
void print_int( int x)
{
printf( "the int is %d\n", x);
}
最初にGCC4.5.xを使用してコンパイルします-GCCドキュメントの例では-O2
を使用していますが、簡単なテストで目に見える結果を得るには、-O3
を使用する必要がありました。
C:\temp>gcc --version
gcc (GCC) 4.5.2
# compile with preparation for LTO
C:\temp>gcc -c -O3 -flto test.c
C:\temp>gcc -c -O3 -flto print_int.c
# link without LTO
C:\temp>gcc -o test-nolto.exe print_int.o test.o
LTOの効果を得るには、リンク段階でも最適化オプションを使用することになっています。リンカーは実際にコンパイラーを呼び出して、コンパイラーが上記の最初のステップでオブジェクトファイルに入れた中間コードの断片をコンパイルします。この段階でも最適化オプションを渡さないと、コンパイラーは探しているインライン化を実行しません。
# link using LTO
C:\temp>gcc -o test-lto.exe -flto -O3 print_int.o test.o
リンク時間の最適化なしのバージョンの逆アセンブル。 print_int()
関数が呼び出されることに注意してください。
C:\temp>gdb test-nolto.exe
GNU gdb (GDB) 7.2
(gdb) start
Temporary breakpoint 1 at 0x401373
Starting program: C:\temp/test-nolto.exe
[New Thread 3324.0xdc0]
Temporary breakpoint 1, 0x00401373 in main ()
(gdb) disassem
Dump of assembler code for function main:
0x00401370 <+0>: Push %ebp
0x00401371 <+1>: mov %esp,%ebp
=> 0x00401373 <+3>: and $0xfffffff0,%esp
0x00401376 <+6>: sub $0x10,%esp
0x00401379 <+9>: call 0x4018ca <__main>
0x0040137e <+14>: movl $0x1,(%esp)
0x00401385 <+21>: call 0x401350 <print_int>
0x0040138a <+26>: movl $0x2a,(%esp)
0x00401391 <+33>: call 0x401350 <print_int>
0x00401396 <+38>: movl $0xffffffff,(%esp)
0x0040139d <+45>: call 0x401350 <print_int>
0x004013a2 <+50>: xor %eax,%eax
0x004013a4 <+52>: leave
0x004013a5 <+53>: ret
リンク時間最適化を使用したバージョンの逆アセンブル。 printf()
の呼び出しは直接行われることに注意してください。
C:\temp>gdb test-lto.exe
GNU gdb (GDB) 7.2
(gdb) start
Temporary breakpoint 1 at 0x401373
Starting program: C:\temp/test-lto.exe
[New Thread 1768.0x126c]
Temporary breakpoint 1, 0x00401373 in main ()
(gdb) disassem
Dump of assembler code for function main:
0x00401370 <+0>: Push %ebp
0x00401371 <+1>: mov %esp,%ebp
=> 0x00401373 <+3>: and $0xfffffff0,%esp
0x00401376 <+6>: sub $0x10,%esp
0x00401379 <+9>: call 0x4018da <__main>
0x0040137e <+14>: movl $0x1,0x4(%esp)
0x00401386 <+22>: movl $0x403064,(%esp)
0x0040138d <+29>: call 0x401acc <printf>
0x00401392 <+34>: movl $0x2a,0x4(%esp)
0x0040139a <+42>: movl $0x403064,(%esp)
0x004013a1 <+49>: call 0x401acc <printf>
0x004013a6 <+54>: movl $0xffffffff,0x4(%esp)
0x004013ae <+62>: movl $0x403064,(%esp)
0x004013b5 <+69>: call 0x401acc <printf>
0x004013ba <+74>: xor %eax,%eax
0x004013bc <+76>: leave
0x004013bd <+77>: ret
End of assembler dump.
そして、これがMSVCでの同じ実験です(最初はLTCGで):
C:\temp>cl -c /GL /Zi /Ox test.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.c
C:\temp>cl -c /GL /Zi /Ox print_int.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
print_int.c
C:\temp>link /LTCG test.obj print_int.obj /out:test-ltcg.exe /debug
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Generating code
Finished generating code
C:\temp>"\Program Files (x86)\Debugging Tools for Windows (x86)"\cdb test-ltcg.exe
Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: test-ltcg.exe
// ...
0:000> u main
*** WARNING: Unable to verify checksum for test-ltcg.exe
test_ltcg!main:
00cd1c20 6a01 Push 1
00cd1c22 68d05dcd00 Push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0)
00cd1c27 e8e3f3feff call test_ltcg!printf (00cc100f)
00cd1c2c 6a2a Push 2Ah
00cd1c2e 68d05dcd00 Push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0)
00cd1c33 e8d7f3feff call test_ltcg!printf (00cc100f)
00cd1c38 6aff Push 0FFFFFFFFh
00cd1c3a 68d05dcd00 Push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0)
00cd1c3f e8cbf3feff call test_ltcg!printf (00cc100f)
00cd1c44 83c418 add esp,18h
00cd1c47 33c0 xor eax,eax
00cd1c49 c3 ret
0:000>
今LTCGなし。 MSVCでは、リンカーがLTCGを実行しないように、/GL
なしで.cファイルをコンパイルする必要があることに注意してください-そうしないと、リンカーは/GL
が指定されたことを検出し、/LTCG
オプションを強制します(ねえ、それはあなたが望んでいたことです初めて/GL
):
C:\temp>cl -c /Zi /Ox test.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.c
C:\temp>cl -c /Zi /Ox print_int.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
print_int.c
C:\temp>link test.obj print_int.obj /out:test-noltcg.exe /debug
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
C:\temp>"\Program Files (x86)\Debugging Tools for Windows (x86)"\cdb test-noltcg.exe
Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: test-noltcg.exe
// ...
0:000> u main
test_noltcg!main:
00c41020 6a01 Push 1
00c41022 e8e3ffffff call test_noltcg!ILT+5(_print_int) (00c4100a)
00c41027 6a2a Push 2Ah
00c41029 e8dcffffff call test_noltcg!ILT+5(_print_int) (00c4100a)
00c4102e 6aff Push 0FFFFFFFFh
00c41030 e8d5ffffff call test_noltcg!ILT+5(_print_int) (00c4100a)
00c41035 83c40c add esp,0Ch
00c41038 33c0 xor eax,eax
00c4103a c3 ret
0:000>
MicrosoftのリンカがLTCGでサポートしていることの1つ それはGCCではサポートされていません(私が知る限り) プロファイルガイド最適化(PGO)です。このテクノロジにより、Microsoftのリンカは、プログラムの以前の実行から収集されたプロファイリングデータに基づいて最適化できます。これにより、リンカは「ホット」関数を同じメモリページに収集し、コードシーケンスを他のメモリページに使用することはめったになく、プログラムのワーキングセットを減らすなどのことができます。
編集(2011年8月28日):-fprofile-generate
や-fprofile-use
などのオプションを使用したGCCサポートプロファイルガイド付き最適化ですが、私はそれらについて完全に知らされていません。
これを私に指摘してくれたKonradRudolphに感謝します。