mir/vm: SSA pin+PHI + short-circuit; user-defined method calls → functions; entry single-pred PHIs; compare-operand pin; VM BoxCall fallback to InstanceBox methods; docs: update CURRENT_TASK (plan + acceptance)

- Lower And/Or to branch+PHI (RHS not evaluated)
- Always slotify compare operands (dominance safety)
- Insert single-predecessor PHIs at then/else/short-circuit entries
- pin_to_slot now logs (NYASH_PIN_TRACE) and participates in PHI
- Rewrite user-defined instance method calls to Box.method/Arity (builder)
- VM fallback: BoxCall on InstanceBox dispatches to lowered functions with 'me'+args
- Keep plugin/BoxCall path for core boxes (String/Array/Map)
- Add env-gated pre-pin for if/loop (NYASH_MIR_PREPIN)
- CURRENT_TASK: add SSA/userbox plan, debug steps, acceptance criteria
This commit is contained in:
nyash-codex
2025-09-26 05:28:20 +09:00
parent 6e1bf149fc
commit cf4b615afb
15 changed files with 1042 additions and 29 deletions

View File

@ -87,9 +87,10 @@ impl super::MirBuilder {
} else {
(lhs, rhs)
};
// Materialize operands in the current block to avoid dominance/undef issues
let lhs2 = lhs2_raw;
let rhs2 = rhs2_raw;
// Ensure operands are safe across blocks: pin ephemeral values into slots
// This guarantees they participate in PHI merges and have block-local defs.
let lhs2 = self.ensure_slotified_for_use(lhs2_raw, "@cmp_lhs")?;
let rhs2 = self.ensure_slotified_for_use(rhs2_raw, "@cmp_rhs")?;
self.emit_instruction(MirInstruction::Compare {
dst,
op,
@ -128,16 +129,24 @@ impl super::MirBuilder {
then_bb: then_block,
else_bb: else_block,
})?;
// Record predecessor block for branch (for single-pred PHI materialization)
let pre_branch_bb = self.current_block()?;
// Snapshot variables before entering branches
let pre_if_var_map = self.variable_map.clone();
// ---- THEN branch ----
self.current_block = Some(then_block);
self.ensure_block_exists(then_block)?;
self.start_new_block(then_block)?;
self.hint_scope_enter(0);
// Reset scope to pre-if snapshot for clean deltas
self.variable_map = pre_if_var_map.clone();
// Materialize all variables at entry via single-pred PHI (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.value_gen.next();
let inputs = vec![(pre_branch_bb, pre_v)];
self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?;
self.variable_map.insert(name.clone(), phi_val);
}
// AND: then → evaluate RHS and reduce to bool
// OR: then → constant true
@ -187,10 +196,16 @@ impl super::MirBuilder {
}
// ---- ELSE branch ----
self.current_block = Some(else_block);
self.ensure_block_exists(else_block)?;
self.start_new_block(else_block)?;
self.hint_scope_enter(0);
self.variable_map = pre_if_var_map.clone();
// Materialize all variables at entry via single-pred PHI (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.value_gen.next();
let inputs = vec![(pre_branch_bb, pre_v)];
self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?;
self.variable_map.insert(name.clone(), phi_val);
}
// AND: else → false
// OR: else → evaluate RHS and reduce to bool
let else_value_raw = if is_and {
@ -238,8 +253,9 @@ impl super::MirBuilder {
}
// ---- MERGE ----
self.current_block = Some(merge_block);
self.ensure_block_exists(merge_block)?;
// Merge block: suppress entry pin copy so PHIs remain first and materialize pins explicitly
self.suppress_next_entry_pin_copy();
self.start_new_block(merge_block)?;
self.push_if_merge(merge_block);
// Result PHI (bool)