開発日記

JITコンパイラの開発日記だった

RuJITの動かし方

Ruby向けJITコンパイラ RuJIT Advent Calendar 3日目です.

本稿では,RuJITのビルド方法と動かし方について説明します.
本稿ではOSX環境を前提に話を進めますが,Linux環境でも同じように動作すると思います.

ビルドに必要なソフトウェア

RuJITはCRubyのVM部分を拡張する形で実装されています.
RuJITのビルドにはCRubyのビルドで必要な以下のソフトウェアがインストールされている必要があります.

RuJITのソースコード取得

RuJITのソースコードは以下のgithubのページから取得することができます.

git clone https://github.com/imasahiro/rujit.git rujit

RuJITのビルド方法

RuJITのビルドはCRubyのビルド方法と同じくconfigure, makeを使って行います.

$ cd /path/to/rujit_src_dir
$ autoreconf -ivf # 必要に応じて
$ cd /path/to/rujit_build_dir
$ /path/to/rujit_src_dir/configure
$ make miniruby

生成されたminirubyバイナリがRuJITのバイナリとなります.(わかりにくいですね.)

RuJITのオプション

RuJITはRuJITをコンパイルする際に設定可能な定数をいくつか用意しています.その中から有用なオプションについて説明したいと思います.

チューニング用途

#define LIR_MIN_TRACE_LENGTH 8 /* min length of instructions jit compile */
#define LIR_MAX_TRACE_LENGTH 1024 /* max length of instructions jit compile */


コンパイル対象となったYARVバイトコード列はLIR命令の長さでLIR_MIN_TRACE_LENGTH <= n <= LIR_MAX_TRACE_LENGTHの時,機械語コンパイルされます.

 

また,以下のオプションによって,トレースがどの程度頻繁に実行されたらコンパイル対象とするかが設定できます.

#define HOT_TRACE_THRESHOLD 2
#define BLACKLIST_TRACE_THRESHOLD 8

デバッグ用途

トレースされたYARVバイトコードの出力
#define DUMP_INST 0 /* 0:disable, 1:dump */

生成されたLIRの出力

#define DUMP_LIR 1 /* 0:disable, 1:dump */

最適化のon/off

LIRに適応する各種最適化パスのon/offがコントロールできるようになっています.
#define LIR_OPT_PEEPHOLE_OPTIMIZATION 1
#define LIR_OPT_CONSTANT_FOLDING 1
#define LIR_OPT_DEAD_CODE_ELIMINATION 1
#define LIR_OPT_INST_COMBINE 1
#define LIR_OPT_INST_COMBINE_STACK_OP 1
#define LIR_OPT_LOOP_INVARIANT_CODE_MOTION 0
#define LIR_OPT_ESCAPE_ANALYSIS 1
#define LIR_OPT_RANGE_ANALYSIS 1
#define LIR_OPT_BLOCK_GUARD_MOTION 1

コード生成器の切り替え

RuJITはバックエンドとして複数のコード生成器を切り替え可能なように設計されています.12月の段階でバックエンドとしてCコンパイラを使うCGENとLLVMコンパイラフレームワークを利用するLLVMの2種類が用意されています.(なおLLVMバックエンドは実験的実装なため非公開となっています.)
以下のオプションではバックエンドを切り替えることが可能となっています.
#define USE_CGEN 1
//#define USE_LLVM 1

まとめ

本稿では,RuJITのビルド方法と動かし方について説明しました.明日はサンプルコードを用いながらRubyプログラムがどのように機械語コンパイルされるかを紹介したいと思います.