Agner Fogの「 C++でソフトウェアを最適化する 」(Intel、AMD、およびVIAのx86プロセッサに固有)を読んでおり、34ページに記載されています
ブール変数は8ビット整数として格納され、値がfalseの場合は0、trueの場合は1になります。ブール変数は、入力としてブール変数を持つすべての演算子が入力に0または1以外の値があるかどうかをチェックするという意味で過剰決定されますが、出力としてブールを持つ演算子は0または1以外の値を生成できません。入力としてのブール変数は必要以上に効率的ではありません。
これは今日でも、どのコンパイラーでも当てはまりますか?例を挙げていただけますか?著者は述べています
オペランドが0と1以外の値を持たないことが確実にわかっている場合、ブール演算をはるかに効率的にすることができます。コンパイラがそのような仮定を行わない理由は、変数が初期化されていないか、不明なソースからのものです。
これは、たとえば関数ポインターbool(*)()
を使用して呼び出した場合、その操作により非効率なコードが生成されることを意味しますか?それとも、ポインターを逆参照するか、参照から読み取ることによってブール値にアクセスしてから操作する場合ですか?
これは事実ではないと思います。
まず第一に、この推論はまったく受け入れられません。
コンパイラがこのような仮定を行わない理由は、変数が初期化されていないか、未知のソースからのものである場合、変数が他の値を持つ可能性があるためです。
いくつかのコードを確認しましょう(clang 6でコンパイルされていますが、GCC 7とMSVC 2017は同様のコードを生成します)。
ブール値または:
bool fn(bool a, bool b) {
return a||b;
}
0000000000000000 <fn(bool, bool)>:
0: 40 08 f7 or dil,sil
3: 40 88 f8 mov al,dil
6: c3 ret
ご覧のとおり、ここでは0/1チェックなし、単純なor
。
boolをintに変換:
int fn(bool a) {
return a;
}
0000000000000000 <fn(bool)>:
0: 40 0f b6 c7 movzx eax,dil
4: c3 ret
繰り返しますが、チェックは不要です。簡単に移動できます。
charをブールに変換:
bool fn(char a) {
return a;
}
0000000000000000 <fn(char)>:
0: 40 84 ff test dil,dil
3: 0f 95 c0 setne al
6: c3 ret
ここでは、charが0かどうかがチェックされ、それに応じてブール値が0または1に設定されます。
ですから、コンパイラはある意味でboolを使用し、常に0/1を含むと言っても安全だと思います。有効性をチェックすることはありません。
効率について:ブール値が最適だと思います。私が想像できる唯一のケースは、このアプローチが最適ではない場合、char-> bool変換です。 bool値が0/1に制限されない場合、その操作は単純なmovになります。他のすべての操作では、現在のアプローチは同等またはそれ以上です。
編集:Peter CordesがABIに言及した。 AMD64のSystem V ABIからの関連テキストを次に示します(i386のテキストも同様です)。
ブール値は、メモリオブジェクトに格納されると、シングルバイトオブジェクトとして格納され、その値は常に0(false)または1(true)です。整数レジスタに格納する場合(引数として渡す場合を除く)、レジスタの8バイトすべてが重要です。ゼロ以外の値はすべて真と見なされます
したがって、SysV ABIに準拠するプラットフォームでは、bool
の値が0/1であることを確認できます。
MSVCのABIドキュメントを検索しましたが、残念ながらbool
について何も見つかりませんでした。
次をclang ++ -O3 -Sでコンパイルしました
bool andbool(bool a, bool b)
{
return a && b;
}
bool andint(int a, int b)
{
return a && b;
}
.s
ファイルに含まれるもの:
andbool(bool, bool): # @andbool(bool, bool)
andb %sil, %dil
movl %edi, %eax
retq
andint(int, int): # @andint(int, int)
testl %edi, %edi
setne %cl
testl %esi, %esi
setne %al
andb %cl, %al
retq
明らかに、実行回数が少ないのはboolバージョンです。