LLVM 2.3 を動かしてみる
なにやら @/id:TAKESAKO さんから 「8/30 の LL Future でパネルディスカッション や ら な い か ?」 (もちろん,実際はもっと非常に丁寧な文章です) というお誘いを受け,ホイホイ快諾してしまったら 「なにやら llvm-gcc を使ってブラウザ上で C とか Python のコードを動かすという構想があるそう.というわけで 『gcc と LLVM が紡ぎだす未来 〜ブラウザで言語処理系を無理やり動かして未来を先取りする〜』 みたいなことをテーマに,gcc フロントエンドとか LLVM とか AVM2 とかと LL の未来についてネタふりしてパネラーの皆さんと楽しく議論してください,超期待してます」 と,いきなりものすごいプレッシャーが.
Running C and Python Code on The Web
C言語をブラウザで実行、Ruby/Python/Perlも然り
なんと交通費まで出していただけることになったので,せめて交通費 + チケット代ぶんぐらいの働きはしないと申し訳なさすぎる.「LLVM は初心者ですが頑張ります」
というわけで,まずは hello, world.
YT さんのブログ連載を読んでいると,LLVM イマイチすぎるなという印象を禁じえなかったわけですが (もちろん,LLVM をターゲットとする独自言語のコンパイラを一から書こうとか変なことを考えなければ,もう十分に実用レベルの技術になってます.COINS とかもそうなんですけど,C とか,公式に対応している以外の言語のコンパイラを書こうとすると,とたんにあの機能も足りない,この機能は未実装かッッ!となるのですが…)
最近,最新版の LLVM 2.3 がリリースされたようなので,改善に期待しつつのんびり見ていきましょう.
とりあえず,公式サイトから Windows mingw 用バイナリを落として解凍 (以下,MSYS + MinGW 環境)
http://llvm.org/releases/2.3/llvm-2.3-x86-mingw32.tar.bz2
Java で言うところの jasmin (バイトコードアセンブラ) が llvm-as.exe で,java (VM + JIT インタプリタ) が lli.exe,javap (逆アセンブラ) が llvm-dis.exe なんでしょうか.他は gcj (GNU Compiler for Java) みたいに,バイトコードからアセンブラを生成したりするときのツールチェインみたいです.
とりあえず YT さんところの hello-world-llvm (ネタ元は既にリンク切れ) を実行してみましょう.
あらら.たぶん C ランタイムへの依存性とか書いてなかったのが悪いのかな.
一回 llvm-gcc も download して,C から llvm コードを吐かせてみた方がよさそうかも.
とりあえず,ネイティブコードまで落とさなければ実行可能みたいですね.puts が呼べているのは,lli.exe が何やら勝手に libc の関数を呼び出しているらしい.
llvm-gcc を使えば,普通に実行ファイル作れますね.
llvm のバイトコードも吐かせることができて,こんな感じになります.
Running C and Python Code on The Web
C言語をブラウザで実行、Ruby/Python/Perlも然り
なんと交通費まで出していただけることになったので,せめて交通費 + チケット代ぶんぐらいの働きはしないと申し訳なさすぎる.「LLVM は初心者ですが頑張ります」
というわけで,まずは hello, world.
YT さんのブログ連載を読んでいると,LLVM イマイチすぎるなという印象を禁じえなかったわけですが (もちろん,LLVM をターゲットとする独自言語のコンパイラを一から書こうとか変なことを考えなければ,もう十分に実用レベルの技術になってます.COINS とかもそうなんですけど,C とか,公式に対応している以外の言語のコンパイラを書こうとすると,とたんにあの機能も足りない,この機能は未実装かッッ!となるのですが…)
最近,最新版の LLVM 2.3 がリリースされたようなので,改善に期待しつつのんびり見ていきましょう.
とりあえず,公式サイトから Windows mingw 用バイナリを落として解凍 (以下,MSYS + MinGW 環境)
http://llvm.org/releases/2.3/llvm-2.3-x86-mingw32.tar.bz2
aloha@LENOVO-A41D2048 /c/tmp
$ tar jxvf llvm-2.3-x86-mingw32.tar.bz2
llvm-2.3/
llvm-2.3/bin/
llvm-2.3/bin/bugpoint.exe
llvm-2.3/bin/fpcmp.exe
llvm-2.3/bin/llc.exe
llvm-2.3/bin/lli.exe
llvm-2.3/bin/llvm-ar.exe
llvm-2.3/bin/llvm-as.exe
llvm-2.3/bin/llvm-bcanalyzer.exe
llvm-2.3/bin/llvm-db.exe
llvm-2.3/bin/llvm-dis.exe
llvm-2.3/bin/llvm-extract.exe
llvm-2.3/bin/llvm-ld.exe
llvm-2.3/bin/llvm-link.exe
llvm-2.3/bin/llvm-nm.exe
llvm-2.3/bin/llvm-PerfectShuffle.exe
llvm-2.3/bin/llvm-prof.exe
llvm-2.3/bin/llvm-ranlib.exe
llvm-2.3/bin/llvm-stub.exe
llvm-2.3/bin/llvmc2.exe
llvm-2.3/bin/opt.exe
llvm-2.3/bin/tblgen.exe
Java で言うところの jasmin (バイトコードアセンブラ) が llvm-as.exe で,java (VM + JIT インタプリタ) が lli.exe,javap (逆アセンブラ) が llvm-dis.exe なんでしょうか.他は gcj (GNU Compiler for Java) みたいに,バイトコードからアセンブラを生成したりするときのツールチェインみたいです.
とりあえず YT さんところの hello-world-llvm (ネタ元は既にリンク切れ) を実行してみましょう.
aloha@LENOVO-A41D2048 /c/tmp/llvm-2.3/test
$ cat test.ll
@.LC0 = internal constant [13 x i8] c"Hello world!\00"
declare i32 @puts(i8 *)
define i32 @main() {
%cast210 = getelementptr [13 x i8]* @.LC0, i64 0, i64 0
call i32 @puts(i8 * %cast210)
ret i32 0
}
$ ../bin/llvm-as.exe test.ll
$ ls
test.bc test.ll test.ll~
$ ../bin/llvm-dis.exe test.bc
c:\tmp\llvm-2.3\bin\llvm-dis.exe: error opening 'test.ll': file exists! Sending to standard output.
; ModuleID = 'test.bc'
@.LC0 = internal constant [13 x i8] c"Hello world!\00" ; <[13 x i8]*> [#uses=1]
declare i32 @puts(i8*)
define i32 @main() {
%cast210 = getelementptr [13 x i8]* @.LC0, i64 0, i64 0 ;[#uses=1]
call i32 @puts( i8* %cast210 ) ;:1 [#uses=0]
ret i32 0
}
$ ../bin/lli.exe test.bc
Hello world!
$ ../bin/llc.exe test.bc
$ ls
test.bc test.ll test.ll~ test.s
$ cat test.s
.text
.align 16
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
Llabel1:
movl %esp, %ebp
Llabel2:
subl $8, %esp
call ___main
movl $_.LC0, (%esp)
call _puts
xorl %eax, %eax
addl $8, %esp
popl %ebp
ret
.data
_.LC0: # .LC0
.asciz "Hello world!"
.def _puts; .scl 2; .type 32; .endef
$ gcc test.s
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
あらら.たぶん C ランタイムへの依存性とか書いてなかったのが悪いのかな.
一回 llvm-gcc も download して,C から llvm コードを吐かせてみた方がよさそうかも.
とりあえず,ネイティブコードまで落とさなければ実行可能みたいですね.puts が呼べているのは,lli.exe が何やら勝手に libc の関数を呼び出しているらしい.
llvm-gcc を使えば,普通に実行ファイル作れますね.
$ tar jxvf llvm-gcc4.2-2.3-x86-mingw32.tar.bz2
$ cat test.c
#include<stdio.h>
int main() {
puts("hello, world!");
return 0;
}
$ ../bin/llvm-gcc.exe test.c
$ ls
a.exe test.c test.c~
$ ./a.exe
hello, world!
llvm のバイトコードも吐かせることができて,こんな感じになります.
$ ../bin/llvm-gcc.exe -emit-llvm -S test.c
$ cat test.s
; ModuleID = 'test.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-mingw32"
@.str = internal constant [14 x i8] c"hello, world!\00" ; <[14 x i8]*> [#uses=1]
define i32 @main() nounwind {
entry:
%retval = alloca i32 ; <i32*> [#uses=2]
%tmp = alloca i32 ; <i32*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
%tmp1 = call i32 @puts( i8* getelementptr ([14 x i8]* @.str, i32 0, i32 0) ) nounwind ; <i32> [#uses=0]
store i32 0, i32* %tmp, align 4
%tmp2 = load i32* %tmp, align 4 ; <i32> [#uses=1]
store i32 %tmp2, i32* %retval, align 4
br label %return
return: ; preds = %entry
%retval3 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval3
}
declare i32 @puts(i8*)
