llvmrubyチュートリアル(その3)

その2で重要なことを書き忘れていました。LLVM::Module.new('hello')の戻り値のLLVM::Moduleクラスのインスタンスは重要です。llvmrubyで何かを行う場合はたいていこの戻り値に対してメソッドを呼び出す形になります。

続いて、実際に実行する命令を定義していきます。

ftype = Type.function(Type::Int32Ty, [P_CHAR])
printf = m.external_function('printf', ftype)

printfを使うよって宣言します。llvmrubyではCの関数も自由に呼べてしまいます。じゃあ、Rubyシステムの関数(rb_hash_newとか)も呼べるのかなというとこれも呼べます。Rubyシステムの関数を呼ぶことで色々面白いことができるのですがそれはまた次の機会で扱いたいと思います。
「ftype = Type.function(Type::Int32Ty, [P_CHAR])」でprintfの型を定義しています。Type.function(戻り値の型, 引数の型)は関数型を返すメソッドです。引数の型は普通複数なので配列で渡します。
で、そもそも型って何?って話ですが、書くことが一杯になっちゃうのでとりあえず(http://llvm.org/docs/LangRef.html#typesystem)にありますってことでお茶を濁します。ここでは必要最低限のことだけを書きます。

Type::Int32Tyってのは32bitの整数です。察しのいい人ならInt8TyとかInt16Tyとかあるんだろうなと思われると思いますがあります。Int1Tyってあるのかなって言うとこれもあります。しかも、重要です。なぜならこれはBoolean型になっていて条件付ジャンプ命令の条件はInt1Tyで無いといけないからです。じゃあ、Int65536Tyでbignumだって考えた方、これもLLVMでは有りみたいです。でもllvmrubyでは対応していないと思います。

そんなこんなで、「Type.function(Type::Int32Ty, [P_CHAR])」でprintfの型を定義しています。これprintfの型ちゃうじゃんって思われた方、その通りなのですがprintfの型を厳密に定義すると面倒なので手抜きしています。

次に「m.external_function('printf', ftype)」でprintfを外から引っ張ってきて使うよって宣言します。戻り値は後でcall命令などを生成するときに使いますので大切に保存しておいてください。存在しない関数を使うよって宣言するとエラーになります。

そういうことで、2行の説明だけで今回は終わってしまいました。

つづく