# 機能設計書 78-性能アノテーション

## 概要

本ドキュメントは、Julia言語における性能アノテーション機能の設計を記述する。`@inline`、`@noinline`、`@inbounds`、`@boundscheck`、`@simd`、`@polly` マクロによる性能最適化ヒントの付与を提供する。

### 本機能の処理概要

性能アノテーション機能は、Juliaコンパイラに対して最適化のヒントを与えるための一連のマクロを提供する。インライン化制御、境界チェック省略、SIMD自動ベクトル化、ポリヘドラル最適化などの最適化戦略をプログラマが明示的に指定できる。

**業務上の目的・背景**：Juliaは高性能数値計算を目指す言語であり、コンパイラの自動最適化に加えて、プログラマがパフォーマンスクリティカルなコードに対して明示的な最適化ヒントを与える能力が重要である。特に、インライン化の制御は関数呼び出しオーバーヘッドの削減に、@inboundsは配列アクセスの高速化に、@simdはループのベクトル化に直接寄与する。

**機能の利用シーン**：高性能数値計算のホットループ最適化、配列アクセスの境界チェック省略による高速化、小さなユーティリティ関数のインライン化促進、大きな関数のインライン化抑制、ループのSIMDベクトル化指示などで使用される。

**主要な処理内容**：
1. `@inline` - 関数定義またはコールサイトでインライン化を促進
2. `@noinline` - 関数定義またはコールサイトでインライン化を抑制
3. `@inbounds` - 境界チェックの省略を指示
4. `@boundscheck` - 境界チェックブロックのマーキング（@inboundsで省略可能）
5. `@simd` - ループのSIMD自動ベクトル化を許可
6. `@simd ivdep` - ループ内のメモリ依存性がないことを宣言
7. `@polly` - ポリヘドラル最適化（Polly）の適用
8. `@constprop :aggressive` - 積極的な定数伝播
9. `@constprop :none` - 定数伝播の無効化
10. `@nospecialize` - 引数に対する特殊化の抑制
11. `@specialize` - 特殊化の再有効化

**関連システム・外部連携**：LLVMコンパイラバックエンドと連携。@simdはLLVMのベクトル化パス、@pollyはPollyポリヘドラル最適化パスに対応。

**権限による制御**：特別な権限制御はない。ただし、@inboundsの不適切な使用はメモリ安全性を損なう。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ソースコード内のマクロとして使用 |

## 機能種別

コンパイラ最適化ヒント

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ex | Expr | Yes | アノテーション対象の式または関数定義 | 有効なJulia式 |
| ivdep | Symbol | No（@simd） | ループ内メモリ依存性の宣言 | :ivdepのみ |
| setting | QuoteNode | Yes（@constprop） | :aggressive または :none | :aggressive / :none |

### 入力データソース

- Juliaソースコード内のマクロ呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| annotated_expr | Expr | メタ情報が付加された式 |

### 出力先

コンパイラのAST/IR処理パイプラインへの入力として機能

## 処理フロー

### 処理シーケンス

```
1. マクロ展開
   └─ @inline / @noinline: Expr(:meta, :inline/:noinline) を関数本体に挿入
   └─ @inbounds: Expr(:inbounds, true) ... Expr(:inbounds, :pop) で式をラップ
   └─ @boundscheck: Expr(:if, Expr(:boundscheck), blk) で条件ブロック化
   └─ @simd: forループをSIMDシリアライズ対応に変換
   └─ @polly: Expr(:meta, :polly) を関数に挿入
2. コンパイラによる解釈
   └─ メタ情報に基づいてコード生成戦略を変更
3. LLVMコード生成
   └─ @simd → LLVM vectorization hints
   └─ @polly → Polly optimization passes
```

### フローチャート

