もちろん可能です。
それを行う最善の方法は、完全なジョブを実行する関数を用意し、実行時にそれらの中から選択することです。これは機能しますが、最適ではありません。
typedef enum
{
calc_type_invalid = 0,
calc_type_plain,
calc_type_sse,
calc_type_avx,
calc_type_max // not a valid value
} calc_type;
void do_my_calculation(float const *input, float *output, size_t len, calc_type ct)
{
float f;
size_t i;
for (i = 0; i < len; ++i)
{
switch (ct)
{
case calc_type_plain:
// plain calculation here
break;
case calc_type_sse:
// SSE calculation here
break;
case calc_type_avx:
// AVX calculation here
break;
default:
fprintf(stderr, "internal error, unexpected calc_type %d", ct);
exit(1);
break
}
}
}
ループを通過するたびに、コードはswitch
ステートメントを実行しますが、これは単なるオーバーヘッドです。本当に賢いコンパイラなら理論的には修正できますが、自分で修正する方がよいでしょう。
代わりに、plain 用、SSE 用、AVX 用の 3 つの個別の関数を記述します。次に、どちらを実行するかを実行時に決定します。
ボーナス ポイントについては、「デバッグ」ビルドで、SSE とプレーンの両方で計算を行い、結果が信頼できるほど近いことを主張します。速度のためではなく、正確さのために、単純なバージョンを書きます。次に、その結果を使用して、巧妙に最適化されたバージョンが正しい答えを得ることを確認します。
伝説的なジョン・カーマックは後者のアプローチを推奨しています。彼はそれを「並列実装」と呼んでいます。それについての彼のエッセイを読んでください。
そのため、プレーン バージョンを最初に作成することをお勧めします。次に、戻って SSE または AVX アクセラレーションを使用してアプリケーションの一部を書き直し、アクセラレーションされたバージョンが正しい答えを返すことを確認します。(また、通常のバージョンには高速化されたバージョンにはないバグがある場合があります。2 つのバージョンを用意してそれらを比較すると、どちらのバージョンでもバグが明らかになります。)