ついに最終段階のアセンブリ生成となりました。もっともややこしいレジスタ割り当てがすでに終わっているので、特に難しいことはなく、SparcAsm.tを本当のSPARCアセンブリとして出力するだけです。
ただし、仮想命令はちゃんと実装する必要があります。条件分岐は比較とブランチで実装します。SaveとRestoreは、すでにセーブした変数の集合stacksetと、変数のスタックにおける位置のリストstackmapとを計算しつつ、ストアとロードで実装します。関数呼び出しでは、レジスタの順に引数を並べ替える処理Emit.shuffleが少し面倒ですが、それ以外は簡単です。
一点だけ自明でない重要な部分として、末尾呼び出し最適化があります。これは「もう後にすることがなく、戻ってこない」ような関数呼び出し(末尾呼び出し)を、Callではなく、ただのジャンプ命令で実装するという処理です。これにより、たとえば冒頭のgcdのような再帰関数を、ただのループとまったく同様に実装することができます。このために、命令列のアセンブリ生成をする関数Emit.gや、各命令のアセンブリ生成をする関数Emit.g'では、末尾かどうかを表すデータ型Emit.destも引数として受け取ります。末尾Tailだったら、他の関数をジャンプ命令で末尾呼び出しするか、さもなくば計算結果を第一レジスタにセットし、SPARCのret命令で関数を終了します。末尾でないNonTail(x)だったら、計算結果をxにセットします。
最後に、ヒープと関数呼び出しスタックを確保するメインルーチンstub.cと、テストプログラムの実行に必要な外部関数libmincaml.Sを用意すれば、MinCamlコンパイラの完成です!