LLVMを使い始めました。
LLVMいいですね。ドキュメントが結構書きたかった物に近くて大分落ち込みました。
最初からLLVMやっておけば良かったとか思ったりしつつ、
イヤイヤ、64bitCPU触っておくのもやっぱり大切だったと思うよと思います。
とりあえず、LLVMで四則演算するコンパイラは作れました。
きつねさんのLLVMの本が欲しいなぁ。
とりあえず、JVMのバイトコードっぽいスタックマシン用コードがなぜか、いい感じに、
無限レジスタに変換されて動くってことが出来るようになりました。
え、こんなんで良いの?って思うんですけど、良いみたいです。
てことで、コレ拡張してけば、なんか、簡単にかなりいい感じのコンパイラが作れるってことがわかったのでした。
(* ASTを作る *) val ast = EBlock([ EPrint(ELong(1)), EPrint(EAdd(ELong(2), ELong(3))), EPrint(EMul(EAdd(ELong(2), ELong(3)),ELong(2)))]); (* コンパイル *) val codes = compile(ast); (* コード出力 *) emit("e.s", codes); exec("llc e.s"); (* アセンブル *) exec("llvm-gcc -m64 e.s.s -o e"); (* 実行 *) exec("./e");
mainはこんな感じでemitがllvm対応にするだけで行けます。
http://d.hatena.ne.jp/miura1729/20090123/1232707764
がとても参考になりました。ありがとうございます。そうか、@expstackを使えば良いのか!
ってなにその、expstackってことなんですけど、ソース読んでください。
val stack:string list ref = ref [] fun pushq(a:string): unit = ( stack := a :: !stack ) fun popq():string = ( case (!stack) of nil => raise (Error("stack is empty")) | x::xs => (stack := xs; x) )
これは、只のスタックですがとりあえず64bitオンリーなのでこれで実装で行けました。
出力コードが以下のようになってます。なんて楽なんだー。
.section __TEXT,__text,regular,pure_instructions .globl _main .align 4, 0x90 _main: ## @main ## BB#0: ## %entry pushq %rax movl $1, %edi callq _print_l movl $5, %edi callq _print_l movl $10, %edi callq _print_l xorl %eax, %eax popq %rdx ret .globl _print_l .align 4, 0x90 _print_l: ## @print_l ## BB#0: ## %entry pushq %rax movq %rdi, %rax movq %rax, (%rsp) leaq L_.str(%rip), %rdi movq %rax, %rsi xorb %al, %al callq _printf popq %rax ret .section __TEXT,__const L_.str: ## @.str .asciz "%ld\n" .subsections_via_symbols
定数式もさっぱり畳み込まれてます。すげぇな、LLVM。
LLVMバージョンD言語に今なら勝てるかもしれないので頑張ってみようっと!
llcのエラーはなんか、色付いたりするんだなぁ
ここからが本当の戦いなのかもしれません。