Files
hakorune/docs/private/roadmap/phases/phase-21-optimization

Phase 21: LLVM最適化フェーズ 🚀

開始予定: Phase 15完了後Phase 21-30の間 目標: nyashの14命令 → LLVM最適化能力の最大活用


🎯 フェーズの目的

現在の実装は正確性優先:

  • 型変換統一TypeCoercion箱
  • 値解決統一PhiDispatchPoint
  • 文字列判定StringTagPolicy

Phase 21ではパフォーマンス最適化にフォーカス:

  • LLVMの強力な最適化機能を活用
  • ポリシー箱による戦略的最適化
  • 未定義動作UBの完全回避

📋 実装ステージ4段階

Stage 1: 基礎インフラ(必須) 🏗️

目的: 安全な最適化の土台作り

1.1 LLVM Verifier統合

# 全関数生成後に自動検証
def verify_function(func):
    """LLVM Verifierで検証"""
    if not func.verify():
        raise CompilerError(f"Invalid IR in {func.name}")

実装タイミング: Stage 1最優先 効果: バグの早期発見(開発速度向上)

1.2 未定義動作UB検出

class UBChecker:
    """未定義動作の自動検出"""

    def check_null_deref(self, ptr):
        """nullポインタ参照チェック"""
        if ptr might be null:
            insert_null_check(ptr)

    def check_overflow(self, val):
        """整数オーバーフローチェック"""
        if signed_int:
            use_checked_arithmetic(val)

対象UB:

  • nullポインタ参照
  • 符号付き整数オーバーフロー
  • 未初期化変数の使用
  • 配列境界外アクセス

1.3 データレイアウト標準化

# ターゲット別のレイアウト定義
target_layouts = {
    "x86_64": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
    "wasm32": "e-m:e-p:32:32-i64:64-n32:64-S128",
}

Stage 2: 型情報活用 📦

目的: Everything is Box → LLVMに構造を教える

2.1 Box構造のLLVM定義

# StringBox の構造体定義
StringBox = ir.LiteralStructType([
    ir.IntType(32),        # length
    ir.IntType(8).as_pointer()  # data*
])

# extractvalue で高速アクセス
length = builder.extract_value(string_box, 0)  # 関数呼び出し不要!

効果:

  • BoxCall呼び出し削減
  • メモリアクセス最適化
  • インライン展開促進

2.2 TBAAType-Based Alias Analysis

class TBAAPolicy:
    """型ベースエイリアシング情報"""

    def annotate_box_access(self, inst, box_type):
        """Box型ごとのTBAA付与"""
        tbaa_metadata = {
            "StringBox": self.string_tbaa_node,
            "IntegerBox": self.integer_tbaa_node,
        }
        inst.set_metadata("tbaa", tbaa_metadata[box_type])

効果:

  • 命令並び替え最適化
  • 不要なメモリアクセス削減
  • ループ最適化向上

2.3 extractvalue命令への置き換え

# Before: 関数呼び出し(遅い)
length = builder.call(get_length_func, [string_box])

# After: 構造体アクセス(速い)
length = builder.extract_value(string_box, 0, name="length")

Stage 3: 関数最適化

目的: LLVM Intrinsics活用 + 関数属性付与

3.1 LLVM Intrinsics活用

# memcpy最適化
# Before: ループでコピー
for i in range(len):
    dst[i] = src[i]

# After: LLVM Intrinsic
builder.call(llvm_memcpy, [dst, src, length])

対象Intrinsics:

  • @llvm.memcpy: メモリ一括コピー
  • @llvm.memmove: オーバーラップ対応コピー
  • @llvm.memset: メモリ初期化
  • @llvm.sqrt: 平方根計算
  • @llvm.abs: 絶対値計算

3.2 関数属性付与

class FunctionAttributePolicy:
    """関数の性質を明示"""

    def annotate_pure_function(self, func):
        """副作用なし関数"""
        func.attributes.add("readnone")
        # LLVMが同じ引数の呼び出しを1回に最適化

    def annotate_readonly_function(self, func):
        """読み込み専用関数"""
        func.attributes.add("readonly")

属性一覧:

  • readnone: 完全な純粋関数Math.add等
  • readonly: 読み込みのみArray.length等
  • nounwind: 例外を投げない
  • alwaysinline: 常にインライン展開

