ARM
UKサイト Chinaサイト 投資家情報 イベント情報 プレスルーム 採用情報 Document Center


THE ARCHITECTURE FOR THE DIGITAL WORLD
メールサービス
会社概要 マーケット プロダクト&ソリューション テクニカルサポート ドキュメント
テクニカルサポート
TOP > テクニカルサポート > よくある質問-FAQ-
ARM技術サポート
よくある質問-FAQ-
トレーニング
購入方法
ARM開発ツールダウンロード

よくある質問-FAQ-

C/C++関数のインライン展開。

インライン展開は、コードサイズとパフォーマンスの間でトレードオフがあります。 組み込みシステムでは、コードサイズが大きな問題です。そのため、ARMコンパイラは、デフォルトでは最低限のコードサイズに抑えてコードを生成します。

標準仕様のC++では、inlineキーワードを使用して、関数をインライン展開する必要があるというヒントをコンパイラに与えることができます。 インライン展開は、もともとのC言語の仕様には含まれていませんが、ほとんどのベンダのツールで、インライン展開を利用することができます。

C言語の場合、ARMコンパイラでは__inlineによってインライン展開の機能が利用できます。C++の場合は標準仕様と同じように利用できます。 キーワードの最初に「__」が必要な理由は、C言語の標準仕様と厳密な互換性を確保するためです。以下のようなステートメントを考えてみます。

int inline; /* this declares an integer called inline in C but is meaningless in C++ */

デフォルトで、コンパイラはこれがインラインコードかどうかを判断します。 インライン展開が実行されるかどうかは、以下のようなポイントで判断されます。

1) __inline/inlineは「ヒント」であって「指示」ではない。

__inline(C言語の場合)とinline(C++の場合)は、コンパイラに対する「ヒント」です。 コンパイラは、関数のサイズや現在の最適化のレベルのほか、速度の最適化(-Otime)を行うかあるいはサイズの最適化(-Ospace)を行うかなど、多数の条件を考慮した上で「ヒント」が適当かどうかを判断し、関数をインライン展開するかどうかを決めます。そのため、ヒントが無視されることもよくあります。

ADSでは、小さな関数はインライン展開される頻度が高くなります。 -Otimeのオプションを付けてコンパイルすると、関数がインライン展開されることが多くなります。 大きな関数は、通常はインライン展開されません。逆にコード密度や性能が低下する可能性があるためです。 関数が強制的に「__inline」としてマークされて常にインライン展開されるコンパイラオプション(ドキュメントには記載されていない)があります。 「--inlinemax=0」(あるいは「--no_inlinemax」)です。 このオプションを使用すると、コードサイズが顕著に増加する可能性と(特にC++の場合)、性能が低下する可能性のあることに注意してください。

SDTでは、インライン関数の最大長に制限はありませんでした。__inlineが付けられた関数は、可能なかぎりすべてインライン展開されていました。 他のベンダのツールでは、最大長に制限のある場合やない場合があります。

ADS 1.1以降では、ユーザが明示的に「ヒント」を与えない場合にも、コンパイラが自動的に適切かどうかを判断して関数をインライン展開します。 これは、最適化レベルが最も高い場合(-O2)にデフォルトで実行されます。 この動作はデフォルトの動作ですが、「-Oautoinline」や「-Ono_autoinline」を指定することでオン・オフを切り替えることができます。 以下の5)を参照してください。

2) __inline/inline関数は他のオブジェクトファイルには含まれない。

インライン展開は、1つのコンパイル単位のコードに対して行われます。 extern関数はインライン展開されません。 関数に__inlineを指定すると、他のコンパイル単位からは呼び出せなくなります。 つまり、__inlineがC++のセマンティクスを持つため、「extern __inline」は期待したとおりに動作しない可能性があります。 C++の標準仕様では、インライン関数は、各「変換単位」で個別に定義される必要があります。そのため、別のファイルのインライン関数とリンクすることはできません。

インライン展開された関数を複数のファイルから利用したい場合には、関数をヘッダファイル(「.h」ファイル)に置いて「extern __inline」と宣言し、この関数が必要な各ファイル内で、このヘッダファイルを「#include」を使用してインクルードします。 コンパイラが関数をインライン展開しないと決めた場合には、リンク後の関数の複製は1つだけになります。

