windowsにおけるただフォワードするだけの関数の機械語比較(VC++/gcc/clang)

本の虫さんの記事にて
linux上のGCCではただ別の関数へフォワードするだけの関数をコンパイルしてもPICが有効だとjmp一文にならない事とその理由を説明した記事を翻訳したものが載った。
そこでふと疑問に思ったのだが、PICとか関係のないwindows上ではどうなっているのだろうか?
というわけで、GCCとclangとVisualStudio2015それぞれでコンパイルして結果をまとめてみた。
なお、最適化の結果消え去るならば問題ないはずとの考えから最適化OFF/ON両方で検証している。

検証に使用したコンパイラのバージョン:
VisualStudio C++ 19.00.22609 for x86
gcc (GCC) 4.8.1
clang version 3.6.0 (tags/RELEASE_360/final)

検証コード

まずは検証に使うソースコードを載せる。

main.cpp

#include <iostream>

void OtherFile();
void TailProc();

void NormalProc() {
  std::cout << "Normal\n";
}

void CheckOtherFile() {
  OtherFile();
}

void CheckTailProc() {
  TailProc();
}

void CheckNormalProc() {
  NormalProc();
}

void TailProc() {
  std::cout << "Tail\n";
}

int main() {
  CheckOtherFile();
  CheckTailProc();
  CheckNormalProc();
  return 0;
}

lib.cpp

#include <iostream>

void OtherFile() {
  std::cout << "OtherFile\n";
}

一応解説しておくと、CheckOtherFileは定義が別の.cpp、CheckTailProcは同じ.cppだが後方で宣言、CheckNormalProcは前方で宣言となっている。

コンパイルに使用した.bat

cl /EHsc /Ox /GL /Fevc_exe.exe main.cpp lib.cpp
cl /EHsc /Od /Fevc_exe_O0.exe main.cpp lib.cpp
g++ -O3 -flto -o gcc_exe.exe main.cpp lib.cpp
g++ -O0 -o gcc_exe_O0.exe main.cpp lib.cpp
clang++ -O3 -o clang_exe.exe main.cpp lib.cpp
clang++ -O0 -o clang_exe_O0.exe main.cpp lib.cpp

clangのみ手元ではリンク時最適化できなかったため通常の最適化のみ。

gcc

最適化OFFの場合

main

各チェック関数

mainでなぜかcallが四つあるが一つ目おそらくコンパイラがつけた特殊関数だと思われる。
問題のcheck部分は元の記事ほど悪くはないがjmp命令ひとつまで縮んでいない。

最適化ONの場合
main

各チェック関数は三つとも完全にインライン展開されている。

VisualStudio C++

最適化OFFの場合

main

各チェック関数

チェック関数は三つともほぼ同じだったため他二つは割愛。

最適化ONの場合
main

三つとも完全にインライン展開されている。

clang

最適化OFFの場合

main

各チェック関数

mainの一つ目のcallはgccと同じくコンパイラが付与したもの。
チェック関数は三つともほぼ同じだったため他二つは割愛。

最適化ONの場合
main

OtherFileだけインライン展開されていないが、それは前述のとおりリンク時最適化が入っていないためと思われる。
CheckOtherFile自体はインライン展開されている。

まとめ

windows上だとVC++/gcc/clangのどれであっても、フォワードするだけの関数をjmp一文に翻訳してくれたりはしない。
だが、最適化を有効にすればどのコンパイラでも、別の.cppでも同じ.cppでも、大体インライン展開されてほぼコスト0になるので気にする必要はほぼない。

終わりに

VC++ではjmp一文にならないのは知っていたが、記事を読んだ範囲ではgccがjmp一文に翻訳するとしかおもえなかったため、コンパイラ比較にいい題材だろうと試してみた結果
このようなどれも結果がほぼ一緒で大した価値のない比較記事が生まれることとなりました、なんてこったい。

一応clangが文字数情報を生成してくっつけてくれてるとか、VC++はmainはほぼ書いたまんまだけどその他は前後にちょっと追加があるとか、clangのフォワード関数部分はgccではなくVC++寄りだとか、見どころはないでもないが全部本題とは無関係である。

まぁ、可読性のために別関数にしたりするぐらいではそう滅多にオーバーヘッドは生まないことが分かっただけでも収穫だろうか。

なにか間違いなどありましたらコメントください。
ではまた。