Files
hakorune/docs/development/current/main/cse-pass-callee-fix-completed.md
nyash-codex 255517ed58 fix(cse): Include callee in Call instruction key generation
Previously, CSE's instruction_key() ignored the callee field, which could
cause different method calls on the same receiver to be incorrectly merged:

  %r1 = call Method { receiver: %obj, method: "upper" } ()
  %r2 = call Method { receiver: %obj, method: "lower" } ()
  // Both had key "call_<obj>_" - WRONG!

Now generates unique keys for all Callee variants:
- Global(name) → call_global_{name}_{args}
- Method { box, method, recv } → call_method_{box}.{method}_{recv}_{args}
- Value(vid) → call_value_{vid}_{args}
- Extern(name) → call_extern_{name}_{args}
- Constructor { box_type } → call_ctor_{type}_{args}
- Closure { .. } → call_closure_{func}_{args}
- None (legacy) → call_legacy_{func}_{args}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 23:33:06 +09:00

199 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CSE Pass Callee フィールド対応修正 - 完了報告
## 日付
2025-12-05
## 概要
CSE (Common Subexpression Elimination) パスの `instruction_key()` 関数で `Call` 命令の `callee` フィールドを無視していたバグを修正しました。
## 問題
### 根本原因
`src/mir/passes/cse.rs``instruction_key()` 関数が `Call` 命令のキー生成時に `callee` フィールドを無視していました:
```rust
// 修正前(バグあり)
MirInstruction::Call { func, args, .. } => {
format!("call_{}_{}", func.as_u32(), args_str)
// ← callee フィールドを無視!
}
```
### 影響範囲
これにより、以下のような問題が発生する可能性がありました:
1. **異なるメソッドの誤統合**
```rust
%r1 = call Method { receiver: %obj, method: "upper", ... } ()
%r2 = call Method { receiver: %obj, method: "lower", ... } ()
// 両方とも "call_<obj>_" という同じキー → 誤って統合される可能性
```
2. **Global 関数の情報損失**
```rust
%r1 = call Global("print") (%msg)
// callee 情報が失われ、func の ValueId だけでキー生成
```
## 修正内容
### コード変更
`src/mir/passes/cse.rs` の `instruction_key()` 関数を修正(行 81-126
```rust
MirInstruction::Call { callee, func, args, .. } => {
let args_str = args.iter()
.map(|v| v.as_u32().to_string())
.collect::<Vec<_>>()
.join(",");
// callee 情報を含めて正確なキー生成
if let Some(c) = callee {
use crate::mir::Callee;
match c {
Callee::Global(name) => {
format!("call_global_{}_{}", name, args_str)
}
Callee::Method { box_name, method, receiver, .. } => {
let recv_str = receiver
.map(|r| r.as_u32().to_string())
.unwrap_or_else(|| "static".to_string());
format!("call_method_{}.{}_{}_{}",
box_name, method, recv_str, args_str)
}
Callee::Value(v) => {
format!("call_value_{}_{}", v.as_u32(), args_str)
}
Callee::Extern(name) => {
format!("call_extern_{}_{}", name, args_str)
}
Callee::Constructor { box_type } => {
format!("call_ctor_{}_{}", box_type, args_str)
}
Callee::Closure { .. } => {
// Closures are unique by definition
format!("call_closure_{}_{}", func.as_u32(), args_str)
}
}
} else {
// Legacy path: backward compatibility
format!("call_legacy_{}_{}", func.as_u32(), args_str)
}
}
```
### キー生成方式
| Callee 種類 | キー形式 | 例 |
|------------|---------|-----|
| Global | `call_global_{name}_{args}` | `call_global_print_200` |
| Method | `call_method_{box}.{method}_{receiver}_{args}` | `call_method_StringBox.upper_100_` |
| Value | `call_value_{vid}_{args}` | `call_value_42_200` |
| Extern | `call_extern_{name}_{args}` | `call_extern_libc.malloc_1024` |
| Constructor | `call_ctor_{box_type}_{args}` | `call_ctor_StringBox_5` |
| Closure | `call_closure_{func}_{args}` | `call_closure_99_` |
| None (legacy) | `call_legacy_{func}_{args}` | `call_legacy_42_200` |
## テスト結果
### 単体テストstandalone
```
✅ Test 1: 同じ receiver、異なる method → 異なるキー
call_method_StringBox.upper_100_ ≠ call_method_StringBox.lower_100_
✅ Test 2: 異なる receiver、同じ method → 異なるキー
call_method_StringBox.upper_100_ ≠ call_method_StringBox.upper_101_
✅ Test 3: 完全に同じ呼び出し → 同じキーCSE が効く)
call_method_StringBox.upper_100_ == call_method_StringBox.upper_100_
✅ Test 4: Global 関数呼び出し → 正しいキー
call_global_print_200
✅ Test 5: Legacy 呼び出しcallee なし)→ 互換性維持
call_legacy_42_200
```
### 統合テスト
```bash
✅ apps/tests/loop_if_phi.hako - sum=9正常
✅ apps/tests/peek_expr_block.hako - found one正常
✅ apps/tests/loop_min_while.hako - 0 1 2正常
✅ apps/tests/string_ops_basic.hako - len=5, sub=bcd正常
```
### ビルド結果
```bash
✅ cargo build --release
Compiling nyash-rust v0.1.0
Finished `release` profile [optimized] target(s) in 0.10s
```
## 達成効果
### ✅ 正確性向上
- 異なるメソッド呼び出しを正しく区別
- receiver と method の両方を考慮したキー生成
- Global/Extern/Constructor 呼び出しを明確に分離
### ✅ バグ予防
- 同じ receiver でも異なるメソッドは別のキーに
- 異なる receiver でも同じメソッドは別のキーに
- callee 情報の完全活用
### ✅ 後方互換性
- `callee: None` の legacy path で既存コード継続動作
- 段階的移行をサポート
### ✅ パフォーマンス
- キー生成コストはわずか(許容範囲)
- CSE の効果は維持(正確性向上)
## 技術的洞察
### Callee 型の重要性
ChatGPT5 Pro が設計した `Callee` enum は、MIR Call 命令の型安全性を大幅に向上させました:
1. **コンパイル時解決**: 関数呼び出しの種類を型で表現
2. **シャドウイング回避**: 実行時文字列解決から脱却
3. **最適化基盤**: CSE などのパスが正確な情報を利用可能
### CSE での活用
Callee 情報により、CSE パスは以下を正確に判断できます:
- 同じメソッド呼び出しの検出receiver + method
- 異なる呼び出しの区別Global vs Method vs Extern
- Constructor と Closure の特別扱い
## 関連ドキュメント
- [MIR Callee 革新](../architecture/mir-callee-revolution.md)
- [Callee 実装ロードマップ](../../private/roadmap2/phases/phase-15/mir-callee-implementation-roadmap.md)
- [CSE Pass 修正提案](cse-pass-callee-fix.md)
## 今後の展開
### 短期Phase 33
- ✅ CSE Pass の callee 対応完了
- 🔄 他の最適化パスでの callee 活用検討
### 中期Phase 34
- 型推論での callee 情報活用
- インライン化での callee 情報利用
### 長期Phase 40+
- Callee ベースの高度な最適化
- JIT での callee 情報活用
## 結論
CSE Pass の callee 対応修正は完全に成功しました。修正は最小限約50行で、テストは全て通過し、期待される効果を達成しています。
この修正により、CSE パスは MIR Call 命令の callee 情報を正確に利用し、異なる呼び出しを正しく区別できるようになりました。これは MIR Callee 型革新Phase 15.5)の重要な実装成果の一つです。
---
**実装者**: Claude Code
**レビュー**: 完了
**マージ準備**: Ready ✅