アセンブラ出力練習ソース
最近は、時間もないので、1日に1回くらい、Ifまでのアセンブラ出力部を空で書けるように練習してみてます。
以下が、昼休みに書いたアセンブラ出力部のプログラムです。
作成順、1、hello world的プログラムを書きます。
2、test.cという、printIntとprintIntを呼び出す、main関数を書きます。
3、gcc test.c -Sでコンパイルします。
4、test.sをコピペして、test.sを出力するプログラムを書きます。
5、gccを内部で実行するように変更します。
6、mov,addを実行出来るだけのデータ構造を作ってコンパイルするプログラムを作ります。
7、if文を実行するだけのプログラムを書く
という、7段階で作成しています。
7の段階はなれるまでは複数段階にわけて書いています。
30分〜40分かかっているので、これを10分くらいで書けるとうれしいんですけど、無理か?
アセンブラのソースをいかに速く書くかがポイントだよなぁとか思ってる今日この頃です。
8、関数がコンパイル出来る
9、末尾再帰最適化できる
10、浮動小数点が扱える
等と発展していきたいのですが、まだしばらく時間が必要です。
これはバックエンドの根元を確実にして、自信を身につけるいい練習になると思います。
みなさんも是非やってみてください。(といっても、手順を細かく書いてないですけど)
この手順を細かく書くのはまだまだ先になると思います。
import java.io._ object run { var p = new PrintWriter(new BufferedWriter(new FileWriter("run.s"))) def asm(a:String) { p.println(a) } def emit(e:T) { asm("\t.cstring") asm("LC0:") asm("\t.ascii \"%d\\12\\0\"") asm("\t.text") asm(".globl _printInt") asm("_printInt:") asm("\tpushq\t%rbp") asm("\tmovq\t%rsp, %rbp") asm("\tsubq\t$16, %rsp") asm("\tmovl\t%edi, -4(%rbp)") asm("\tmovl\t-4(%rbp), %esi") asm("\tleaq\tLC0(%rip), %rdi") asm("\tmovl\t$0, %eax") asm("\tcall\t_printf") asm("\tleave") asm("\tret") asm(".globl _main") asm("_main:") asm("\tpushq\t%rbp") asm("\tmovq\t%rsp, %rbp") g("%edi", e) asm("\tcall\t_printInt") asm("\tleave") asm("\tret") } def main(argv:Array[String]) { emit(Let("%edi",Mov("$3"), Let("%edi",Add("%edi","$5"), Ans(IfEq("%edi","$9",Ans(Mov("$100")),Ans(Mov("$200"))))))) p.close() exec("gcc -m64 -o run run.s") match { case 0 => exec("./run") case a => } } def exec(cmd:String):Int = { val p = Runtime.getRuntime().exec(cmd) def f(i:InputStream) { var ii = new BufferedReader(new InputStreamReader(i)) def rd() { ii.readLine() match { case null => case a => println(a); rd() } } rd() } f(p.getInputStream()) f(p.getErrorStream()) p.waitFor() } var counter = 0 def genid(s:String):String = { counter += 1 s + counter } abstract sealed class T case class Ans(a:Exp) extends T case class Let(a:String, b:Exp, c:T) extends T abstract sealed class Exp case class Mov(a:String) extends Exp case class Add(a:String,b:String) extends Exp case class IfEq(a:String, b:String, c:T, d:T) extends Exp def g(e:(String,T)) { e match { case (a,Ans(b)) => g2(a,b) case (a,Let(b,c,d)) => g2(b,c); g(a, d) } } def g2(e:(String,Exp)) { e match { case (a,Mov(b)) => asm("movl "+b+","+a) case (a,Add(b,c)) => asm("movl "+b+","+a); asm("addl "+c+","+a) case (a,IfEq(b,c,d,e)) => val id_else = genid("je_else") val id_cont = genid("je_cont") asm("cmpl "+c+","+b) asm("jne "+id_else) g(a, d) asm("jmp "+id_cont) asm(id_else+":") g(a, e) asm(id_cont+":") } } } def g2(e:(String,Exp)) { e match { case (a,Mov(b)) => asm("movl "+b+","+a) case (a,Add(b,c)) => asm("movl "+b+","+a); asm("addl "+c+","+a) case (a,IfEq(b,c,d,e)) => val id_else = genid("je_else") val id_cont = genid("je_cont") asm("cmpl "+c+","+b) asm("jne "+id_else) g(a, d) asm("jmp "+id_cont) asm(id_else+":") g(a, e) asm(id_cont+":") } } }