chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更
Phase 25.1 完了成果: - ✅ LoopForm v2 テスト・ドキュメント・コメント完備 - 4ケース(A/B/C/D)完全テストカバレッジ - 最小再現ケース作成(SSAバグ調査用) - SSOT文書作成(loopform_ssot.md) - 全ソースに [LoopForm] コメントタグ追加 - ✅ Stage-1 CLI デバッグ環境構築 - stage1_cli.hako 実装 - stage1_bridge.rs ブリッジ実装 - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh) - アーキテクチャ改善提案文書 - ✅ 環境変数削減計画策定 - 25変数の完全調査・分類 - 6段階削減ロードマップ(25→5、80%削減) - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG) Phase 26-D からの累積変更: - PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等) - MIRビルダーリファクタリング - 型伝播・最適化パス改善 - その他約300ファイルの累積変更 🎯 技術的成果: - SSAバグ根本原因特定(条件分岐内loop変数変更) - Region+next_iパターン適用完了(UsingCollectorBox等) - LoopFormパターン文書化・テスト化完了 - セルフホスティング基盤強化 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com> Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
@ -17,7 +17,9 @@ pub(super) fn builder_debug_log(msg: &str) {
|
||||
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; }
|
||||
if n >= cap {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!("[BUILDER] {}", msg);
|
||||
@ -32,28 +34,38 @@ impl super::MirBuilder {
|
||||
#[inline]
|
||||
pub(crate) fn next_value_id(&mut self) -> super::ValueId {
|
||||
if let Some(ref mut f) = self.current_function {
|
||||
f.next_value_id() // Function context
|
||||
f.next_value_id() // Function context
|
||||
} else {
|
||||
self.value_gen.next() // Module context
|
||||
self.value_gen.next() // Module context
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 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) }
|
||||
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) }
|
||||
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) }
|
||||
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) }
|
||||
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) }
|
||||
pub(crate) fn local_cond(&mut self, v: super::ValueId) -> super::ValueId {
|
||||
super::ssa::local::cond(self, v)
|
||||
}
|
||||
/// 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 {
|
||||
@ -93,12 +105,15 @@ impl super::MirBuilder {
|
||||
// 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
|
||||
if false && !self.suppress_pin_entry_copy_next {
|
||||
// Keep old code for reference
|
||||
// First pass: copy all pin slots and remember old->new mapping
|
||||
let names: Vec<String> = self.variable_map.keys().cloned().collect();
|
||||
let mut pin_renames: Vec<(super::ValueId, super::ValueId)> = Vec::new();
|
||||
for name in names.iter() {
|
||||
if !name.starts_with("__pin$") { continue; }
|
||||
if !name.starts_with("__pin$") {
|
||||
continue;
|
||||
}
|
||||
if let Some(&src) = self.variable_map.get(name) {
|
||||
let dst = self.next_value_id();
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
|
||||
@ -169,8 +184,13 @@ impl super::MirBuilder {
|
||||
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") {
|
||||
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,
|
||||
@ -314,18 +334,27 @@ impl super::MirBuilder {
|
||||
|
||||
/// 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.
|
||||
pub(crate) fn pin_to_slot(&mut self, v: super::ValueId, hint: &str) -> Result<super::ValueId, String> {
|
||||
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);
|
||||
// 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
|
||||
f.next_value_id() // Function context: use local ID
|
||||
} else {
|
||||
self.value_gen.next() // Module context: use global ID
|
||||
self.value_gen.next() // Module context: use global ID
|
||||
};
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
||||
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));
|
||||
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
|
||||
));
|
||||
}
|
||||
// Propagate lightweight metadata so downstream resolution/type inference remains stable
|
||||
crate::mir::builder::metadata::propagate::propagate(self, v, dst);
|
||||
@ -339,12 +368,15 @@ impl super::MirBuilder {
|
||||
|
||||
/// Ensure a value has a local definition in the current block by inserting a Copy.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn materialize_local(&mut self, v: super::ValueId) -> Result<super::ValueId, String> {
|
||||
pub(crate) fn materialize_local(
|
||||
&mut self,
|
||||
v: super::ValueId,
|
||||
) -> Result<super::ValueId, String> {
|
||||
// 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
|
||||
f.next_value_id() // Function context: use local ID
|
||||
} else {
|
||||
self.value_gen.next() // Module context: use global ID
|
||||
self.value_gen.next() // Module context: use global ID
|
||||
};
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
||||
// Propagate metadata (type/origin) from source to the new local copy
|
||||
@ -354,11 +386,18 @@ impl super::MirBuilder {
|
||||
|
||||
/// Insert a Copy immediately after PHI nodes in the current block (position-stable).
|
||||
#[allow(dead_code)]
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
eprintln!(
|
||||
"[utils/insert-copy-after-phis] bb={:?} dst=%{} src=%{} attempting...",
|
||||
bb, dst.0, src.0
|
||||
);
|
||||
}
|
||||
if let Some(block) = function.get_block_mut(bb) {
|
||||
if std::env::var("NYASH_SCHEDULE_TRACE").ok().as_deref() == Some("1") {
|
||||
@ -382,7 +421,11 @@ impl super::MirBuilder {
|
||||
|
||||
/// 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> {
|
||||
pub(crate) fn ensure_slotified_for_use(
|
||||
&mut self,
|
||||
v: super::ValueId,
|
||||
hint: &str,
|
||||
) -> Result<super::ValueId, String> {
|
||||
self.pin_to_slot(v, hint)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user