diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md
index cdfb453c..f85e727f 100644
--- a/docs/development/current/main/10-Now.md
+++ b/docs/development/current/main/10-Now.md
@@ -62,7 +62,8 @@
- P1.5-DBG: boundary entry params の契約チェックを追加(VM実行前 fail-fast)。
- P1.6: 契約チェックの薄い集約 `run_all_pipeline_checks()` を導入(pipeline の責務を縮退)。
- P1.13: Pattern2 boundary entry params を `join_module.entry.params` SSOT へ寄せた(ValueId 推測生成の撤去)。
- - P1.13.5: Boundary SSOT 統一(Pattern4/6/7 横展開 + 共通ヘルパ `get_entry_function()` 抽出)。
+ - P1.13.5(= Phase 256.8.5): Boundary SSOT 統一(Pattern4/6/7 横展開 + hardcoded ValueId/PARAM_MIN 撤去)。
+ - Known issue(非ブロッカー): Pattern7 integration smoke の `phi predecessor mismatch` は残存(今回の修正とは独立)。
## 2025-12-20:Phase 257(last_index_of early return loop)🔜
diff --git a/docs/development/current/main/phases/phase-256/README.md b/docs/development/current/main/phases/phase-256/README.md
index 8b877500..4536c955 100644
--- a/docs/development/current/main/phases/phase-256/README.md
+++ b/docs/development/current/main/phases/phase-256/README.md
@@ -15,11 +15,14 @@ Related:
- 次フェーズ: Phase 257(`last_index_of/2` の reverse scan + early return loop)
- 直近の完了:
- P1.13: Pattern2 boundary entry_param_mismatch 根治(`join_module.entry.params` SSOT 化)
+ - P1.13.5(= Phase 256.8.5): Pattern4/6/7 でも `boundary.join_inputs` を `join_module.entry.params` SSOT に統一(hardcoded ValueId/PARAM_MIN を撤去)
- P1.10: DCE が `jump_args` 参照を保持し、`instruction_spans` と同期するよう修正(回帰テスト追加)
- P1.7: SSA undef(`%49/%67`)根治(continuation 関数名の SSOT 不一致)
- P1.6: pipeline contract checks を `run_all_pipeline_checks()` に集約
- 次の作業: Phase 257(last_index_of pattern - loop with return support)
- 設計メモ(ChatGPT Pro 相談まとめ): `docs/development/current/main/investigations/phase-256-joinir-contract-questions.md`
+- Known issue(非ブロッカー):
+ - Pattern7 integration smoke で `phi predecessor mismatch` が残っている(今回の boundary SSOT 統一とは独立)
---
diff --git a/docs/development/current/main/phases/phase-257/README.md b/docs/development/current/main/phases/phase-257/README.md
index 0f5d2acf..2dbb4e0c 100644
--- a/docs/development/current/main/phases/phase-257/README.md
+++ b/docs/development/current/main/phases/phase-257/README.md
@@ -176,13 +176,46 @@ return/break を正規化して共通語彙へ落とし、JoinIR patterns を縮
## 進捗(P0)
-### 次のステップ
+### ✅ 実装完了 (2025-12-20)
-1. Pattern6 の forward scan parts と差分を整理(init/cond/step/return)
-2. reverse scan の extractor を実装(Fail-Fast)
-3. JoinIR lowerer へ reverse scan を追加(既存 contract に従う)
-4. integration smokes + quick profile を回して SSOT 更新
+**実装内容**:
+1. ✅ `ScanDirection` enum 追加 (Forward/Reverse)
+2. ✅ `ScanParts` 構造体拡張(scan_direction フィールド追加)
+3. ✅ `is_const_step_pattern()` 更新(`i + 1` / `i - 1` 両対応)
+4. ✅ `extract_scan_with_init_parts()` 更新(forward/reverse 両検出)
+ - Forward: `i < s.length()`, step +1
+ - Reverse: `i >= 0`, step -1
+5. ✅ `lower_scan_with_init_reverse()` 新規作成
+6. ✅ Pattern6 lowering 分岐実装(scan direction に応じて適切な lowerer 選択)
+
+**ファイル変更**:
+- `src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs`
+- `src/mir/join_ir/lowering/scan_with_init_reverse.rs` (新規)
+- `src/mir/join_ir/lowering/mod.rs`
+
+**ビルド状況**:
+- ✅ コンパイル成功(0エラー)
+- ✅ コード品質維持(既存パターン踏襲、SSOT原則遵守)
+
+### 🔍 既知の問題(実装前から存在)
+
+**PHI predecessor mismatch bug**:
+- Error: `phi pred mismatch at ValueId(X): no input for predecessor BasicBlockId(Y)`
+- Pattern6 forward scan (phase254_p0_index_of) でも同じエラー発生
+- **Phase 257 P0 実装前から存在** していたバグ
+- phase254 テストは期待終了コード=1 のため "PASS" と表示されるが、実際はエラー終了
+- **Scope外**: Pattern6 全体の PHI 生成バグであり、Phase 257 P0 では修正しない
+
+### 次のアクション
+
+#### Phase 257 P1(将来)
+- PHI predecessor mismatch bug 修正(JoinIR merger の PHI ノード生成ロジック)
+- Pattern6 全体のテスト整備(forward/reverse 両方の正常動作確認)
+
+#### Phase 258(次フェーズ)
+- quick profile の次の FAIL へ進む
+- last_index_of が通った後の最初のエラーを調査
---
-**最終更新**: 2025-12-20
+**最終更新**: 2025-12-20 (Phase 257 P0 実装完了、PHI bug は既知の問題として文書化)
diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs b/src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
index 58b66494..5cf11753 100644
--- a/src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
+++ b/src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs
@@ -39,6 +39,15 @@ use crate::ast::{ASTNode, BinaryOperator, LiteralValue};
use crate::mir::builder::MirBuilder;
use crate::mir::ValueId;
+/// Phase 257 P0: Scan direction for forward/reverse scan
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ScanDirection {
+ /// Forward scan: i < s.length(), i = i + 1
+ Forward,
+ /// Reverse scan: i >= 0, i = i - 1
+ Reverse,
+}
+
/// Phase 254 P1: Extracted structure for scan-with-init pattern
///
/// This structure contains all the information needed to lower an index_of-style loop.
@@ -50,12 +59,14 @@ struct ScanParts {
haystack: String,
/// Needle variable name (e.g., "ch")
needle: String,
- /// Step literal (P0: must be 1)
+ /// Step literal (Phase 257: can be 1 forward or -1 reverse)
step_lit: i64,
/// Early return expression (P0: must be Variable(loop_var))
early_return_expr: ASTNode,
/// Not-found return literal (P0: must be -1)
not_found_return_lit: i64,
+ /// Scan direction (Phase 257 P0)
+ scan_direction: ScanDirection,
}
/// Phase 254 P0: Detection for Pattern 6 (ScanWithInit)
@@ -133,16 +144,18 @@ fn contains_methodcall(node: &ASTNode) -> bool {
}
}
-/// Check if value is ConstStep pattern (i = i + 1)
+/// Check if value is ConstStep pattern (i = i + 1 or i = i - 1)
+/// Phase 257 P0: Accept both forward (Add) and reverse (Subtract)
fn is_const_step_pattern(value: &ASTNode) -> bool {
match value {
ASTNode::BinaryOp {
- operator: crate::ast::BinaryOperator::Add,
+ operator,
left,
right,
..
} => {
- matches!(left.as_ref(), ASTNode::Variable { .. })
+ matches!(operator, crate::ast::BinaryOperator::Add | crate::ast::BinaryOperator::Subtract)
+ && matches!(left.as_ref(), ASTNode::Variable { .. })
&& matches!(right.as_ref(), ASTNode::Literal { .. })
}
_ => false,
@@ -168,8 +181,8 @@ fn is_const_step_pattern(value: &ASTNode) -> bool {
///
/// # P0 Restrictions
///
-/// - Loop condition must be `i < s.length()`
-/// - Step must be `i = i + 1` (step_lit == 1)
+/// - Loop condition must be `i < s.length()` (forward) or `i >= 0` (reverse)
+/// - Step must be `i = i + 1` (forward, step_lit == 1) or `i = i - 1` (reverse, step_lit == -1)
/// - Not-found return must be `-1`
/// - Early return must be `return loop_var`
fn extract_scan_with_init_parts(
@@ -179,8 +192,9 @@ fn extract_scan_with_init_parts(
) -> Result