ローカルだけで呼び出される関数(「static」)は、ヘッダファイルに配置しないでください。これらの「static inline」関数は共有できないので、リンク後に複数の複製が存在することがあります。 ローカルだけで利用される関数に、「inline」ではなく「static inline」と指定する必要は必ずしもありませんが、コーディングスタイルとしては推奨されます。コンパイラが別の最適化を行うことができるためです。

3) __inline/inline関数は、呼び出される前に定義が必要な場合がある(ADS 1.0.1以前)。

コンパイラは、インライン関数用のコンパイルされたコードを、他の関数をコンパイルしたときに、その関数内に配置する必要があります。 コンパイラの古いバージョン(SDT 2.5xおよびADS 1.0.1)では、一回のパスでコンパイルが実行されます。 つまり、__inline関数の実際のコードが存在しない場合には、インライン展開できません。

ADS 1.1以降では2回のパスでコンパイルの処理が行われます。 これによって、インライン関数が、利用される場所よりも、(同じ)ソースファイルの後の方に存在する場合にもインライン展開されます。

(C++を開発した)Bjarne Stroustrup氏は以下のように述べています。 「コンパイルとリンクの機能がかなり高い場合を除いて、インライン展開を行うにはインライン関数の定義(宣言ではなく)がスコープ内に存在する必要があります。」

4) デバッグデータ

インライン関数を使用した場合に、複数の場所に存在するデバッグ情報をすべて提供するには非常に複雑な処理が必要になります。 結果として、inlineで宣言されている関数をデバッグすることと、関数をinline展開することの間にはトレードオフがあります。

SDT 2.5xでは、「#pragma debug_inlines」を宣言しない場合にはインライン関数用のデバッグデータは生成されません。 「SDT 2.51 Reference Guide」の3〜4ページと、STDのFAQ「armcc/tcc Source-level debugging __inline functions」を参照してください。

ADSには、同様の機能を提供する「-Oinline」と「-Ono_inline」のコマンドラインオプションがあります。 「-Ono_inline」を使用すると、C言語とアセンブラが混在するインライン関数をデバッグする際に便利です。

5) 他のモジュールから呼び出されない関数を「static」と宣言する。

ADS 1.1以降では、関数に「__inline/inline」が付加されていない場合にも、コンパイラが自動的に適切かどうかを判断して関数をインライン展開します。 これは、最適化レベルが最も高い場合(-O2)にデフォルトで実行されます。 この動作はデフォルトの動作ですが、「-Oautoinline」や「-Ono_autoinline」を指定することでオン・オフを切り替えることができます。 以下の5)を参照してください。

関数が自動的にインライン展開される場合、関数が「static」として宣言されてないときには、関数のインライン展開されたコードと通常のコードの両方が最終イメージの中に存在し、コードサイズが増加する可能性があることに注意してください。

関数が「static」として(あるいは__inlineとして)宣言されておらず、その関数が他のモジュールから呼び出されない場合は、コンパイラはその関数の通常のコードをオブジェクトファイルに挿入します。 リンカは、コードが「-zo」オプション(領域ごとに1つの関数)でコンパイルされていない場合には、使用されていない通常コードの関数をオブジェクトから削除することはできません。 このような重複を避けるには、モジュールの外部から呼び出されないことが明確な関数は「static」で宣言する必要があります。

関数の、インライン展開されたコードと通常のコードの両方が存在すると、デバッグも複雑になります。ブレークポイントの設定やシングルステップの実行で混乱する可能性があります。 デバッガは、ソースビューの中にインライン展開されたコードと通常のコードの両方を表示する必要があります。このような表示が行われると、ユーザは、両者のコードのステップ実行をする場合に何が起こっているかを参照することができます。

一般的に、関数が他のモジュールから呼び出されないことが明らかな場合には、「static」として宣言するべきです。 これには以下のような2つの効果があります。

a) コードサイズが小さくなる(イメージの中に通常のコードは含まれない)。
b) デバッグが単純になる(通常のコードは表示されない)。

6) ROMイメージ内でインライン展開された関数にブレークポイントを設定する。

インライン関数にブレークポイントを設定すると、ARMデバッガはブレークポイントを関数の各インラインインスタンスに設定しようとします。 ROM内のイメージをデバッグするためにMulti-ICEや他のハードウェアを使用しており、インライン展開された関数が、利用可能なハードウェアブレークポイントの数よりも多い場合、デバッガはブレークポイントを設定できずエラーが生成されます。
してください。


<< FAQへ戻る

page top

UKサイト お問い合わせ サイトマップ このサイトについて
Copyright