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>
286 lines
10 KiB
Markdown
286 lines
10 KiB
Markdown
# Phase 33 コード重複マップ - 視覚化ガイド
|
||
|
||
## 🎯 目的
|
||
|
||
Pattern 1-4の共通コードを視覚的に理解し、箱化の対象を明確にする。
|
||
|
||
---
|
||
|
||
## 📊 重複コード分布図
|
||
|
||
```
|
||
Pattern Lowerer Structure (Before Optimization)
|
||
================================================
|
||
|
||
pattern1_minimal.rs (176行) pattern2_with_break.rs (219行)
|
||
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
||
│ ✅ can_lower() │ │ ✅ can_lower() │
|
||
│ ✅ lower() │ │ ✅ lower() │
|
||
│ │ │ │
|
||
│ ⚠️ DUPLICATE INIT (50行) │ │ ⚠️ DUPLICATE INIT (50行) │
|
||
│ - extract_loop_var │ │ - extract_loop_var │
|
||
│ - variable_map lookup │ │ - variable_map lookup │
|
||
│ - trace::varmap() │ │ - trace::varmap() │
|
||
│ │ │ │
|
||
│ ⚠️ DUPLICATE CONVERT (30行)│ │ ⚠️ DUPLICATE CONVERT (30行)│
|
||
│ - convert_join_to_mir │ │ - convert_join_to_mir │
|
||
│ - trace::joinir_stats() │ │ - trace::joinir_stats() │
|
||
│ - JoinInlineBoundary │ │ - JoinInlineBoundary │
|
||
│ - merge_joinir_blocks │ │ - merge_joinir_blocks │
|
||
│ │ │ │
|
||
│ ✅ Pattern 1 specific (96行)│ │ ✅ Pattern 2 specific (139行)│
|
||
└─────────────────────────────┘ └─────────────────────────────┘
|
||
|
||
pattern3_with_if_phi.rs (165行) pattern4_with_continue.rs (343行)
|
||
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
||
│ ✅ can_lower() │ │ ✅ can_lower() │
|
||
│ ✅ lower() │ │ ✅ lower() │
|
||
│ │ │ │
|
||
│ ⚠️ DUPLICATE INIT (50行) │ │ ⚠️ DUPLICATE INIT (50行) │
|
||
│ - extract_loop_var │ │ - extract_loop_var │
|
||
│ - variable_map lookup │ │ - variable_map lookup │
|
||
│ - trace::varmap() │ │ - trace::varmap() │
|
||
│ │ │ │
|
||
│ ⚠️ DUPLICATE CONVERT (30行)│ │ ⚠️ DUPLICATE CONVERT (30行)│
|
||
│ - convert_join_to_mir │ │ - convert_join_to_mir │
|
||
│ - trace::joinir_stats() │ │ - trace::joinir_stats() │
|
||
│ - JoinInlineBoundary │ │ - JoinInlineBoundary │
|
||
│ - merge_joinir_blocks │ │ - merge_joinir_blocks │
|
||
│ │ │ │
|
||
│ ✅ Pattern 3 specific (85行) │ │ ✅ Pattern 4 specific (263行)│
|
||
│ │ │ + LoopUpdateAnalyzer │
|
||
│ │ │ + ContinueNormalizer │
|
||
└─────────────────────────────┘ └─────────────────────────────┘
|
||
|
||
⚠️ = 重複コード(削減対象)
|
||
✅ = パターン固有ロジック(維持)
|
||
```
|
||
|
||
---
|
||
|
||
## 🔥 重複コードの詳細内訳
|
||
|
||
### 重複箇所1: 初期化ロジック(4箇所×50行 = 200行)
|
||
|
||
**Pattern 1の例**:
|
||
```rust
|
||
// src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs:64-79
|
||
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);
|
||
|
||
// Pattern 2, 3, 4でも同一コード
|
||
```
|
||
|
||
**重複パターン**:
|
||
- Pattern 1: `pattern1_minimal.rs:64-79` (16行)
|
||
- Pattern 2: `pattern2_with_break.rs:56-71` (16行)
|
||
- Pattern 3: `pattern3_with_if_phi.rs:56-71` (16行)
|
||
- Pattern 4: `pattern4_with_continue.rs:115-130` (16行)
|
||
|
||
**合計**: 4箇所 × 16行 = **64行重複**
|
||
|
||
---
|
||
|
||
### 重複箇所2: JoinIR変換パイプライン(4箇所×30行 = 120行)
|
||
|
||
**Pattern 1の例**:
|
||
```rust
|
||
// src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs:100-130
|
||
let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta)
|
||
.map_err(|e| format!("[cf_loop/joinir/pattern1] MIR conversion failed: {:?}", e))?;
|
||
|
||
trace::trace().joinir_stats(
|
||
"pattern1",
|
||
join_module.functions.len(),
|
||
mir_module.blocks.len(),
|
||
);
|
||
|
||
let boundary = JoinInlineBoundary::new_inputs_only(
|
||
vec![ValueId(0)],
|
||
vec![loop_var_id],
|
||
);
|
||
|
||
let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?;
|
||
|
||
// Pattern 2, 3, 4でも同一フロー(細部のみ異なる)
|
||
```
|
||
|
||
**重複パターン**:
|
||
- Pattern 1: `pattern1_minimal.rs:100-130` (31行)
|
||
- Pattern 2: `pattern2_with_break.rs:120-150` (31行)
|
||
- Pattern 3: `pattern3_with_if_phi.rs:105-135` (31行)
|
||
- Pattern 4: `pattern4_with_continue.rs:200-230` (31行)
|
||
|
||
**合計**: 4箇所 × 31行 = **124行重複**
|
||
|
||
---
|
||
|
||
## 🎯 箱化後の理想構造
|
||
|
||
```
|
||
After Optimization (CommonPatternInitializer + JoinIRConversionPipeline)
|
||
=========================================================================
|
||
|
||
pattern1_minimal.rs (126行 → 28%削減)
|
||
┌─────────────────────────────┐
|
||
│ ✅ can_lower() │
|
||
│ ✅ lower() │
|
||
│ │
|
||
│ 📦 CommonPatternInitializer │ ← 新しい箱!
|
||
│ .extract_loop_context() │ ← 1行で50行分の処理
|
||
│ │
|
||
│ 📦 JoinIRConversionPipeline │ ← 新しい箱!
|
||
│ .convert_and_merge() │ ← 1行で30行分の処理
|
||
│ │
|
||
│ ✅ Pattern 1 specific (96行)│ ← 変更なし
|
||
└─────────────────────────────┘
|
||
|
||
pattern2_with_break.rs (169行 → 23%削減)
|
||
pattern3_with_if_phi.rs (115行 → 30%削減)
|
||
pattern4_with_continue.rs (293行 → 15%削減)
|
||
↑
|
||
全パターン同様に削減!
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 削減インパクト分析
|
||
|
||
### Before / After 比較表
|
||
|
||
| ファイル | Before | After | 削減行数 | 削減率 |
|
||
|---------|-------|-------|---------|-------|
|
||
| pattern1_minimal.rs | 176行 | 126行 | -50行 | 28% |
|
||
| pattern2_with_break.rs | 219行 | 169行 | -50行 | 23% |
|
||
| pattern3_with_if_phi.rs | 165行 | 115行 | -50行 | 30% |
|
||
| pattern4_with_continue.rs | 343行 | 293行 | -50行 | 15% |
|
||
| **patterns/ 合計** | **1,801行** | **1,601行** | **-200行** | **11%** |
|
||
|
||
### 新規追加ファイル
|
||
|
||
| ファイル | 行数 | 役割 |
|
||
|---------|-----|-----|
|
||
| common_init.rs | 60行 | CommonPatternInitializer実装 |
|
||
| conversion_pipeline.rs | 50行 | JoinIRConversionPipeline実装 |
|
||
|
||
**実質削減**: 200行 - 110行 = **90行削減** + 保守性大幅向上
|
||
|
||
---
|
||
|
||
## 🔍 コード重複検出コマンド
|
||
|
||
```bash
|
||
# 重複箇所1: Loop variable extraction
|
||
grep -A 10 "extract_loop_variable_from_condition" \
|
||
src/mir/builder/control_flow/joinir/patterns/pattern*.rs
|
||
|
||
# 重複箇所2: JoinIR conversion
|
||
grep -A 15 "convert_join_module_to_mir_with_meta" \
|
||
src/mir/builder/control_flow/joinir/patterns/pattern*.rs
|
||
|
||
# 重複箇所3: Merge call
|
||
grep -A 5 "merge_joinir_mir_blocks" \
|
||
src/mir/builder/control_flow/joinir/patterns/pattern*.rs
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 実装順序(推奨)
|
||
|
||
### Phase 1: CommonPatternInitializer (1時間)
|
||
|
||
```bash
|
||
# Step 1: 新規ファイル作成
|
||
touch src/mir/builder/control_flow/joinir/patterns/common_init.rs
|
||
|
||
# Step 2: Pattern 1で動作確認
|
||
cargo test --release loop_min_while
|
||
|
||
# Step 3: Pattern 2, 3, 4に適用
|
||
# (各10分)
|
||
|
||
# Step 4: 全体テスト
|
||
cargo test --release loop_min_while loop_with_break \
|
||
loop_with_if_phi_sum loop_with_continue
|
||
```
|
||
|
||
### Phase 2: JoinIRConversionPipeline (1時間)
|
||
|
||
```bash
|
||
# Step 1: 新規ファイル作成
|
||
touch src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs
|
||
|
||
# Step 2: Pattern 1で動作確認
|
||
cargo test --release loop_min_while
|
||
|
||
# Step 3: Pattern 2, 3, 4に適用
|
||
# (各10分)
|
||
|
||
# Step 4: 全体テスト
|
||
cargo test --release
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 成功基準
|
||
|
||
1. **ビルド成功**: 0エラー・0警告
|
||
2. **テスト全PASS**: Pattern 1-4の既存テスト全て通過
|
||
3. **SSA-undefゼロ**: MIRレベルのエラーなし
|
||
4. **削減達成**: patterns/モジュール全体で200行削減
|
||
5. **保守性向上**: 重複コードゼロ、単一責任の原則適用
|
||
|
||
---
|
||
|
||
## 🚨 リスク管理
|
||
|
||
### 潜在的リスク
|
||
|
||
1. **テスト失敗**: 初期化ロジックの微妙な差異を見落とす可能性
|
||
- **対策**: Pattern毎に個別テスト実行、段階的移行
|
||
|
||
2. **デバッグ困難化**: エラー時のスタックトレースが深くなる
|
||
- **対策**: 適切なエラーメッセージ、pattern_name引数の維持
|
||
|
||
3. **将来の拡張性**: Pattern 5/6で異なる初期化が必要になる可能性
|
||
- **対策**: CommonPatternInitializerを柔軟に設計(オプション引数)
|
||
|
||
### 緊急時のロールバック手順
|
||
|
||
```bash
|
||
# Step 1: 変更前のコミットに戻る
|
||
git revert HEAD
|
||
|
||
# Step 2: テスト確認
|
||
cargo test --release
|
||
|
||
# Step 3: 原因分析
|
||
# → phase33-post-analysis.md の「テスト計画」を参照
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 関連ドキュメント
|
||
|
||
- [Phase 33-19 実装完了レポート](phase33-17-implementation-complete.md)
|
||
- [Phase 33-21 Parameter remapping fix](../../../private/) (未作成)
|
||
- [JoinIRアーキテクチャ概要](joinir-architecture-overview.md)
|
||
- [Pattern Router設計](phase33-16-INDEX.md)
|
||
|
||
---
|
||
|
||
## 📝 変更履歴
|
||
|
||
- 2025-12-07: 初版作成(Phase 33-21完了後の調査結果)
|