Files
hakorune/docs/development/current/main/phase33-optimization-guide.md
nyash-codex 4e32a803a7 feat(joinir): Phase 33-22 CommonPatternInitializer & JoinIRConversionPipeline integration
Unifies initialization and conversion logic across all 4 loop patterns,
eliminating code duplication and establishing single source of truth.

## Changes

### Infrastructure (New)
- CommonPatternInitializer (117 lines): Unified loop var extraction + CarrierInfo building
- JoinIRConversionPipeline (127 lines): Unified JoinIR→MIR→Merge flow

### Pattern Refactoring
- Pattern 1: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 2: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 3: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 4: Uses CommonPatternInitializer + JoinIRConversionPipeline (-40 lines)

### Code Reduction
- Total reduction: ~115 lines across all patterns
- Zero code duplication in initialization/conversion
- Pattern files: 806 lines total (down from ~920)

### Quality Improvements
- Single source of truth for initialization
- Consistent conversion flow across all patterns
- Guaranteed boundary.loop_var_name setting (prevents SSA-undef bugs)
- Improved maintainability and testability

### Testing
- All 4 patterns tested and passing:
  - Pattern 1 (Simple While): 
  - Pattern 2 (With Break): 
  - Pattern 3 (If-Else PHI): 
  - Pattern 4 (With Continue): 

### Documentation
- Phase 33-22 inventory and results document
- Updated joinir-architecture-overview.md with new infrastructure

## Breaking Changes
None - pure refactoring with no API changes

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-07 21:02:20 +09:00

532 lines
14 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.

