Scheme Compiler の勉強(42) - 変換、変換!
- 自作コンパイラもどきは、 3.11 を飛ばして 3.12 Assignment, 3.13 Extending Syntax あたりを行った。これでかなりコンパイラらしくなってきた。
- 3.11 Complex Constants は説明がわからないのでスキップ。"An Incremental Approach to Compiler Construction"は論文であって教科書ではないので、あちこち不親切。
- Assignment Conversion で set! が導入されたが、何でも更新可能な変数と見なしているので無駄が多く、今まで動いていた fib が動かなくなった。そのうち本当に set! されるときだけ変換すればいい、はず。
- S-式を変換する操作が多い。マクロの入門者には、非効率でも何でもいいので「let* を let の入れ子に変換するプログラム」を書くことをお勧め。これを書いてちゃんと変換漏れが無いようにできると、単純な式変形を行うマクロにはたぶん困らない。util.match も一緒に慣れるとベター。
さて、3.14 Symbols, Libraries, and Separate Compilation を進めている。既に一部の関数は LLVM 直書きではなく scheme で書いているので、一部は先取りしていると言っても良い。シンボルに関する説明は例によって少なく、分からない。
わたしの理解は、car とか add1 とかのプリミティブを全て runtime に移す。今までは全て命令列に変換していたものが、LLVM レベルの関数になり、call で呼び出す形になる。しかし小さいプリミティブはインライン化されて欲しい。
構成。
- stst.ll, stst.bc - scheme プログラムがコンパイルされた LLVM IRプログラムと、llvm-as でコンパイルされた bc(bit code) ファイル。
- runtime.bc - コンパイル済みの LLVM bc ファイル。ここに car とか cdr とかを記述する。
- stst.rt.bc runtime と link (llvm-link)されたプログラム。
LLVM の関数定義には alwaysinline オプションがあるのでこれを使ってみた。
- リンク前の stst.bc を最適化しても add1 はインライン化されない(当たり前)。また、llvm-link 自体は最適化はしていなそう(自信無し)。
- stst.rt.bc(リンク結果)を opt -always-inline で最適化するとインライン化された。(正確にはインライン化された結果さらに定数になってしまった)
- noinline を指定するとインライン化されない。
満足の行く内容なので、プリミティブをランタイムに移す作業を続けよう。