🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
|
|
|
|
use super::{BasicBlock, BasicBlockId};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
use crate::mir::{BarrierOp, TypeOpKind, WeakRefOp};
|
2025-09-27 08:45:25 +09:00
|
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
2025-09-25 00:41:56 +09:00
|
|
|
|
// include path resolver removed (using handles modules)
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
|
|
// Optional builder debug logging
|
|
|
|
|
|
pub(super) fn builder_debug_enabled() -> bool {
|
|
|
|
|
|
std::env::var("NYASH_BUILDER_DEBUG").is_ok()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 08:45:25 +09:00
|
|
|
|
static BUILDER_DEBUG_COUNT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
2025-09-03 05:04:56 +09:00
|
|
|
|
pub(super) fn builder_debug_log(msg: &str) {
|
|
|
|
|
|
if builder_debug_enabled() {
|
2025-09-27 08:45:25 +09:00
|
|
|
|
// Optional cap: limit the number of builder debug lines to avoid flooding the terminal.
|
|
|
|
|
|
// Set via env: NYASH_BUILDER_DEBUG_LIMIT=<N> (default: unlimited)
|
|
|
|
|
|
if let Ok(cap_s) = std::env::var("NYASH_BUILDER_DEBUG_LIMIT") {
|
|
|
|
|
|
if let Ok(cap) = cap_s.parse::<usize>() {
|
|
|
|
|
|
let n = BUILDER_DEBUG_COUNT.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
|
if n >= cap { return; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
eprintln!("[BUILDER] {}", msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
|
|
|
|
impl super::MirBuilder {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
// ---- Value ID allocation (function-local or module-global) ----
|
|
|
|
|
|
/// Allocate a new ValueId in the appropriate context
|
|
|
|
|
|
/// - Inside function: uses function-local allocator
|
|
|
|
|
|
/// - Outside function: uses module-global allocator
|
|
|
|
|
|
#[inline]
|
2025-11-17 06:31:31 +09:00
|
|
|
|
pub(crate) fn next_value_id(&mut self) -> super::ValueId {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
if let Some(ref mut f) = self.current_function {
|
|
|
|
|
|
f.next_value_id() // Function context
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.value_gen.next() // Module context
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// ---- LocalSSA convenience (readability helpers) ----
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn local_recv(&mut self, v: super::ValueId) -> super::ValueId { super::ssa::local::recv(self, v) }
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn local_arg(&mut self, v: super::ValueId) -> super::ValueId { super::ssa::local::arg(self, v) }
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn local_cmp_operand(&mut self, v: super::ValueId) -> super::ValueId { super::ssa::local::cmp_operand(self, v) }
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn local_field_base(&mut self, v: super::ValueId) -> super::ValueId { super::ssa::local::field_base(self, v) }
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn local_cond(&mut self, v: super::ValueId) -> super::ValueId { super::ssa::local::cond(self, v) }
|
🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
|
|
|
|
/// Ensure a basic block exists in the current function
|
|
|
|
|
|
pub(crate) fn ensure_block_exists(&mut self, block_id: BasicBlockId) -> Result<(), String> {
|
|
|
|
|
|
if let Some(ref mut function) = self.current_function {
|
|
|
|
|
|
if !function.blocks.contains_key(&block_id) {
|
|
|
|
|
|
let block = BasicBlock::new(block_id);
|
|
|
|
|
|
function.add_block(block);
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err("No current function".to_string())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Start a new basic block and set as current
|
|
|
|
|
|
pub(crate) fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> {
|
|
|
|
|
|
if let Some(ref mut function) = self.current_function {
|
2025-11-17 09:39:26 +09:00
|
|
|
|
if !function.blocks.contains_key(&block_id) {
|
|
|
|
|
|
function.add_block(BasicBlock::new(block_id));
|
|
|
|
|
|
}
|
🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
|
|
|
|
self.current_block = Some(block_id);
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// Local SSA cache is per-block; clear on block switch
|
|
|
|
|
|
self.local_ssa_map.clear();
|
|
|
|
|
|
// BlockSchedule materialize cache is per-block as well
|
|
|
|
|
|
self.schedule_mat_map.clear();
|
2025-11-17 03:19:03 +09:00
|
|
|
|
// Entry materialization for pinned slots: re-read from variable_map after PHIs are emitted.
|
|
|
|
|
|
// This ensures pinned slots reflect the correct PHI values in merge blocks.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Strategy: Instead of emitting Copy instructions (which would be before PHIs),
|
|
|
|
|
|
// we simply update the variable_map to point to the current block's values.
|
|
|
|
|
|
// LoopBuilder and IfBuilder already update variable_map with PHI values, so
|
|
|
|
|
|
// pinned slots will automatically pick up the correct values.
|
|
|
|
|
|
//
|
|
|
|
|
|
// No action needed here - just clear caches.
|
2025-09-26 05:28:20 +09:00
|
|
|
|
if !self.suppress_pin_entry_copy_next {
|
2025-11-17 03:19:03 +09:00
|
|
|
|
// Cache clearing is already done above, so nothing more to do here.
|
|
|
|
|
|
// The key insight: pinned slot variables are part of variable_map,
|
|
|
|
|
|
// and LoopBuilder/IfBuilder already manage PHIs for ALL variables in variable_map,
|
|
|
|
|
|
// including pinned slots.
|
|
|
|
|
|
}
|
|
|
|
|
|
if false && !self.suppress_pin_entry_copy_next { // Keep old code for reference
|
2025-09-28 12:38:15 +09:00
|
|
|
|
// First pass: copy all pin slots and remember old->new mapping
|
2025-09-26 05:28:20 +09:00
|
|
|
|
let names: Vec<String> = self.variable_map.keys().cloned().collect();
|
2025-09-28 12:38:15 +09:00
|
|
|
|
let mut pin_renames: Vec<(super::ValueId, super::ValueId)> = Vec::new();
|
|
|
|
|
|
for name in names.iter() {
|
2025-09-26 05:28:20 +09:00
|
|
|
|
if !name.starts_with("__pin$") { continue; }
|
2025-09-28 12:38:15 +09:00
|
|
|
|
if let Some(&src) = self.variable_map.get(name) {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-26 05:28:20 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
|
2025-09-28 20:38:09 +09:00
|
|
|
|
crate::mir::builder::metadata::propagate::propagate(self, src, dst);
|
2025-09-26 05:28:20 +09:00
|
|
|
|
self.variable_map.insert(name.clone(), dst);
|
2025-09-28 12:38:15 +09:00
|
|
|
|
pin_renames.push((src, dst));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Second pass: update any user variables that pointed to old pin ids to the new ones
|
|
|
|
|
|
if !pin_renames.is_empty() {
|
|
|
|
|
|
let snapshot: Vec<(String, super::ValueId)> = self
|
|
|
|
|
|
.variable_map
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.filter(|(k, _)| !k.starts_with("__pin$"))
|
|
|
|
|
|
.map(|(k, &v)| (k.clone(), v))
|
|
|
|
|
|
.collect();
|
|
|
|
|
|
for (k, v) in snapshot.into_iter() {
|
|
|
|
|
|
if let Some((_, newv)) = pin_renames.iter().find(|(oldv, _)| *oldv == v) {
|
|
|
|
|
|
self.variable_map.insert(k, *newv);
|
|
|
|
|
|
}
|
2025-09-26 05:28:20 +09:00
|
|
|
|
}
|
2025-09-26 04:17:56 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-26 05:28:20 +09:00
|
|
|
|
// Reset suppression flag after use (one-shot)
|
|
|
|
|
|
self.suppress_pin_entry_copy_next = false;
|
🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
|
|
|
|
Ok(())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err("No current function".to_string())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 03:54:44 +09:00
|
|
|
|
|
|
|
|
|
|
impl super::MirBuilder {
|
|
|
|
|
|
/// Emit a Box method call or plugin call (unified BoxCall)
|
|
|
|
|
|
pub(super) fn emit_box_or_plugin_call(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
dst: Option<super::ValueId>,
|
|
|
|
|
|
box_val: super::ValueId,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
method_id: Option<u16>,
|
|
|
|
|
|
args: Vec<super::ValueId>,
|
|
|
|
|
|
effects: super::EffectMask,
|
|
|
|
|
|
) -> Result<(), String> {
|
2025-09-28 12:32:26 +09:00
|
|
|
|
// Ensure receiver has a definition in the current block to avoid undefined use across
|
|
|
|
|
|
// block boundaries (LoopForm/header, if-joins, etc.).
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// LocalSSA: ensure receiver has an in-block definition (kind=0 = recv)
|
|
|
|
|
|
let box_val = self.local_recv(box_val);
|
|
|
|
|
|
// LocalSSA: ensure args are materialized in current block
|
|
|
|
|
|
let args: Vec<super::ValueId> = args.into_iter().map(|a| self.local_arg(a)).collect();
|
2025-09-28 12:19:49 +09:00
|
|
|
|
// Check environment variable for unified call usage, with safe overrides for core/user boxes
|
|
|
|
|
|
let use_unified_env = super::calls::call_unified::is_unified_call_enabled();
|
|
|
|
|
|
// First, try to determine the box type
|
|
|
|
|
|
let mut box_type: Option<String> = self.value_origin_newbox.get(&box_val).cloned();
|
|
|
|
|
|
if box_type.is_none() {
|
|
|
|
|
|
if let Some(t) = self.value_types.get(&box_val) {
|
|
|
|
|
|
match t {
|
|
|
|
|
|
super::MirType::String => box_type = Some("StringBox".to_string()),
|
|
|
|
|
|
super::MirType::Box(name) => box_type = Some(name.clone()),
|
|
|
|
|
|
_ => {}
|
2025-09-24 02:11:59 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-28 12:19:49 +09:00
|
|
|
|
}
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// Route decision is centralized in RouterPolicyBox(仕様不変)。
|
|
|
|
|
|
let bx_name = box_type.clone().unwrap_or_else(|| "UnknownBox".to_string());
|
|
|
|
|
|
let route = crate::mir::builder::router::policy::choose_route(
|
|
|
|
|
|
&bx_name,
|
|
|
|
|
|
&method,
|
|
|
|
|
|
crate::mir::definitions::call_unified::TypeCertainty::Union,
|
|
|
|
|
|
args.len(),
|
|
|
|
|
|
);
|
|
|
|
|
|
if super::utils::builder_debug_enabled() || std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
if matches!(method.as_str(), "parse" | "substring" | "has_errors" | "length") {
|
|
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[boxcall-decision] method={} bb={:?} recv=%{} class_hint={:?} prefer_legacy={}",
|
|
|
|
|
|
method,
|
|
|
|
|
|
self.current_block,
|
|
|
|
|
|
box_val.0,
|
|
|
|
|
|
box_type,
|
|
|
|
|
|
matches!(route, crate::mir::builder::router::policy::Route::BoxCall)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-17 17:31:09 +09:00
|
|
|
|
// Unified path from BoxCall helper is only allowed when we are not
|
|
|
|
|
|
// already in a BoxCall fallback originating from emit_unified_call.
|
|
|
|
|
|
// in_unified_boxcall_fallback is set by emit_unified_call's RouterPolicy
|
|
|
|
|
|
// guard when it has already decided that this call must be a BoxCall.
|
|
|
|
|
|
if use_unified_env
|
|
|
|
|
|
&& matches!(route, crate::mir::builder::router::policy::Route::Unified)
|
|
|
|
|
|
&& !self.in_unified_boxcall_fallback
|
|
|
|
|
|
{
|
2025-09-24 02:11:59 +09:00
|
|
|
|
let target = super::builder_calls::CallTarget::Method {
|
|
|
|
|
|
box_type,
|
|
|
|
|
|
method: method.clone(),
|
|
|
|
|
|
receiver: box_val,
|
|
|
|
|
|
};
|
|
|
|
|
|
return self.emit_unified_call(dst, target, args);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Legacy implementation
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::BoxCall {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
box_val,
|
|
|
|
|
|
method: method.clone(),
|
|
|
|
|
|
method_id,
|
|
|
|
|
|
args,
|
|
|
|
|
|
effects,
|
|
|
|
|
|
})?;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
if let Some(d) = dst {
|
|
|
|
|
|
let mut recv_box: Option<String> = self.value_origin_newbox.get(&box_val).cloned();
|
|
|
|
|
|
if recv_box.is_none() {
|
|
|
|
|
|
if let Some(t) = self.value_types.get(&box_val) {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
match t {
|
|
|
|
|
|
super::MirType::String => recv_box = Some("StringBox".to_string()),
|
|
|
|
|
|
super::MirType::Box(name) => recv_box = Some(name.clone()),
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
2025-09-16 03:54:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(bt) = recv_box {
|
|
|
|
|
|
if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) {
|
|
|
|
|
|
self.value_types.insert(d, mt.clone());
|
|
|
|
|
|
} else {
|
2025-09-24 09:30:42 +09:00
|
|
|
|
// Phase 15.5: Unified plugin-based type resolution
|
|
|
|
|
|
// Former core boxes (StringBox, ArrayBox, MapBox) now use plugin_method_sigs only
|
|
|
|
|
|
// No special hardcoded inference - all boxes treated uniformly
|
2025-09-16 03:54:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2025-09-17 07:43:07 +09:00
|
|
|
|
pub(super) fn emit_type_check(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
value: super::ValueId,
|
|
|
|
|
|
expected_type: String,
|
|
|
|
|
|
) -> Result<super::ValueId, String> {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::TypeOp {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: TypeOpKind::Check,
|
|
|
|
|
|
value,
|
|
|
|
|
|
ty: super::MirType::Box(expected_type),
|
|
|
|
|
|
})?;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2025-09-17 07:43:07 +09:00
|
|
|
|
pub(super) fn emit_cast(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
value: super::ValueId,
|
|
|
|
|
|
target_type: super::MirType,
|
|
|
|
|
|
) -> Result<super::ValueId, String> {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::TypeOp {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: TypeOpKind::Cast,
|
|
|
|
|
|
value,
|
|
|
|
|
|
ty: target_type.clone(),
|
|
|
|
|
|
})?;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2025-09-17 07:43:07 +09:00
|
|
|
|
pub(super) fn emit_weak_new(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
box_val: super::ValueId,
|
|
|
|
|
|
) -> Result<super::ValueId, String> {
|
|
|
|
|
|
if crate::config::env::mir_core13_pure() {
|
|
|
|
|
|
return Ok(box_val);
|
|
|
|
|
|
}
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::WeakRef {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: WeakRefOp::New,
|
|
|
|
|
|
value: box_val,
|
|
|
|
|
|
})?;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2025-09-17 07:43:07 +09:00
|
|
|
|
pub(super) fn emit_weak_load(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
weak_ref: super::ValueId,
|
|
|
|
|
|
) -> Result<super::ValueId, String> {
|
|
|
|
|
|
if crate::config::env::mir_core13_pure() {
|
|
|
|
|
|
return Ok(weak_ref);
|
|
|
|
|
|
}
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::WeakRef {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: WeakRefOp::Load,
|
|
|
|
|
|
value: weak_ref,
|
|
|
|
|
|
})?;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
pub(super) fn emit_barrier_read(&mut self, ptr: super::ValueId) -> Result<(), String> {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::Barrier {
|
|
|
|
|
|
op: BarrierOp::Read,
|
|
|
|
|
|
ptr,
|
|
|
|
|
|
})
|
2025-09-16 03:54:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
|
pub(super) fn emit_barrier_write(&mut self, ptr: super::ValueId) -> Result<(), String> {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::Barrier {
|
|
|
|
|
|
op: BarrierOp::Write,
|
|
|
|
|
|
ptr,
|
|
|
|
|
|
})
|
2025-09-16 03:54:44 +09:00
|
|
|
|
}
|
2025-09-26 04:17:56 +09:00
|
|
|
|
|
2025-09-26 05:28:20 +09:00
|
|
|
|
/// Pin a block-crossing ephemeral value into a pseudo local slot and register it in variable_map
|
|
|
|
|
|
/// so it participates in PHI merges across branches/blocks. Safe default for correctness-first.
|
2025-09-26 04:17:56 +09:00
|
|
|
|
pub(crate) fn pin_to_slot(&mut self, v: super::ValueId, hint: &str) -> Result<super::ValueId, String> {
|
|
|
|
|
|
self.temp_slot_counter = self.temp_slot_counter.wrapping_add(1);
|
|
|
|
|
|
let slot_name = format!("__pin${}${}", self.temp_slot_counter, hint);
|
2025-11-17 00:48:18 +09:00
|
|
|
|
// Phase 25.1b: Use function-local ID allocator to avoid SSA verification failures
|
|
|
|
|
|
let dst = if let Some(ref mut f) = self.current_function {
|
|
|
|
|
|
f.next_value_id() // Function context: use local ID
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.value_gen.next() // Module context: use global ID
|
|
|
|
|
|
};
|
2025-09-26 04:17:56 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
2025-09-26 05:28:20 +09:00
|
|
|
|
if super::utils::builder_debug_enabled() || std::env::var("NYASH_PIN_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
super::utils::builder_debug_log(&format!("pin slot={} src={} dst={}", slot_name, v.0, dst.0));
|
|
|
|
|
|
}
|
2025-09-26 14:47:52 +09:00
|
|
|
|
// Propagate lightweight metadata so downstream resolution/type inference remains stable
|
2025-09-28 20:38:09 +09:00
|
|
|
|
crate::mir::builder::metadata::propagate::propagate(self, v, dst);
|
2025-09-26 04:17:56 +09:00
|
|
|
|
self.variable_map.insert(slot_name, dst);
|
|
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Ensure a value has a local definition in the current block by inserting a Copy.
|
2025-11-18 18:56:35 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-09-26 04:17:56 +09:00
|
|
|
|
pub(crate) fn materialize_local(&mut self, v: super::ValueId) -> Result<super::ValueId, String> {
|
2025-11-17 00:48:18 +09:00
|
|
|
|
// Phase 25.1b: Use function-local ID allocator to avoid SSA verification failures
|
|
|
|
|
|
let dst = if let Some(ref mut f) = self.current_function {
|
|
|
|
|
|
f.next_value_id() // Function context: use local ID
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.value_gen.next() // Module context: use global ID
|
|
|
|
|
|
};
|
2025-09-26 04:17:56 +09:00
|
|
|
|
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// Propagate metadata (type/origin) from source to the new local copy
|
|
|
|
|
|
crate::mir::builder::metadata::propagate::propagate(self, v, dst);
|
2025-09-26 04:17:56 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
2025-09-26 05:28:20 +09:00
|
|
|
|
|
2025-09-28 20:38:09 +09:00
|
|
|
|
/// Insert a Copy immediately after PHI nodes in the current block (position-stable).
|
2025-11-18 18:56:35 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-09-28 20:38:09 +09:00
|
|
|
|
pub(crate) fn insert_copy_after_phis(&mut self, dst: super::ValueId, src: super::ValueId) -> Result<(), String> {
|
|
|
|
|
|
if let (Some(ref mut function), Some(bb)) = (&mut self.current_function, self.current_block) {
|
2025-11-17 03:19:03 +09:00
|
|
|
|
if std::env::var("NYASH_SCHEDULE_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[utils/insert-copy-after-phis] bb={:?} dst=%{} src=%{} attempting...",
|
|
|
|
|
|
bb, dst.0, src.0);
|
|
|
|
|
|
}
|
2025-09-28 20:38:09 +09:00
|
|
|
|
if let Some(block) = function.get_block_mut(bb) {
|
2025-11-17 03:19:03 +09:00
|
|
|
|
if std::env::var("NYASH_SCHEDULE_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[utils/insert-copy-after-phis] bb={:?} dst=%{} src=%{} phi_count={} SUCCESS",
|
|
|
|
|
|
bb, dst.0, src.0, block.phi_instructions().count());
|
|
|
|
|
|
}
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// Propagate effects on the block
|
|
|
|
|
|
block.insert_instruction_after_phis(super::MirInstruction::Copy { dst, src });
|
|
|
|
|
|
// Lightweight metadata propagation (unified)
|
|
|
|
|
|
crate::mir::builder::metadata::propagate::propagate(self, src, dst);
|
|
|
|
|
|
return Ok(());
|
2025-11-17 03:19:03 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
if std::env::var("NYASH_SCHEDULE_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[utils/insert-copy-after-phis] bb={:?} dst=%{} src=%{} FAILED: block not found",
|
|
|
|
|
|
bb, dst.0, src.0);
|
|
|
|
|
|
}
|
2025-09-28 20:38:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Err("No current function/block to insert copy".to_string())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 05:28:20 +09:00
|
|
|
|
/// Ensure a value is safe to use in the current block by slotifying (pinning) it.
|
|
|
|
|
|
/// Currently correctness-first: always pin to get a block-local def and PHI participation.
|
|
|
|
|
|
pub(crate) fn ensure_slotified_for_use(&mut self, v: super::ValueId, hint: &str) -> Result<super::ValueId, String> {
|
|
|
|
|
|
self.pin_to_slot(v, hint)
|
|
|
|
|
|
}
|
2025-09-28 20:38:09 +09:00
|
|
|
|
|
|
|
|
|
|
/// Local SSA: ensure a value has a definition in the current block and cache it per-block.
|
|
|
|
|
|
/// kind: 0 = recv (reserved for args in future)
|
|
|
|
|
|
pub(crate) fn local_ssa_ensure(&mut self, v: super::ValueId, kind: u8) -> super::ValueId {
|
|
|
|
|
|
use super::ssa::local::{ensure, LocalKind};
|
|
|
|
|
|
let lk = match kind {
|
|
|
|
|
|
0 => LocalKind::Recv,
|
|
|
|
|
|
1 => LocalKind::Arg,
|
|
|
|
|
|
2 => LocalKind::CompareOperand,
|
|
|
|
|
|
4 => LocalKind::Cond,
|
|
|
|
|
|
x => LocalKind::Other(x),
|
|
|
|
|
|
};
|
|
|
|
|
|
ensure(self, v, lk)
|
|
|
|
|
|
}
|
2025-09-16 03:54:44 +09:00
|
|
|
|
}
|