# LLVM最適化戦略(Gemini提案統合版) **出典**: Gemini AI提案(2025-10-02) **統合者**: Claude (Sonnet 4.5) --- ## 🎯 **基本方針** nyashの14個の命令 → LLVMの何百もの低レベル命令 この「言葉のレベルの違い」をうまく利用するのが最適化の鍵! --- ## 📚 **最適化手法(4つの柱)** ### **1. LLVM Intrinsics(魔法の関数)を使う** 🪄 LLVMには `@llvm.` で始まる特別な関数(Intrinsics)がある。 これらは**LLVMのオプティマイザが特別な意味を知っている**魔法の関数! #### **主要Intrinsics** | Intrinsic | 用途 | 効果 | |-----------|------|------| | `@llvm.memcpy` | メモリ一括コピー | CPUの最速命令に変換 | | `@llvm.memmove` | オーバーラップ対応コピー | 安全な一括コピー | | `@llvm.memset` | メモリ初期化 | 一括ゼロクリア | | `@llvm.sqrt.f64` | 平方根計算 | CPU命令1個に変換 | | `@llvm.abs.i64` | 絶対値計算 | 分岐なし高速化 | | `@llvm.bswap.i64` | バイトスワップ | エンディアン変換 | #### **実装例: メモリコピー最適化** ```python # ❌ Before: 自前ループ(遅い) def copy_array_slow(dst, src, length): for i in range(length): dst_ptr = builder.gep(dst, [ir.Constant(i64, i)]) src_ptr = builder.gep(src, [ir.Constant(i64, i)]) val = builder.load(src_ptr) builder.store(val, dst_ptr) # ✅ After: LLVM Intrinsic(速い) def copy_array_fast(dst, src, length): memcpy_func = declare_llvm_memcpy(module) builder.call(memcpy_func, [ dst, # destination src, # source length, # byte count ir.Constant(i1, 0) # is_volatile ]) ``` **効果**: - ループオーバーヘッド削減 - SIMD命令への自動変換 - CPUのDMA機能活用 --- ### **2. Box構造をLLVMに教える** 📦 nyashでは「Everything is Box」だが、LLVMには具体的な構造体として伝える必要がある。 #### **Box構造の明示** ```python # StringBox の構造定義 StringBox = ir.LiteralStructType([ ir.IntType(32), # 0: length ir.IntType(8).as_pointer() # 1: data* ]) # IntegerBox の構造定義 IntegerBox = ir.LiteralStructType([ ir.IntType(64) # 0: value ]) ``` #### **extractvalue命令への置き換え** ```python # ❌ Before: 関数呼び出し(遅い) length_func = module.get_function("StringBox.length") length = builder.call(length_func, [string_box]) # ✅ After: 構造体アクセス(速い) length = builder.extract_value(string_box, 0, name="length") # → たった1命令!関数呼び出しオーバーヘッドなし ``` **効果**: - 関数呼び出しコスト削減(10-100倍高速化) - インライン展開促進 - レジスタ割り当て最適化 --- ### **3. TBAA(Type-Based Alias Analysis)ヒント** 🎯 「このポインタとあのポインタは別物だよ!」とLLVMに教えてあげる。 #### **TBAAメタデータの設定** ```python class TBAABuilder: """TBAA(型ベースエイリアス解析)メタデータ生成""" def __init__(self, module): self.module = module self.root = self._create_tbaa_root() self.box_types = {} def _create_tbaa_root(self): """TBAA階層のルート""" return self.module.add_metadata([ ir.MetaDataString(self.module, "nyash-tbaa") ]) def create_box_type(self, box_name): """Box型ごとのTBAAノード""" if box_name not in self.box_types: self.box_types[box_name] = self.module.add_metadata([ ir.MetaDataString(self.module, box_name), self.root, ir.IntType(64)(0) # offset ]) return self.box_types[box_name] def annotate_load(self, load_inst, box_name): """load命令にTBAAメタデータ付与""" tbaa_node = self.create_box_type(box_name) load_inst.set_metadata("tbaa", tbaa_node) # 使用例 tbaa = TBAABuilder(module) # StringBoxへのアクセス str_load = builder.load(string_ptr) tbaa.annotate_load(str_load, "StringBox") # IntegerBoxへのアクセス int_load = builder.load(integer_ptr) tbaa.annotate_load(int_load, "IntegerBox") ``` **効果**: ```python # TBAA情報があると、LLVMはこう最適化できる: # ① 整数を読む int_val = load(integer_box) # ② 文字列を書き込む(IntegerBoxとは無関係!) store(string_val, string_box) # ③ もう一度同じ整数を読む # → LLVMは「②の書き込みは①の整数に影響しない」と判断 # → ③の再読み込みを省略! int_val を再利用 int_val_reused = int_val # load削減! ``` --- ### **4. 関数属性(Function Attributes)** 🏷️ 関数の「性格」をLLVMに伝える。 #### **主要属性** | 属性 | 意味 | 対象関数例 | |-----|------|-----------| | `readnone` | 副作用なし・メモリ読まない | Math.add, Math.sqrt | | `readonly` | 読み込みのみ・書き込みなし | Array.length, String.length | | `nounwind` | 例外を投げない | すべてのnyash関数 | | `alwaysinline` | 常にインライン展開 | 小さいヘルパー関数 | | `noinline` | インライン展開禁止 | デバッグ用関数 | | `cold` | めったに実行されない | エラーハンドラ | #### **実装例** ```python def annotate_pure_function(func): """純粋関数の最適化""" # 副作用なし → LLVMが同じ引数の呼び出しを1回に最適化 func.attributes.add("readnone") func.attributes.add("nounwind") # 小さい関数は積極的にインライン化 if count_instructions(func) < 10: func.attributes.add("alwaysinline") # 使用例 math_add_func = module.get_function("Math.add") annotate_pure_function(math_add_func) # ✅ 最適化結果: # result1 = Math.add(1, 2) # → 実行される # result2 = Math.add(1, 2) # → LLVMが省略!result1を再利用 ``` --- ## 🚨 **注意点(絶対守るべきルール)** ### **1. 未定義動作(UB)を絶対に避ける** ⚠️ LLVMは未定義動作があると**とんでもないコードを生成する**ことがある! #### **主要UB一覧** | UB | 例 | 対策 | |---|---|------| | nullポインタ参照 | `*null_ptr` | null check挿入 | | 符号付きオーバーフロー | `INT_MAX + 1` | チェック付き演算 | | 未初期化変数使用 | `int x; return x;` | 明示的初期化 | | 配列境界外アクセス | `arr[length]` | 境界チェック | #### **実装例: null check** ```python def safe_load(ptr, name="load"): """null check付きload""" # null check is_null = builder.icmp_unsigned('==', ptr, ir.Constant(ptr.type, None)) with builder.if_then(is_null): # nullならエラー builder.call(panic_func, [ ir.Constant.literal_struct([ ir.Constant(i8p, "Null pointer dereference") ]) ]) # 安全にload return builder.load(ptr, name=name) ``` --- ### **2. データレイアウト・呼び出し規約の統一** 📐 プラットフォーム別の標準ルールに従う。 ```python # ターゲット別のデータレイアウト TARGET_LAYOUTS = { "x86_64-unknown-linux-gnu": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", "wasm32-unknown-unknown": "e-m:e-p:32:32-i64:64-n32:64-S128", "aarch64-unknown-linux-gnu": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", } # モジュールに設定 module.triple = target_triple module.data_layout = TARGET_LAYOUTS[target_triple] ``` --- ### **3. PHI命令は慎重に** 🔀 全ての前任ブロックからの値を漏れなく指定! ```python # ✅ 正しいPHI phi = builder.phi(i64, name="phi_result") phi.add_incoming(value_from_if, if_block) phi.add_incoming(value_from_else, else_block) # ❌ 間違い: else_blockからの値を忘れた phi = builder.phi(i64, name="phi_result") phi.add_incoming(value_from_if, if_block) # → Verifierエラー! ``` --- ### **4. Verifierを毎回実行** ✅ 開発中は関数を1つ生成するたびに検証! ```python def build_function(func_name, ...): # 関数生成 func = ir.Function(module, func_type, name=func_name) # ... IRを生成 ... # 必ず検証! if not func.verify(): raise CompilerError(f"Invalid IR in {func_name}") return func ``` --- ## 📊 **期待される効果(ベンチマーク予測)** | 最適化手法 | 期待される効果 | |-----------|-------------| | LLVM Intrinsics | メモリ操作: 5-10倍高速化 | | Box構造明示 | メソッド呼び出し: 10-100倍高速化 | | TBAA | ループ内load削減: 20-50% | | 関数属性 | 関数呼び出しオーバーヘッド: 50-90%削減 | **総合効果**: 現在比で **2-5倍の性能向上**を予測 --- ## 🎯 **実装優先順位** 1. **Verifier統合** 🔴 最優先 2. **UBチェック** 🔴 最優先 3. **データレイアウト標準化** 🟡 重要 4. **Box構造明示** 🟡 重要 5. **LLVM Intrinsics** 🟢 中 6. **関数属性** 🟢 中 7. **TBAA** 🔵 低(効果大だが実装複雑) --- ## 📚 **参考資料** - [LLVM Language Reference Manual](https://llvm.org/docs/LangRef.html) - [LLVM Alias Analysis Infrastructure](https://llvm.org/docs/AliasAnalysis.html) - [LLVM Function Attributes](https://llvm.org/docs/LangRef.html#function-attributes) - [LLVM Intrinsics](https://llvm.org/docs/LangRef.html#intrinsic-functions) --- **まとめ**: Geminiの提案は**実用的で効果的**!Phase 21で段階的に実装していく価値がある 🎊