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

@ -14,6 +14,7 @@ impl MirBuilder {
// Heuristic pre-pin: if condition is a comparison, evaluate its operands now and pin them
// so that subsequent branches can safely reuse these values across blocks.
// This leverages existing variable_map merges (PHI) at the merge block.
if crate::config::env::mir_pre_pin_compare_operands() {
if let ASTNode::BinaryOp { operator, left, right, .. } = &condition {
match operator {
BinaryOperator::Equal
@ -32,6 +33,7 @@ impl MirBuilder {
_ => {}
}
}
}
let condition_val = self.build_expression(condition)?;
@ -41,6 +43,7 @@ impl MirBuilder {
let merge_block = self.block_gen.next();
// Branch
let pre_branch_bb = self.current_block()?;
self.emit_instruction(MirInstruction::Branch {
condition: condition_val,
then_bb: then_block,
@ -51,12 +54,18 @@ impl MirBuilder {
let pre_if_var_map = self.variable_map.clone();
// then
self.current_block = Some(then_block);
self.ensure_block_exists(then_block)?;
self.start_new_block(then_block)?;
// Scope enter for then-branch
self.hint_scope_enter(0);
let then_ast_for_analysis = then_branch.clone();
self.variable_map = pre_if_var_map.clone();
// Materialize all variables at block 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);
}
let then_value_raw = self.build_expression(then_branch)?;
let then_exit_block = self.current_block()?;
let then_var_map_end = self.variable_map.clone();
@ -67,10 +76,16 @@ impl MirBuilder {
}
// else
self.current_block = Some(else_block);
self.ensure_block_exists(else_block)?;
self.start_new_block(else_block)?;
// Scope enter for else-branch
self.hint_scope_enter(0);
// Materialize all variables at block 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);
}
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) = if let Some(else_ast) = else_branch {
self.variable_map = pre_if_var_map.clone();
let val = self.build_expression(else_ast.clone())?;
@ -88,8 +103,9 @@ impl MirBuilder {
}
// merge: primary result via helper, then delta-based variable merges
self.current_block = Some(merge_block);
self.ensure_block_exists(merge_block)?;
// Ensure PHIs are first in the block by suppressing entry pin copies here
self.suppress_next_entry_pin_copy();
self.start_new_block(merge_block)?;
self.push_if_merge(merge_block);
// Pre-analysis: identify then/else assigned var for skip and hints