# 機能設計書 119-clang-nvlink-wrapper

## 概要

本ドキュメントは、LLVMプロジェクトにおけるNVIDIA nvlinkラッパーツール「clang-nvlink-wrapper」の機能設計を記述する。

### 本機能の処理概要

clang-nvlink-wrapperは、NVIDIAのnvlinkリンカをラップするユーティリティである。nvlinkはNVPTXアプリケーションの作成に必要だが、LTO（Link Time Optimization）やアーカイブ処理などの一般的な機能をサポートしていない。本ツールはこれらの不足機能を補い、LLVMのLTOパイプラインとの統合を実現する。

**業務上の目的・背景**：CUDA/GPUプログラミングにおいて、nvlinkは複数のPTXやcubinファイルをリンクしてデバイスコードを生成する。しかしnvlinkは静的ライブラリ（.a）のサポートやLTO機能を持たない。本ツールはこれらの欠点を補い、通常のリンカと同様のワークフローを可能にする。

**機能の利用シーン**：
- CUDA/GPUプログラムのリンク
- NVPTX向けLTO（Link Time Optimization）
- 静的ライブラリ（.aアーカイブ）の処理
- ビットコードファイルからのPTX/cubin生成

**主要な処理内容**：
1. 入力ファイルの収集と分類
2. アーカイブファイルの展開と必要メンバーの抽出
3. ビットコードファイルのLTO処理
4. PTXからcubinへのアセンブル（ptxas呼び出し）
5. nvlinkによる最終リンク

**関連システム・外部連携**：NVIDIA nvlink、NVIDIA ptxas、LLVM LTOライブラリ

**権限による制御**：特になし。ファイルシステムへのアクセス権限およびnvlink/ptxasの実行権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI | 主機能 | コマンドラインインターフェースによる操作 |

## 機能種別

リンク / LTO / GPU開発支援

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| 入力ファイル | string[] | Yes | ビットコード、オブジェクト、アーカイブ | ファイル存在確認 |
| -o | string | No | 出力ファイル名（デフォルト: a.out） | パス妥当性確認 |
| -arch | string | Yes | NVPTXアーキテクチャ（sm_XX） | 有効なアーキテクチャ |
| -l | string[] | No | ライブラリ名 | - |
| -L | string[] | No | ライブラリ検索パス | - |
| --cuda-path | string | No | CUDAツールキットのパス | - |
| --lto-emit-llvm | bool | No | LTO後にビットコード出力 | - |
| --lto-emit-asm | bool | No | LTO後にアセンブリ出力 | - |
| --save-temps | bool | No | 一時ファイルを保持 | - |
| --dry-run | bool | No | コマンド表示のみ | - |
| -j/--jobs | int | No | LTO並列度 | 正の整数 |

### 入力データソース

- LLVMビットコードファイル（.bc）
- NVPTXオブジェクトファイル（.o / .cubin）
- 静的ライブラリ（.a）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| LinkedBinary | binary | リンク済みデバイスバイナリ |
| Bitcode | binary | LTO後ビットコード（--lto-emit-llvm時） |
| Assembly | text | PTXアセンブリ（--lto-emit-asm時） |

### 出力先

- 指定されたファイル（-oオプション）
- デフォルト: a.out

## 処理フロー

### 処理シーケンス

