feat(joinir): Phase 92完了 - ConditionalStep + body-local変数サポート
## Phase 92全体の成果 **Phase 92 P0-P2**: ConditionalStep JoinIR生成とbody-local変数サポート - ConditionalStep(条件付きキャリア更新)のJoinIR生成実装 - Body-local変数(ch等)の条件式での参照サポート - 変数解決優先度: ConditionEnv → LoopBodyLocalEnv **Phase 92 P3**: BodyLocalPolicyBox + 安全ガード - BodyLocalPolicyDecision実装(Accept/Reject判定) - BodyLocalSlot + DualValueRewriter(JoinIR/MIR二重書き込み) - Fail-Fast契約(Cannot promote LoopBodyLocal検出) **Phase 92 P4**: E2E固定+回帰最小化 (本コミット) - Unit test 3本追加(body-local変数解決検証) - Integration smoke追加(phase92_pattern2_baseline.sh、2ケースPASS) - P4-E2E-PLAN.md、P4-COMPLETION.md作成 ## 主要な実装 ### ConditionalStep(条件付きキャリア更新) - `conditional_step_emitter.rs`: JoinIR Select命令生成 - `loop_with_break_minimal.rs`: ConditionalStep検出と統合 - `loop_with_continue_minimal.rs`: Pattern4対応 ### Body-local変数サポート - `condition_lowerer.rs`: body-local変数解決機能 - `lower_condition_to_joinir`: body_local_env パラメータ追加 - 変数解決優先度実装(ConditionEnv優先) - Unit test 3本追加: 変数解決/優先度/エラー - `header_break_lowering.rs`: break条件でbody-local変数参照 - 7ファイルで後方互換ラッパー(lower_condition_to_joinir_no_body_locals) ### Body-local Policy & Safety - `body_local_policy.rs`: BodyLocalPolicyDecision(Accept/Reject) - `body_local_slot.rs`: JoinIR/MIR二重書き込み - `dual_value_rewriter.rs`: ValueId書き換えヘルパー ## テスト体制 ### Unit Tests (+3) - `test_body_local_variable_resolution`: body-local変数解決 - `test_variable_resolution_priority`: 変数解決優先度(ConditionEnv優先) - `test_undefined_variable_error`: 未定義変数エラー - 全7テストPASS(cargo test --release condition_lowerer::tests) ### Integration Smoke (+1) - `phase92_pattern2_baseline.sh`: - Case A: loop_min_while.hako (Pattern2 baseline) - Case B: phase92_conditional_step_minimal.hako (条件付きインクリメント) - 両ケースPASS、integration profileで発見可能 ### 退行確認 - ✅ 既存Pattern2Breakテスト正常(退行なし) - ✅ Phase 135 smoke正常(MIR検証PASS) ## アーキテクチャ設計 ### 変数解決メカニズム ```rust // Priority 1: ConditionEnv (loop params, captured) if let Some(value_id) = env.get(name) { return Ok(value_id); } // Priority 2: LoopBodyLocalEnv (body-local like `ch`) if let Some(body_env) = body_local_env { if let Some(value_id) = body_env.get(name) { return Ok(value_id); } } ``` ### Fail-Fast契約 - Delta equality check (conditional_step_emitter.rs) - Variable resolution error messages (ConditionEnv) - Body-local promotion rejection (BodyLocalPolicyDecision::Reject) ## ドキュメント - `P4-E2E-PLAN.md`: 3レベルテスト戦略(Level 1-2完了、Level 3延期) - `P4-COMPLETION.md`: Phase 92完了報告 - `README.md`: Phase 92全体のまとめ ## 将来の拡張(Phase 92スコープ外) - Body-local promotionシステム拡張 - P5bパターン認識の汎化(flagベース条件サポート) - 完全なP5b E2Eテスト(body-local promotion実装後) 🎯 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -25,9 +25,12 @@ pub(super) fn allocate_blocks(
|
||||
// This exit_block_id will be returned and used by instruction_rewriter and exit_phi_builder
|
||||
let exit_block_id = builder.next_block_id();
|
||||
|
||||
eprintln!(
|
||||
"[cf_loop/joinir/block_allocator] Phase 177-3: Allocated exit_block_id = {:?}",
|
||||
exit_block_id
|
||||
trace::trace().dev(
|
||||
"cf_loop/joinir/block_allocator",
|
||||
&format!(
|
||||
"Phase 177-3: Allocated exit_block_id = {:?}",
|
||||
exit_block_id
|
||||
),
|
||||
);
|
||||
|
||||
// Phase 195: Use unified trace
|
||||
|
||||
@ -53,13 +53,17 @@ pub fn init_value(
|
||||
name: &str,
|
||||
debug: bool,
|
||||
) -> ValueId {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
match init {
|
||||
CarrierInit::FromHost => {
|
||||
// Use host variable's ValueId directly (no const emission needed)
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[carrier_init_builder] '{}': FromHost -> ValueId({})",
|
||||
name, host_id.0
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[carrier_init_builder] '{}': FromHost -> ValueId({})",
|
||||
name, host_id.0
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
host_id
|
||||
@ -72,9 +76,12 @@ pub fn init_value(
|
||||
value: ConstValue::Bool(*val),
|
||||
});
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[carrier_init_builder] '{}': BoolConst({}) -> ValueId({})",
|
||||
name, val, const_id.0
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[carrier_init_builder] '{}': BoolConst({}) -> ValueId({})",
|
||||
name, val, const_id.0
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
const_id
|
||||
@ -87,9 +94,12 @@ pub fn init_value(
|
||||
value: ConstValue::Integer(0),
|
||||
});
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[carrier_init_builder] '{}': LoopLocalZero -> ValueId({})",
|
||||
name, const_id.0
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[carrier_init_builder] '{}': LoopLocalZero -> ValueId({})",
|
||||
name, const_id.0
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
const_id
|
||||
|
||||
@ -84,20 +84,31 @@ impl ExitMetaCollector {
|
||||
let dev_on = crate::config::env::joinir_dev_enabled();
|
||||
let verbose = debug || dev_on;
|
||||
let strict = crate::config::env::joinir_strict_enabled() || dev_on;
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] ExitMetaCollector: Collecting {} exit values",
|
||||
exit_meta.exit_values.len()
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"Collecting {} exit values",
|
||||
exit_meta.exit_values.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
// Iterate over ExitMeta entries and build bindings
|
||||
for (carrier_name, join_exit_value) in &exit_meta.exit_values {
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] checking carrier '{}' in variable_ctx.variable_map",
|
||||
carrier_name
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"checking carrier '{}' in variable_ctx.variable_map",
|
||||
carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -124,9 +135,14 @@ impl ExitMetaCollector {
|
||||
};
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] collected '{}' JoinIR {:?} → HOST {:?}, role={:?}",
|
||||
carrier_name, join_exit_value, host_slot, role
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"collected '{}' JoinIR {:?} → HOST {:?}, role={:?}",
|
||||
carrier_name, join_exit_value, host_slot, role
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -156,9 +172,14 @@ impl ExitMetaCollector {
|
||||
};
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] collected ConditionOnly carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
|
||||
carrier_name, join_exit_value
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"collected ConditionOnly carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
|
||||
carrier_name, join_exit_value
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -175,9 +196,14 @@ impl ExitMetaCollector {
|
||||
};
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] collected FromHost carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
|
||||
carrier_name, join_exit_value
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"collected FromHost carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
|
||||
carrier_name, join_exit_value
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -193,9 +219,14 @@ impl ExitMetaCollector {
|
||||
};
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] collected loop-local carrier '{}' JoinIR {:?} (no host slot)",
|
||||
carrier_name, join_exit_value
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!(
|
||||
"collected loop-local carrier '{}' JoinIR {:?} (no host slot)",
|
||||
carrier_name, join_exit_value
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -209,7 +240,7 @@ impl ExitMetaCollector {
|
||||
if strict {
|
||||
panic!("{}", msg);
|
||||
} else if verbose {
|
||||
eprintln!("{}", msg);
|
||||
trace.emit_if("exit-line", "collector", &msg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,10 +248,11 @@ impl ExitMetaCollector {
|
||||
}
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] ExitMetaCollector: collected {} bindings: {:?}",
|
||||
bindings.len(),
|
||||
bindings
|
||||
trace.emit_if(
|
||||
"exit-line",
|
||||
"collector",
|
||||
&format!("collected {} bindings: {:?}", bindings.len(), bindings),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -84,11 +84,15 @@ impl ExitLineOrchestrator {
|
||||
carrier_phis: &BTreeMap<String, ValueId>,
|
||||
debug: bool,
|
||||
) -> Result<(), String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let verbose = debug || crate::config::env::joinir_dev_enabled();
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] orchestrator start: {} carrier PHIs",
|
||||
carrier_phis.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] orchestrator start: {} carrier PHIs",
|
||||
carrier_phis.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -96,7 +100,7 @@ impl ExitLineOrchestrator {
|
||||
ExitLineReconnector::reconnect(builder, boundary, carrier_phis, debug)?;
|
||||
|
||||
if verbose {
|
||||
eprintln!("[joinir/exit-line] orchestrator complete");
|
||||
trace.stderr_if("[joinir/exit-line] orchestrator complete", true);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -79,24 +79,31 @@ impl ExitLineReconnector {
|
||||
carrier_phis: &BTreeMap<String, ValueId>,
|
||||
debug: bool,
|
||||
) -> Result<(), String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let dev_on = crate::config::env::joinir_dev_enabled();
|
||||
let strict = crate::config::env::joinir_strict_enabled() || dev_on;
|
||||
let verbose = debug || dev_on;
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] reconnect: {} exit bindings, {} carrier PHIs",
|
||||
boundary.exit_bindings.len(),
|
||||
carrier_phis.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] reconnect: {} exit bindings, {} carrier PHIs",
|
||||
boundary.exit_bindings.len(),
|
||||
carrier_phis.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
if !boundary.exit_bindings.is_empty() {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] bindings {:?}",
|
||||
boundary
|
||||
.exit_bindings
|
||||
.iter()
|
||||
.map(|b| (&b.carrier_name, b.role, b.join_exit_value))
|
||||
.collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] bindings {:?}",
|
||||
boundary
|
||||
.exit_bindings
|
||||
.iter()
|
||||
.map(|b| (&b.carrier_name, b.role, b.join_exit_value))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -104,16 +111,19 @@ impl ExitLineReconnector {
|
||||
// Early return for empty exit_bindings
|
||||
if boundary.exit_bindings.is_empty() {
|
||||
if verbose {
|
||||
eprintln!("[joinir/exit-line] reconnect: no exit bindings, skip");
|
||||
trace.stderr_if("[joinir/exit-line] reconnect: no exit bindings, skip", true);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] reconnecting {} exit bindings with {} carrier PHIs",
|
||||
boundary.exit_bindings.len(),
|
||||
carrier_phis.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] reconnecting {} exit bindings with {} carrier PHIs",
|
||||
boundary.exit_bindings.len(),
|
||||
carrier_phis.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -123,9 +133,12 @@ impl ExitLineReconnector {
|
||||
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||
if binding.role == CarrierRole::ConditionOnly {
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] skip ConditionOnly carrier '{}' (no variable_ctx.variable_map update)",
|
||||
binding.carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] skip ConditionOnly carrier '{}' (no variable_ctx.variable_map update)",
|
||||
binding.carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
@ -135,9 +148,12 @@ impl ExitLineReconnector {
|
||||
let phi_dst = carrier_phis.get(&binding.carrier_name);
|
||||
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] carrier '{}' → phi_dst={:?}",
|
||||
binding.carrier_name, phi_dst
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] carrier '{}' → phi_dst={:?}",
|
||||
binding.carrier_name, phi_dst
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -150,16 +166,22 @@ impl ExitLineReconnector {
|
||||
{
|
||||
// Phase 177-STRUCT: Always log for debugging
|
||||
if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] variable_ctx.variable_map['{}'] {:?} → {:?}",
|
||||
binding.carrier_name, *var_vid, phi_value
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] variable_ctx.variable_map['{}'] {:?} → {:?}",
|
||||
binding.carrier_name, *var_vid, phi_value
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
*var_vid = phi_value;
|
||||
} else if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] warning: carrier '{}' not found in variable_ctx.variable_map",
|
||||
binding.carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] warning: carrier '{}' not found in variable_ctx.variable_map",
|
||||
binding.carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
} else if strict {
|
||||
return Err(format!(
|
||||
@ -175,9 +197,12 @@ impl ExitLineReconnector {
|
||||
carrier_phis.len()
|
||||
));
|
||||
} else if verbose {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] warning: No PHI dst for carrier '{}' (may be condition-only variable)",
|
||||
binding.carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/exit-line] warning: No PHI dst for carrier '{}' (may be condition-only variable)",
|
||||
binding.carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -186,8 +211,9 @@ impl ExitLineReconnector {
|
||||
// Backward compatibility warning for deprecated host_outputs
|
||||
#[allow(deprecated)]
|
||||
if !boundary.host_outputs.is_empty() && debug {
|
||||
eprintln!(
|
||||
"[joinir/exit-line] WARNING: Using deprecated host_outputs. Migrate to exit_bindings."
|
||||
trace.stderr_if(
|
||||
"[joinir/exit-line] WARNING: Using deprecated host_outputs. Migrate to exit_bindings.",
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -220,13 +246,17 @@ impl ExitLineReconnector {
|
||||
variable_map: &BTreeMap<String, ValueId>,
|
||||
) {
|
||||
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
|
||||
for binding in &boundary.exit_bindings {
|
||||
// Phase 228-8: Skip ConditionOnly carriers (not in variable_ctx.variable_map by design)
|
||||
if binding.role == CarrierRole::ConditionOnly {
|
||||
eprintln!(
|
||||
"[JoinIR/ExitLine/Contract] Phase 228-8: Skipping ConditionOnly carrier '{}' (not in variable_ctx.variable_map)",
|
||||
binding.carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[JoinIR/ExitLine/Contract] Phase 228-8: Skipping ConditionOnly carrier '{}' (not in variable_ctx.variable_map)",
|
||||
binding.carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -236,9 +266,12 @@ impl ExitLineReconnector {
|
||||
if phi_dst.is_none() {
|
||||
// Skip loop variable (it's handled separately in loop_header_phi)
|
||||
// Only check carriers that have exit_bindings
|
||||
eprintln!(
|
||||
"[JoinIR/ExitLine/Contract] WARNING: Carrier '{}' has exit_binding but no PHI in carrier_phis",
|
||||
binding.carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[JoinIR/ExitLine/Contract] WARNING: Carrier '{}' has exit_binding but no PHI in carrier_phis",
|
||||
binding.carrier_name
|
||||
),
|
||||
true,
|
||||
);
|
||||
// Don't panic for now - loop variable might not be in carrier_phis
|
||||
// Future: Distinguish loop_var from carriers in exit_bindings
|
||||
|
||||
@ -24,6 +24,8 @@ pub(super) fn build_exit_phi(
|
||||
carrier_inputs: &BTreeMap<String, Vec<(BasicBlockId, ValueId)>>,
|
||||
debug: bool,
|
||||
) -> Result<(Option<ValueId>, BTreeMap<String, ValueId>), String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let verbose = debug || crate::config::env::joinir_dev_enabled();
|
||||
let mut carrier_phis: BTreeMap<String, ValueId> = BTreeMap::new();
|
||||
|
||||
let exit_phi_result_id = if let Some(ref mut func) = builder.scope_ctx.current_function {
|
||||
@ -45,9 +47,12 @@ pub(super) fn build_exit_phi(
|
||||
.instruction_spans
|
||||
.push(crate::ast::Span::unknown());
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Exit block PHI (expr result): {:?} = phi {:?}",
|
||||
phi_dst, exit_phi_inputs
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Exit block PHI (expr result): {:?} = phi {:?}",
|
||||
phi_dst, exit_phi_inputs
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
Some(phi_dst)
|
||||
@ -78,19 +83,25 @@ pub(super) fn build_exit_phi(
|
||||
|
||||
carrier_phis.insert(carrier_name.clone(), phi_dst);
|
||||
|
||||
// DEBUG-177: Always log exit block PHI creation for carrier debugging
|
||||
eprintln!(
|
||||
"[DEBUG-177] Exit block PHI (carrier '{}'): {:?} = phi {:?}",
|
||||
carrier_name, phi_dst, inputs
|
||||
// DEBUG-177: Exit block PHI creation for carrier debugging
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Exit block PHI (carrier '{}'): {:?} = phi {:?}",
|
||||
carrier_name, phi_dst, inputs
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
|
||||
func.add_block(exit_block);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Created exit block: {:?} with {} carrier PHIs",
|
||||
exit_block_id,
|
||||
carrier_phis.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Created exit block: {:?} with {} carrier PHIs",
|
||||
exit_block_id,
|
||||
carrier_phis.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
phi_result
|
||||
|
||||
@ -45,25 +45,33 @@ impl ExprResultResolver {
|
||||
remapper: &JoinIrIdRemapper,
|
||||
debug: bool,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
|
||||
// Step 1: Check if expr_result exists
|
||||
let expr_result_id = match expr_result {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 221: expr_result is None, returning None");
|
||||
trace.stderr_if(
|
||||
"[cf_loop/joinir] Phase 221: expr_result is None, returning None",
|
||||
true,
|
||||
);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 221: Resolving expr_result {:?}, exit_bindings={:?}",
|
||||
expr_result_id,
|
||||
exit_bindings
|
||||
.iter()
|
||||
.map(|b| (b.carrier_name.as_str(), b.join_exit_value))
|
||||
.collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 221: Resolving expr_result {:?}, exit_bindings={:?}",
|
||||
expr_result_id,
|
||||
exit_bindings
|
||||
.iter()
|
||||
.map(|b| (b.carrier_name.as_str(), b.join_exit_value))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -74,9 +82,12 @@ impl ExprResultResolver {
|
||||
// expr_result is a carrier! Use the carrier PHI dst
|
||||
if let Some(&carrier_phi_dst) = carrier_phis.get(&binding.carrier_name) {
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 221: expr_result {:?} is carrier '{}', returning PHI dst {:?}",
|
||||
expr_result_id, binding.carrier_name, carrier_phi_dst
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 221: expr_result {:?} is carrier '{}', returning PHI dst {:?}",
|
||||
expr_result_id, binding.carrier_name, carrier_phi_dst
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
return Ok(Some(carrier_phi_dst));
|
||||
@ -92,9 +103,12 @@ impl ExprResultResolver {
|
||||
// Step 3: expr_result is NOT a carrier - use remapped value
|
||||
if let Some(remapped_expr) = remapper.get_value(expr_result_id) {
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 221: Returning non-carrier expr_result: JoinIR {:?} → Host {:?}",
|
||||
expr_result_id, remapped_expr
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 221: Returning non-carrier expr_result: JoinIR {:?} → Host {:?}",
|
||||
expr_result_id, remapped_expr
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
Ok(Some(remapped_expr))
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
use super::loop_header_phi_info::LoopHeaderPhiInfo;
|
||||
use super::merge_result::MergeResult;
|
||||
use super::tail_call_classifier::{classify_tail_call, TailCallKind};
|
||||
use super::super::trace;
|
||||
use crate::mir::builder::joinir_id_remapper::JoinIrIdRemapper;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
|
||||
use crate::mir::{BasicBlock, BasicBlockId, MirInstruction, MirModule, ValueId};
|
||||
@ -51,8 +52,17 @@ pub(super) fn merge_and_rewrite(
|
||||
exit_block_id: BasicBlockId,
|
||||
debug: bool,
|
||||
) -> Result<MergeResult, String> {
|
||||
let trace = trace::trace();
|
||||
let verbose = debug || crate::config::env::joinir_dev_enabled();
|
||||
macro_rules! log {
|
||||
($enabled:expr, $($arg:tt)*) => {
|
||||
trace.stderr_if(&format!($($arg)*), $enabled);
|
||||
};
|
||||
}
|
||||
|
||||
// Phase 177-3: exit_block_id is now passed in from block_allocator
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[cf_loop/joinir/instruction_rewriter] Phase 177-3: Using exit_block_id = {:?}",
|
||||
exit_block_id
|
||||
);
|
||||
@ -84,7 +94,8 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
// DETERMINISM FIX: Sort functions by name to ensure consistent iteration order
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 189: Merging {} functions",
|
||||
mir_module.functions.len()
|
||||
);
|
||||
@ -103,7 +114,8 @@ pub(super) fn merge_and_rewrite(
|
||||
let is_continuation_func = func_name == K_EXIT_FUNC_NAME || func_name.ends_with("k_exit");
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Merging function '{}' with {} blocks, entry={:?} (is_continuation={})",
|
||||
func_name,
|
||||
func.blocks.len(),
|
||||
@ -118,7 +130,8 @@ pub(super) fn merge_and_rewrite(
|
||||
// Processing continuation functions would add undefined ValueIds to PHI.
|
||||
if is_continuation_func {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-15: Skipping continuation function '{}' blocks",
|
||||
func_name
|
||||
);
|
||||
@ -169,18 +182,21 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
// DEBUG: Print block being processed
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] === Processing block {:?} (from func '{}') ===",
|
||||
old_block_id, func_name
|
||||
);
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Original block has {} instructions:",
|
||||
old_block.instructions.len()
|
||||
);
|
||||
for (idx, inst) in old_block.instructions.iter().enumerate() {
|
||||
eprintln!("[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
log!(true, "[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
}
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Original block terminator: {:?}",
|
||||
old_block.terminator
|
||||
);
|
||||
@ -195,7 +211,8 @@ pub(super) fn merge_and_rewrite(
|
||||
is_loop_entry_point && !loop_header_phi_info.carrier_phis.is_empty();
|
||||
|
||||
if is_loop_entry_point {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[cf_loop/joinir] Phase 177-3 DEBUG: is_loop_entry_point={}, carrier_phis.len()={}, is_loop_header_with_phi={}",
|
||||
is_loop_entry_point,
|
||||
loop_header_phi_info.carrier_phis.len(),
|
||||
@ -217,7 +234,8 @@ pub(super) fn merge_and_rewrite(
|
||||
};
|
||||
|
||||
if is_loop_header_with_phi && !phi_dst_ids_for_block.is_empty() {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[cf_loop/joinir] Phase 177-3: Loop header with {} PHI dsts to protect: {:?}",
|
||||
phi_dst_ids_for_block.len(),
|
||||
phi_dst_ids_for_block
|
||||
@ -232,12 +250,14 @@ pub(super) fn merge_and_rewrite(
|
||||
if let MirInstruction::Copy { dst, src } = inst {
|
||||
// Check if this copy's dst is a PHI dst (after remapping)
|
||||
let dst_remapped = remapper.get_value(*dst).unwrap_or(*dst);
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[cf_loop/joinir] Phase 177-3 DEBUG: Copy {:?} = {:?}, dst_remapped = {:?}, in phi_dsts = {}",
|
||||
dst, src, dst_remapped, phi_dst_ids_for_block.contains(&dst_remapped)
|
||||
);
|
||||
if phi_dst_ids_for_block.contains(&dst_remapped) {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[cf_loop/joinir] Phase 177-3: ✅ Skipping loop header Copy to PHI dst {:?} (original {:?})",
|
||||
dst_remapped, dst
|
||||
);
|
||||
@ -251,10 +271,7 @@ pub(super) fn merge_and_rewrite(
|
||||
if let crate::mir::types::ConstValue::String(_) = value {
|
||||
if value_to_func_name.contains_key(dst) {
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Skipping function name const: {:?}",
|
||||
inst
|
||||
);
|
||||
log!(true, "[cf_loop/joinir] Skipping function name const: {:?}", inst);
|
||||
}
|
||||
continue; // Skip this instruction
|
||||
}
|
||||
@ -263,7 +280,7 @@ pub(super) fn merge_and_rewrite(
|
||||
// that initialize boundary inputs. BoundaryInjector provides these values via Copy.
|
||||
if is_loop_entry_point && boundary_input_set.contains(dst) {
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Skipping boundary input const (replaced by BoundaryInjector Copy): {:?}", inst);
|
||||
log!(true, "[cf_loop/joinir] Skipping boundary input const (replaced by BoundaryInjector Copy): {:?}", inst);
|
||||
}
|
||||
continue; // Skip - BoundaryInjector will provide the value
|
||||
}
|
||||
@ -282,7 +299,8 @@ pub(super) fn merge_and_rewrite(
|
||||
found_tail_call = true;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Detected tail call to '{}' (args={:?}), will convert to Jump",
|
||||
func_name, args
|
||||
);
|
||||
@ -306,7 +324,8 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
if is_header_phi_dst {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-20: Skipping Copy that would overwrite header PHI dst {:?}",
|
||||
remapped_dst
|
||||
);
|
||||
@ -354,7 +373,8 @@ pub(super) fn merge_and_rewrite(
|
||||
if debug {
|
||||
match inst {
|
||||
MirInstruction::BoxCall { .. } => {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Adding BoxCall to block {:?}: {:?}",
|
||||
new_block_id, inst
|
||||
);
|
||||
@ -368,12 +388,13 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
// DEBUG: Print what was added to the block after first pass
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] After first pass, new_block has {} instructions",
|
||||
new_block.instructions.len()
|
||||
);
|
||||
for (idx, inst) in new_block.instructions.iter().enumerate() {
|
||||
eprintln!("[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
log!(true, "[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,7 +402,8 @@ pub(super) fn merge_and_rewrite(
|
||||
// Phase 188-Impl-3: Use actual parameter ValueIds from target function
|
||||
if let Some((target_block, args)) = tail_call_target {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Inserting param bindings for tail call to {:?}",
|
||||
target_block
|
||||
);
|
||||
@ -412,7 +434,8 @@ pub(super) fn merge_and_rewrite(
|
||||
// %phi_dst = copy %undefined ← ❌ This overwrites the PHI!
|
||||
if is_loop_entry_point {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-21: Skip param bindings in header block (PHIs define carriers)"
|
||||
);
|
||||
}
|
||||
@ -434,7 +457,8 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
if is_header_phi_dst {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 131-6: Skip param binding to PHI dst {:?} (PHI receives value via incoming edge)",
|
||||
param_val_remapped
|
||||
);
|
||||
@ -449,7 +473,8 @@ pub(super) fn merge_and_rewrite(
|
||||
});
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Param binding: arg {:?} → param {:?}",
|
||||
arg_val_remapped, param_val_remapped
|
||||
);
|
||||
@ -479,7 +504,8 @@ pub(super) fn merge_and_rewrite(
|
||||
);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-16: Set latch incoming for '{}': block={:?}, value={:?}",
|
||||
loop_var_name, new_block_id, latch_value
|
||||
);
|
||||
@ -497,7 +523,8 @@ pub(super) fn merge_and_rewrite(
|
||||
if let Some(ref loop_var) = b.loop_var_name {
|
||||
if &binding.carrier_name == loop_var {
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 176-4: Skipping loop variable '{}' in exit_bindings (handled separately)",
|
||||
binding.carrier_name
|
||||
);
|
||||
@ -516,14 +543,16 @@ pub(super) fn merge_and_rewrite(
|
||||
);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 176-4: Set latch incoming for carrier '{}': block={:?}, value={:?} (arg[{}])",
|
||||
binding.carrier_name, new_block_id, latch_value, carrier_arg_idx
|
||||
);
|
||||
}
|
||||
carrier_arg_idx += 1;
|
||||
} else if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-20 WARNING: No arg for carrier '{}' at index {}",
|
||||
binding.carrier_name, carrier_arg_idx
|
||||
);
|
||||
@ -547,7 +576,8 @@ pub(super) fn merge_and_rewrite(
|
||||
TailCallKind::BackEdge => {
|
||||
// Back edge: redirect to header block where PHIs are
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-16: BackEdge detected, redirecting from {:?} to header {:?}",
|
||||
target_block, loop_header_phi_info.header_block
|
||||
);
|
||||
@ -557,7 +587,8 @@ pub(super) fn merge_and_rewrite(
|
||||
TailCallKind::LoopEntry => {
|
||||
// Loop entry: no redirect (entry block IS the header)
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 33-16: LoopEntry detected, using direct target {:?}",
|
||||
target_block
|
||||
);
|
||||
@ -576,19 +607,20 @@ pub(super) fn merge_and_rewrite(
|
||||
|
||||
// DEBUG: Print final state after adding parameter bindings
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] After adding param bindings, new_block has {} instructions",
|
||||
new_block.instructions.len()
|
||||
);
|
||||
for (idx, inst) in new_block.instructions.iter().enumerate() {
|
||||
eprintln!("[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
log!(true, "[cf_loop/joinir] [{}] {:?}", idx, inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
new_block.instruction_spans = old_block.instruction_spans.clone();
|
||||
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Span sync: new_block.instructions.len()={}, old_block.instruction_spans.len()={}, new_block.instruction_spans.len()={}",
|
||||
log!(true, "[cf_loop/joinir] Span sync: new_block.instructions.len()={}, old_block.instruction_spans.len()={}, new_block.instruction_spans.len()={}",
|
||||
new_block.instructions.len(),
|
||||
old_block.instruction_spans.len(),
|
||||
new_block.instruction_spans.len()
|
||||
@ -613,7 +645,8 @@ pub(super) fn merge_and_rewrite(
|
||||
if let Some(_ret_val) = value {
|
||||
// Phase 246-EX: Check if this block has jump_args metadata
|
||||
if let Some(ref jump_args) = old_block.jump_args {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX: Block {:?} has jump_args metadata: {:?}",
|
||||
old_block.id, jump_args
|
||||
);
|
||||
@ -624,7 +657,8 @@ pub(super) fn merge_and_rewrite(
|
||||
.map(|&arg| remapper.remap_value(arg))
|
||||
.collect();
|
||||
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX: Remapped jump_args: {:?}",
|
||||
remapped_args
|
||||
);
|
||||
@ -643,7 +677,7 @@ pub(super) fn merge_and_rewrite(
|
||||
if strict_exit {
|
||||
return Err(msg);
|
||||
} else {
|
||||
eprintln!("[DEBUG-177] {}", msg);
|
||||
log!(verbose, "[DEBUG-177] {}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -651,7 +685,8 @@ pub(super) fn merge_and_rewrite(
|
||||
// First arg is the loop variable (expr_result)
|
||||
if let Some(&loop_var_exit) = remapped_args.first() {
|
||||
exit_phi_inputs.push((new_block_id, loop_var_exit));
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX: exit_phi_inputs from jump_args[0]: ({:?}, {:?})",
|
||||
new_block_id, loop_var_exit
|
||||
);
|
||||
@ -663,7 +698,8 @@ pub(super) fn merge_and_rewrite(
|
||||
.entry(loop_var_name.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((new_block_id, loop_var_exit));
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX-P5: Added loop_var '{}' to carrier_inputs: ({:?}, {:?})",
|
||||
loop_var_name, new_block_id, loop_var_exit
|
||||
);
|
||||
@ -685,7 +721,8 @@ pub(super) fn merge_and_rewrite(
|
||||
{
|
||||
// Phase 227: Skip ConditionOnly carriers
|
||||
if carrier.role == crate::mir::join_ir::lowering::carrier_info::CarrierRole::ConditionOnly {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 227: Skipping ConditionOnly carrier '{}' from exit PHI",
|
||||
carrier.name
|
||||
);
|
||||
@ -701,7 +738,8 @@ pub(super) fn merge_and_rewrite(
|
||||
.entry(carrier.name.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((new_block_id, carrier_exit));
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX-FIX: Collecting carrier '{}': from {:?} using jump_args[{}] = {:?}",
|
||||
carrier.name, new_block_id, jump_args_idx, carrier_exit
|
||||
);
|
||||
@ -713,7 +751,8 @@ pub(super) fn merge_and_rewrite(
|
||||
if strict_exit {
|
||||
return Err(msg);
|
||||
} else {
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX WARNING: No jump_args entry for carrier '{}' at index {}",
|
||||
carrier.name, jump_args_idx
|
||||
);
|
||||
@ -721,12 +760,16 @@ pub(super) fn merge_and_rewrite(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("[DEBUG-177] Phase 246-EX WARNING: No carrier_info in boundary!");
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX WARNING: No carrier_info in boundary!"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: Use header PHI dst (old behavior for blocks without jump_args)
|
||||
eprintln!(
|
||||
log!(
|
||||
verbose,
|
||||
"[DEBUG-177] Phase 246-EX: Block {:?} has NO jump_args, using header PHI fallback",
|
||||
old_block.id
|
||||
);
|
||||
@ -738,7 +781,8 @@ pub(super) fn merge_and_rewrite(
|
||||
{
|
||||
exit_phi_inputs.push((new_block_id, phi_dst));
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 246-EX fallback: Using header PHI dst {:?} for exit (loop_var='{}')",
|
||||
phi_dst, loop_var_name
|
||||
);
|
||||
@ -850,7 +894,8 @@ pub(super) fn merge_and_rewrite(
|
||||
if let Some(remapped) = remapper.get_value(binding.join_value) {
|
||||
value_map_for_injector.insert(binding.join_value, remapped);
|
||||
if debug {
|
||||
eprintln!(
|
||||
log!(
|
||||
true,
|
||||
"[cf_loop/joinir] Phase 171-fix: Condition binding '{}': JoinIR {:?} → remapped {:?} (HOST {:?})",
|
||||
binding.name, binding.join_value, remapped, binding.host_value
|
||||
);
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
//! (instruction_rewriter).
|
||||
|
||||
use super::loop_header_phi_info::{CarrierPhiEntry, LoopHeaderPhiInfo};
|
||||
use super::super::trace;
|
||||
use crate::mir::{BasicBlockId, MirInstruction, ValueId};
|
||||
|
||||
/// Builder for loop header PHIs
|
||||
@ -73,14 +74,21 @@ impl LoopHeaderPhiBuilder {
|
||||
expr_result_is_loop_var: bool,
|
||||
debug: bool,
|
||||
) -> Result<LoopHeaderPhiInfo, String> {
|
||||
let trace = trace::trace();
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 33-16: Building header PHIs at {:?}",
|
||||
header_block
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 33-16: Building header PHIs at {:?}",
|
||||
header_block
|
||||
),
|
||||
true,
|
||||
);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Loop var '{}' init={:?}, entry_block={:?}",
|
||||
loop_var_name, loop_var_init, entry_block
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Loop var '{}' init={:?}, entry_block={:?}",
|
||||
loop_var_name, loop_var_init, entry_block
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -101,14 +109,15 @@ impl LoopHeaderPhiBuilder {
|
||||
.value_types
|
||||
.insert(loop_var_phi_dst, init_type.clone());
|
||||
|
||||
if debug || std::env::var("NYASH_CARRIER_PHI_DEBUG").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[carrier/phi] Loop var '{}': dst=%{} entry_type={:?} (backedge ignored)",
|
||||
loop_var_name,
|
||||
loop_var_phi_dst.as_u32(),
|
||||
init_type
|
||||
);
|
||||
}
|
||||
),
|
||||
debug || std::env::var("NYASH_CARRIER_PHI_DEBUG").ok().as_deref() == Some("1"),
|
||||
);
|
||||
}
|
||||
|
||||
info.carrier_phis.insert(
|
||||
@ -124,9 +133,12 @@ impl LoopHeaderPhiBuilder {
|
||||
info.carrier_order.push(loop_var_name.to_string());
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Loop var PHI: {:?} = phi [(from {:?}, {:?}), (latch TBD)]",
|
||||
loop_var_phi_dst, entry_block, loop_var_init
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Loop var PHI: {:?} = phi [(from {:?}, {:?}), (latch TBD)]",
|
||||
loop_var_phi_dst, entry_block, loop_var_init
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -150,14 +162,15 @@ impl LoopHeaderPhiBuilder {
|
||||
.value_types
|
||||
.insert(phi_dst, init_type.clone());
|
||||
|
||||
if debug || std::env::var("NYASH_CARRIER_PHI_DEBUG").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[carrier/phi] Carrier '{}': dst=%{} entry_type={:?} (backedge ignored)",
|
||||
name,
|
||||
phi_dst.as_u32(),
|
||||
init_type
|
||||
);
|
||||
}
|
||||
),
|
||||
debug || std::env::var("NYASH_CARRIER_PHI_DEBUG").ok().as_deref() == Some("1"),
|
||||
);
|
||||
}
|
||||
|
||||
info.carrier_phis.insert(
|
||||
@ -173,9 +186,12 @@ impl LoopHeaderPhiBuilder {
|
||||
info.carrier_order.push(name.clone());
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Carrier '{}' PHI: {:?} = phi [(from {:?}, {:?}), (latch TBD)], role={:?}",
|
||||
name, phi_dst, entry_block, init_value, role
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Carrier '{}' PHI: {:?} = phi [(from {:?}, {:?}), (latch TBD)], role={:?}",
|
||||
name, phi_dst, entry_block, init_value, role
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -184,9 +200,12 @@ impl LoopHeaderPhiBuilder {
|
||||
if expr_result_is_loop_var {
|
||||
info.expr_result_phi = Some(loop_var_phi_dst);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] expr_result = {:?} (loop var PHI)",
|
||||
loop_var_phi_dst
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] expr_result = {:?} (loop var PHI)",
|
||||
loop_var_phi_dst
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -208,11 +227,15 @@ impl LoopHeaderPhiBuilder {
|
||||
info: &LoopHeaderPhiInfo,
|
||||
debug: bool,
|
||||
) -> Result<(), String> {
|
||||
let trace = trace::trace();
|
||||
let dev_debug = debug || crate::config::env::joinir_dev_enabled();
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 33-16: Finalizing header PHIs at {:?}",
|
||||
info.header_block
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 33-16: Finalizing header PHIs at {:?}",
|
||||
info.header_block
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@ -260,10 +283,13 @@ impl LoopHeaderPhiBuilder {
|
||||
phi_instructions.push(phi);
|
||||
|
||||
if dev_debug {
|
||||
eprintln!(
|
||||
"[joinir/header-phi] Finalized carrier '{}' PHI: {:?} = phi [({:?}, {:?}), ({:?}, {:?})]",
|
||||
name, entry.phi_dst, entry_block, entry_val, latch_block, latch_val
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/header-phi] Finalized carrier '{}' PHI: {:?} = phi [({:?}, {:?}), ({:?}, {:?})]",
|
||||
name, entry.phi_dst, entry_block, entry_val, latch_block, latch_val
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,9 +306,12 @@ impl LoopHeaderPhiBuilder {
|
||||
header_block.instruction_spans = new_spans;
|
||||
|
||||
if dev_debug {
|
||||
eprintln!(
|
||||
"[joinir/header-phi] Header block now has {} instructions",
|
||||
header_block.instructions.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[joinir/header-phi] Header block now has {} instructions",
|
||||
header_block.instructions.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ mod value_collector;
|
||||
pub use loop_header_phi_builder::LoopHeaderPhiBuilder;
|
||||
pub use loop_header_phi_info::LoopHeaderPhiInfo;
|
||||
|
||||
use super::trace;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
|
||||
use crate::mir::{MirModule, ValueId};
|
||||
|
||||
@ -77,13 +78,15 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
debug: bool,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
let verbose = debug || crate::config::env::joinir_dev_enabled();
|
||||
let trace = trace::trace();
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] merge_joinir_mir_blocks called with {} functions",
|
||||
mir_module.functions.len()
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
if verbose {
|
||||
if let Some(boundary) = boundary {
|
||||
@ -109,31 +112,43 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
})
|
||||
.collect();
|
||||
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Boundary join_inputs={:?} host_inputs={:?}",
|
||||
boundary.join_inputs, boundary.host_inputs
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Boundary join_inputs={:?} host_inputs={:?}",
|
||||
boundary.join_inputs, boundary.host_inputs
|
||||
),
|
||||
true,
|
||||
);
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Boundary exit_bindings ({}): {}",
|
||||
boundary.exit_bindings.len(),
|
||||
exit_summary.join(", ")
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Boundary exit_bindings ({}): {}",
|
||||
boundary.exit_bindings.len(),
|
||||
exit_summary.join(", ")
|
||||
),
|
||||
true,
|
||||
);
|
||||
if !cond_summary.is_empty() {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Boundary condition_bindings ({}): {}",
|
||||
cond_summary.len(),
|
||||
cond_summary.join(", ")
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Boundary condition_bindings ({}): {}",
|
||||
cond_summary.len(),
|
||||
cond_summary.join(", ")
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
if let Some(ci) = &boundary.carrier_info {
|
||||
let carriers: Vec<String> = ci.carriers.iter().map(|c| c.name.clone()).collect();
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Boundary carrier_info: loop_var='{}', carriers={:?}",
|
||||
ci.loop_var_name, carriers
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Boundary carrier_info: loop_var='{}', carriers={:?}",
|
||||
ci.loop_var_name, carriers
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
eprintln!("[cf_loop/joinir] No boundary provided");
|
||||
trace.stderr_if("[cf_loop/joinir] No boundary provided", true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,23 +164,25 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Phase 171-fix: Add condition_bindings' join_values to used_values for remapping
|
||||
if let Some(boundary) = boundary {
|
||||
for binding in &boundary.condition_bindings {
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 171-fix: Adding condition binding '{}' JoinIR {:?} to used_values",
|
||||
binding.name, binding.join_value
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
used_values.insert(binding.join_value);
|
||||
}
|
||||
|
||||
// Phase 172-3: Add exit_bindings' join_exit_values to used_values for remapping
|
||||
for binding in &boundary.exit_bindings {
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 172-3: Adding exit binding '{}' JoinIR {:?} to used_values",
|
||||
binding.carrier_name, binding.join_exit_value
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
used_values.insert(binding.join_exit_value);
|
||||
}
|
||||
}
|
||||
@ -237,20 +254,24 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
.collect()
|
||||
};
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 201-A: Pre-building header PHIs for loop_var='{}' at {:?}",
|
||||
loop_var_name, entry_block_remapped
|
||||
);
|
||||
eprintln!(
|
||||
),
|
||||
debug,
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] loop_var_init={:?}, carriers={:?}",
|
||||
loop_var_init,
|
||||
other_carriers
|
||||
.iter()
|
||||
.map(|(n, _, _, _)| n.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
// Build PHI info (this allocates PHI dst ValueIds)
|
||||
LoopHeaderPhiBuilder::build(
|
||||
@ -286,22 +307,24 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
|
||||
// Phase 201-A: Get reserved PHI dst ValueIds and set in MirBuilder
|
||||
let reserved_phi_dsts = loop_header_phi_info.reserved_value_ids();
|
||||
if debug && !reserved_phi_dsts.is_empty() {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 201-A: Reserved PHI dsts: {:?}",
|
||||
reserved_phi_dsts
|
||||
);
|
||||
}
|
||||
),
|
||||
debug && !reserved_phi_dsts.is_empty(),
|
||||
);
|
||||
|
||||
// Phase 201-A: Set reserved IDs in MirBuilder so next_value_id() skips them
|
||||
// This protects against carrier corruption when break conditions emit Const instructions
|
||||
builder.comp_ctx.reserved_value_ids = reserved_phi_dsts.clone();
|
||||
if debug && !builder.comp_ctx.reserved_value_ids.is_empty() {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 201-A: Set builder.comp_ctx.reserved_value_ids = {:?}",
|
||||
builder.comp_ctx.reserved_value_ids
|
||||
);
|
||||
}
|
||||
),
|
||||
debug && !builder.comp_ctx.reserved_value_ids.is_empty(),
|
||||
);
|
||||
|
||||
// Phase 3: Remap ValueIds (with reserved PHI dsts protection)
|
||||
remap_values(
|
||||
@ -313,28 +336,40 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
)?;
|
||||
|
||||
// Phase 177-3 DEBUG: Verify remapper state after Phase 3
|
||||
eprintln!("[DEBUG-177] === Remapper state after Phase 3 ===");
|
||||
eprintln!("[DEBUG-177] used_values count: {}", used_values.len());
|
||||
trace.stderr_if("[DEBUG-177] === Remapper state after Phase 3 ===", verbose);
|
||||
trace.stderr_if(
|
||||
&format!("[DEBUG-177] used_values count: {}", used_values.len()),
|
||||
verbose,
|
||||
);
|
||||
for value_id in &used_values {
|
||||
if let Some(remapped) = remapper.get_value(*value_id) {
|
||||
eprintln!("[DEBUG-177] JoinIR {:?} → Host {:?}", value_id, remapped);
|
||||
trace.stderr_if(
|
||||
&format!("[DEBUG-177] JoinIR {:?} → Host {:?}", value_id, remapped),
|
||||
verbose,
|
||||
);
|
||||
} else {
|
||||
eprintln!("[DEBUG-177] JoinIR {:?} → NOT FOUND ❌", value_id);
|
||||
trace.stderr_if(
|
||||
&format!("[DEBUG-177] JoinIR {:?} → NOT FOUND ❌", value_id),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check condition_bindings specifically
|
||||
if let Some(boundary) = boundary {
|
||||
eprintln!("[DEBUG-177] === Condition bindings check ===");
|
||||
trace.stderr_if("[DEBUG-177] === Condition bindings check ===", verbose);
|
||||
for binding in &boundary.condition_bindings {
|
||||
let lookup_result = remapper.get_value(binding.join_value);
|
||||
eprintln!(
|
||||
"[DEBUG-177] '{}': JoinIR {:?} → {:?}",
|
||||
binding.name, binding.join_value, lookup_result
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] '{}': JoinIR {:?} → {:?}",
|
||||
binding.name, binding.join_value, lookup_result
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
}
|
||||
eprintln!("[DEBUG-177] ==============================");
|
||||
trace.stderr_if("[DEBUG-177] ==============================", verbose);
|
||||
|
||||
// Phase 3.5: Override remapper for function parameters to use PHI dsts
|
||||
//
|
||||
@ -390,15 +425,21 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
.collect();
|
||||
|
||||
if !condition_binding_ids.is_empty() {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3: Protected ValueIds (condition-only, not carriers): {:?}",
|
||||
condition_binding_ids
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 177-3: Protected ValueIds (condition-only, not carriers): {:?}",
|
||||
condition_binding_ids
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
for cb in &boundary.condition_bindings {
|
||||
let is_carrier = carrier_names.contains(cb.name.as_str());
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3: '{}': JoinIR {:?} (carrier={})",
|
||||
cb.name, cb.join_value, is_carrier
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 177-3: '{}': JoinIR {:?} (carrier={})",
|
||||
cb.name, cb.join_value, is_carrier
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -407,25 +448,34 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
let loop_step_func_name = "join_func_1";
|
||||
|
||||
if function_params.get(main_func_name).is_none() {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
|
||||
main_func_name,
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
|
||||
main_func_name,
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
if let Some(main_params) = function_params.get(main_func_name) {
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: main ({}) params: {:?}",
|
||||
main_func_name, main_params
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 33-21: main ({}) params: {:?}",
|
||||
main_func_name, main_params
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: carrier_phis count: {}, names: {:?}",
|
||||
loop_header_phi_info.carrier_phis.len(),
|
||||
loop_header_phi_info
|
||||
.carrier_phis
|
||||
.iter()
|
||||
.map(|(n, _)| n.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 33-21: carrier_phis count: {}, names: {:?}",
|
||||
loop_header_phi_info.carrier_phis.len(),
|
||||
loop_header_phi_info
|
||||
.carrier_phis
|
||||
.iter()
|
||||
.map(|(n, _)| n.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
// Map main's parameters to header PHI dsts
|
||||
// main params: [i_init, carrier1_init, ...]
|
||||
@ -436,15 +486,21 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
if let Some(&main_param) = main_params.get(idx) {
|
||||
// Phase 177-3: Don't override condition_bindings
|
||||
if condition_binding_ids.contains(&main_param) {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3: Skipping override for condition_binding {:?} ('{}')",
|
||||
main_param, carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 177-3: Skipping override for condition_binding {:?} ('{}')",
|
||||
main_param, carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: REMAP main param[{}] {:?} → {:?} ('{}')",
|
||||
idx, main_param, entry.phi_dst, carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 33-21: REMAP main param[{}] {:?} → {:?} ('{}')",
|
||||
idx, main_param, entry.phi_dst, carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
remapper.set_value(main_param, entry.phi_dst);
|
||||
}
|
||||
@ -466,9 +522,12 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
continue;
|
||||
}
|
||||
// This is a body-only carrier - remap it to PHI dst
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3-B: Body-only carrier '{}': JoinIR {:?} → PHI {:?}",
|
||||
carrier_name, binding.join_value, entry.phi_dst
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 177-3-B: Body-only carrier '{}': JoinIR {:?} → PHI {:?}",
|
||||
carrier_name, binding.join_value, entry.phi_dst
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
remapper.set_value(binding.join_value, entry.phi_dst);
|
||||
}
|
||||
@ -476,22 +535,31 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
|
||||
// Map loop_step's parameters
|
||||
// DEBUG-177: Always log function_params keys to diagnose multi-carrier issue
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: function_params keys: {:?}",
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 33-21: function_params keys: {:?}",
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
if function_params.get(loop_step_func_name).is_none() {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
|
||||
loop_step_func_name,
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] WARNING: function_params.get('{}') returned None. Available keys: {:?}",
|
||||
loop_step_func_name,
|
||||
function_params.keys().collect::<Vec<_>>()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
if let Some(loop_step_params) = function_params.get(loop_step_func_name) {
|
||||
// DEBUG-177: Always log loop_step params
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 33-21: loop_step ({}) params: {:?}",
|
||||
loop_step_func_name, loop_step_params
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 33-21: loop_step ({}) params: {:?}",
|
||||
loop_step_func_name, loop_step_params
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
// Phase 177-FIX: Process loop_step params but skip if already mapped
|
||||
//
|
||||
@ -501,9 +569,12 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
for loop_step_param in loop_step_params {
|
||||
// Phase 177-3: Don't override condition_bindings
|
||||
if condition_binding_ids.contains(loop_step_param) {
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 177-FIX: Skipping condition_binding {:?}",
|
||||
loop_step_param
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 177-FIX: Skipping condition_binding {:?}",
|
||||
loop_step_param
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -517,9 +588,12 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
.any(|(name, _)| name == &cb.name)
|
||||
});
|
||||
if already_mapped {
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 177-FIX: Skipping {:?} (already mapped by Phase 177-3-B)",
|
||||
loop_step_param
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 177-FIX: Skipping {:?} (already mapped by Phase 177-3-B)",
|
||||
loop_step_param
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -537,9 +611,12 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
loop_header_phi_info.get_carrier_at_index(param_idx),
|
||||
loop_header_phi_info.get_entry_at_index(param_idx),
|
||||
) {
|
||||
eprintln!(
|
||||
"[DEBUG-177] Phase 177-STRUCT-2: REMAP loop_step param[{}] {:?} → {:?} (carrier '{}')",
|
||||
param_idx, loop_step_param, entry.phi_dst, carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] Phase 177-STRUCT-2: REMAP loop_step param[{}] {:?} → {:?} (carrier '{}')",
|
||||
param_idx, loop_step_param, entry.phi_dst, carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
remapper.set_value(*loop_step_param, entry.phi_dst);
|
||||
}
|
||||
@ -556,15 +633,17 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Phase 177-3: Don't override condition_bindings
|
||||
if !condition_binding_ids.contains(&ValueId(0)) {
|
||||
remapper.set_value(ValueId(0), phi_dst);
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 33-16 fallback: Override remap ValueId(0) → {:?} (PHI dst)",
|
||||
phi_dst
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding ValueId(0)"
|
||||
trace.stderr_if(
|
||||
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding ValueId(0)",
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -581,28 +660,35 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// Phase 177-3: Don't override condition_bindings
|
||||
if !condition_binding_ids.contains(&join_value_id) {
|
||||
remapper.set_value(join_value_id, entry.phi_dst);
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 33-20 fallback: Override remap {:?} → {:?} (carrier '{}' PHI dst)",
|
||||
join_value_id, entry.phi_dst, carrier_name
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding {:?} ('{}')",
|
||||
join_value_id, carrier_name
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 177-3 fallback: Skipping override for condition_binding {:?} ('{}')",
|
||||
join_value_id, carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 177-3 DEBUG: Check remapper after Phase 33-21 overrides
|
||||
eprintln!("[DEBUG-177] === Remapper state after Phase 33-21 ===");
|
||||
trace.stderr_if("[DEBUG-177] === Remapper state after Phase 33-21 ===", verbose);
|
||||
for binding in &boundary.condition_bindings {
|
||||
let lookup_result = remapper.get_value(binding.join_value);
|
||||
eprintln!(
|
||||
"[DEBUG-177] '{}': JoinIR {:?} → {:?} (after 33-21)",
|
||||
binding.name, binding.join_value, lookup_result
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[DEBUG-177] '{}': JoinIR {:?} → {:?} (after 33-21)",
|
||||
binding.name, binding.join_value, lookup_result
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
|
||||
@ -630,12 +716,13 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// By now, instruction_rewriter has set latch_incoming for all carriers.
|
||||
// We can finalize the PHIs and insert them into the header block.
|
||||
if !loop_header_phi_info.carrier_phis.is_empty() {
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 4.5: Finalizing {} header PHIs",
|
||||
loop_header_phi_info.carrier_phis.len()
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
LoopHeaderPhiBuilder::finalize(builder, &loop_header_phi_info, debug)?;
|
||||
}
|
||||
|
||||
@ -673,12 +760,16 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// The exit PHI correctly merges values from both exit paths, giving us the final result.
|
||||
let carrier_phis = &exit_carrier_phis;
|
||||
|
||||
if debug && !carrier_phis.is_empty() {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 246-EX: Using EXIT PHI dsts for variable_map (not header): {:?}",
|
||||
carrier_phis.iter().map(|(n, v)| (n.as_str(), v)).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
carrier_phis
|
||||
.iter()
|
||||
.map(|(n, v)| (n.as_str(), v))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
debug && !carrier_phis.is_empty(),
|
||||
);
|
||||
|
||||
// Phase 6: Reconnect boundary (if specified)
|
||||
// Phase 197-B: Pass remapper to enable per-carrier exit value lookup
|
||||
@ -694,40 +785,49 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
// The header_block in loop_header_phi_info is the remapped entry block
|
||||
let entry_block = loop_header_phi_info.header_block;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Entry block (from loop_header_phi_info): {:?}",
|
||||
entry_block
|
||||
);
|
||||
eprintln!(
|
||||
),
|
||||
debug,
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Current block before emit_jump: {:?}",
|
||||
builder.current_block
|
||||
);
|
||||
eprintln!(
|
||||
),
|
||||
debug,
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Jumping to entry block: {:?}",
|
||||
entry_block
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
crate::mir::builder::emission::branch::emit_jump(builder, entry_block)?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] After emit_jump, current_block: {:?}",
|
||||
builder.current_block
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
// Switch to exit block for subsequent code
|
||||
builder.start_new_block(exit_block_id)?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 189: Merge complete: {} functions merged, continuing from {:?}",
|
||||
mir_module.functions.len(),
|
||||
exit_block_id
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
// Phase 200-3: Verify JoinIR contracts (debug only)
|
||||
#[cfg(debug_assertions)]
|
||||
@ -742,21 +842,23 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
boundary,
|
||||
);
|
||||
}
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 200-3: Contract verification passed");
|
||||
}
|
||||
trace.stderr_if(
|
||||
"[cf_loop/joinir] Phase 200-3: Contract verification passed",
|
||||
debug,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 201-A: Clear reserved ValueIds after merge completes
|
||||
// Future loops will set their own reserved IDs
|
||||
if !builder.comp_ctx.reserved_value_ids.is_empty() {
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 201-A: Clearing reserved_value_ids (was {:?})",
|
||||
builder.comp_ctx.reserved_value_ids
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
builder.comp_ctx.reserved_value_ids.clear();
|
||||
}
|
||||
|
||||
@ -777,12 +879,13 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
if let Some(binding) = loop_var_binding {
|
||||
if binding.join_exit_value == expr_result_id {
|
||||
// expr_result is the loop variable! Use exit_phi_result_id
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 246-EX-FIX: expr_result {:?} is loop variable '{}', using exit_phi_result_id {:?}",
|
||||
expr_result_id, loop_var_name, exit_phi_result_id
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
exit_phi_result_id
|
||||
} else {
|
||||
// expr_result is not the loop variable, resolve as carrier
|
||||
@ -823,21 +926,23 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
|
||||
// Return expr_result if present, otherwise fall back to exit_phi_result_id
|
||||
if let Some(resolved) = expr_result_value {
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 246-EX-FIX: Returning expr_result_value {:?}",
|
||||
resolved
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
Ok(Some(resolved))
|
||||
} else {
|
||||
// Fallback: return exit_phi_result_id (for legacy patterns or carrier-only loops)
|
||||
if debug && exit_phi_result_id.is_some() {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 221-R: Returning exit_phi_result_id (fallback): {:?}",
|
||||
exit_phi_result_id
|
||||
);
|
||||
}
|
||||
),
|
||||
debug && exit_phi_result_id.is_some(),
|
||||
);
|
||||
Ok(exit_phi_result_id)
|
||||
}
|
||||
}
|
||||
@ -854,13 +959,15 @@ fn remap_values(
|
||||
reserved_ids: &std::collections::HashSet<ValueId>,
|
||||
debug: bool,
|
||||
) -> Result<(), String> {
|
||||
if debug {
|
||||
eprintln!(
|
||||
let trace = trace::trace();
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 3: Remapping {} ValueIds (reserved: {})",
|
||||
used_values.len(),
|
||||
reserved_ids.len()
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
|
||||
for old_value in used_values {
|
||||
// Phase 201-A: Allocate new ValueId, skipping reserved PHI dsts
|
||||
@ -870,21 +977,23 @@ fn remap_values(
|
||||
break candidate;
|
||||
}
|
||||
// Skip reserved ID - will try next one
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Phase 201-A: Skipping reserved PHI dst {:?}",
|
||||
candidate
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
};
|
||||
|
||||
remapper.set_value(*old_value, new_value);
|
||||
if debug {
|
||||
eprintln!(
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Value remap: {:?} → {:?}",
|
||||
old_value, new_value
|
||||
);
|
||||
}
|
||||
),
|
||||
debug,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -27,8 +27,12 @@ pub(super) fn collect_values(
|
||||
),
|
||||
String,
|
||||
> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
if debug {
|
||||
eprintln!("[cf_loop/joinir] Phase 189: Collecting value IDs from all functions");
|
||||
trace.stderr_if(
|
||||
"[cf_loop/joinir] Phase 189: Collecting value IDs from all functions",
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
let mut used_values: BTreeSet<ValueId> = BTreeSet::new();
|
||||
@ -63,9 +67,12 @@ pub(super) fn collect_values(
|
||||
// Without this, subsequent instructions referencing dst will fail
|
||||
used_values.insert(*dst);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Found function name constant: {:?} = '{}'",
|
||||
dst, s
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Found function name constant: {:?} = '{}'",
|
||||
dst, s
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -95,9 +102,12 @@ pub(super) fn collect_values(
|
||||
}
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[cf_loop/joinir] Collected {} unique values",
|
||||
used_values.len()
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
"[cf_loop/joinir] Collected {} unique values",
|
||||
used_values.len()
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user