# 機能設計書 52-llvm-diff

## 概要

本ドキュメントは、LLVMプロジェクトにおけるllvm-diffツールの機能設計を記述する。llvm-diffは、2つのLLVMモジュール（IRファイル）間の構造的な差分を検出・表示するツールである。

### 本機能の処理概要

llvm-diffは、2つのLLVM中間表現（IR）ファイルを比較し、構造的な差分を検出して表示するコマンドラインツールである。単純なテキスト比較ではなく、LLVM IRのセマンティクスを理解した上で、関数レベル・基本ブロックレベル・命令レベルで意味のある差分を報告する。

**業務上の目的・背景**：コンパイラ開発において、最適化パスの変更が正しく動作しているかを検証する必要がある。従来のテキストdiffでは、変数名の変更や命令順序の変更など、意味的には同等でも形式的に異なるコードを正しく比較できない。llvm-diffは、IR構造を理解した意味的な比較を提供し、コンパイラのリグレッションテストや最適化パスのデバッグを支援する。

**機能の利用シーン**：
- 最適化パスの動作検証
- コンパイラのリグレッションテスト
- 異なるコンパイラバージョン間のIR比較
- デバッグ情報の影響確認

**主要な処理内容**：
1. 2つのLLVM IRファイル（.ll または .bc）の読み込みとパース
2. モジュールレベルでの関数一覧比較
3. 関数ごとの引数・基本ブロック構造の比較
4. 命令レベルでの詳細な差分検出
5. 差分結果のカラー表示による可視化

**関連システム・外部連携**：
- LLVMのIRReader（parseIRFile）との連携
- LLVM IRモジュール解析ライブラリとの連携

**権限による制御**：本ツールはファイルシステムへの読み取りアクセスのみを必要とし、特別な権限は不要である。

## 関連画面

本ツールはCLI（コマンドラインインターフェース）ツールであり、GUI画面は存在しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | コマンドライン | 主画面 | 2つのIRファイルの指定、差分結果の表示 |

## 機能種別

差分解析 / 比較処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| LeftFilename | string | Yes | 比較元（左側）のIRファイルパス | ファイルが存在すること |
| RightFilename | string | Yes | 比較先（右側）のIRファイルパス | ファイルが存在すること |
| GlobalsToCompare | list<string> | No | 比較対象のグローバル名（関数名等） | 空の場合は全関数を比較 |

### 入力データソース

- LLVM IRファイル（.ll：テキスト形式、.bc：ビットコード形式）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FunctionDiff | text | 関数単位の差分情報 |
| BlockDiff | text | 基本ブロック単位の差分情報 |
| InstructionDiff | text | 命令単位の差分情報（カラー表示） |

### 出力先

- 標準出力（stdout）：差分情報
- 標準エラー出力（stderr）：エラーメッセージ

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数パース
   └─ 左右のファイル名と比較対象グローバルを取得
2. 左側モジュール読み込み
   └─ parseIRFileでIRをパースしModuleを生成
3. 右側モジュール読み込み
   └─ parseIRFileでIRをパースしModuleを生成
4. DifferenceEngine初期化
   └─ DiffConsumerを接続
5. 比較実行
   └─ 特定関数指定時: diffGlobalで個別比較
   └─ 指定なし時: Engine.diff(LModule, RModule)でモジュール全体比較
