値を格納するために型を使用していますint
。プログラムのセマンティクスにより、値は常に非常に狭い範囲 (0 - 36) で変化し、 CPU 効率のためだけにint
(not a char
) が使用されます。
このような狭い範囲の整数に対して、多くの特殊な算術最適化を実行できるようです。これらの整数に対する多くの関数呼び出しは、小さな「魔法の」操作セットに最適化される可能性があり、一部の関数はテーブル検索に最適化される可能性もあります。
では、これが常にその狭い範囲内にあることをコンパイラに伝えint
、コンパイラがそれらの最適化を行うことは可能でしょうか?
ベストアンサー1
はい、可能です。たとえば、次のようにして、不可能な条件をコンパイラーに通知するgcc
ことができます。__builtin_unreachable
if (value < 0 || value > 36) __builtin_unreachable();
上記の条件をマクロでラップすることができます。
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
次のように使用します:
assume(x >= 0 && x <= 10);
ご覧のようには、gcc
この情報に基づいて最適化を実行します。
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
int func(int x){
assume(x >=0 && x <= 10);
if (x > 11){
return 2;
}
else{
return 17;
}
}
生産:
func(int):
mov eax, 17
ret
しかし、欠点はコードがそのような仮定を破った場合、未定義の動作が発生します。。
デバッグ ビルドであっても、これが発生したときに通知されません。仮定を使用してバグをより簡単にデバッグ/テスト/キャッチするには、次のように、ハイブリッドの assert/assert マクロ (クレジットは @David Z 氏) を使用できます。
#if defined(NDEBUG)
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#else
#include <cassert>
#define assume(cond) assert(cond)
#endif
デバッグビルド(NDEBUG
ない定義されている場合、通常の のように動作しassert
、エラー メッセージを出力してabort
プログラムを し、リリース ビルドでは仮定を使用して最適化されたコードを生成します。
ただし、これは通常の代替ではないことに注意してください。assert
-cond
はリリース ビルドに残るので、 のようなことは行わないでくださいassume(VeryExpensiveComputation())
。