```
1. 初期化処理
   ├─ ターゲット初期化
   └─ オプション解析
2. 入力ファイル収集（getInput）
   ├─ ライブラリパス設定
   ├─ 入力ファイル処理ループ
   │   ├─ -lオプション → ライブラリ検索
   │   ├─ ビットコード/オブジェクト → 直接追加
   │   └─ アーカイブ → メンバー展開
   └─ シンボル解決によるメンバー選択
3. LTO処理
   ├─ ビットコードファイル抽出
   ├─ LTOバックエンド作成（createLTO）
   ├─ シンボル解決設定
   ├─ LTO実行
   └─ PTXファイル生成
4. PTXアセンブル（runPTXAs）
   └─ ptxas呼び出し → cubin生成
5. nvlinkリンク（runNVLink）
   ├─ 引数構築
   └─ nvlink実行
6. クリーンアップ
   └─ 一時ファイル削除（--save-temps未指定時）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ターゲット初期化]
    B --> C[オプション解析]
    C --> D[getInput呼び出し]
    D --> E[入力ファイルループ]
    E --> F{ファイル種別?}
    F -->|bitcode| G[InputFilesに追加]
    F -->|object| G
    F -->|archive| H[アーカイブ展開]
    H --> I{--whole-archive?}
    I -->|Yes| J[全メンバー追加]
    I -->|No| K[IsLazy=true]
    J --> L[シンボル解決ループ]
    K --> L
    G --> L
    L --> M{参照解決?}
    M -->|Yes| N[LinkerInputに追加]
    M -->|No| O{次のファイル?}
    N --> O
    O -->|Yes| E
    O -->|No| P[ビットコード抽出]
    P --> Q{ビットコードあり?}
    Q -->|Yes| R[createLTO]
    Q -->|No| S[オブジェクトのみ]
    R --> T[LTO.add per bitcode]
    T --> U[LTO.run]
    U --> V{--lto-emit-*?}
    V -->|Yes| W[早期終了]
    V -->|No| X[runPTXAs]
    X --> Y[cubin生成]
    S --> Z[runNVLink]
    Y --> Z
    Z --> AA{dry-run?}
    AA -->|Yes| AB[コマンド表示]
    AA -->|No| AC[nvlink実行]
    AB --> AD[一時ファイル削除]
    AC --> AD
    AD --> AE[終了]
    W --> AE
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | アーキテクチャ必須 | -archオプションでGPUアーキテクチャ指定必須 | ptxas/nvlink呼び出し時 |
| BR-002 | シンボル解決 | アーカイブメンバーは未定義シンボル解決時のみ抽出 | アーカイブ処理時 |
| BR-003 | cubin拡張子 | nvlinkへの入力はcubin拡張子が必要 | nvlink呼び出し時 |
| BR-004 | FatBinary処理 | ELFだがNVPTX以外のアーキテクチャはFatBinaryとして処理 | hasFatBinary判定時 |
| BR-005 | LTO出力形式 | LTOはPTX形式で出力し、ptxasでcubinに変換 | LTO処理時 |

### 計算ロジック

- シンボル解決：未定義シンボルを定義するオブジェクトを選択
- Weak/Strong解決：Strongシンボルが優先

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

該当なし（ファイルベースのツール）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | プログラム未検出 | nvlink/ptxasが見つからない | エラーメッセージ出力後終了 |
| - | アーキテクチャ未指定 | -archなしでptxas/nvlink呼び出し | エラーメッセージ出力後終了 |
| - | ライブラリ未検出 | -l指定のライブラリが見つからない | エラーメッセージ出力後終了 |
| - | LTOエラー | LTO処理中のエラー | エラーメッセージ出力後終了 |

### リトライ仕様

リトライ処理なし

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

該当なし

## パフォーマンス要件

- LTO並列処理対応（-j/--jobs）

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

- 外部プログラム（nvlink/ptxas）の実行
- 一時ファイルの適切な管理

## 備考

- nvlinkの不足機能を補完するラッパー
- NVIDIA CUDA Toolkitに依存
- NVIDIAがリンカを改善するか、ld.lldに移植するまでの暫定ツール

---

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

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

### 推奨読解順序

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

Symbol構造体がシンボル情報を保持し、アーカイブメンバー選択に使用される。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp` | Symbol構造体（260-299行目） |

**読解のコツ**: Symbolはフラグ（Undefined/Weak）とファイル参照を持ち、シンボル解決に使用。UsedInRegularObjはLTOでの可視性決定に使用。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp` | main関数（766-820行目） |

**主要処理フロー**:
1. **767-772行目**: 初期化（InitLLVM、ターゲット初期化）
2. **777-782行目**: オプション解析
3. **805-807行目**: getInput呼び出し
4. **809-811行目**: runNVLink呼び出し
5. **813-817行目**: 一時ファイル削除

#### Step 3: 入力収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp` | getInput関数（500-713行目） |