6. 結果判定
   └─ Consumer.hadDifferences()で差分有無を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[コマンドライン引数パース]
    B --> C[左側モジュール読み込み]
    C --> D{読み込み成功?}
    D -->|No| E[エラー終了]
    D -->|Yes| F[右側モジュール読み込み]
    F --> G{読み込み成功?}
    G -->|No| E
    G -->|Yes| H[DifferenceEngine初期化]
    H --> I{特定関数指定?}
    I -->|Yes| J[diffGlobalで個別比較]
    I -->|No| K[モジュール全体比較]
    J --> L[差分結果出力]
    K --> L
    L --> M{差分あり?}
    M -->|Yes| N[終了コード1]
    M -->|No| O[終了コード0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 関数名一致 | 同名の関数同士を比較対象とする | 常時 |
| BR-02 | 引数マッピング | 関数の引数を順序で対応付けて比較 | 関数比較時 |
| BR-03 | 基本ブロック統合 | 対応する基本ブロックを特定して詳細比較 | 関数内比較時 |
| BR-04 | 値等価性判定 | 定数・変数の等価性を構造的に判定 | 命令比較時 |
| BR-05 | 匿名関数除外 | 名前のない関数は比較対象から除外（警告表示） | モジュール比較時 |

### 計算ロジック

差分検出アルゴリズム：
- 優先キューを使用したブロック統合（未処理先行ブロック数でソート）
- 動的計画法による命令列の最適マッチング（コスト計算）
- 仮定ベースの等価性判定（ループ内PHIノード対応）

## データベース操作仕様

本ツールはデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| file_not_found | 入力エラー | 指定ファイルが存在しない | ファイルパスを確認 |
| parse_error | 解析エラー | IRファイルの形式が不正 | 正しいIRファイルを使用 |
| function_not_found | 検索エラー | 指定した関数がどちらかのモジュールに存在しない | 関数名を確認 |

### リトライ仕様

リトライ処理は実装されていない（単発実行ツール）。

## トランザクション仕様

該当なし（読み取り専用処理）。

## パフォーマンス要件

特に明示的な性能要件はないが、動的計画法による最適マッチングアルゴリズムは命令数に対してO(n^2)の計算量となる。

## セキュリティ考慮事項

- ファイル読み取り権限のみを必要とする
- 不正な形式のファイルに対してはエラーを返す

## 備考

- llvm-diffは構造的な差分を検出するため、変数名の変更など意味的に同等な変更は差分として報告しない
- カラー出力をサポート（赤：左のみ、緑：右のみ）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

差分検出に使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DifferenceEngine.h | `llvm/tools/llvm-diff/lib/DifferenceEngine.h` | DifferenceEngineクラス、Consumerインターフェース |
| 1-2 | DiffConsumer.h | `llvm/tools/llvm-diff/lib/DiffConsumer.h` | DiffConsumerクラス、DiffContextの定義 |
| 1-3 | DiffLog.h | `llvm/tools/llvm-diff/lib/DiffLog.h` | DiffLogBuilder、DiffChange列挙型 |

**読解のコツ**: DifferenceEngineが比較ロジックの中核で、DiffConsumerが差分結果の収集・表示を担当する。

#### Step 2: エントリーポイントを理解する

処理の起点となるmain関数を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | llvm-diff.cpp | `llvm/tools/llvm-diff/llvm-diff.cpp` | main関数とモジュール読み込み処理 |

**主要処理フロー**:
1. **69-71行目**: コマンドライン引数パースとオプション非表示設定
2. **73-78行目**: 左右のモジュールを読み込み
3. **80-81行目**: DiffConsumerとDifferenceEngineの初期化
4. **84-86行目**: 特定関数指定時の個別比較
5. **89-90行目**: モジュール全体比較
6. **93行目**: 差分有無を終了コードとして返却

#### Step 3: 差分エンジンの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DifferenceEngine.cpp | `llvm/tools/llvm-diff/lib/DifferenceEngine.cpp` | FunctionDifferenceEngineクラス |

**主要処理フロー**:
- **114-783行目**: FunctionDifferenceEngineクラス（関数内部の詳細比較）
- **767-782行目**: diff(Function, Function)メソッド
- **965-1013行目**: diff(Module, Module)メソッド
- **792-942行目**: runBlockDiff - 動的計画法による命令マッチング

#### Step 4: 結果出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | DiffConsumer.cpp | `llvm/tools/llvm-diff/lib/DiffConsumer.cpp` | 差分結果の表示処理 |

**主要処理フロー**:
- **196-223行目**: logd - 差分のカラー表示（赤：左のみ、緑：右のみ）

### プログラム呼び出し階層図

```
main()
    │
    ├─ readModule() [x2]
    │      └─ parseIRFile()
    │
    ├─ DiffConsumer::DiffConsumer()
    ├─ DifferenceEngine::DifferenceEngine()
    │
    ├─ diffGlobal() [特定関数指定時]
    │      └─ DifferenceEngine::diff(Function*, Function*)
    │             └─ FunctionDifferenceEngine::diff()
    │                    ├─ tryUnify()
    │                    ├─ processQueue()
    │                    ├─ diff(BasicBlock, BasicBlock)
    │                    └─ runBlockDiff()
    │
    └─ DifferenceEngine::diff(Module*, Module*)
           └─ [上記と同様の関数比較処理]
```

### データフロー図

```
[入力]               [処理]                    [出力]

左側IRファイル  ───▶ parseIRFile()     ───▶ Module(L)
                        │
右側IRファイル  ───▶ parseIRFile()     ───▶ Module(R)
                        │
                        ▼
                  DifferenceEngine
                        │
                        ├─ 関数比較
                        │
                        ├─ ブロック比較
                        │
                        └─ 命令比較
                              │
                              ▼
                        DiffConsumer  ───▶ 差分出力
                                           (stdout/stderr)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-diff.cpp | `llvm/tools/llvm-diff/llvm-diff.cpp` | ソース | メインエントリーポイント |
| DifferenceEngine.cpp | `llvm/tools/llvm-diff/lib/DifferenceEngine.cpp` | ソース | 差分検出エンジン実装 |
| DifferenceEngine.h | `llvm/tools/llvm-diff/lib/DifferenceEngine.h` | ヘッダー | 差分エンジンインターフェース |
| DiffConsumer.cpp | `llvm/tools/llvm-diff/lib/DiffConsumer.cpp` | ソース | 差分結果表示実装 |
| DiffConsumer.h | `llvm/tools/llvm-diff/lib/DiffConsumer.h` | ヘッダー | 差分結果表示インターフェース |
| DiffLog.cpp | `llvm/tools/llvm-diff/lib/DiffLog.cpp` | ソース | ログ出力ユーティリティ |
| DiffLog.h | `llvm/tools/llvm-diff/lib/DiffLog.h` | ヘッダー | ログ出力定義 |
| CMakeLists.txt | `llvm/tools/llvm-diff/CMakeLists.txt` | ビルド設定 | ビルド構成の定義 |
