The LLVM Compiler Infrastructure

by syoyo

nyaxt さんの日記で知りました。

The LLVM Compiler Infrastructure
http://llvm.org/

要は、VM の API + VM ランタイム + JIT コンパイラ + バイトコード後のプログラムの各種最適化処理を含んだもの、という感じでしょうか。

LLVM のバイトコードを出力するように変更を加えた gcc も提供されているため、

o C プログラム -> LLVM バイトコード -> インタプリタ実行
o C プログラム -> LLVM バイトコード -> JIT コンパイル

という一連の流れまでサポートしています。

Mac OS X の時期バージョン Leopard では、OpenGL(の実装)が LLVM 上で動くようになっています。
http://lists.cs.uiuc.edu/pipermail/llvmdev/2006-August/006492.html

OpenGL のプログラムでは、パラメータが多いため(フォグが有効か?など)、
あらかじめどの設定にも適した最適化バイナリを作っておくことが難しい。
ただ、一度設定されれば、あとはずっと不変の場合が多い。
そこで、一度 OpenGL プログラムを LLVM のバイトコードにしておき、
実行時に必要に応じて JIT コンパイルすることでパフォーマンスの改善を期待する、
とあります。

なるほど、OpenGL やシェーディング処理などはこのフレームワークに適していそうですね。

リンク先の一文にある specialization というのも、シェーダの世界では
MSR による先駆的な研究があります。

Brian Guenter, Todd B. Knoblock, Erik Ruf.
specializing shaders.
SIGGRAPH ’95. Pages: 343 – 350, 1995.
http://citeseer.ist.psu.edu/guenter95specializing.html

ここで言われている LLVM の specialization というのは、specializing shaders の
specialization とはもしかしたら違うのかもしれませんが、基本的には、
よく実行される部分をキャッシュしたりひとまとめにしておくことで処理の高速化をはかる、
というような意味合いだと思います。

シェーディングを LLVM 化するとどうなる?…

lucille のシェーダ言語方式は、

RenderMan SL -> C プログラム -> ネイティブコード

という形を取っていますが、
C コンパイラを LLVM バイトコードを出力するコンパイラに変更することで、
LLVM 上で動かすことができるでしょう。
もしくは、RenderMan SL から直接 LLVM バイトコード(LLVM アセンブラ)を
出力するパーサを書くのもよさそうです。

VM 化することの利点として、

o C シェーダにバグがあるとレンダラそのものが落ちる(mental ray のように)、ということはない
o バイトコード自体はクロスプラットフォームなので、プラットフォームごとにコンパイルする必要がなくなる

という点があげられると思います。

また、バイトコード後でも LLVM の各種最適化処理の恩恵を受けられる、というのもあります。
(自分で最適化処理のコードを書かなくて済むのは大きい。
LLVM はプラグインという形で自作の最適化処理を追加することもできるようです)

コンパイル前にコードを最適化するよりも、
実行時のシェーディング処理の動きをみて最適化処理をかけながら(Profile-Guided optimization)、
JIT コンパイルを行ったほうが効果が大きい場合は(OpenGL の場合と同じでシェーダもたぶんそうだと思う)、
VM 化によるパフォーマンス低下はネイティブコードよりもそれほど無いと考えています。

また、LLVM は VM 自体を拡張できるそうなので、
シェーダでよく使われる関数を VM のインストラクションに追加することで、
パフォーマンスの改善が期待できそうです。
(たとえば trace() インストラクションを追加するなど)

多くの RenderMan レンダラではシェーダ言語を中間言語方式で実装していますが、
このようにシェーダ言語を中間言語方式で動かすことの利点は、
このようにシェーディングに特化したインストラクションセット + クロスプラットフォーム
実行可能であると思うので、VM ランタイムを自分でわざわざ書かなくとも、
LLVM のインフラを使ってそれを実現することができるのは大きいと考えます(しかも JIT つき)。

問題は、LLVM 自体のライブラリがでかいことでしょうか。
気軽には自作のプログラムに LLVM をリンクさせたり、LLVM に拡張を追加するのは難しそうです。

API 利用のサンプルなどは多いので、理解はしやすそうではあります。

Advertisements