refactor(joinir): Phase 189 - Remove hardcoded 'sum' variable, generalize exit PHI connection

Key improvements:
1. **Eliminate hardcoded variable name**: Replace hardcoded "sum" with generic
   ValueId-based variable_map updates. Add new JoinInlineBoundary constructor
   `new_with_input_and_host_outputs()` for Pattern 3.

2. **Generalize output slot mapping**: Exit PHI result now updates all host_outputs
   entries in variable_map, not just hardcoded "sum". Prepares for future
   multi-carrier patterns.

3. **PHI preservation in blocks**: Fix block finalization to preserve existing
   PHI instructions (from handle_select) instead of overwriting them.

4. **Stable function name→ValueId mapping**: Ensure consistent ValueId
   assignment for tail call detection across multi-function merges.

5. **Enhanced debugging**: Add detailed logging in block converter and meta
   analysis for PHI verification.

Files modified:
- src/mir/builder/control_flow.rs: Remove hardcoded "sum", use boundary outputs
- src/mir/join_ir/lowering/inline_boundary.rs: Add new constructor
- src/mir/join_ir_vm_bridge/joinir_block_converter.rs: Stable mappings, PHI preservation
- src/mir/join_ir_vm_bridge/meta.rs: Debug output for PHI tracking
- src/mir/builder/joinir_id_remapper.rs: PHI value remapping
- src/mir/builder/joinir_inline_boundary_injector.rs: Span preservation

Test status: Pattern 3 (loop_if_phi.hako) still produces correct result (sum=9, RC=9)

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

Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-05 19:39:54 +09:00
parent e01d1b8a7c
commit 0397df5240
9 changed files with 202 additions and 46 deletions

View File

@ -795,29 +795,17 @@ impl super::MirBuilder {
// Phase 188-Impl-3: Create and pass JoinInlineBoundary for Pattern 3
// Pattern 3 has TWO carriers: i and sum
self.trace_varmap("pattern3_before_merge");
let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only(
let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_with_input_and_host_outputs(
vec![ValueId(0), ValueId(1)], // JoinIR's main() parameters (i, sum init)
vec![loop_var_id, sum_var_id], // Host's loop variables
vec![sum_var_id], // Host output slot to be updated with exit PHI
);
let exit_phi_result = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?;
self.trace_varmap("pattern3_after_merge");
// Phase 189-Fix: Update variable_map["sum"] to point to exit PHI result
// The exit PHI contains the final value of sum after the loop completes.
// This ensures subsequent references to "sum" (e.g., `return sum`) use the correct value.
if let Some(exit_phi) = exit_phi_result {
self.variable_map.insert("sum".to_string(), exit_phi);
if debug {
eprintln!(
"[cf_loop/joinir/pattern3] Updated variable_map['sum'] to exit PHI {:?}",
exit_phi
);
}
self.trace_varmap("pattern3_exit_phi_connected");
}
// Phase 188-Impl-3: Return Void (the loop itself doesn't produce a value, but its result
// is now accessible via variable_map["sum"])
// Phase 189-Refine: variable_map の更新は merge_joinir_mir_blocks 内で
// JoinInlineBoundary.host_outputs を用いて行われる。
// この関数では Void を返すだけでよい(戻り値は後続の `return sum` が扱う)。
let void_val = crate::mir::builder::emission::constant::emit_void(self);
if debug {
@ -864,8 +852,9 @@ impl super::MirBuilder {
/// # Returns
///
/// Returns `Ok(Some(exit_phi_id))` if the merged JoinIR functions have return values
/// that were collected into an exit block PHI. This allows the caller to connect
/// the exit PHI result to the appropriate host variable.
/// that were collected into an exit block PHI. さらに、`boundary` に
/// host_outputs が指定されている場合は、exit PHI の結果をホスト側の
/// SSA スロットへ再接続するvariable_map 内の ValueId を更新する)。
fn merge_joinir_mir_blocks(
&mut self,
mir_module: &crate::mir::MirModule,
@ -1349,19 +1338,29 @@ impl super::MirBuilder {
};
// Phase 189-Fix: Store exit PHI result in variable_map so host code can reference it
// The loop result should update the corresponding carrier variable
// The loop result should update the corresponding carrier variable(s) declared
// in JoinInlineBoundary.host_outputs.
if let Some(phi_result) = exit_phi_result_id {
// Use boundary output info to connect exit PHI to host variables
if let Some(ref boundary) = boundary {
// If boundary has outputs, map JoinIR output to host output
if !boundary.join_outputs.is_empty() && !boundary.host_outputs.is_empty() {
// For now, we assume single output (sum in the pattern)
// Future: support multiple outputs
if debug {
eprintln!(
"[cf_loop/joinir] Would connect exit PHI {:?} to host output {:?}",
phi_result, boundary.host_outputs
);
// Phase 189-Refine: 現時点では単一出力 (Pattern 3 の sum) のみを想定し、
// host_outputs に登録された ValueId と同じ値を持つ variable_map の
// エントリを exit PHI 結果に差し替える。
//
// 将来 Multi-carrier を扱う際は、join_outputs と host_outputs の
// ペアに対して同様の処理を行う。
for &host_out in &boundary.host_outputs {
// variable_map は name → ValueId のマップなので、
// 値が host_out になっているものを exit PHI に更新する。
for (name, vid) in self.variable_map.iter_mut() {
if *vid == host_out {
*vid = phi_result;
if debug {
eprintln!(
"[cf_loop/joinir] Updated variable_map['{}'] to exit PHI {:?}",
name, phi_result
);
}
}
}
}
}