feat(mir/phi): improve LoopForm parameter detection - track param names

**Problem**: is_parameter() was too simple, checking only ValueId which changes
through copies/PHIs. This caused parameters like 'data' to be misclassified as
carriers, leading to incorrect PHI construction.

**Solution**: Track original parameter names at function entry.

**Changes**:

1. **Added function_param_names field** (builder.rs):
   - HashSet<String> to track original parameter names
   - Populated in lower_static_method_as_function()
   - Cleared and repopulated for each new function

2. **Improved is_parameter()** (loop_builder.rs):
   - Check name against function_param_names instead of ValueId
   - More reliable than checking func.params (ValueIds change)
   - __pin$*$@* variables correctly classified as carriers
   - Added debug logging with NYASH_LOOPFORM_DEBUG

3. **Enhanced debug output** (loopform_builder.rs):
   - Show carrier/pinned classification during prepare_structure()
   - Show variable_map state after emit_header_phis()

**Test Results**:
-  'args' correctly identified as parameter (was working)
-  'data' now correctly identified as parameter (was broken)
-  __pin variables correctly classified as carriers
-  PHI values allocated and variable_map updated correctly
- ⚠️ ValueId undefined errors persist (separate issue)

**Remaining Issue**:
ValueId(10) undefined error suggests PHI visibility problem or VM verification
issue. Needs further investigation of emit_phi_at_block_start() or VM executor.

**Backward Compatibility**:
- Flag OFF: 100% existing behavior preserved (legacy path unchanged)
- Feature-flagged with NYASH_LOOPFORM_PHI_V2=1

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-17 05:24:07 +09:00
parent f85e485195
commit c459135238
6 changed files with 258 additions and 11 deletions

View File

@ -109,6 +109,10 @@ pub struct MirBuilder {
/// Index of static methods seen during lowering: name -> [(BoxName, arity)]
pub(super) static_method_index: std::collections::HashMap<String, Vec<(String, usize)>>,
/// Function parameter names (for LoopForm PHI construction)
/// Tracks the original parameter names at function entry
pub(super) function_param_names: HashSet<String>,
/// Fast lookup: method+arity tail → candidate function names (e.g., ".str/0" → ["JsonNode.str/0", ...])
pub(super) method_tail_index: std::collections::HashMap<String, Vec<String>>,
/// Source size snapshot to detect when to rebuild the tail index
@ -191,9 +195,10 @@ impl MirBuilder {
plugin_method_sigs,
current_static_box: None,
static_method_index: std::collections::HashMap::new(),
function_param_names: HashSet::new(),
method_tail_index: std::collections::HashMap::new(),
method_tail_index_source_len: 0,
loop_header_stack: Vec::new(),
loop_exit_stack: Vec::new(),
if_merge_stack: Vec::new(),
@ -549,6 +554,34 @@ impl MirBuilder {
}
}
/// Update an existing PHI instruction's inputs (for loop sealing)
/// Used by LoopFormBuilder to complete incomplete PHI nodes
pub(super) fn update_phi_instruction(
&mut self,
block: BasicBlockId,
phi_id: ValueId,
new_inputs: Vec<(BasicBlockId, ValueId)>,
) -> Result<(), String> {
if let Some(ref mut function) = self.current_function {
if let Some(block_data) = function.get_block_mut(block) {
// Find PHI instruction with matching dst
for inst in &mut block_data.instructions {
if let MirInstruction::Phi { dst, inputs } = inst {
if *dst == phi_id {
*inputs = new_inputs;
return Ok(());
}
}
}
Err(format!("PHI instruction {} not found in block {}", phi_id, block))
} else {
Err(format!("Block {} not found", block))
}
} else {
Err("No current function".to_string())
}
}
// フェーズM: is_no_phi_mode()メソッド削除
// フェーズM: insert_edge_copy()メソッド削除no_phi_mode撤廃により不要