337 lines
9.6 KiB
Markdown
337 lines
9.6 KiB
Markdown
# 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で段階的に実装していく価値がある 🎊
|