ソースファイルにこの小さな関数があるとしましょう
static void foo() {}
そして、私は自分のバイナリの最適化されたバージョンを構築していますが、この関数をインライン化したくありません(最適化のため)。インライン化を防ぐためにソースコードに追加できるマクロはありますか?
ソースファイルにこの小さな関数があるとしましょう
static void foo() {}
そして、私は自分のバイナリの最適化されたバージョンを構築していますが、この関数をインライン化したくありません(最適化のため)。インライン化を防ぐためにソースコードに追加できるマクロはありますか?
回答:
gcc
-specific noinline
属性が必要です。
この関数属性は、関数がインライン化の対象と見なされないようにします。関数に副作用がない場合、関数呼び出しはライブですが、関数呼び出しが最適化される原因となるインライン化以外の最適化があります。このような呼び出しが最適化されないようにするには、
asm ("");
次のように使用します。
void __attribute__ ((noinline)) foo()
{
...
}
GCCには、
-fno-inline-small-functions
したがって、gccを呼び出すときにそれを使用します。しかし、副作用として、他のすべての小さな関数もインライン化されていません。
-fno-inline
はまったく機能しません。gdb
まだステップオーバー時にメソッドに入ります。何かが壊れています、そして私はそれが疑いgdb
ます。
これを行う移植可能な方法は、ポインタを介して関数を呼び出すことです。
void (*foo_ptr)() = foo;
foo_ptr();
これは分岐するための異なる命令を生成しますが、それはあなたの目標ではないかもしれません。これは良い点をもたらします:ここであなたの目標は何ですか?
質問がGCCに関するものであることはわかっていますが、他のコンパイラについても、コンパイラに関する情報があると役立つと思いました。
GCCの
noinline
関数属性は、他のコンパイラーでも人気があります。それは少なくとも以下によってサポートされます:
__has_attribute(noinline)
)__TI_GNU_ATTRIBUTE_SUPPORT__
)さらに、MSVCは__declspec(noinline)
Visual Studio 7.1までをサポートし
ています。Intelもおそらくサポートしています(GCCとMSVCの両方との互換性を確保しようとします)が、それを確認する必要はありません。構文は基本的に同じです:
__declspec(noinline)
static void foo(void) { }
PGI 10.2+(およびおそらくより古い)はnoinline
、次の関数に適用されるプラグマをサポートしています。
#pragma noinline
static void foo(void) { }
TI 6.0以降は、FUNC_CANNOT_INLINE
CとC ++で(厄介なことに)異なる動作をするプラグマをサポートしてい
ます。C ++では、PGIに似ています。
#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }
ただし、Cでは関数名が必要です。
#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }
Cray 6.4以降(およびおそらく以前のバージョン)も同様のアプローチをとっており、関数名が必要です。
#pragma _CRI inline_never foo
static void foo(void) { }
Oracle Developer Studioは、少なくともForte Developer 6までさかのぼって関数名をとるプラグマもサポートしますが、最近のバージョンでも、宣言の後に置く必要があることに注意してください。
static void foo(void);
#pragma no_inline(foo)
どれだけ専念しているかによって、どこでも機能するマクロを作成できますが、関数名と宣言を引数として持つ必要があります。
OTOH、ほとんどの人にうまく機能するもので大丈夫であれば、もう少し美的で満足のいくもので、何度も繰り返す必要がないもので済ますことができます。これが、私がHedleyに採用したアプローチです。現在のHEDLEY_NEVER_INLINEのバージョンは 次のようになります。
#if \
HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
HEDLEY_TI_VERSION_CHECK(8,0,0) || \
(HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
# define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
# define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
# define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
# define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif
Hedley(単一のパブリックドメイン/ CC0ヘッダーです)を使用したくない場合は、それほど多くの労力をかけずにバージョンチェックマクロを変換できますが、私がtoに入れようと思っている以上のものです。
私はgcc 7.2を使用しています。ライブラリにインスタンス化する必要があるため、関数をインライン化しないようにする必要がありました。__attribute__((noinline))
答えだけでなく、答えも試しましたasm("")
。どちらも問題を解決しなかった。
最後に、関数内で静的変数を定義すると、静的変数ブロックに静的変数を割り当てるスペースがコンパイラーに強制され、関数が最初に呼び出されたときに初期化が発行されることを理解しました。
これはちょっと汚いトリックですが、うまくいきます。
inline void foo(void) { ... }
ヘッダーで関数を定義extern inline void foo(void);
し、ライブラリソースファイルで宣言できます。C99のセマンティクスに従って、ライブラリでオブジェクトコードを許可し、オブジェクトコードを発行すると、コンパイラーは関数をインライン化できます。「静的」または「extern」なしの「インライン」がC99で役立つことを参照してください。。