LLVM中間表現(IR)の詳細解析

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
}

タグ: LLVM コンパイラ 中間表現 SSA 三アドレスコード

7月20日 19:01 投稿