```mermaid
flowchart TD
    A[性能アノテーション] --> B{アノテーションの種類}
    B -->|"@inline"| C["Expr(:meta, :inline)"]
    B -->|"@noinline"| D["Expr(:meta, :noinline)"]
    B -->|"@inbounds"| E["Expr(:inbounds, true/pop)"]
    B -->|"@boundscheck"| F["Expr(:if, :boundscheck, blk)"]
    B -->|"@simd"| G["forループ変換"]
    B -->|"@polly"| H["Expr(:meta, :polly)"]
    B -->|"@constprop"| I["Expr(:meta, :aggressive_constprop/:no_constprop)"]
    C --> J[コンパイラが最適化適用]
    D --> J
    E --> J
    F --> J
    G --> J
    H --> J
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-78-01 | インライン優先順位 | コールサイトアノテーションが定義アノテーションに優先する | @inline/@noinline |
| BR-78-02 | ネストインライン | ネストしたコールサイトアノテーションは最内が優先 | 複数@inline/@noinline |
| BR-78-03 | @inbounds安全性 | @inboundsの不正使用は未定義動作（クラッシュ/データ破壊） | 全@inbounds使用箇所 |
| BR-78-04 | @boundscheck要件 | @boundscheckは対象関数がインライン化されて初めて@inboundsが効果を持つ | getindex/setindex!実装 |
| BR-78-05 | @simd要件 | 最内ループ、直線コード、ユニットストライドアクセスが必要 | @simd使用時 |
| BR-78-06 | @simd ivdep | ループ内にメモリ依存性がないことを宣言 | @simd ivdep使用時 |
| BR-78-07 | @constpropモード | :aggressiveは積極的定数伝播、:noneは定数伝播無効化 | @constprop使用時 |
| BR-78-08 | @nospecialize効果 | コード生成の多様性を制限するが型推論には影響しない | @nospecialize使用時 |

### 計算ロジック

- `@inbounds` は `Expr(:inbounds, true)` を式の前に、`Expr(:inbounds, :pop)` を式の後に挿入する3要素のブロック式を生成する
- `@boundscheck` は `Expr(:if, Expr(:boundscheck), blk)` を生成し、@inboundsスコープ内では条件がfalseとなりブロックが省略される

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

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SimdError | 例外 | @simdの第1引数がivdepでない | :ivdepを指定 |
| ArgumentError | 例外 | @constpropの設定が:aggressive/:noneでない | 正しい設定を指定 |
| - | 未定義動作 | @inboundsで範囲外アクセス | 事前に境界を検証 |

### リトライ仕様

リトライ不要（コンパイル時処理）

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

該当なし

## パフォーマンス要件

- @inlineは関数呼び出しオーバーヘッド（数ns）を除去
- @inboundsは配列アクセスごとの境界チェック（数ns〜数十ns）を除去
- @simdはSIMD命令による2x〜8x程度のループ高速化を可能にする
- @pollyはポリヘドラルモデルによるループ最適化（タイリング等）を適用

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

- **@inboundsは重大なセキュリティリスク**：範囲外メモリアクセスは任意のメモリ読み書きに繋がる可能性がある
- @inboundsの使用は、アクセスが確実に範囲内であることを開発者が保証した場合のみ許可される
- 信頼できないコードでの@inbounds使用は避けるべき

## 備考

- Julia 1.8で@inline/@noinlineのコールサイトアノテーションが追加
- Julia 1.10で@constpropの関数本体内使用が追加
- @pollyは実験的機能であり、広く使用されていない
- @nospecializeは型推論には影響せず、コード生成のみに影響

---

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

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

### 推奨読解順序

#### Step 1: 基本的なメタアノテーションを理解する

マクロがどのようなExprを生成するかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | boot.jl | `base/boot.jl` | @inline / @noinline の基本定義（329-330行目）: `Expr(:meta, :inline)` / `Expr(:meta, :noinline)` |
| 1-2 | essentials.jl | `base/essentials.jl` | @nospecialize（119-128行目）: `Expr(:meta, :nospecialize, vars...)` |
| 1-3 | essentials.jl | `base/essentials.jl` | @boundscheck（899-901行目）: `Expr(:if, Expr(:boundscheck), blk)` |
| 1-4 | essentials.jl | `base/essentials.jl` | @inbounds（931-937行目）: `Expr(:inbounds, true)` ... `Expr(:inbounds, :pop)` |

**読解のコツ**: これらのマクロはすべてExprのメタノードを生成する。コンパイラはこれらのメタノードを解釈して最適化戦略を変更する。`:meta`タグは関数レベルの指示、`:inbounds`/`:boundscheck`は式レベルの指示。

#### Step 2: 拡張アノテーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | expr.jl | `base/expr.jl` | @inline(x)（383-385行目）: annotate_meta_def_or_block で関数定義またはコールサイトに適用 |
| 2-2 | expr.jl | `base/expr.jl` | @noinline(x)（460-462行目）: 同上 |
| 2-3 | expr.jl | `base/expr.jl` | @constprop（499-518行目）: :aggressive_constprop / :no_constprop メタタグ |
| 2-4 | expr.jl | `base/expr.jl` | @polly（1086-1088行目）: pushmeta!(ex, :polly) |

**主要処理フロー**:
1. **383-385行目**: `@inline(x)` - annotate_meta_def_or_block(x, :inline) を呼び出し
2. **499-518行目**: `@constprop(setting, ex)` - constprop_setting で :aggressive→:aggressive_constprop、:none→:no_constprop に変換

#### Step 3: SIMDアノテーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | simdloop.jl | `base/simdloop.jl` | @simdマクロ（127-137行目）: compile関数でforループを変換 |

**主要処理フロー**:
- **127-129行目**: `@simd(forloop)` - compile(forloop, nothing) でSIMD変換
- **131-137行目**: `@simd(ivdep, forloop)` - compile(forloop, Symbol("julia.ivdep")) でivdep付きSIMD変換

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

```
@inline function f() ... end
    └─ Expr(:meta, :inline) を関数本体に挿入