**getInput処理フロー**:
- **501-503行目**: ライブラリパス収集
- **507-561行目**: 入力ファイル処理ループ
  - **509-513行目**: --whole-archive処理
  - **515-518行目**: -lオプションのライブラリ検索
  - **533-537行目**: ビットコード/オブジェクト直接追加
  - **538-556行目**: アーカイブ展開
- **563-591行目**: シンボル解決ループ（Extractedフラグ）
- **595-599行目**: ビットコードファイル抽出
- **601-689行目**: LTO処理

#### Step 4: LTO処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp` | createLTO関数（347-414行目） |

**createLTO処理フロー**:
- **348-349行目**: nvptx64トリプル設定
- **360行目**: CPU設定（archオプション）
- **375-379行目**: 最適化レベル設定
- **387行目**: CGFileType::AssemblyFile（PTX出力）
- **389-398行目**: --lto-emit-llvm時のフック設定

#### Step 5: nvlink/ptxas呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp` | runPTXAs関数（301-345行目）、runNVLink関数（715-762行目） |

**runPTXAs処理フロー**:
- **302-306行目**: ptxasパス検索
- **321-335行目**: アセンブラ引数構築
- **341行目**: ExecuteAndWait呼び出し

**runNVLink処理フロー**:
- **719-721行目**: nvlinkパス検索
- **731-743行目**: 引数構築（ラッパー専用オプション除外）
- **758行目**: ExecuteAndWait呼び出し

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

```
main()
    │
    ├─ InitLLVM / InitializeAllTargets等
    │
    ├─ getOptTable().parseArgs()
    │
    ├─ getInput()
    │      │
    │      ├─ 入力ファイル分類
    │      │      ├─ searchLibrary() [-l処理]
    │      │      ├─ ビットコード/オブジェクト直接追加
    │      │      └─ Archive::create() + メンバー展開
    │      │
    │      ├─ シンボル解決ループ
    │      │      ├─ getSymbols()
    │      │      │      ├─ getSymbolsFromBitcode()
    │      │      │      └─ getSymbolsFromObject()
    │      │      └─ 未解決シンボル解決
    │      │
    │      ├─ createLTO()
    │      │      └─ lto::LTO構築
    │      │
    │      ├─ LTO.add() [per bitcode]
    │      │
    │      ├─ LTO.run()
    │      │      └─ PTXファイル生成
    │      │
    │      └─ runPTXAs() [per PTX]
    │             └─ ptxas呼び出し → cubin
    │
    ├─ runNVLink()
    │      └─ nvlink呼び出し
    │
    └─ 一時ファイル削除
```

### データフロー図

```
入力ファイル群
    │
    ├─ .bc (ビットコード) ──┐
    ├─ .o (オブジェクト) ──┼──▶ getInput()
    └─ .a (アーカイブ) ────┘         │
                                      ▼
                               シンボル解決
                                      │
                    ┌─────────────────┼─────────────────┐
                    ▼                 ▼                 ▼
              LinkerInput       BitcodeFiles      hasFatBinary
                  │                   │                 │
                  │                   ▼                 │
                  │             createLTO()             │
                  │                   │                 │
                  │                   ▼                 │
                  │             LTO.add()               │
                  │                   │                 │
                  │                   ▼                 │
                  │             LTO.run()               │
                  │                   │                 │
                  │                   ▼                 │
                  │              PTXファイル            │
                  │                   │                 │
                  │                   ▼                 │
                  │             runPTXAs()              │
                  │                   │                 │
                  │                   ▼                 │
                  │               cubin                 │
                  │                   │                 │
                  └───────────────────┼─────────────────┘
                                      ▼
                               runNVLink()
                                      │
                                      ▼
                            リンク済みバイナリ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ClangNvlinkWrapper.cpp | `clang/tools/clang-nvlink-wrapper/` | ソース | メイン処理 |
| NVLinkOpts.td | `clang/tools/clang-nvlink-wrapper/` | テーブルジェン | オプション定義 |
| LTO.h | `llvm/include/LTO/` | ヘッダ | LTOインターフェース |
| Archive.h | `llvm/include/Object/` | ヘッダ | アーカイブ操作 |
| CMakeLists.txt | `clang/tools/clang-nvlink-wrapper/` | 設定 | ビルド設定 |
