LLVM-IR(LLVM中間コード)用コンパイラの作り方 その5

前回の続き

Tiny Basicの代入文「A=A+10」のコード生成で、
(1)変数Aを定義、ゼロで初期化
(2)変数Aのメモリをレジスタ1に取り出す
(3)定数10をレジスタ2に入れる
(4)レジスタ1とレジスタ2を加算し、結果をレジスタ1に入れる
(5)レジスタ1の内容を変数Aのメモリに書き込む
というのを、実際にLLVM-IR中間コードアセンブラで書いてみる。

まず、
(1)変数Aを定義、ゼロで初期化
について、
変数Aを定義するにはLLVM-IRアセンブリ言語では、
 %A = alloca i32 , align 4
と書く。
allocaというのはC言語などでお馴染みのメモリを割り当てる命令だ。
i32というのは32bit整数型という意味だ。(作っているのが整数型Tiny Basicなので)
%Aは、そのメモリのアドレス値を記録するポインタ変数になる。
メモリを割り当てただけでは、その中身がゼロにならないので、自前で初期化をしないといけない。
 store i32 0 , i32* %A , align 4
と、store命令を使って変数Aのメモリに0を書き込む。

次に、
(2)変数Aのメモリをレジスタ1に取り出す
について、
 %1 = load i32 * %A , align 4
と書く。
%1というのは使い捨てのレジスタ的な変数だ。

次に、
(3)定数10をレジスタ2に入れる
について、
 %2 = 10
と書きたいのだけど、直接書けない。
あらかじめ変数accを定義して、
 %acc = alloca i32 , align 4
そのaccを使って、
 store i32 10 , i32* %acc , align 4
 %2 = load i32 * %acc , align 4
と書いた。
もっとスマートな書き方があるかもしれない。

次に、
(4)レジスタ1とレジスタ2を加算し、結果をレジスタ1に入れる
について、
 %3 = add nsw i32 %1, %2
と書く。
本当は%1に結果を入れたいのだけど、それはできない。
前に書いた静的単一代入形式(SAA)のルールだからだ。
代わりに新しい 使い捨てのレジスタ的な変数%3を使う。

次に、
(5)レジスタ1の内容を変数Aのメモリに書き込む
について、
レジスタは3に変更。
 store i32 %3 , i32* %A , align 4
と書く。
store命令で、変数Aのメモリに%3の内容を書き込む。

このように手作業でコード生成すると、「A=A+10」はこんな感じのLLVM-IRのコードになる。
 %acc = alloca i32 , align 4
 %A = alloca i32 , align 4
 store i32 0 , i32* %A , align 4
 %1 = load i32 * %A , align 4
 store i32 10 , i32* %acc , align 4
 %2 = load i32 * %acc , align 4
 %3 = add nsw i32 %1, %2
 store i32 %3 , i32* %A , align 4

変数の番号の%1,%2,%3とかの部分を決めうちでなく汎用性を持たせてコード生成するプログラムを作れば、自動でコード生成するコンパイラとなる。




コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.

7 × 1 =