4.2.4.3 インライン展開

CC-RHでは,関数ごとのインライン展開ができます。ここでは,インライン展開の指定について説明します。

(1)

インライン展開とは

インライン展開とは,関数呼び出し部分に関数本体を展開することを言います。これにより,関数呼び出しによるオーバーヘッドが小さくなり,また,最適化の可能性が高められることから,実行速度向上を図ることができます。

ただし,インライン展開を行うと,オブジェクト・サイズは増大することになります。

インライン展開したい関数は,#pragma inlineで指定します。

#pragma inline ( 関数名 [, 関数名]... ) 

外側のかっこは省略可能です。

 

関数名は,C言語記述の関数名を記述してください。たとえば,"void func1 ( ) { }"という関数であれば"func1"と指定します。また,関数名は“,”(カンマ)で区切って複数指定することができます。

#pragma inline  func1, func2
void    func1() {...}
void    func2() {...}
void func(void) {
    func1();    /*インライン展開対象*/
    func2();    /*インライン展開対象*/
}

(2)

インライン展開の条件

#pragma inline指定された関数をインライン展開するためには,最低限次の条件が必要となります。

ただし,CC-RHの内部処理の関係により,次の条件を満たしていてもインライン展開されない場合があります。

(a)

インライン展開を“する関数”と“される関数”を同一ファイル内に記述する

インライン展開を“する関数”と“される関数”,つまり,“関数呼び出し”と“関数定義”は“同一ファイル内”に存在しなければなりません。別のCソースに書かれてある関数をインライン展開することはできません。この場合,CC-RHはエラーも警告メッセージも出力せず,インライン展開指定を無視します。

(b)

#pragma inlineを“関数定義より前”に記述する

pragma inlineが,関数定義よりも後ろに記述されていた場合,警告を出力してインライン展開指定を無視します。ただし,関数のプロトタイプ宣言との記述順序は問いません。次に例を示します。

【インライン展開指定:有効】
#pragma inline  func1, func2
void    func1();  /*プロトタイプ宣言*/
void    func2();  /*プロトタイプ宣言*/
void    func1() {...}  /*関数定義*/
void    func2() {...}  /*関数定義*/
【インライン展開指定:無効】
void    func1();  /*プロトタイプ宣言*/
void    func2();  /*プロトタイプ宣言*/
void    func1() {...}  /*関数定義*/
void    func1() {...}  /*関数定義*/
#pragma inline  func1, func2

(c)

インライン展開する関数の“呼び出し”と“定義”の間で,“引数の数”を同じにする

インライン展開する関数の“呼び出し”と“定義”の間で“引数の数”が違う場合,インライン展開指定を無視します。

(d)

インライン展開する関数の“呼び出し”と“定義”の間で,“戻り値の型”や“引数の型”を同じにする

インライン展開する関数の“呼び出し”と“定義”の間で,“戻り値の型”や“引数の型”が異なる場合,インライン展開指定を無視します。ただし,引数の型が整数型(enumを含む),またはポインタ型でサイズが同じ場合は,インライン展開を行います。

(e)

インライン展開する関数の引数は“可変個”にしない

引数が“可変個”の関数にインライン展開指定した場合,エラーも警告メッセージも出力せず,インライン展開指定を無視します。

(f)

“再帰関数”はインライン展開できない

自分自身を呼び出す“再帰関数”をインライン展開指定した場合,エラーも警告メッセージも出力せず,インライン展開指定を無視します。ただし,関数呼び出しが複数ネストし,そのネストした中に自分自身を呼び出すコードが存在した場合,インライン展開する場合があります。

(g)

展開対象関数のアドレスを介して呼び出しを行わない

展開対象関数のアドレスを介して呼び出しを行った場合,エラーも警告メッセージも出力せず,インライン展開指定を無視します。

(h)

“割り込みハンドラ”はインライン展開できない

#pragma interruptで記述された関数は“割り込みハンドラ”として認識されますが,この関数に対してインライン展開指定した場合,警告メッセージを出力して,インライン展開指定を無視します。

(i)

#pragma block_interrupt指定で関数内を割り込み禁止にすると,インライン展開できない

#pragma block_interruptで,関数内を割り込み禁止として宣言された関数に対してインライン展開指定した場合,警告メッセージを出力して,インライン展開指定を無視します。

(j)

#pragma inline_asm指定をした場合は#pragma inline指定を無視する

#pragma inline_asmで,アセンブリ記述関数をインライン展開指定した場合,警告メッセージを出力して,#pragma inline指定を無視します。

(k)

-Xmerge_filesを指定した場合は,同一ファイル内に記述していなくても展開される場合がある

(3)

インライン展開対象外関数

-Oinline オプション使用時に特定関数のインライン展開を抑止したい場合,インライン展開を抑止したい関数は,#pragma noinlineで指定します。

#pragma noinline (関数名[,関数名]...)

外側のかっこは省略可能です。

 

同一翻訳単位内で,同じ関数に対して#pragma inlineと#pragma noinlineを同時に指定するとエラーとなります。

(4)

オプション指定によるインライン展開動作の違いの例

#pragma inline指定とオプション指定による“インライン展開動作の違い”は,次のようになります。

-Oinline=0

エラーも警告メッセージも出力せず,インライン展開指定を無視します。

-Oinline=1

インライン展開指定した関数をインライン展開します。

-Oinline=2

インライン展開指定していない関数でも自動的にインライン展開します。

ただし,インライン展開対象外関数指定した関数は,インライン展開しません。

-Oinline=3

インライン展開指定していない関数でも自動的にインライン展開します。

ただし,インライン展開対象外関数指定した関数は,インライン展開しません。

(5)

インライン展開の例

インライン展開の例は,次のようになります。

-

Cソース

#pragma inline  (func)
static int      func(int a, int b)
{
        return  (a+b)/2;
}
int     x;
main()
{
        x = func (10, 20);
}

-

展開イメージ

int     x;
main()
{
        int     func_result;
{
        int     a_1 = 10, b_1 = 20;
        func_result = (a_1+b_1)/2;
}
        x = func_result;
}