LLVM IRの基本概念
LLVM IRはコンパイラフレームワークの中間言語として設計されており、抽象化レベルと表現力のバランスを特徴とします。この中間表現はソースコードの情報を保持しつつ、最適化とコード生成の柔軟性を提供します。
三アドレスコード形式
LLVM IRは三アドレスコード(TAC)形式を採用しており、各命令は最大3つのオペランドで構成されます。基本的な構造は四項組で表現可能です:
(演算子, 入力1, 入力2, 出力)
| 命令タイプ | IR例 | 四項組 |
|---|---|---|
| 算術演算 | %res = add i32 %x, %y | (add, %x, %y, %res) |
| メモリ操作 | store i32 %val, ptr %addr | (store, %val, %addr, ) |
| 制御フロー | br label %dest | (br, , , %dest) |
静的単一代入(SSA)形式
LLVM IRはSSA形式を厳格に採用しており、各変数は単一の代入のみを受けます。この設計によりデータフロー解析が効率化されます:
; 非SSA形式(無効) %tmp = mul i32 4, 5 %tmp = add i32 %tmp, 6 ; SSA形式(有効) %prod = mul i32 4, 5 %sum = add i32 %prod, 6 ret i32 %sum
IRの構成要素
モジュール構造
LLVM IRの最上位構造はモジュールで、ターゲット情報とグローバル定義を含みます:
; モジュールメタデータ target datalayout = "e-m:e-p270:32:32..." target triple = "x86_64-unknown-linux" ; グローバル変数 @global_var = global i32 100
関数定義
関数は引数リストと基本ブロックで構成され、明示的な型指定を特徴とします:
define i32 @calculate(i32 %input1, i32 %input2) {
%result = add i32 %input1, %input2
ret i32 %result
}
基本ブロック
基本ブロックは連続命令列で、終端命令で完結します:
entry: %val1 = load i32, ptr %addr %cmp = icmp eq i32 %val1, 0 br i1 %cmp, label %true_branch, label %false_branch
メモリモデル
LLVMのメモリモデルでは、明示的なロード/ストア命令を使用します:
define void @memory_example() {
%ptr = alloca i32
store i32 42, ptr %ptr
%data = load i32, ptr %ptr
ret void
}
完全なIRサンプル
define i32 @factorial(i32 %n) {
entry:
%cmp_init = icmp eq i32 %n, 0
br i1 %cmp_init, label %base_case, label %recursive
base_case:
ret i32 1
recursive:
%dec_val = sub i32 %n, 1
%rec_call = call i32 @factorial(i32 %dec_val)
%result = mul i32 %n, %rec_call
ret i32 %result
}