@inline f(x)    [コールサイト]
    └─ annotate_meta_def_or_block(x, :inline)

@inbounds A[i]
    │
    ├─ Expr(:inbounds, true)
    ├─ val = A[i]        // @boundscheckが省略される
    └─ Expr(:inbounds, :pop)

@boundscheck checkbounds(A, i)
    └─ Expr(:if, Expr(:boundscheck), checkbounds(A, i))
           └─ @inboundsスコープ内では除去

@simd for i in 1:n ... end
    └─ compile(forloop, nothing)
           └─ ループ本体にSIMDメタ情報を付加

@constprop :aggressive f(x) = ...
    └─ constprop_setting(:aggressive) → :aggressive_constprop
           └─ Expr(:meta, :aggressive_constprop)
```

### データフロー図

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

関数定義 Expr ──────▶ @inline/@noinline ────▶ Expr + :meta タグ
                         annotate_meta_def_or_block

式 Expr ─────────────▶ @inbounds ───────────▶ Expr(:inbounds, true) + val + Expr(:inbounds, :pop)

for ループ Expr ─────▶ @simd ──────────────▶ SIMD変換済みループ Expr
                         compile(forloop, ...)

関数定義 Expr ──────▶ @constprop ─────────▶ Expr + :aggressive_constprop/:no_constprop タグ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| boot.jl | `base/boot.jl` | ソース | @inline/@noinline の基本定義（引数なし版） |
| essentials.jl | `base/essentials.jl` | ソース | @nospecialize/@specialize/@boundscheck/@inbounds の定義 |
| expr.jl | `base/expr.jl` | ソース | @inline(x)/@noinline(x)/@constprop/@polly の拡張定義 |
| simdloop.jl | `base/simdloop.jl` | ソース | @simd マクロとSimdLoopモジュール |
| codegen.cpp | `src/codegen.cpp` | ソース（C++） | アノテーションを解釈するLLVMコード生成 |
