両方ともここで見ることができる階乗関数の単純なバージョンを実装しました。GCCトランクを使用しています。2つのソースファイルがあり、1つ目は関数バージョンで、2つ目はテンプレートバージョンです。各ソースファイルには、関連する出力を持つ2つのコンパイラが添付されています。各ソースファイルに接続されている2つのコンパイラの唯一の違いは、左側のコンパイラではコンパイラフラグまたは最適化がオンになっておらず、右側のバージョンでは-O3
レベル3の最適化がオンに設定されていることです。
これが私の機能です:
// Function Version
int factorial(int n) {
if (n == 0 || n == 1) return 1;
if (n == 2) return 2;
return (n * factorial(n-1));
}
// Template Version:
template<unsigned N>
static auto constexpr factorial_t() {
return (N * factorial<N-1>());
}
template<>
auto constexpr factorial_t<0>() {
return 1;
}
template<>
auto constexpr factorial_t<1>() {
return 1;
}
template<>
auto constexpr factorial_t<2>() {
return 2;
}
IDE
Visual Studio 2017
を使用してローカルPCにインストールしたものでこれらを実行すると、c++17
期待される出力がから返されmain()
、戻り値は両方の実装で正しいです。
これをCompilerExplorerに移植して、他のコンパイラとその最適化をテストし、生成されたアセンブリ命令を比較しました。これはかなり簡単なプロセスです。
これらの関数をそのように実行すると、次のようになります。
ソース#1
int main() {
return factorial(6);
}
ソース#2
int main() {
return factorial_t<6>();
}
コンパイラエクスプローラは、次の命令カウントを生成します。
| Assembly Instruction Count |
Type | Without O3 | With O3 Turned On |
Function | 34 | 29 |
Template | 50 | 3 |
すべてが良いです。
4つのプログラム実行はすべて、値を返します208
。
今私の質問に:
ただし、レジスタの計算を行わずに、最初と3番目のコンパイラのアセンブリ内で直接明らかではありませんが、バージョンとバージョンの-O3
両方でオンになっている2番目と最後のコンパイラでは、値はのリターン呼び出しの前にレジスタに格納されます。なぜコンパイラExplorerが表示されます。代わりに?function
template
720
EAX
main()
Program returned: 208
720
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加