feat(joinir): Phase 61-1 If-in-loop JoinIR化インフラ整備完了
## 実装内容 ### 新規ファイル - `if_phi_context.rs`: If-in-loop用PHIコンテキスト構造体 (135行) - `IfPhiContext::for_loop_body()`: ループ内if用コンストラクタ - `is_carrier()`: ループキャリア変数判定 - 単体テスト2個完全動作 ### 既存ファイル拡張 - `if_select.rs`, `if_merge.rs`: context パラメータ追加 (+68行) - `with_context()` コンストラクタ実装 - Pure If との完全互換性維持 - `mod.rs`: `try_lower_if_to_joinir()` シグネチャ拡張 (+25行) - `context: Option<&IfPhiContext>` パラメータ追加 - 既存呼び出し箇所6箇所修正完了 - `loop_builder.rs`: JoinIR経路実装 (+43行) - `NYASH_JOINIR_IF_SELECT=1` で試行 - フォールバック設計(PhiBuilderBox経路保持) - デバッグログ完備 ## テスト結果 - ✅ loopform テスト 14/14 PASS(退行なし) - ✅ ビルド成功(エラー0件) - ✅ Borrow Checker 問題解決 ## コード変更量 - 新規: +135行 - 拡張: +136行 - 削除: -18行 - 純増: +253行(インフラ投資、Phase 61-3で-226行削減予定) ## 次のステップ Phase 61-2: join_inst dry-run実装で実際のPHI生成を行う 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -131,7 +131,7 @@
|
|||||||
- docs:
|
- docs:
|
||||||
- `docs/private/roadmap2/phases/phase-46-ifmerge-loop-reassign/README.md`
|
- `docs/private/roadmap2/phases/phase-46-ifmerge-loop-reassign/README.md`
|
||||||
|
|
||||||
### 1-00i. Phase 49–56 — JoinIR Frontend 本線統合(print_tokens / filter)✅ 進行中
|
### 1-00i. Phase 49–56 — JoinIR Frontend 本線統合(print_tokens / filter)✅ 完了
|
||||||
|
|
||||||
- Phase 49–52: `cf_loop` に JoinIR Frontend ルートを追加し(dev フラグ付き)、`LoopFrontendBinding` / JSON v0 / expr タイプ(Field/NewBox)を整備。
|
- Phase 49–52: `cf_loop` に JoinIR Frontend ルートを追加し(dev フラグ付き)、`LoopFrontendBinding` / JSON v0 / expr タイプ(Field/NewBox)を整備。
|
||||||
- `HAKO_JOINIR_PRINT_TOKENS_MAIN` / `HAKO_JOINIR_ARRAY_FILTER_MAIN` で対象ループだけを Frontend 経由にルーティング。
|
- `HAKO_JOINIR_PRINT_TOKENS_MAIN` / `HAKO_JOINIR_ARRAY_FILTER_MAIN` で対象ループだけを Frontend 経由にルーティング。
|
||||||
@ -140,6 +140,17 @@
|
|||||||
- Phase 56: `ArrayExtBox.filter/2` 向けに `LoopFrontendBinding::for_array_filter` を MethodCall ベース(`arr.size()`)に修正し、外部参照 `arr/pred` を Binding 経由で渡す構造に統一。
|
- Phase 56: `ArrayExtBox.filter/2` 向けに `LoopFrontendBinding::for_array_filter` を MethodCall ベース(`arr.size()`)に修正し、外部参照 `arr/pred` を Binding 経由で渡す構造に統一。
|
||||||
- JoinIR に `ConditionalMethodCall` / Unary / Call を追加し、filter の「pred が true のときだけ push する」パターンを 4 ブロック構造で表現。
|
- JoinIR に `ConditionalMethodCall` / Unary / Call を追加し、filter の「pred が true のときだけ push する」パターンを 4 ブロック構造で表現。
|
||||||
- `HAKO_JOINIR_ARRAY_FILTER_MAIN=1` で Route B(JoinIR Frontend 経路)がフォールバックなし完走(テスト済み、既定は従来ルート)。
|
- `HAKO_JOINIR_ARRAY_FILTER_MAIN=1` で Route B(JoinIR Frontend 経路)がフォールバックなし完走(テスト済み、既定は従来ルート)。
|
||||||
|
|
||||||
|
### 1-00j. Phase 57–58 — If 側 PHI Level 3 本体(conservative/if_phi 残り)✅ 仕上げ中
|
||||||
|
|
||||||
|
- Phase 57 では、新しい抽象を増やさずに既存の Conservative/IfPHI 本体のうち安全な部分を薄くした。
|
||||||
|
- `phi.rs` での冗長な `ConservativeMerge::analyze` 呼び出しを 2 回→1 回に削減し、軽量化。
|
||||||
|
- `PhiMergeOps` trait と loop_builder.rs 側の実装を完全削除し、Loop 側の PHI 生成責務を JoinIR+LoopScopeShape 側に寄せた。
|
||||||
|
- `infer_type_from_phi` には「レガシー型推論箱であり、JoinIR 型情報導入後の削減候補」であることをコメントで明示し、将来の削除条件をドキュメント化。
|
||||||
|
- Phase 58 では ConservativeMerge 本体を `phi_merge.rs::merge_all_vars` にインライン化し、`conservative.rs` の多くをドキュメントコメント+最小限の補助関数だけに縮退。
|
||||||
|
- conservative.rs: 149 行 → 57 行(約 92 行削減、約 62% 削減)。
|
||||||
|
- ConservativeMerge struct 定義と付随テストコードを削除し、挙動差分がないことを phi_core / JoinIR テストで確認。
|
||||||
|
- JoinIR/phi_core 関連テストは全て PASS。既知の `local` キーワード問題を除き、新たな退行はなし。
|
||||||
- Phase P1: **If Handler 箱化モジュール化** ✅ 完了(2025-11-29)
|
- Phase P1: **If Handler 箱化モジュール化** ✅ 完了(2025-11-29)
|
||||||
- ループ内 If 処理の 5 パターン(Empty/SingleVarThen/SingleVarBoth/ConditionalEffect/Unsupported)を `IfInLoopPattern` enum で分類。
|
- ループ内 If 処理の 5 パターン(Empty/SingleVarThen/SingleVarBoth/ConditionalEffect/Unsupported)を `IfInLoopPattern` enum で分類。
|
||||||
- `if_in_loop/` モジュール(9 ファイル、~480 行)を新設し、`stmt_handlers.rs` から 154 行削減(40% 削減達成)。
|
- `if_in_loop/` モジュール(9 ファイル、~480 行)を新設し、`stmt_handlers.rs` から 154 行削減(40% 削減達成)。
|
||||||
@ -166,6 +177,9 @@
|
|||||||
- 他の関数(print_tokens 等)も JoinIR 経路に乗せてから本体削除
|
- 他の関数(print_tokens 等)も JoinIR 経路に乗せてから本体削除
|
||||||
- **Classifier Trio**
|
- **Classifier Trio**
|
||||||
- LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox を LoopScopeShape に吸収し、JoinIR lowering / LoopForm 側から直接 LoopScopeShape を見る構造に整理。
|
- LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox を LoopScopeShape に吸収し、JoinIR lowering / LoopForm 側から直接 LoopScopeShape を見る構造に整理。
|
||||||
|
- **Mir 決定性(小フェーズ予定)**
|
||||||
|
- 一部テスト(`loop_with_continue_and_break_edge_copy_merge` / `nested_loop_with_multi_continue_break_edge_copy_merge`)で、`MirFunction.blocks: HashMap` / `BasicBlock.predecessors: HashSet` に起因する非決定的な predecessor 順のフラッキーテストが残っている。
|
||||||
|
- 将来の小フェーズで Phase 25.1 と同様のパターン(`BTreeMap` / `BTreeSet` など決定的な順序構造、もしくはテスト側で sort 比較)に寄せて解消する予定。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ impl IfLoweringDryRunner {
|
|||||||
func,
|
func,
|
||||||
*block_id,
|
*block_id,
|
||||||
self.debug_level >= 3,
|
self.debug_level >= 3,
|
||||||
|
None, // Phase 61-1: Pure If(dry-runは常にPure If)
|
||||||
) {
|
) {
|
||||||
Some(join_inst) => {
|
Some(join_inst) => {
|
||||||
lowered_count += 1;
|
lowered_count += 1;
|
||||||
|
|||||||
@ -18,8 +18,13 @@ use crate::mir::join_ir::{JoinInst, MergePair};
|
|||||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
// Phase 61-1: If-in-loop context support
|
||||||
|
use super::if_phi_context::IfPhiContext;
|
||||||
|
|
||||||
pub struct IfMergeLowerer {
|
pub struct IfMergeLowerer {
|
||||||
debug_level: u8,
|
debug_level: u8,
|
||||||
|
// Phase 61-1: If-in-loop context (None = Pure If)
|
||||||
|
context: Option<IfPhiContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 検出された IfMerge パターン情報
|
/// 検出された IfMerge パターン情報
|
||||||
@ -39,13 +44,37 @@ struct IfBranch {
|
|||||||
|
|
||||||
impl IfMergeLowerer {
|
impl IfMergeLowerer {
|
||||||
pub fn new(debug_level: u8) -> Self {
|
pub fn new(debug_level: u8) -> Self {
|
||||||
Self { debug_level }
|
Self {
|
||||||
|
debug_level,
|
||||||
|
context: None, // Phase 61-1: デフォルトは Pure If
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 33-8: debug-level backward compat wrapper
|
/// Phase 33-8: debug-level backward compat wrapper
|
||||||
pub fn with_debug(debug: bool) -> Self {
|
pub fn with_debug(debug: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
debug_level: if debug { 1 } else { 0 },
|
debug_level: if debug { 1 } else { 0 },
|
||||||
|
context: None, // Phase 61-1: デフォルトは Pure If
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 61-1: If-in-loop 用コンストラクタ
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `debug_level` - デバッグログレベル (0-3)
|
||||||
|
/// * `context` - If-in-loop コンテキスト(carrier_names 情報を含む)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
/// let lowerer = IfMergeLowerer::with_context(debug_level, context);
|
||||||
|
/// ```
|
||||||
|
pub fn with_context(debug_level: u8, context: IfPhiContext) -> Self {
|
||||||
|
Self {
|
||||||
|
debug_level,
|
||||||
|
context: Some(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
132
src/mir/join_ir/lowering/if_phi_context.rs
Normal file
132
src/mir/join_ir/lowering/if_phi_context.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//! Phase 61-1: If-in-loop 用 PHI コンテキスト
|
||||||
|
//!
|
||||||
|
//! loop_builder.rs から carrier_names 情報を JoinIR に渡すための構造体
|
||||||
|
//!
|
||||||
|
//! ## 背景
|
||||||
|
//!
|
||||||
|
//! ループ内の if では、ループキャリア変数に対して「片腕 PHI」が必要になる。
|
||||||
|
//! 従来は PhiBuilderBox::set_if_context() で carrier_names を渡していたが、
|
||||||
|
//! Phase 61-1 で JoinIR 経路に統一するため、この情報を渡す手段が必要。
|
||||||
|
//!
|
||||||
|
//! ## 設計
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! // loop_builder.rs
|
||||||
|
//! let carrier_names = ...;
|
||||||
|
//! let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
//! try_lower_if_to_joinir(func, block_id, debug, Some(&context));
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## 責務
|
||||||
|
//!
|
||||||
|
//! - ループ内 if のコンテキスト情報を保持
|
||||||
|
//! - carrier_names の判定ユーティリティ提供
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
/// If-in-loop 用 PHI コンテキスト
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct IfPhiContext {
|
||||||
|
/// ループ内の if かどうか
|
||||||
|
///
|
||||||
|
/// true の場合、carrier_names に含まれる変数は「片腕 PHI」が必要
|
||||||
|
pub in_loop_body: bool,
|
||||||
|
|
||||||
|
/// ループキャリア変数名リスト
|
||||||
|
///
|
||||||
|
/// ループ内 if で片腕 PHI が必要な変数を指定する。
|
||||||
|
/// 例: `loop(i < 3) { if cond { x = 1 } }` の場合、
|
||||||
|
/// x は carrier 変数として扱われ、else 側で pre_if 値を使用する PHI を生成する。
|
||||||
|
pub carrier_names: BTreeSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IfPhiContext {
|
||||||
|
/// ループ内 if 用コンテキスト作成
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `carrier_names` - ループキャリア変数名リスト(BTreeSet で決定的イテレーション保証)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let carrier_names = pre_if_var_map
|
||||||
|
/// .keys()
|
||||||
|
/// .filter(|name| !name.starts_with("__pin$"))
|
||||||
|
/// .cloned()
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
/// ```
|
||||||
|
pub fn for_loop_body(carrier_names: BTreeSet<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
in_loop_body: true,
|
||||||
|
carrier_names,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 指定された変数がループキャリアかどうか判定
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `var_name` - 判定対象の変数名
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// - `true`: ループキャリア変数(片腕 PHI が必要)
|
||||||
|
/// - `false`: 通常変数(純粋な if PHI)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// if context.is_carrier("x") {
|
||||||
|
/// // 片腕 PHI 生成: phi [then_val, pre_if_val]
|
||||||
|
/// } else {
|
||||||
|
/// // 純粋 if PHI: phi [then_val, else_val]
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn is_carrier(&self, var_name: &str) -> bool {
|
||||||
|
self.carrier_names.contains(var_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ループキャリア変数の数を取得
|
||||||
|
pub fn carrier_count(&self) -> usize {
|
||||||
|
self.carrier_names.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ループ内 if かどうか判定
|
||||||
|
pub fn is_in_loop(&self) -> bool {
|
||||||
|
self.in_loop_body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_for_loop_body() {
|
||||||
|
let mut carrier_names = BTreeSet::new();
|
||||||
|
carrier_names.insert("x".to_string());
|
||||||
|
carrier_names.insert("y".to_string());
|
||||||
|
|
||||||
|
let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
|
||||||
|
assert!(context.is_in_loop());
|
||||||
|
assert!(context.is_carrier("x"));
|
||||||
|
assert!(context.is_carrier("y"));
|
||||||
|
assert!(!context.is_carrier("z"));
|
||||||
|
assert_eq!(context.carrier_count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_carrier() {
|
||||||
|
let mut carrier_names = BTreeSet::new();
|
||||||
|
carrier_names.insert("loop_var".to_string());
|
||||||
|
|
||||||
|
let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
|
||||||
|
assert!(context.is_carrier("loop_var"));
|
||||||
|
assert!(!context.is_carrier("local_var"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,8 +13,13 @@
|
|||||||
use crate::mir::join_ir::JoinInst;
|
use crate::mir::join_ir::JoinInst;
|
||||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||||
|
|
||||||
|
// Phase 61-1: If-in-loop context support
|
||||||
|
use super::if_phi_context::IfPhiContext;
|
||||||
|
|
||||||
pub struct IfSelectLowerer {
|
pub struct IfSelectLowerer {
|
||||||
debug_level: u8,
|
debug_level: u8,
|
||||||
|
// Phase 61-1: If-in-loop context (None = Pure If)
|
||||||
|
context: Option<IfPhiContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If/Else パターンの分類
|
/// If/Else パターンの分類
|
||||||
@ -46,13 +51,37 @@ struct IfBranch {
|
|||||||
|
|
||||||
impl IfSelectLowerer {
|
impl IfSelectLowerer {
|
||||||
pub fn new(debug_level: u8) -> Self {
|
pub fn new(debug_level: u8) -> Self {
|
||||||
Self { debug_level }
|
Self {
|
||||||
|
debug_level,
|
||||||
|
context: None, // Phase 61-1: デフォルトは Pure If
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 33-8: debug-level backward compat wrapper
|
/// Phase 33-8: debug-level backward compat wrapper
|
||||||
pub fn with_debug(debug: bool) -> Self {
|
pub fn with_debug(debug: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
debug_level: if debug { 1 } else { 0 },
|
debug_level: if debug { 1 } else { 0 },
|
||||||
|
context: None, // Phase 61-1: デフォルトは Pure If
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 61-1: If-in-loop 用コンストラクタ
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `debug_level` - デバッグログレベル (0-3)
|
||||||
|
/// * `context` - If-in-loop コンテキスト(carrier_names 情報を含む)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let context = IfPhiContext::for_loop_body(carrier_names);
|
||||||
|
/// let lowerer = IfSelectLowerer::with_context(debug_level, context);
|
||||||
|
/// ```
|
||||||
|
pub fn with_context(debug_level: u8, context: IfPhiContext) -> Self {
|
||||||
|
Self {
|
||||||
|
debug_level,
|
||||||
|
context: Some(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ pub mod funcscanner_trim;
|
|||||||
pub mod generic_case_a;
|
pub mod generic_case_a;
|
||||||
pub mod if_dry_runner; // Phase 33-10.0
|
pub mod if_dry_runner; // Phase 33-10.0
|
||||||
pub mod if_merge; // Phase 33-7
|
pub mod if_merge; // Phase 33-7
|
||||||
|
pub mod if_phi_context; // Phase 61-1
|
||||||
pub mod if_select; // Phase 33
|
pub mod if_select; // Phase 33
|
||||||
pub mod loop_form_intake;
|
pub mod loop_form_intake;
|
||||||
pub mod loop_scope_shape;
|
pub mod loop_scope_shape;
|
||||||
@ -92,11 +93,16 @@ pub(crate) fn is_loop_lowered_function(name: &str) -> bool {
|
|||||||
/// - 1 variable → Select
|
/// - 1 variable → Select
|
||||||
/// - 2+ variables → IfMerge
|
/// - 2+ variables → IfMerge
|
||||||
///
|
///
|
||||||
|
/// Phase 61-1: If-in-loop support
|
||||||
|
/// - `context` parameter: If-in-loop context (carrier_names for loop variables)
|
||||||
|
/// - None = Pure If, Some(_) = If-in-loop
|
||||||
|
///
|
||||||
/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise.
|
/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise.
|
||||||
pub fn try_lower_if_to_joinir(
|
pub fn try_lower_if_to_joinir(
|
||||||
func: &MirFunction,
|
func: &MirFunction,
|
||||||
block_id: BasicBlockId,
|
block_id: BasicBlockId,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
context: Option<&if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context
|
||||||
) -> Option<JoinInst> {
|
) -> Option<JoinInst> {
|
||||||
// 1. dev トグルチェック
|
// 1. dev トグルチェック
|
||||||
if !crate::config::env::joinir_if_select_enabled() {
|
if !crate::config::env::joinir_if_select_enabled() {
|
||||||
@ -151,7 +157,12 @@ pub fn try_lower_if_to_joinir(
|
|||||||
|
|
||||||
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
// 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン)
|
||||||
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
// IfMerge が成功すればそれを返す、失敗したら Select を試行
|
||||||
let if_merge_lowerer = if_merge::IfMergeLowerer::new(debug_level);
|
// Phase 61-1: context がある場合は with_context() を使用
|
||||||
|
let if_merge_lowerer = if let Some(ctx) = context {
|
||||||
|
if_merge::IfMergeLowerer::with_context(debug_level, ctx.clone())
|
||||||
|
} else {
|
||||||
|
if_merge::IfMergeLowerer::new(debug_level)
|
||||||
|
};
|
||||||
|
|
||||||
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
if if_merge_lowerer.can_lower_to_if_merge(func, block_id) {
|
||||||
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) {
|
||||||
@ -166,7 +177,12 @@ pub fn try_lower_if_to_joinir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
// 4. IfMerge が失敗したら Select を試行(単一変数パターン)
|
||||||
let if_select_lowerer = if_select::IfSelectLowerer::new(debug_level);
|
// Phase 61-1: context がある場合は with_context() を使用
|
||||||
|
let if_select_lowerer = if let Some(ctx) = context {
|
||||||
|
if_select::IfSelectLowerer::with_context(debug_level, ctx.clone())
|
||||||
|
} else {
|
||||||
|
if_select::IfSelectLowerer::new(debug_level)
|
||||||
|
};
|
||||||
|
|
||||||
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
if !if_select_lowerer.can_lower_to_select(func, block_id) {
|
||||||
if debug_level >= 1 {
|
if debug_level >= 1 {
|
||||||
|
|||||||
@ -1151,38 +1151,76 @@ impl<'a> LoopBuilder<'a> {
|
|||||||
// Region 情報(entry/exit/slots)をログに出すよ。
|
// Region 情報(entry/exit/slots)をログに出すよ。
|
||||||
crate::mir::region::observer::observe_control_form(self.parent_builder, &form);
|
crate::mir::region::observer::observe_control_form(self.parent_builder, &form);
|
||||||
|
|
||||||
let mut ops = Ops(self);
|
// Phase 61-1: If-in-loop JoinIR化(開発フラグ制御)
|
||||||
|
// carrier_namesを作成(両経路で共通)
|
||||||
// Phase 26-F-2: BodyLocalPhiBuilder削除
|
|
||||||
// Phase 35-5: if_body_local_merge.rs削除、PhiBuilderBoxに吸収
|
|
||||||
// 理由: 箱理論による責務分離(ループスコープ分析 vs if-merge専用処理)
|
|
||||||
|
|
||||||
// Phase 26-E: PhiBuilderBox SSOT統合(If PHI生成)
|
|
||||||
// Legacy: merge_modified_with_control() → New: PhiBuilderBox::generate_phis()
|
|
||||||
let mut phi_builder = crate::mir::phi_core::phi_builder_box::PhiBuilderBox::new();
|
|
||||||
|
|
||||||
// Phase 26-F-3: ループ内if-mergeコンテキスト設定(ChatGPT設計)
|
|
||||||
// pre_if_var_mapにある全変数をcarrier候補として扱う(保守的だが安全)
|
|
||||||
// 理由: ループ内変数は全てキャリア候補の可能性があるため
|
|
||||||
let carrier_names: std::collections::BTreeSet<String> = pre_if_var_map
|
let carrier_names: std::collections::BTreeSet<String> = pre_if_var_map
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|name| !name.starts_with("__pin$")) // 一時変数除外
|
.filter(|name| !name.starts_with("__pin$")) // 一時変数除外
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
phi_builder.set_if_context(
|
// Phase 61-1: JoinIR経路を試行(`Ops`作成前に実行)
|
||||||
true, // in_loop_body = true
|
let joinir_success = if crate::config::env::joinir_if_select_enabled() {
|
||||||
carrier_names,
|
// IfPhiContext作成
|
||||||
);
|
let if_phi_context =
|
||||||
|
crate::mir::join_ir::lowering::if_phi_context::IfPhiContext::for_loop_body(
|
||||||
|
carrier_names.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
// Phase 35-5: if_body_local_merge.rs削除、ロジックはPhiBuilderBox内に統合
|
// JoinIR経路を試行
|
||||||
|
if let Some(ref func) = self.parent_builder.current_function {
|
||||||
|
match crate::mir::join_ir::lowering::try_lower_if_to_joinir(
|
||||||
|
func,
|
||||||
|
pre_branch_bb,
|
||||||
|
false, // debug
|
||||||
|
Some(&if_phi_context),
|
||||||
|
) {
|
||||||
|
Some(join_inst) => {
|
||||||
|
eprintln!("[Phase 61-1] ✅ If-in-loop lowered via JoinIR: {:?}", join_inst);
|
||||||
|
|
||||||
let post_snapshots = if let Some(ref else_map) = else_var_map_end_opt {
|
// TODO: join_inst を dry-run して PHI 生成
|
||||||
vec![then_var_map_end.clone(), else_map.clone()]
|
// Phase 61-1では一旦スキップし、Phase 61-2で実装
|
||||||
|
eprintln!("[Phase 61-1] ⚠️ JoinIR dry-run not yet implemented, using fallback");
|
||||||
|
false // 一旦フォールバック
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
eprintln!("[Phase 61-1] ⏭️ JoinIR pattern not matched, using fallback");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![then_var_map_end.clone()]
|
false
|
||||||
};
|
};
|
||||||
phi_builder.generate_phis(&mut ops, &form, &pre_if_var_map, &post_snapshots)?;
|
|
||||||
|
let mut ops = Ops(self);
|
||||||
|
|
||||||
|
// Phase 26-F-2: BodyLocalPhiBuilder削除
|
||||||
|
// Phase 35-5: if_body_local_merge.rs削除、PhiBuilderBoxに吸収
|
||||||
|
// 理由: 箱理論による責務分離(ループスコープ分析 vs if-merge専用処理)
|
||||||
|
|
||||||
|
// フォールバック: PhiBuilderBox経路(既存)
|
||||||
|
if !joinir_success {
|
||||||
|
// Phase 26-E: PhiBuilderBox SSOT統合(If PHI生成)
|
||||||
|
// Legacy: merge_modified_with_control() → New: PhiBuilderBox::generate_phis()
|
||||||
|
let mut phi_builder = crate::mir::phi_core::phi_builder_box::PhiBuilderBox::new();
|
||||||
|
|
||||||
|
// Phase 26-F-3: ループ内if-mergeコンテキスト設定(ChatGPT設計)
|
||||||
|
phi_builder.set_if_context(
|
||||||
|
true, // in_loop_body = true
|
||||||
|
carrier_names,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Phase 35-5: if_body_local_merge.rs削除、ロジックはPhiBuilderBox内に統合
|
||||||
|
let post_snapshots = if let Some(ref else_map) = else_var_map_end_opt {
|
||||||
|
vec![then_var_map_end.clone(), else_map.clone()]
|
||||||
|
} else {
|
||||||
|
vec![then_var_map_end.clone()]
|
||||||
|
};
|
||||||
|
phi_builder.generate_phis(&mut ops, &form, &pre_if_var_map, &post_snapshots)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 26-E-4: PHI生成後に variable_map をリセット(ChatGPT/Task先生指示)
|
// Phase 26-E-4: PHI生成後に variable_map をリセット(ChatGPT/Task先生指示)
|
||||||
// 理由: else_var_map_end_opt が正しい snapshot を保持したまま PHI 生成に渡す必要がある
|
// 理由: else_var_map_end_opt が正しい snapshot を保持したまま PHI 生成に渡す必要がある
|
||||||
|
|||||||
@ -133,7 +133,7 @@ mod tests {
|
|||||||
|
|
||||||
let func = create_simple_pattern_mir();
|
let func = create_simple_pattern_mir();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, true);
|
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_some(),
|
result.is_some(),
|
||||||
@ -159,7 +159,7 @@ mod tests {
|
|||||||
// ==== 2. Local pattern (env ON) ====
|
// ==== 2. Local pattern (env ON) ====
|
||||||
let func = create_local_pattern_mir();
|
let func = create_local_pattern_mir();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, true);
|
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_some(),
|
result.is_some(),
|
||||||
@ -187,7 +187,7 @@ mod tests {
|
|||||||
|
|
||||||
let func = create_simple_pattern_mir();
|
let func = create_simple_pattern_mir();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, false);
|
let result = try_lower_if_to_joinir(&func, entry_block, false, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_none(),
|
result.is_none(),
|
||||||
@ -202,7 +202,7 @@ mod tests {
|
|||||||
let mut func = create_simple_pattern_mir();
|
let mut func = create_simple_pattern_mir();
|
||||||
func.signature.name = "WrongName.test/1".to_string();
|
func.signature.name = "WrongName.test/1".to_string();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, true);
|
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_none(),
|
result.is_none(),
|
||||||
@ -519,7 +519,7 @@ mod tests {
|
|||||||
|
|
||||||
let func = create_if_merge_simple_pattern_mir();
|
let func = create_if_merge_simple_pattern_mir();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, true);
|
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_some(),
|
result.is_some(),
|
||||||
@ -560,7 +560,7 @@ mod tests {
|
|||||||
|
|
||||||
let func = create_if_merge_multiple_pattern_mir();
|
let func = create_if_merge_multiple_pattern_mir();
|
||||||
let entry_block = func.entry_block;
|
let entry_block = func.entry_block;
|
||||||
let result = try_lower_if_to_joinir(&func, entry_block, true);
|
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_some(),
|
result.is_some(),
|
||||||
|
|||||||
Reference in New Issue
Block a user