まずは
Hello Worldなんだろうなあ、やっぱり。最初にやるのは1+1主義者としては釈然としないが……実際に何かを試そうとしたとき最初に見かけるサンプルはHelo Worldが圧倒的に多いので、1+1のソースを作成する敷居を越えるためにHello Worldを利用しなければならないこの現実にどう立ち向かえばいいのだろうか。
大袈裟に云い回そうとしても所詮Hello Worldなので無理があります。
http://weblog.metareal.org/2007/07/22/hello-world-llvm/
@.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 }
...>llvm-as hello.ll ...>llvm-dis hello.bc llvm-dis: error opening 'hello.ll': file exists! Sending to standard output. ; ModuleID = 'hello.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 } ...>lli hello.bc WARNING: Program called __main but was not linked to libcrtend.a. This probably won't hurt anything unless the program is written in C++. Hello world!
なんかビルドに失敗しているっぽい警告が出てますが……MinGWランタイムにlibcrtend.aなんて無いぞ。
それは無視して、putsが呼べているのは、lliはlibcを使うためらしいです。
だからこんなのはエラーになるはず。
@.LC0 = internal constant [13 x i8] c"Hello world!\00" declare coldcc i32 @_MessageBoxA (i32, i8 *, i8 *, i32) define i32 @main() { %cast210 = getelementptr [13 x i8]* @.LC0, i64 0, i64 0 call coldcc i32 @_MessageBoxA (i32 0, i8 * %cast210, i8 * %cast210, i32 0) ret i32 0 }
...>llvm-as winhello.ll ...>lli winhello.bc Assertion failed: 0 && "Unsupported calling convention", file X86ISelLowering.cp p, line 3517 abnormal program termination
なんか思ってたのと違うエラー出た。
えー、なに、coldccってstdcallの事じゃないの!?
まあ復帰後に暴走するだけで、関数自体はcdeclでも呼べるよな、とcoldccを削除してみた。
...>llvm-as -f winhello.ll ...>lli winhello.bc ERROR: Program used external function '_MessageBoxA' which could not be resolved ! abnormal program termination
よし予想通り。
実はMinGWでは_MessageBoxA@16なんですけどね。@がLLVMで使われているもので、識別子に使えないのです。こんな調子で実用になるのかと一瞬不安がよぎりましたが忘れます。
とりあえず1+1。
@.LC0 = internal constant [4 x i8] c"%d\0a\00" declare i32 @printf(i8 *, i32) define i32 @main() { %cast210 = getelementptr [4 x i8]* @.LC0, i64 0, i64 0 %z = add i32 1, 1 call i32 @printf(i8 * %cast210, i32 %z) ret i32 0 }
...>llvm-as "1+1.ll" ...>lli "1+1.bc" WARNING: Program called __main but was not linked to libcrtend.a. This probably won't hurt anything unless the program is written in C++. 2
どんな機械語になってるのかな……。
...>llc "1+1.bc": CommandLine Error: Argument 'mattr' defined more than once! : CommandLine Error: Argument 'mcpu' defined more than once! : CommandLine Error: Argument 'march' defined more than once! llc: CommandLine Error: Argument 'mattr' defined more than once! llc: CommandLine Error: Argument 'mcpu' defined more than once! llc: CommandLine Error: Argument 'march' defined more than once!
警告いっぱい出た。
.text .align 16 .globl _main .def _main; .scl 2; .type 32; .endef _main: subl $12, %esp movl %ebp, 8(%esp) leal 8(%esp), %ebp andl $4294967280, %esp movl $16, %eax call __alloca call ___main fnstcw -2(%ebp) movb $2, -1(%ebp) fldcw -2(%ebp) subl $16, %esp movl $2, 4(%esp) movl $_.LC0, (%esp) call _printf addl $16, %esp xorl %eax, %eax movl %ebp, %esp popl %ebp ret .data _.LC0: # .LC0 .asciz "%d\n" .def _printf; .scl 2; .type 32; .endef
……大丈夫か、大丈夫なのか?LLVM?
FPUのコントロールワードを設定しているのはmainだから大目に見るとして、定数値でallocaとか最適化を謳うVMとして正気なのか?その後もmovl %ebp, %espしてるならaddl $16, %esp要らないはずですし。-O5付けても変化なし。optなんかもbcファイルレベルの最適化をして、機械語の生成には関わってないっぽいし。
やっぱビルド間違えてるかなあ……。
http://kikyou.info/diary/?200605なんか読んでも、実行速度はgccの3割増しの代わりに、大局的な最適化はやたら凄いらしいということが伝わってきますが、バックエンドとしては、スタックの使い方やレジスタ割り付けなどの中間コードより上ではどう頑張っても指定できない部分が上手い方が魅力がありますよね……。私だけ?
1+1程度しか試してないのに語るなって?そりゃごもっともですハイ。
ところで、LLVMについては、提灯記事はいっぱいあっても、売りのはずの後からの最適化をやっている例が見つからないような気がするのは何故だ。みんなそんなにプロファイリングを取りながらの実行は嫌なのか?私は嫌です。仮に、Firefoxとかただでさえ遅いのが、最適化のためにプロファイリングしながら実行していると聞いたら、反射的にそんな余計な仕組み入れずに軽く作ってくれと思ってしまう気がする。というよりnot implementedなだけかもしれない。not implementedでは無かった。
http://llvm.cs.uiuc.edu/viewvc/llvm-project/llvm/trunk/utils/profile.pl?view=markup&sortby=rev
profile_rt.soというファイルが必要らしい。
恐らくLinuxでビルドしたら生成されるんだろう……。恐ろしいことに、profile_rt.soに言及した日本語のページがひとつも無いあたり、如何にLLVMが実際使われていないかを(ry
1+1程度しか試してないのに語るなって?そりゃごもっともですハイ。
とりあえず今のところLLVMの一番の利点は、一応libLLVM*.aはありますがそんなもの使わなくても、テキストファイルとして.llを出力してしまえば、内部なんか何も知らなくてもコンパイラが作れてしまうことですね。gccのフロントエンドはMake-lang.inを書くところからして気が遠くなるからなあ……。確かgccは思惑があってわざわざ中間コードを扱えなくしてるんでしたっけ。ビルドにかかる時間を思えば、トライアンドエラーなんてできないし。その点テキストなら、極端な話、正規表現の羅列だけでコンパイラが書けるわけで。
……あろはさんに怒られそうです。gccのフロントエンド作る日記、楽しみに読ませていただいてますよっ。