web-dev-qa-db-ja.com

関数をインライン化しないようにgccに指示するにはどうすればよいですか?

ソースファイルにこの小さな関数があるとします

static void foo() {}

バイナリの最適化バージョンを構築しますが、この関数をインライン化したくありません(最適化のため)。インライン化を防ぐためにソースコードに追加できるマクロはありますか?

112
vehomzzz

gcc- specific noinline 属性が必要です。

この関数属性は、関数がインライン化の対象となるのを防ぎます。関数に副作用がない場合、関数呼び出しはライブですが、関数呼び出しが最適化されないようにするインライン化以外の最適化があります。そのような呼び出しが最適化されないようにするには、asm ("");

次のように使用します。

void __attribute__ ((noinline)) foo() 
{
  ...
}
134
alex tingle

GCCには、というスイッチがあります

-fno-inline-small-functions

そのため、gccを呼び出すときに使用します。しかし、副作用は、他のすべての小さな関数もインライン化されないことです。

28
lukmac

これを行うポータブルな方法は、ポインターを使用して関数を呼び出すことです。

void (*foo_ptr)() = foo;
foo_ptr();

これは分岐するための異なる命令を生成しますが、それはあなたの目標ではないかもしれません。どちらが良い点をもたらします:ここで何isあなたの目標ですか?

21
Andy Ross

__attribute__((noinline))のコンパイラエラーが発生した場合は、次を試してください。

noinline int func(int arg)
{
    ....
}
13
Sam Liao

私は質問がGCCに関するものであることを知っていますが、コンパイラーや他のコンパイラーについての情報もあると便利だと思いました。

GCCの noinline 関数属性は、他のコンパイラでも非常に人気があります。少なくとも以下でサポートされています。

  • Clang(__has_attribute(noinline)で確認)
  • Intel C/C++ Compiler(それらのドキュメントはひどいですが、16.0 +で動作することは確かです)
  • Oracle Solaris Studioを少なくとも12.2に戻す
  • ARM C/C++コンパイラを少なくとも4.1に戻しました
  • IBM XL C/C++を少なくとも10.1に戻す
  • TI 8.0+(または--gccを使用する7.3+、これは__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 に戻るプラグマもサポートしていますが、after宣言、最近のバージョンでも:

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_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

Hedley(単一のパブリックドメイン/ CC0ヘッダー)を使用したくない場合は、バージョンチェックマクロをあまり手間をかけずに変換できますが、私は喜んでinに入れます。

10
nemequ
static __attribute__ ((noinline))  void foo()
{

}

これは私のために働いたものです。

9
KenBee

noinlineattribute を使用します。

int func(int arg) __attribute__((noinline))
{
}

関数を外部で使用するために宣言するときと、関数を記述するときの両方で使用する必要があります。

7
Chris Lutz

Gcc 7.2を使用しています。ライブラリ内でインスタンス化する必要があるため、関数をインライン化しないことが特に必要でした。 __attribute__((noinline))回答とasm("")回答を試しました。どちらも問題を解決しませんでした。

最後に、関数内で静的変数を定義すると、コンパイラが静的変数ブロックにその変数にスペースを割り当て、関数が最初に呼び出されたときに初期化を発行するようになります。

これは一種の汚いトリックですが、動作します。

1
Ofri Sadowsky