技術

3.5. ドライバの変更と結論

LLVMによるプログラミング言語の実装チュートリアル日本語訳
第3章 万華鏡: LLVM IRコードの生成
第5節 ドライバの変更と結論

今のところ、LLVMに対するコード生成は、きれいなIRコールを見ることが出来るという事以外は、実際にはあまり役立たない。
Codegenメソッドに”HandleDefinition”や”HandleExtern”などの関数呼び出しを追加すると、LLVM IRのダンプが見れる。
これは、LLVM IRを簡単な関数で見れる良い方法である。
例えばその出力は以下のようになる。

ready> 4+5;
Read top-level expression:
define double @0() {
entry:
  ret double 9.000000e+00
}

構文解析器が、トップレベルの式をどのように匿名関数に変換するかに注意。
これは、次の章においてJITサポートを追加するときに役立つだろう。
コードは、そっくりそのまま翻訳され、IRBuilderによる簡単な定数の畳み込みを除いて最適化が行われていないことにも注意。
最適化機能は次の章で追加する。

ready> def foo(a b) a*a + 2*a*b + b*b;
Read function definition:
define double @foo(double %a, double %b) {
entry:
  %multmp = fmul double %a, %a
  %multmp1 = fmul double 2.000000e+00, %a
  %multmp2 = fmul double %multmp1, %b
  %addtmp = fadd double %multmp, %multmp2
  %multmp3 = fmul double %b, %b
  %addtmp4 = fadd double %addtmp, %multmp3
  ret double %addtmp4
}

これは、幾つかの簡単な計算を示している。
命令を生成するために使用したLLVM Builderの呼び出しとの著しい類似性に注目。

ready> def bar(a) foo(a, 4.0) + bar(31337);
Read function definition:
define double @bar(double %a) {
entry:
  %calltmp = call double @foo(double %a, double 4.000000e+00)
  %calltmp1 = call double @bar(double 3.133700e+04)
  %addtmp = fadd double %calltmp, %calltmp1
  ret double %addtmp
}

これは関数呼び出しを示している。
この関数を呼び出したとしたら、実行に長い時間がかかるであろう事に注意。
再帰を便利にするため、この先の章で、条件付き制御フローを追加する予定である。

ready> extern cos(x);
Read extern:
declare double @cos(double)

ready> cos(1.234);
Read top-level expression:
define double @1() {
entry:
  %calltmp = call double @cos(double 1.234000e+00)
  ret double %calltmp
}

これは、libmの”cos”関数のためのextern宣言と、その呼び出しを示している。

ready> ^D
; ModuleID = 'my cool jit'

define double @0() {
entry:
  %addtmp = fadd double 4.000000e+00, 5.000000e+00
  ret double %addtmp
}

define double @foo(double %a, double %b) {
entry:
  %multmp = fmul double %a, %a
  %multmp1 = fmul double 2.000000e+00, %a
  %multmp2 = fmul double %multmp1, %b
  %addtmp = fadd double %multmp, %multmp2
  %multmp3 = fmul double %b, %b
  %addtmp4 = fadd double %addtmp, %multmp3
  ret double %addtmp4
}

define double @bar(double %a) {
entry:
  %calltmp = call double @foo(double %a, double 4.000000e+00)
  %calltmp1 = call double @bar(double 3.133700e+04)
  %addtmp = fadd double %calltmp, %calltmp1
  ret double %addtmp
}

declare double @cos(double)

define double @1() {
entry:
  %calltmp = call double @cos(double 1.234000e+00)
  ret double %calltmp
}

入力中のデモを終了するとき、生成されたモジュール全体のIRのダンプを出力する。
お互いに参照しあってる全ての関数を含む全体が見れるのが分かると思う。
これで万華鏡チュートリアルの第3章は終わりである。
次は、実際にコードを実行できるようにするために、JITコード生成と最適化サポートの追加について説明する。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください