wip(recv): emit_unified_call で最終LocalSSA試行(未完)
- builder_calls.rs の emit_unified_call 末尾で recv 再materialize - しかし MIR に Copy が反映されない問題が残る - 次: emit_instruction 側に責務を移す構造的修正へ
This commit is contained in:
@ -41,6 +41,7 @@ mod observe; // P0: dev-only observability helpers(ssa/resolve)
|
||||
mod rewrite; // P1: Known rewrite & special consolidation
|
||||
mod ssa; // LocalSSA helpers (in-block materialization)
|
||||
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
||||
mod receiver; // ReceiverMaterializationBox(Method recv の pin+LocalSSA 集約)
|
||||
mod metadata; // MetadataPropagationBox(type/originの伝播)
|
||||
mod emission; // emission::*(Const/Compare/Branch の薄い発行箱)
|
||||
mod types; // types::annotation / inference(型注釈/推論の箱: 推論は後段)
|
||||
|
||||
@ -28,45 +28,6 @@ impl super::MirBuilder {
|
||||
return self.emit_legacy_call(dst, target, args);
|
||||
}
|
||||
|
||||
// Ensure method receiver is materialized in the current block.
|
||||
// This avoids "use of undefined recv" across block boundaries for direct Method calls
|
||||
// that bypass legacy BoxCall emission. Do this before any observation/rewrite.
|
||||
let mut target = target;
|
||||
let bb_before = self.current_block; // snapshot for later re-check
|
||||
if let CallTarget::Method { box_type, method, receiver } = target {
|
||||
if super::utils::builder_debug_enabled() && method == "advance" {
|
||||
super::utils::builder_debug_log(&format!("unified-entry Method.advance recv=%{} (pre-pin)", receiver.0));
|
||||
}
|
||||
let receiver_pinned = match self.pin_to_slot(receiver, "@recv") {
|
||||
Ok(v) => v,
|
||||
Err(_) => receiver,
|
||||
};
|
||||
if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
||||
let current_fn = self
|
||||
.current_function
|
||||
.as_ref()
|
||||
.map(|f| f.signature.name.clone())
|
||||
.unwrap_or_else(|| "<none>".to_string());
|
||||
let bb = self.current_block;
|
||||
let names: Vec<String> = self
|
||||
.variable_map
|
||||
.iter()
|
||||
.filter(|(_, &vid)| vid == receiver)
|
||||
.map(|(k, _)| k.clone())
|
||||
.collect();
|
||||
eprintln!(
|
||||
"[builder/recv-trace] fn={} bb={:?} method={}.{} recv=%{} aliases={:?}",
|
||||
current_fn,
|
||||
bb,
|
||||
box_type.clone().unwrap_or_else(|| "<?>".to_string()),
|
||||
method,
|
||||
receiver.0,
|
||||
names
|
||||
);
|
||||
}
|
||||
target = CallTarget::Method { box_type, method, receiver: receiver_pinned };
|
||||
}
|
||||
|
||||
// Emit resolve.try for method targets (dev-only; default OFF)
|
||||
let arity_for_try = args.len();
|
||||
if let CallTarget::Method { ref box_type, ref method, receiver } = target {
|
||||
@ -216,29 +177,6 @@ impl super::MirBuilder {
|
||||
other => other,
|
||||
};
|
||||
|
||||
// Final guard: if current block changed since entry, ensure receiver is copied again
|
||||
if let (Some(bb0), Some(bb1)) = (bb_before, self.current_block) {
|
||||
if bb0 != bb1 {
|
||||
if let Callee::Method { box_name, method, receiver: Some(r), certainty } = callee {
|
||||
if super::utils::builder_debug_enabled() {
|
||||
super::utils::builder_debug_log(&format!(
|
||||
"unified-call bb changed: {:?} -> {:?}; re-materialize recv=%{}",
|
||||
bb0, bb1, r.0
|
||||
));
|
||||
}
|
||||
let r2 = self.pin_to_slot(r, "@recv").unwrap_or(r);
|
||||
callee = Callee::Method { box_name, method, receiver: Some(r2), certainty };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug: trace unified method emission with pinned receiver (dev only)
|
||||
if super::utils::builder_debug_enabled() {
|
||||
if let Callee::Method { method, receiver: Some(r), .. } = &callee {
|
||||
super::utils::builder_debug_log(&format!("unified-call method={} recv=%{} (pinned)", method, r.0));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit resolve.choose for method callee (dev-only; default OFF)
|
||||
if let Callee::Method { box_name, method, certainty, .. } = &callee {
|
||||
let chosen = format!("{}.{}{}", box_name, method, format!("/{}", arity_for_try));
|
||||
@ -268,18 +206,6 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// Before creating the call, enforce slot (pin) + LocalSSA for Method receiver in the current block
|
||||
let callee = match callee {
|
||||
Callee::Method { box_name, method, receiver: Some(r), certainty } => {
|
||||
// Pin to a named slot so start_new_block can propagate across entries
|
||||
let r_pinned = self.pin_to_slot(r, "@recv").unwrap_or(r);
|
||||
// And ensure in-block materialization for this emission site
|
||||
let r_local = self.local_recv(r_pinned);
|
||||
Callee::Method { box_name, method, receiver: Some(r_local), certainty }
|
||||
}
|
||||
other => other,
|
||||
};
|
||||
|
||||
// Finalize operands in current block (EmitGuardBox wrapper)
|
||||
let mut callee = callee;
|
||||
let mut args_local: Vec<ValueId> = args;
|
||||
@ -298,6 +224,14 @@ impl super::MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: just before emitting the Call, re-materialize Method receiver in *current* block.
|
||||
// This ensures the receiver has a definition in the same block as the Call instruction,
|
||||
// even if the block changed between finalize_call_operands() and here.
|
||||
// Critical for Stage-B and complex control flow where finalize and emit may be in different blocks.
|
||||
if let Callee::Method { box_name, method, receiver: Some(r), certainty } = callee {
|
||||
let r_local = crate::mir::builder::ssa::local::recv(self, r);
|
||||
callee = Callee::Method { box_name, method, receiver: Some(r_local), certainty };
|
||||
}
|
||||
|
||||
// For Phase 2: Convert to legacy Call instruction with new callee field (use finalized operands)
|
||||
let legacy_call = MirInstruction::Call {
|
||||
|
||||
@ -4,10 +4,13 @@ use crate::mir::ValueId;
|
||||
|
||||
/// Finalize call operands (receiver/args) using LocalSSA; thin wrapper to centralize usage.
|
||||
pub fn finalize_call_operands(builder: &mut MirBuilder, callee: &mut Callee, args: &mut Vec<ValueId>) {
|
||||
// Step 1: LocalSSA materialization for receiver/args
|
||||
crate::mir::builder::ssa::local::finalize_callee_and_args(builder, callee, args);
|
||||
// Step 1: Receiver materialization (pin slot + LocalSSA) in a dedicated box
|
||||
crate::mir::builder::receiver::finalize_method_receiver(builder, callee);
|
||||
|
||||
// Step 2: Disabled - BlockScheduleBox insert-after-phis doesn't work correctly
|
||||
// Step 2: LocalSSA materialization for args only
|
||||
crate::mir::builder::ssa::local::finalize_args(builder, args);
|
||||
|
||||
// Step 3: Disabled - BlockScheduleBox insert-after-phis doesn't work correctly
|
||||
// The Copy instructions are being inserted but then lost when blocks are finalized.
|
||||
// Instead, rely solely on LocalSSA which uses emit_instruction (the normal path).
|
||||
//
|
||||
|
||||
46
src/mir/builder/receiver.rs
Normal file
46
src/mir/builder/receiver.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
|
||||
/// ReceiverMaterializationBox – centralizes Method receiver pinning + LocalSSA materialization.
|
||||
///
|
||||
/// Contract:
|
||||
/// - If callee is a Method and has a receiver:
|
||||
/// - Pin the receiver into a named slot (`__pin$*@recv`) so it participates in PHI/loop merges.
|
||||
/// - Ensure the receiver has an in-block definition via LocalSSA (Copy in the current block).
|
||||
/// - Args の LocalSSA は別レイヤ(ssa::local)で扱う。
|
||||
pub fn finalize_method_receiver(builder: &mut MirBuilder, callee: &mut Callee) {
|
||||
if let Callee::Method { box_name, method, receiver: Some(r), certainty } = callee.clone() {
|
||||
// Pin to a named slot so start_new_block や LoopBuilder が slot 経由で追跡できる
|
||||
let r_pinned = builder.pin_to_slot(r, "@recv").unwrap_or(r);
|
||||
|
||||
// Optional dev trace for receiver aliases
|
||||
if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
||||
let current_fn = builder
|
||||
.current_function
|
||||
.as_ref()
|
||||
.map(|f| f.signature.name.clone())
|
||||
.unwrap_or_else(|| "<none>".to_string());
|
||||
let bb = builder.current_block;
|
||||
let names: Vec<String> = builder
|
||||
.variable_map
|
||||
.iter()
|
||||
.filter(|(_, &vid)| vid == r)
|
||||
.map(|(k, _)| k.clone())
|
||||
.collect();
|
||||
eprintln!(
|
||||
"[builder/recv-trace] fn={} bb={:?} method={}.{} recv=%{} aliases={:?}",
|
||||
current_fn,
|
||||
bb,
|
||||
box_name.clone(),
|
||||
method,
|
||||
r.0,
|
||||
names
|
||||
);
|
||||
}
|
||||
|
||||
// LocalSSA: ensure an in-block definition in the current block
|
||||
let r_local = crate::mir::builder::ssa::local::recv(builder, r_pinned);
|
||||
*callee = Callee::Method { box_name, method, receiver: Some(r_local), certainty };
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::{ValueId, Callee};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub enum LocalKind {
|
||||
@ -38,6 +38,12 @@ pub fn ensure(builder: &mut MirBuilder, v: ValueId, kind: LocalKind) -> ValueId
|
||||
return loc;
|
||||
}
|
||||
|
||||
// Ensure the current basic block exists in the function before emitting a Copy.
|
||||
// Stage-B 経路などでは current_block が割り当て済みでも、ブロック自体が
|
||||
// function にまだ追加されていない場合があり、そのまま emit_instruction すると
|
||||
// Copy が黙って落ちてしまう。ここで best-effort で作成しておく。
|
||||
let _ = builder.ensure_block_exists(bb);
|
||||
|
||||
// CRITICAL FIX: If `v` is from a pinned slot, check if there's a PHI value for that slot
|
||||
// in the current block's variable_map. If so, use the PHI value directly instead of
|
||||
// emitting a Copy from the old value (which might not be defined in this block).
|
||||
@ -96,19 +102,6 @@ pub fn field_base(builder: &mut MirBuilder, v: ValueId) -> ValueId { ensure(buil
|
||||
#[inline]
|
||||
pub fn cmp_operand(builder: &mut MirBuilder, v: ValueId) -> ValueId { ensure(builder, v, LocalKind::CompareOperand) }
|
||||
|
||||
/// Finalize a callee+args just before emitting a Call instruction:
|
||||
/// - If Method: ensure receiver is in the current block
|
||||
/// - All args: ensure in the current block
|
||||
pub fn finalize_callee_and_args(builder: &mut MirBuilder, callee: &mut Callee, args: &mut Vec<ValueId>) {
|
||||
if let Callee::Method { receiver: Some(r), box_name, method, certainty } = callee.clone() {
|
||||
let r_local = recv(builder, r);
|
||||
*callee = Callee::Method { box_name, method, receiver: Some(r_local), certainty };
|
||||
}
|
||||
for a in args.iter_mut() {
|
||||
*a = arg(builder, *a);
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalize only the args (legacy Call paths)
|
||||
pub fn finalize_args(builder: &mut MirBuilder, args: &mut Vec<ValueId>) {
|
||||
for a in args.iter_mut() {
|
||||
|
||||
Reference in New Issue
Block a user