世の中間言語を集める
個人的なプロジェクトとして、コンパイラの中間言語の設計に取り組んでいる。 今できてるのはラムダ計算に毛が生えてコード生成に向いてるセマンティクスを持つみたいなやつで、『星を継ぐもの』に登場するコリエルというキャラクターから名前をもらってkorielと呼んでいる。
まだまだ未完成で、Haskellで扱うためのライブラリはできたが、ドキュメントもなければバイナリ表現やテキスト表現もない。
今後korielの開発を進めるに当たって、他の「中間言語」について調べてみようと思った。 プログラミング言語については良く知っているが、言語処理系の中間表現についてはあまり詳しくないからだ。
中間表現と中間言語
中間言語っぽいものを表す言葉は二つある。 「中間表現」"Intermediate representation"と「中間言語」"Intermediate language"だ。 これは混乱を招くので、ちょっと整理しておきたい。
まず、中間表現とは、コンパイラやVM*1でソースコードを表現するためのデータ構造だ。単純な文字列ではなく、木構造(ASTとか)やグラフ構造(モジュールの依存関係グラフとか)のように、コンパイラやVMにとって都合のいいデータ構造が使われている。
中間表現の中でも、プログラムによって読み書きできるコードの形になっているものを中間言語と呼ぶ。
An IR may take one of several forms: an in-memory data structure, or a special tuple- or stack-based code readable by the program.[3] In the latter case it is also called an intermediate language. Intermediate representation - Wikipedia
C
Cは割と良く使われる中間言語だ。もちろん、Cは汎用プログラミング言語として設計された。しかし、他の言語に比べてアセンブリに近いこと、多くのOS、CPUの上で動作する性能の良い処理系が存在していることから、中間言語として採用されることが多い。
言語Aのコンパイラを作るときに、いきなりA to assemblyなコンパイラを書くのは骨が折れる。そこで、A to Cなコンパイラを書き、あとのことはCコンパイラに任せる、というスタイルがある。
他にも、部分的にコードをCにコンパイルすることで高速化をはかることもある。 Cythonはその好例だ。
LLVM IR
LLVM*2はコンパイラのさまざまな機能を提供するツールチェーンだ。 もちろん中間言語もあって、LLVM IRという。 Clang, Rustなど多くのコンパイラで使われている。
Kotlin/Native*3というプロジェクトでは、KotlinをJVMを介さずネイティブなバイナリにコンパイルするが、ここでもLLVMが使われている。
他にも非常に多くのプロジェクトで使われている、デファクトスタンダード的存在である。
SSAをベースとしており、Cのより中間言語向きなバージョンといった雰囲気。
共通中間言語 (CIL)
LLVMがデファクトスタンダードである一方で、CILはもっとも「名前は聞いたことがある」中間言語だろう。
C#で使われている中間言語で、.NET対応言語はこの中間言語にコンパイルされ、アプリケーションやライブラリはこの中間言語の状態で配布される。 ユーザーの環境にインストールされた.NETのVMがこれを解釈したりJITコンパイルしながら実行される。
パッと調べたところ、例えば以下の記事が詳しい。
スタックベースで、オブジェクト指向をサポートするための言語機能が充実している。
JVM byte code
JVMはおそらく(Oracleを信じるなら)30億のデバイスにインストールされている。 JVMが実行するJVM byte codeもそれなりに良く使われる中間言語で、Scala、Kotlin、Groovyなど、JVMで動く言語も多い。RubyにはJVMで走るように実装されたJRubyという実装がある。
これもCILと同様に、スタックベースの言語であり、オブジェクト指向をサポートするための言語機能が充実している。
TODO(追記予定)
p-code
Go asm
論文:Compiling with Continuations, or without? Whatever
Kage
- Ebitenのシェーダー言語。Goを中間表現的に使ってるっぽい?
- 他にもシェーダー言語については要調査 ebiten.org