llvmのsub expressionっぽいやつの書き方
2017-02-06
Techメモ。
LLVM IRは基本的に以下のような構造をしている。
; (レジスタ名) = (命令名) (引数 ...)
%2 = mul i64 %0, %1
ところがコンパイラが生成した.llファイルを見ていると、引数の部分に別の命令が入っていたりする。
%4 = mul i32 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i32), %3
ここではmul命令の引数に、ptrtoint命令とgetelementptr命令の呼び出しが入っている…ように見える。しかしそれにしては括弧の位置が微妙におかしい。例えば「to i32」はどの命令にかかるのだろうか?
実はこれらはConstant Expressionsと呼ばれるもので、特定の命令だけ、このような書き方が許されている。上記の例では以下の2つのConstant Expressionが使われている。
ptrtoint (CST to TYPE)
getelementptr (TY, CSTPTR, IDX0, IDX1, ...)
ということで、上記の「to i32」はptrtointと対応しているのであった。
例
以下のような構造体Aについて、これのサイズを計算したいとする。
%A = type { i32 }
これは以下のように書ける。
; nullを%A*と見なして、1だけ進めた位置のアドレスを得る
%addr = getelementptr %A, %A* null, i32 1
; アドレス値を整数に変換する
%A_size = ptrtoint %A* %addr to i64
この2行を1行にまとめるにはどうすれば良いか。まず1行目のgetelementptrをConstant Expressionとして書き直すと以下のようになる。
getelementptr (%A, %A* null, i32 1)
これを2行目の%addrと差し替えれば出来上がり。
%A_size = ptrtoint %A* getelementptr (%A, %A* null, i32 1) to i64
(LLVM構造体のサイズ計算についてはこのエントリを参考にした)