# Phase 33 最適化実装ガイド - Step by Step
**所要時間**: 2.5時間CommonPatternInitializer: 1h + JoinIRConversionPipeline: 1h + 検証: 0.5h
**削減見込み**: 351行patterns/モジュール: 200行 + merge/mod.rs: 31行 + パイプライン: 120行
---
## 🚀 Phase 1: CommonPatternInitializer箱化1時間
### Step 1.1: 新規ファイル作成5分
```bash
cd /home/tomoaki/git/hakorune-selfhost
# 新規ファイル作成
cat > src/mir/builder/control_flow/joinir/patterns/common_init.rs << 'EOF'
//! Phase 33-22: Common Pattern Initializer Box
//!
//! Extracts duplicate initialization logic from Pattern 1-4 lowerers.
//!
//! # Purpose
//!
//! All 4 patterns (Pattern1Minimal, Pattern2WithBreak, Pattern3WithIfPhi, Pattern4WithContinue)
//! share the same initialization steps:
//! 1. Extract loop variable name from condition
//! 2. Look up ValueId in variable_map
//! 3. Trace variable map state
//!
//! This module provides a unified initializer to eliminate 200 lines of duplicate code.
use crate::ast::ASTNode;
use crate::mir::builder::MirBuilder;
use crate::mir::ValueId;
use super::super::trace;
/// Loop context extracted from condition and variable_map
#[derive(Debug, Clone)]
pub struct LoopContext {
pub loop_var_name: String,
pub loop_var_id: ValueId,
}
/// Common Pattern Initializer Box
pub struct CommonPatternInitializer;
impl CommonPatternInitializer {
/// Extract loop context from condition
///
/// # Arguments
///
/// * `builder` - MirBuilder instance (for variable_map access)
/// * `condition` - Loop condition AST node
/// * `pattern_name` - Pattern identifier for error messages (e.g., "pattern1", "pattern2")
///
/// # Returns
///
/// LoopContext containing loop_var_name and loop_var_id
///
/// # Example
///
/// ```rust
/// let ctx = CommonPatternInitializer::extract_loop_context(
/// builder,
/// condition,
/// "pattern1",
/// )?;
/// // ctx.loop_var_name = "i"
/// // ctx.loop_var_id = ValueId(42)
/// ```
pub fn extract_loop_context(
builder: &MirBuilder,
condition: &ASTNode,
pattern_name: &str,
) -> Result<LoopContext, String> {
// Step 1: Extract loop variable name from condition (e.g., "i" from "i < 3")
let loop_var_name = builder.extract_loop_variable_from_condition(condition)?;
// Step 2: Look up ValueId in variable_map
let loop_var_id = builder
.variable_map
.get(&loop_var_name)
.copied()
.ok_or_else(|| {
format!(
"[cf_loop/{}] Loop variable '{}' not found in variable_map",
pattern_name, loop_var_name
)
})?;
// Step 3: Trace variable map state for debugging
trace::trace().varmap(&format!("{}_start", pattern_name), &builder.variable_map);
Ok(LoopContext {
loop_var_name,
loop_var_id,
})
}
}
EOF
# mod.rsに追加
echo "pub mod common_init;" >> src/mir/builder/control_flow/joinir/patterns/mod.rs
```
### Step 1.2: Pattern 1に適用15分
**Before (pattern1_minimal.rs:64-79)**:
```rust
let loop_var_name = self.extract_loop_variable_from_condition(condition)?;
let loop_var_id = self
.variable_map
.get(&loop_var_name)
.copied()
.ok_or_else(|| {
format!(
"[cf_loop/pattern1] Loop variable '{}' not found in variable_map",
loop_var_name
)
})?;
trace::trace().varmap("pattern1_start", &self.variable_map);
```
**After**:
```rust
use super::common_init::{CommonPatternInitializer, LoopContext};
// ...
let LoopContext { loop_var_name, loop_var_id } =
CommonPatternInitializer::extract_loop_context(self, condition, "pattern1")?;
```
**編集コマンド**:
```bash
# Pattern 1のファイルを開く
vim src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs
# 3行目あたりにuse追加:
# use super::common_init::{CommonPatternInitializer, LoopContext};
# 64-79行を削除して1行に置き換え:
# let LoopContext { loop_var_name, loop_var_id } =
# CommonPatternInitializer::extract_loop_context(self, condition, "pattern1")?;
```
**テスト**:
```bash
cargo test --release loop_min_while -- --nocapture
```
### Step 1.3: Pattern 2, 3, 4に適用各10分 = 30分
**Pattern 2**:
```bash
vim src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs
# 56-71行を削除して1行に置き換え
# let LoopContext { loop_var_name, loop_var_id } =
# CommonPatternInitializer::extract_loop_context(self, condition, "pattern2")?;
cargo test --release loop_with_break -- --nocapture
```
**Pattern 3**:
```bash
vim src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs
# 56-71行を削除して1行に置き換え
# let LoopContext { loop_var_name, loop_var_id } =
# CommonPatternInitializer::extract_loop_context(self, condition, "pattern3")?;
cargo test --release loop_with_if_phi_sum -- --nocapture
```
**Pattern 4**:
```bash
vim src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs
# 115-130行を削除して1行に置き換え
# let LoopContext { loop_var_name, loop_var_id } =
# CommonPatternInitializer::extract_loop_context(self, condition, "pattern4")?;
cargo test --release loop_with_continue -- --nocapture
```
### Step 1.4: 全体テスト10分
```bash
# ビルド確認
cargo build --release
# 全パターンテスト
cargo test --release loop_min_while loop_with_break \
loop_with_if_phi_sum loop_with_continue
# SSA-undefエラーチェック
cargo test --release 2>&1 | grep -i "ssa-undef\|undefined"
# 結果確認
if [ $? -eq 0 ]; then
echo "✅ Phase 1完了200行削減達成"
else
echo "❌ Phase 1失敗、ロールバックが必要"
fi
```
---
## 🎯 Phase 2: JoinIRConversionPipeline箱化1時間
### Step 2.1: 新規ファイル作成5分
```bash
cat > src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs << 'EOF'
//! Phase 33-22: JoinIR Conversion Pipeline Box
//!
//! Unified pipeline for JoinModule → MIR conversion + merge.
//!
//! # Purpose
//!
//! All 4 patterns share the same conversion flow:
//! 1. convert_join_module_to_mir_with_meta()
//! 2. trace::joinir_stats()
//! 3. merge_joinir_mir_blocks()
//!
//! This module eliminates 120 lines of duplicate code.
use crate::mir::builder::MirBuilder;
use crate::mir::join_ir::JoinModule;
use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta;
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
use crate::mir::ValueId;
use std::collections::BTreeMap;
use super::super::trace;
/// JoinIR Conversion Pipeline Box
pub struct JoinIRConversionPipeline;
impl JoinIRConversionPipeline {
/// Convert JoinModule to MIR and merge into host function
///
/// # Arguments
///
/// * `builder` - MirBuilder instance (mutable for merge)
/// * `join_module` - JoinModule generated by pattern lowerer
/// * `boundary` - JoinInlineBoundary for input/output mapping
/// * `pattern_name` - Pattern identifier for trace/error messages
/// * `debug` - Debug flag for verbose output
///
/// # Returns
///
/// Option<ValueId> from merge operation (loop result value)
///
/// # Example
///
/// ```rust
/// let boundary = JoinInlineBoundary::new_inputs_only(
/// vec![ValueId(0)],
/// vec![loop_var_id],
/// );
///
/// let result = JoinIRConversionPipeline::convert_and_merge(
/// builder,
/// join_module,
/// boundary,
/// "pattern1",
/// debug,
/// )?;
/// ```
pub fn convert_and_merge(
builder: &mut MirBuilder,
join_module: JoinModule,
boundary: JoinInlineBoundary,
pattern_name: &str,
debug: bool,
) -> Result<Option<ValueId>, String> {
// Step 1: Convert JoinModule to MIR
let empty_meta = BTreeMap::new();
let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta)
.map_err(|e| {
format!(
"[cf_loop/joinir/{}] MIR conversion failed: {:?}",
pattern_name, e
)
})?;
// Step 2: Trace JoinIR stats for debugging
trace::trace().joinir_stats(
pattern_name,
join_module.functions.len(),
mir_module.blocks.len(),
);
// Step 3: Merge MIR blocks into host function
builder.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)
}
}
EOF
# mod.rsに追加
echo "pub mod conversion_pipeline;" >> src/mir/builder/control_flow/joinir/patterns/mod.rs
```
### Step 2.2: Pattern 1-4に適用各10分 = 40分
**Pattern 1の例**:
```bash
vim src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs
# use追加:
# use super::conversion_pipeline::JoinIRConversionPipeline;
# 100-130行を削除して以下に置き換え:
# let boundary = JoinInlineBoundary::new_inputs_only(
# vec![ValueId(0)],
# vec![loop_var_id],
# );
#
# let _ = JoinIRConversionPipeline::convert_and_merge(
# self,
# join_module,
# boundary,
# "pattern1",
# debug,
# )?;
cargo test --release loop_min_while
```
**Pattern 2, 3, 4も同様に適用**各10分
### Step 2.3: 全体テスト15分
```bash
cargo build --release
cargo test --release
# 削減確認
wc -l src/mir/builder/control_flow/joinir/patterns/pattern*.rs
# Pattern 1: 176 → 126行
# Pattern 2: 219 → 169行
# Pattern 3: 165 → 115行
# Pattern 4: 343 → 293行
```
---
## ⚠️ Phase 3: Legacy Fallback削除検証30分
### Step 3.1: Fallbackコメントアウト5分
```bash
vim src/mir/builder/control_flow/joinir/merge/mod.rs
# 277-307行をコメントアウト:
# /*
# if function_params.get(main_func_name).is_none() && ...
# ...
# }
# */
```
### Step 3.2: テスト実行20分
```bash
cargo test --release loop_min_while loop_with_break \
loop_with_if_phi_sum loop_with_continue 2>&1 | tee /tmp/fallback-test.log
# エラー確認
grep -i "error\|failed" /tmp/fallback-test.log
```
### Step 3.3: 判定5分
**テスト全てPASS → Fallback削除OK**:
```bash
# 277-307行を完全削除
vim src/mir/builder/control_flow/joinir/merge/mod.rs
# コミット
git add -A
git commit -m "feat(joinir): Phase 33-22 Remove legacy fallback (31 lines)"
```
**テスト失敗 → Fallback必要**:
```bash
# コメントアウトを戻す
git checkout src/mir/builder/control_flow/joinir/merge/mod.rs
# コメント追加(なぜ必要か記録)
vim src/mir/builder/control_flow/joinir/merge/mod.rs
# 277行目あたりに:
# // Phase 33-22検証済み: このFallbackはのケースで必要
# // 削除するとtest_XXXが失敗する
```
---
## ✅ 完了チェックリスト
### Phase 1: CommonPatternInitializer
- [ ] common_init.rs作成済み60行
- [ ] Pattern 1適用済み176 → 126行
- [ ] Pattern 2適用済み219 → 169行
- [ ] Pattern 3適用済み165 → 115行
- [ ] Pattern 4適用済み343 → 293行
- [ ] テスト全PASS
- [ ] ビルド警告ゼロ
### Phase 2: JoinIRConversionPipeline
- [ ] conversion_pipeline.rs作成済み50行
- [ ] Pattern 1適用済みさらに30行削減
- [ ] Pattern 2適用済みさらに30行削減
- [ ] Pattern 3適用済みさらに30行削減
- [ ] Pattern 4適用済みさらに30行削減
- [ ] テスト全PASS
- [ ] ビルド警告ゼロ
### Phase 3: Legacy Fallback削除
- [ ] Fallbackコメントアウト済み
- [ ] テスト実行済み
- [ ] 判定完了(削除 or 保持)
- [ ] ドキュメント更新済み
---
## 🚨 トラブルシューティング
### Q1: テストが失敗する
**症状**:
```
test loop_min_while ... FAILED
SSA-undef: ValueId(42) not found
```
**原因**: LoopContext.loop_var_idのマッピングミス
**対処**:
```bash
# デバッグ出力有効化
NYASH_TRACE_VARMAP=1 cargo test --release loop_min_while -- --nocapture
# variable_mapの状態確認
grep "varmap.*pattern1" の出力を確認
```
### Q2: ビルドエラー
**症状**:
```
error[E0433]: failed to resolve: use of undeclared type `LoopContext`
```
**原因**: use文の追加忘れ
**対処**:
```bash
# 各patternファイルに追加
use super::common_init::{CommonPatternInitializer, LoopContext};
use super::conversion_pipeline::JoinIRConversionPipeline;
```
### Q3: Fallback削除でテスト失敗
**症状**:
```
test loop_XXX ... FAILED
ValueId(0) not found in remapper
```
**原因**: 一部パターンでFallbackが必要
**対処**:
```bash
# Fallbackを保持
git checkout src/mir/builder/control_flow/joinir/merge/mod.rs
# コメント追加
# このFallbackはPattern Xで必要理由: ...
```
---
## 📚 参考ドキュメント
- [Phase 33-22 分析レポート](phase33-post-analysis.md)
- [コード重複マップ](phase33-duplication-map.md)
- [JoinIRアーキテクチャ](joinir-architecture-overview.md)
---
## 📝 完了後のコミット
```bash
git add -A
git commit -m "feat(joinir): Phase 33-22 CommonPatternInitializer + JoinIRConversionPipeline
- CommonPatternInitializer: Pattern 1-4の初期化ロジック統一化200行削減
- JoinIRConversionPipeline: JoinIR変換フロー統一化120行削減
- Legacy Fallback削除: merge/mod.rs 277-307行削除31行削減
Total: 351行削減
Phase 33-22完了"
```
---
**最終確認**:
```bash
# ビルド成功
cargo build --release
# テスト全PASS
cargo test --release
# 削減確認
git diff --stat HEAD~1
# patterns/ モジュール: -200行
# merge/mod.rs: -31行
# conversion_pipeline.rs: +50行
# common_init.rs: +60行
# 実質削減: -121行
```
✅ Phase 33-22最適化完了