web-dev-qa-db-ja.com

Clang / LLVMで関数を強制的にインライン化する

Clang/LLVMでインライン関数を強制する方法はありますか?

AFAIK、以下はコンパイラへの単なるヒントですが、リクエストを無視することができます。

__attribute__((always_inline))

関数をインライン化できない場合、コンパイルが失敗してもかまいません。

14
DavidS

ClangのデフォルトであるC99でコンパイルする場合、良い解決策があります。単にinline属性を使用します。

inline void foo() {} 

Clangの互換性ページ :によく書かれています。

デフォルトでは、ClangはC99標準に従ってCコードを構築します。これは、GCCのデフォルトの動作とは異なるセマンティクスをインラインキーワードに提供します...

C99では、インラインとは、関数の定義がインライン化のためにのみ提供され、プログラムのどこかに別の定義(インラインなし)があることを意味します。これは、addがインライン化されていない場合(たとえば、最適化せずにコンパイルする場合)、mainが他の定義への未解決の参照を持つため、このプログラムが不完全であることを意味します。したがって、(正しい)リンク時間エラーが発生します...

GCCはそれを拡張機能として認識し、オプティマイザーへのヒントとして扱います。

したがって、関数がインライン化されていることを保証するには、次のようにします。

  1. 静的インラインを使用しないでください。
  2. インライン属性を持たない関数に別の実装を追加しないでください。
  3. 最適化を使用する必要があります。しかし、最適化がなくても、コンパイルは失敗します。これは良いことです。
  4. GNU89でコンパイルしないように注意してください。
14
DavidS

私はあなたの質問をClang/LLVMフレームワーク内のツールを求めるものとして扱います。これが私の提案です:コードをLLVMビットコードにコンパイルしてから 常にインラインパス を実行します。

例えば:

> clang <other CFLAGS> -emit-llvm -c -o foo.bc foo.c
> opt -always-inline foo.bc -o foo_inline.bc
> clang -c -o foo.o foo_inline.bc

以前にこのシーケンスを使用したことがあり、「always_inline」とマークされたすべての関数がインライン化されています。私の場合、ビットコードですでに他の分析と変換を行っていたので、optにフラグを追加するだけで済みました。

6
Brian

次の実験から始めることができます:clang -mllvm -inline-threshold = n

パラメータnが大きいほど、インライン化はより積極的になります。デフォルトは225なので、もっと大きい値に設定します。非常に積極的なインライン化により、大きなコードサイズと長いコンパイル時間が予想されます。収穫逓減のポイントに達したら、コードをプロファイリングして、頻繁に呼び出されるがインライン化されていない関数を探し、attribute((always_inline)でマークを付けることができます。 )さらにインライン化するため。

「インライン」とマークされた関数がある場合は、-inline-thresholdよりも大きい-inlinehint-thresholdを試して、これによって何かが変わるかどうかを確認することもできます。

また、リンク時間の最適化を使用してコンパイルしていますか?それらがないと、インライン化は個々のコンパイル単位に制限されます。

**から取得 groups.google.comフォーラム

4
yehudahs

役に立つかもしれないほんの少しの発言。

OPのコメントについて:

  1. 複数の_static inline_定義は、それらの1つを変更すると、複数の異なる関数が発生し、多くのヘッドスクラッチが発生する可能性があるため、注意が必要です。 、特にインライン化が開始され、実際の呼び出しがステートメントのさまざまなシーケンスに蒸発する場合。
  2. これは1と同様の効果があります。
  3. インライン化は最適化であり、コンパイラのマニュアルを調べて、いつ開始されるかを確認できます(例: gcc doc page )。通常、それは最初のレベルにあります。 this answerも参照してください。

有用な議論と推奨事項を見つけることができます ここ 。 C99のアドバイスは次のように要約されます。

  1. ヘッダーファイルで以下を定義し、必要な場所にインクルードします。

    inline void foo() { /*...*/ }

  2. 単一のソースファイルで、externを使用して外部シンボルを生成することを宣言します。

    extern inline foo();

提案されたLLVMIRメソッドに関しては、それは機能しますが、ソース言語ドメインが渡され、異なるルールのセットが適用されます(ツールに大きく依存します)。簡単な説明的な議論は見つけることができます ここ

1
compor

ブルートフォース方式は、それをマクロに変換するだけです。

0
kchoi