LoginSignup
4
4

More than 5 years have passed since last update.

gccのソースコードを読む アセンブリコード出力

Posted at

gccのアセンブリコード出力部分のソースコードを読んでみたので、分かったことを書いてみました。

まぁ、分かってみると、ただのテンプレートエンジンみたいな文字列処理をしているだけでしたよ。

gccはgithub https://github.com/gcc-mirror/gcc/
にある2018-04-26のソースコードを使いました。

final()

gccの アセンブリコード 出力はfinal.cのfinal()で行います。
final()に、引数としてコード生成済みのrtxと出力先のアセンブラファイルのファイルポインタを私ます。

 void
 final (rtx_insn *first, FILE *file, int optimize_p)

で実際の アセンブリコード出力部分はここから、もうちょっと奥に進んだ部分です。

final() -> final_1() -> final_scan_insn() -> final_scan_insn_1()

final_scan_insn_1()も長い関数なのですが、重要なのは3つの処理です。

  • insnのリストから、insnを一つ取り出し、そのinsnに対応するコード番号を取得する。
  • コード番号から、テンプレートを取得する。 
    • テンプレートにはコード番号に対応したアセンブラコード文字列が格納されています。このテンプレートは各アーキテクチャの*.mdファイルに記載されています。
  • テンプレートを使ってアセンブラ出力する。 (recog_data.operandはrecog_memoized()を呼ぶと設定されるグローバル変数で、中身はアセンブラ命令のオペランドです。)
    insn_code_number = recog_memoized (insn);
...
    /* Find the proper template for this insn.  */
    templ = get_insn_template (insn_code_number, insn);
...
    /* Output assembler code from the template.  */
    output_asm_insn (templ, recog_data.operand);

output_asm_insn()

output_asm_insn()内で実際にファイルにアセンブリコードを出力しています。

output_asm_insn()の最低限必要な部分だけ示すと下記になります。

void
output_asm_insn (const char *templ, rtx *operands)
{
  const char *p;
  int c;
  int oporder[MAX_RECOG_OPERANDS];
  char opoutput[MAX_RECOG_OPERANDS];
  int ops = 0;
...
  memset (opoutput, 0, sizeof opoutput);
  p = templ;
  putc ('\t', asm_out_file);

  while ((c = *p++))
    switch (c)
      {
...
      case '%':
    if (*p == '%'
        )
      {
...
      }
    /* % followed by a digit outputs an operand the default way.  */
    else if (ISDIGIT (*p))
      {
        unsigned long opnum;
        char *endptr;

        opnum = strtoul (p, &endptr, 10);
        if (this_is_asm_operands && opnum >= insn_noperands)
          output_operand_lossage ("operand number out of range");
        else
          output_operand (operands[opnum], 0);

        if (!opoutput[opnum])
          oporder[ops++] = opnum;
        opoutput[opnum] = 1;

        p = endptr;
        c = *p;
      }
...
    break;

      default:
    putc (c, asm_out_file);
      }

  putc ('\n', asm_out_file);
}

ざっくりとした処理の内容

  • \tを出力
  • テンプレートの文字列を1文字ずつ出力
  • テンプレートに含まれる%数字を、数字に対応するoperandに置き換えて出力
  • 改行を出力

この処理を例で示すと、templateがmovl %2, %0で、operandが%ebxNULL_RTX%ecxならば、

    movl  %ecx, %ebx

がアセンブリコード出力されます。

gccのソースコードを読みを再開してみたのですが、ソースコード全体の理解度が上がってきたので、以前よりは、だいぶ動作が追えるようになってきた気がする。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4