Files
hakorune/src/mir/builder/ssa/local.rs

223 lines
8.2 KiB
Rust
Raw Normal View History

use crate::mir::builder::MirBuilder;
use crate::mir::ValueId;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum LocalKind {
Recv,
Arg,
CompareOperand,
Cond,
FieldBase,
Other(u8),
}
impl LocalKind {
#[inline]
fn tag(self) -> u8 {
match self {
LocalKind::Recv => 0,
LocalKind::Arg => 1,
LocalKind::CompareOperand => 2,
LocalKind::Cond => 4,
LocalKind::FieldBase => 0, // share recv slot for bases
LocalKind::Other(k) => k,
}
}
}
/// Ensure a value has an in-block definition and cache it per (bb, orig, kind).
/// Always emits a Copy in the current block when not cached.
pub fn ensure(builder: &mut MirBuilder, v: ValueId, kind: LocalKind) -> ValueId {
let bb_opt = builder.current_block;
if let Some(bb) = bb_opt {
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!("[local-ssa] ensure bb={:?} kind={:?} v=%{}", bb, kind, v.0);
}
let key = (bb, v, kind.tag());
if let Some(&loc) = builder.local_ssa_map.get(&key) {
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 で作成しておく。
// CRITICAL: Check for errors - if block creation fails, return original value.
if let Err(e) = builder.ensure_block_exists(bb) {
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!(
"[local-ssa] ensure_block_exists FAILED bb={:?} kind={:?} v=%{} err={}",
bb, kind, v.0, e
);
}
return v;
}
// CRITICAL FIX: If `v` is from a pinned slot, check if there's a PHI value for that slot
refactor(mir): Remove VariableContext legacy fields (Phase 2-6/7) 完全移行→削除の安全順序(Option C)に従い、VariableContext の deprecated フィールドと sync helpers を完全削除。 ## Changes - Migrated all 66+ access sites to variable_ctx.variable_map - Removed 1 deprecated field (variable_map) from MirBuilder - Removed 2 sync helpers (sync_variable_ctx_to_legacy, sync_legacy_to_variable_ctx) - Fixed BoxCompilationContext.variable_map references (kept as-is, different scope) - Fixed ExitBindingBuilder.variable_map references (kept as-is, local field) - Updated observer.rs to use variable_map() accessor method ## JoinIR Integration Verified - CarrierInfo::from_variable_map() works correctly - ExitLine contract maintained (Phase 132-135) - NYASH_TRACE_VARMAP debug support preserved - Pattern 1-5 lowering all functional ## Tests - cargo test --release --lib: 1033 passed, 0 failed - phase135_trim_mir_verify.sh: PASS (MIR SSA/ValueId OK) - cargo build --release: SUCCESS - Deprecation warnings: reduced (86 remaining, from other contexts) ## Statistics - 27 files changed - 146 insertions(+), 174 deletions(-) - Net: -28 lines Phase 2 Progress: 6/7 contexts complete (86%) - ✅ MetadataContext - ✅ CoreContext - ✅ TypeContext - ✅ ScopeContext - ✅ BindingContext - ✅ VariableContext (this commit) - ⏳ CompilationContext (Phase 2-7 next) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 03:48:44 +09:00
// in the current block's variable_ctx.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).
// Try to detect pinned slots for this value and redirect to the latest slot value.
refactor(mir): Remove VariableContext legacy fields (Phase 2-6/7) 完全移行→削除の安全順序(Option C)に従い、VariableContext の deprecated フィールドと sync helpers を完全削除。 ## Changes - Migrated all 66+ access sites to variable_ctx.variable_map - Removed 1 deprecated field (variable_map) from MirBuilder - Removed 2 sync helpers (sync_variable_ctx_to_legacy, sync_legacy_to_variable_ctx) - Fixed BoxCompilationContext.variable_map references (kept as-is, different scope) - Fixed ExitBindingBuilder.variable_map references (kept as-is, local field) - Updated observer.rs to use variable_map() accessor method ## JoinIR Integration Verified - CarrierInfo::from_variable_map() works correctly - ExitLine contract maintained (Phase 132-135) - NYASH_TRACE_VARMAP debug support preserved - Pattern 1-5 lowering all functional ## Tests - cargo test --release --lib: 1033 passed, 0 failed - phase135_trim_mir_verify.sh: PASS (MIR SSA/ValueId OK) - cargo build --release: SUCCESS - Deprecation warnings: reduced (86 remaining, from other contexts) ## Statistics - 27 files changed - 146 insertions(+), 174 deletions(-) - Net: -28 lines Phase 2 Progress: 6/7 contexts complete (86%) - ✅ MetadataContext - ✅ CoreContext - ✅ TypeContext - ✅ ScopeContext - ✅ BindingContext - ✅ VariableContext (this commit) - ⏳ CompilationContext (Phase 2-7 next) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 03:48:44 +09:00
// 1) First, look for "__pin$" entries in variable_ctx.variable_map that still point to v.
// 2) If not found, consult builder.pin_slot_names to recover the slot name
// and then look up the current ValueId for that slot.
let mut slot_name_opt: Option<String> = None;
let names_for_v: Vec<String> = builder
.variable_ctx
.variable_map
.iter()
.filter(|(k, &vid)| vid == v && k.starts_with("__pin$"))
.map(|(k, _)| k.clone())
.collect();
if let Some(first_pin_name) = names_for_v.first() {
slot_name_opt = Some(first_pin_name.clone());
} else if let Some(name) = builder.pin_slot_names.get(&v) {
slot_name_opt = Some(name.clone());
}
if let Some(slot_name) = slot_name_opt {
refactor(mir): Remove VariableContext legacy fields (Phase 2-6/7) 完全移行→削除の安全順序(Option C)に従い、VariableContext の deprecated フィールドと sync helpers を完全削除。 ## Changes - Migrated all 66+ access sites to variable_ctx.variable_map - Removed 1 deprecated field (variable_map) from MirBuilder - Removed 2 sync helpers (sync_variable_ctx_to_legacy, sync_legacy_to_variable_ctx) - Fixed BoxCompilationContext.variable_map references (kept as-is, different scope) - Fixed ExitBindingBuilder.variable_map references (kept as-is, local field) - Updated observer.rs to use variable_map() accessor method ## JoinIR Integration Verified - CarrierInfo::from_variable_map() works correctly - ExitLine contract maintained (Phase 132-135) - NYASH_TRACE_VARMAP debug support preserved - Pattern 1-5 lowering all functional ## Tests - cargo test --release --lib: 1033 passed, 0 failed - phase135_trim_mir_verify.sh: PASS (MIR SSA/ValueId OK) - cargo build --release: SUCCESS - Deprecation warnings: reduced (86 remaining, from other contexts) ## Statistics - 27 files changed - 146 insertions(+), 174 deletions(-) - Net: -28 lines Phase 2 Progress: 6/7 contexts complete (86%) - ✅ MetadataContext - ✅ CoreContext - ✅ TypeContext - ✅ ScopeContext - ✅ BindingContext - ✅ VariableContext (this commit) - ⏳ CompilationContext (Phase 2-7 next) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 03:48:44 +09:00
if let Some(&current_val) = builder.variable_ctx.variable_map.get(&slot_name) {
if current_val != v {
// The slot has been updated (likely by a PHI or header rewrite).
// Use the updated value instead of the stale pinned ValueId.
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!(
"[local-ssa] phi-redirect bb={:?} kind={:?} slot={} %{} -> %{}",
bb, kind, slot_name, v.0, current_val.0
);
}
builder.local_ssa_map.insert(key, current_val);
return current_val;
}
}
}
let loc = builder.next_value_id();
// CRITICAL: Check emit_instruction result - if Copy fails, return original value
// to avoid returning undefined ValueId.
if let Err(e) =
builder.emit_instruction(crate::mir::MirInstruction::Copy { dst: loc, src: v })
{
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!("[local-ssa] emit_instruction Copy FAILED bb={:?} kind={:?} v=%{} dst=%{} err={}",
bb, kind, v.0, loc.0, e);
}
// Failed to emit Copy - return original value instead of undefined dst
return v;
}
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!(
"[local-ssa] copy bb={:?} kind={:?} %{} -> %{}",
bb, kind, v.0, loc.0
);
}
// Success: register metadata and cache
if let Some(t) = builder.type_ctx.value_types.get(&v).cloned() {
builder.type_ctx.value_types.insert(loc, t);
}
if let Some(cls) = builder.type_ctx.value_origin_newbox.get(&v).cloned() {
builder
.type_ctx
.value_origin_newbox
.insert(loc, cls.clone());
// CRITICAL FIX: For receiver kind, if type is missing but origin exists,
// infer MirType::Box from origin
if kind == LocalKind::Recv && builder.type_ctx.value_types.get(&loc).is_none() {
builder
.type_ctx
.value_types
.insert(loc, crate::mir::MirType::Box(cls));
}
}
builder.local_ssa_map.insert(key, loc);
loc
} else {
v
}
}
#[inline]
pub fn recv(builder: &mut MirBuilder, v: ValueId) -> ValueId {
ensure(builder, v, LocalKind::Recv)
}
#[inline]
pub fn arg(builder: &mut MirBuilder, v: ValueId) -> ValueId {
ensure(builder, v, LocalKind::Arg)
}
#[inline]
pub fn cond(builder: &mut MirBuilder, v: ValueId) -> ValueId {
ensure(builder, v, LocalKind::Cond)
}
#[inline]
pub fn field_base(builder: &mut MirBuilder, v: ValueId) -> ValueId {
ensure(builder, v, LocalKind::FieldBase)
}
#[inline]
pub fn cmp_operand(builder: &mut MirBuilder, v: ValueId) -> ValueId {
ensure(builder, v, LocalKind::CompareOperand)
}
/// Finalize only the args (legacy Call paths)
pub fn finalize_args(builder: &mut MirBuilder, args: &mut Vec<ValueId>) {
for a in args.iter_mut() {
*a = arg(builder, *a);
}
}
/// Finalize a single branch condition just before emitting a Branch.
/// Ensures the condition has a definition in the current block.
pub fn finalize_branch_cond(builder: &mut MirBuilder, condition_v: &mut ValueId) {
*condition_v = cond(builder, *condition_v);
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
if let Some(bb) = builder.current_block {
eprintln!(
"[local-ssa] finalize-branch bb={:?} cond=%{}",
bb, condition_v.0
);
}
}
}
/// Finalize compare operands just before emitting a Compare.
/// Applies in-block materialization to both lhs and rhs.
pub fn finalize_compare(builder: &mut MirBuilder, lhs: &mut ValueId, rhs: &mut ValueId) {
*lhs = cmp_operand(builder, *lhs);
*rhs = cmp_operand(builder, *rhs);
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
if let Some(bb) = builder.current_block {
eprintln!(
"[local-ssa] finalize-compare bb={:?} lhs=%{} rhs=%{}",
bb, lhs.0, rhs.0
);
}
}
}
/// Finalize field use sites: ensure base and all args are in the current block.
pub fn finalize_field_base_and_args(
builder: &mut MirBuilder,
base: &mut ValueId,
args: &mut Vec<ValueId>,
) {
*base = field_base(builder, *base);
for a in args.iter_mut() {
*a = arg(builder, *a);
}
if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
if let Some(bb) = builder.current_block {
eprintln!(
"[local-ssa] finalize-field bb={:?} base=%{} argc={}",
bb,
base.0,
args.len()
);
}
}
}