3.3 インライン展開ヒント

# 小さい関数は積極的にインライン化
if func_size < 10:
    func.attributes.add("alwaysinline")
elif func_size > 100:
    func.attributes.add("noinline")

Stage 4: ポリシー箱実装 🎁

目的: 戦略的最適化の統一管理

4.1 TypeSafetyPolicy

class TypeSafetyPolicy:
    """型安全性戦略"""

    STRICT = "strict"       # 型不一致は即エラー
    PERMISSIVE = "permissive"  # 暗黙的変換OK現在
    DEBUG = "debug"         # 全変換をログ出力

    def convert(self, val, target_type, mode):
        if mode == STRICT:
            if val.type != target_type:
                raise TypeError(f"Strict mode: {val.type} != {target_type}")
        elif mode == PERMISSIVE:
            return TypeCoercion.to_type(builder, val, target_type)
        elif mode == DEBUG:
            log_conversion(val, target_type)
            return TypeCoercion.to_type(builder, val, target_type)

4.2 ErrorHandlingPolicy

class ErrorHandlingPolicy:
    """エラー処理戦略"""

    FAIL_FAST = "panic"     # 即座にエラー
    FALLBACK = "default"    # デフォルト値(現在)
    COLLECT = "accumulate"  # エラー収集後一括報告

    def handle_type_error(self, error, mode):
        if mode == FAIL_FAST:
            raise error
        elif mode == FALLBACK:
            return Constant(i64, 0)  # ← 現在の実装
        elif mode == COLLECT:
            self.errors.append(error)
            return Constant(i64, 0)

4.3 OptimizationPolicy

class OptimizationPolicy:
    """最適化レベル戦略"""

    def convert_with_opt(self, val, opt_level):
        if opt_level == 0:  # -O0デバッグ
            # 境界チェック付き変換
            return checked_conversion(val)
        elif opt_level >= 2:  # -O2/-O3リリース
            # 高速変換(チェックなし)
            return TypeCoercion.to_i64(builder, val)

4.4 PlatformPolicy

class PlatformPolicy:
    """プラットフォーム戦略"""

    def get_native_int(self, target):
        """ターゲット別のネイティブ整数型"""
        if target == "x86_64":
            return ir.IntType(64)  # ← 現在
        elif target == "wasm32":
            return ir.IntType(32)
        elif target == "arm32":
            return ir.IntType(32)

🎯 実装優先順位

Stage 優先度 実装タイミング
Stage 1基礎インフラ 🔴 最高 Phase 21開始直後
Stage 2型情報活用 🟡 Stage 1完了後
Stage 3関数最適化 🟢 Stage 2完了後
Stage 4ポリシー箱 🔵 具体的問題発生時

📊 期待される効果

パフォーマンス向上

  • BoxCall削減: 30-50%削減extractvalue化
  • メモリアクセス最適化: TBAA活用
  • 関数呼び出しオーバーヘッド削減: Intrinsics/インライン化

開発体験向上

  • Verifier: バグの早期発見
  • UBチェック: 未定義動作の完全回避
  • エラー収集モード: デバッグ効率化

移植性向上

  • PlatformPolicy: 複数プラットフォーム対応
  • データレイアウト標準化: クロスコンパイル対応

🚨 注意点Gemini指摘事項

1. 未定義動作UBを絶対に避ける

  • nullポインタ参照
  • 符号付き整数オーバーフロー
  • 未初期化変数の使用

2. PHI命令は特に慎重に

  • 全ての前任ブロックからの値を指定
  • 漏れがあると検証エラー

3. Verifierを親友にする

  • 開発中は毎回実行
  • 問題の早期発見が鍵

4. データレイアウト・呼び出し規約の統一

  • ターゲット別の標準ルールに従う
  • C言語ライブラリとの互換性確保

📚 関連ドキュメント


🎊 まとめ

Phase 21は正確性から性能への転換点:

  • Stage 1-3: 実装必須(基礎インフラ・型活用・関数最適化)
  • Stage 4: YAGNI原則必要になったら実装

箱理論の実践: 最適化戦略も箱で管理!


作成日: 2025-10-02 ベース: Gemini最適化提案 + Claude分析統合