4.2.4.2 アセンブラ命令の記述

CC-RHでは,Cソース・プログラム中にアセンブラ命令が記述できます。

(1)

#pragma指令

アセンブラ命令を埋め込む#pragma 指令には,#pragma inline_asmがあります。

これは関数そのものをアセンブラ命令のみとみなして,呼び出し箇所にインライン展開します。

#pragma inline_asm ( 関数指定 [, 関数指定]... )
  関数指定 : 関数名 [(size=数値)]

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

 

#pragma inline_asm で宣言したアセンブリ記述関数をインライン展開します。

アセンブラ埋め込みインライン関数の呼び出し規則は通常関数の呼び出し規則と同様です。

(size=数値)を指定しても,コンパイル結果には影響しません。

 

-

Cソース

#pragma inline_asm      func_add
static int      func_add(int a, int b){
        add     r6, r7
        mov     r7, r10
}
void func(int *p){
        *p = func_add(10,20);
}

-

出力コード

_func:
prepare r20, 0
mov     r6, r20
movea   0x0014, r0, r7
mov     10, r6
add     r6, r7
mov     r7, r10

(2)

#pragma inline_asm使用時の注意事項

-

#pragma inline_asm は,関数本体の定義の前に指定してください。

-

#pragma inline_asm で指定した関数に対しても外部定義を生成します。

-

アセンブラ埋め込みインライン関数内で関数の出入口で保証するレジスタを使用する場合は,アセンブラ埋め込みインライン関数の先頭と最後でこれらのレジスタの退避/復帰が必要です。

-

コンパイラは#pragma inline_asm 内に書いた文字列を,チェックも変更もなしで,そのままアセンブラに渡します。

-

(size=数値)で指定する数値は,正の整数定数のみです。数値が浮動小数点数,または負の整数定数の場合,エラーとなります。

-

static 関数に#pragma inline_asmを指定した場合,関数定義はインライン展開後に削除されます。

-

アセンブリ記述は,プリプロセッサの処理対象となります。このため,アセンブリ言語で使用される命令やレジスタと同じ名前のマクロ(例: "MOV"や"r5"など)を#defineでマクロ定義する場合は注意してください。

-

RH850 のアセンブリ言語は,#で始まるコメントを使用できますが,この#コメントを使うと,プリプロセッサは前処理指令と解釈するため,アセンブリ記述関数内では#コメントを使わないでください。

-

#pragma inline_asmは,次の#pragma指令とは同時に指定できません。

#pragma inline_asm,#pragma inline,#pragma noinline,#pragma interrupt,

#pragma block_interrupt,#pragma stack_protector

-

アセンブリ記述関数内にラベルを書くと,インライン展開の数だけ同一名のラベルが作られてしまいます。

この場合は,次のいずれかの方法で対処してください。

-

アセンブリ記述のローカル・ラベルを使ってください。ローカル・ラベルはアセンブリ・ソースでは同一名ですが,アセンブラが自動的に別名に変換します。

-

ラベルは1箇所のみに展開されるように記述してください。

-

アセンブリ記述関数を同じソース・ファイル内から呼び出す場合は,アセンブリ記述関数定義にstaticを指定し,1か所のみからアセンブリ記述関数を呼び出してください。また,アセンブリ記述関数のアドレスを取得しないでください。

-

アセンブリ記述関数を同じソース・ファイル内から呼び出さない場合は,アセンブリ記述関数を外部関数としてください。

出力コード例を次に示します。

-

Cソース

#pragma inline_asm func1
static void func1(void) /* ラベル定義を含むinline_asm指定関数を */
{                       /* 同一ファイルから呼び出す場合は,static関数とする */
  .PUBLIC _label1
  add 1, r6
_label1:
  add -1, r6
}
 
void main(void) {
  func1();            /* ラベル定義を含むinline_asm指定関数を呼び出す */
}
 
#pragma inline_asm func2
void func2(void)      /* ラベル定義を含むinline_asm指定関数を */
{                     /* 同一ファイルから呼び出さない場合は,外部関数とする */
  .PUBLIC _label2
  add -1, r6
_label2:
  add 1, r6
}

-

出力アセンブリ・ソース

_main:
  .stack _main = 0
  ._line_top inline_asm
  .PUBLIC _label1
  add 1, r6
_label1:
  add -1, r6
  ._line_end inline_asm
  jmp [r31]
 
_func2:
  ._line_top inline_asm
  .PUBLIC _label2
  add -1, r6
_label2:
  add 1, r6
  ._line_end inline_asm
  jmp [r31]