最適化のこの種は、で定義されているようprintf
という名前の関数は唯一printf
関数とすることができることを知って、コンパイラに依存Cの標準。プログラムがprintf
を他に意味すると定義している場合、プログラムは未定義の動作を呼び出しています。これにより、標準のprintf
関数が呼び出されているかのように動作する場合に、コンパイラはputs
への呼び出しを代入することができます。ユーザーが定義したprintf
関数が呼び出されたかのように "あたかも"動作しているかどうか心配する必要はありません。したがって、これらの種類の関数置換最適化は、CまたはC++標準で定義された関数にかなり制限されています。コンパイラが何らかの形で与えられた標準が有効であることを何とか知っていれば他の標準もあるかもしれません。
コンパイラのソースコードを自分で修正するのではなく、コンパイラにこれらの種類の関数置換が可能です独自の機能。しかし、制限があるため、インライン関数と同様のことができます。たとえば、あなたはこのようなものでprintf
/puts
最適化に似たものを実現することができます。しかし、最適化を
inline int myprintf(char const *fmt, char const *arg) {
if (strcmp(fmt, "%s\n") == 0) {
return myputs(args);
}
return _myprintf_impl(fmt, arg)
}
がfmt
パラメータに基づいて呼び出すように機能し、コンパイル時に選択することができますコンパイラオンのみの場合それは定数文字列であると判断できます。それができない場合、または最適化が有効になっていない場合、コンパイラは呼び出しごとにチェックするコードを生成する必要があり、簡単にこれをペシメーゼーションに変えることができます。この最適化は、コンパイラがstrcmp
の仕組みを知っていることと、呼び出しを完全に削除することに依存していることに注意してください。コンパイラが行うことができる別のライブラリ関数呼び出しの例もあります。あなたはGCCの__builtin_constant_p
機能でこれを改善することができます
:
inline int myprintf(char const *fmt, char const *arg) {
if (__builtin_constant_p(fmt[0])
&& strcmp(fmt, "%s\n") == 0) {
return myputs(arg);
}
return _myprintf_impl(fmt, arg);
}
GCCの下で、これはフォーマット文字列に実行時間をチェックしたことがないコードになります。fmt
がコンパイル時に"%s\n"
であると判断できる場合は、無条件にmyputs
を呼び出すコードを生成し、それ以外の場合は無条件に_myprintf_impl
を呼び出すコードを生成します。最適化を有効にすると、この機能は決して悲観的なものではありません。残念ながら、clangは__builtin_constant_p
関数をサポートしていますが、私のclangは常に_myprintf_impl
を無条件に呼び出すコードを生成します。
だからclangはオープンソースなので、確かにできます:)もっと最適なコードを書くのは簡単ではないでしょうか? –
私は知りません(または私は答えます)が、私の知る限り、この種の特殊なケーシングが適用されているのは、ほんのわずかな特定の標準ライブラリ関数です。 'memset'は、コンパイラがしばしば固定小サイズ用であるかどうかを識別し、そのような場合にインライン展開する特殊なケースです。 – ShadowRanger
それは問題です。 clangのソースでlibcの最適化を行っていますか(私はclangをforkしません)か、libcのソースにありますか(私自身のライブラリに最適化を書くことができるという意味ですか? – LodeRunner