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:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -1,9 +1,7 @@
use super::{
lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext,
};
use super::super::ast::{CatchV0, StmtV0};
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
use std::collections::HashMap;
use super::super::ast::{StmtV0, CatchV0};
pub(super) fn lower_try_stmt(
f: &mut MirFunction,
@ -23,9 +21,23 @@ pub(super) fn lower_try_stmt(
if catches.len() > 1 {
// Fallback to safe lowering (ignore catches) for multi-catch
let mut tmp_vars = vars.clone();
let mut next_bb = super::lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
let mut next_bb = super::lower_stmt_list_with_vars(
f,
cur_bb,
try_body,
&mut tmp_vars,
loop_stack,
env,
)?;
if !finally.is_empty() {
next_bb = super::lower_stmt_list_with_vars(f, next_bb, finally, &mut tmp_vars, loop_stack, env)?;
next_bb = super::lower_stmt_list_with_vars(
f,
next_bb,
finally,
&mut tmp_vars,
loop_stack,
env,
)?;
}
*vars = tmp_vars;
return Ok(next_bb);
@ -34,29 +46,47 @@ pub(super) fn lower_try_stmt(
let base_vars = vars.clone();
let try_bb = new_block(f);
let catch_bb_opt = if has_catch { Some(new_block(f)) } else { None };
let finally_bb = if !finally.is_empty() { Some(new_block(f)) } else { None };
let finally_bb = if !finally.is_empty() {
Some(new_block(f))
} else {
None
};
let exit_bb = new_block(f);
f.set_jump_terminator(cur_bb, try_bb)?;
if let Some(succ) = f.get_block_mut(try_bb) { succ.add_predecessor(cur_bb); }
if let Some(succ) = f.get_block_mut(try_bb) {
succ.add_predecessor(cur_bb);
}
// Install thread-local throw context so nested throw expressions jump to catch_bb
if has_catch {
let catch_bb = catch_bb_opt.expect("catch_bb must exist when has_catch");
if crate::config::env::cli_verbose() {
eprintln!("[Bridge] try_result_mode: set ThrowCtx (catch_bb={:?})", catch_bb);
eprintln!(
"[Bridge] try_result_mode: set ThrowCtx (catch_bb={:?})",
catch_bb
);
}
super::throw_ctx::set(catch_bb);
} else if crate::config::env::cli_verbose() {
eprintln!("[Bridge] try_result_mode: no catch present; ThrowCtx not set");
}
let mut try_vars = base_vars.clone();
let try_end = super::lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
let try_end =
super::lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
// Take recorded incoming exceptions
let incoming_exc = if has_catch { super::throw_ctx::take().map(|c| c.incoming).unwrap_or_default() } else { Vec::new() };
let incoming_exc = if has_catch {
super::throw_ctx::take()
.map(|c| c.incoming)
.unwrap_or_default()
} else {
Vec::new()
};
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(try_end, target)?;
if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(try_end); }
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(try_end);
}
let try_branch_vars = try_vars.clone();
// Lower catch block if present and reachable
@ -72,7 +102,9 @@ pub(super) fn lower_try_stmt(
if let Some(_bb) = f.get_block_mut(catch_bb) {
let mut inputs = incoming_exc.clone();
inputs.sort_by_key(|(bbid, _)| bbid.0);
crate::mir::ssot::cf_common::insert_phi_at_head(f, catch_bb, phi_dst, inputs);
crate::mir::ssot::cf_common::insert_phi_at_head(
f, catch_bb, phi_dst, inputs,
);
}
catch_vars.insert(param.clone(), phi_dst);
}
@ -87,7 +119,9 @@ pub(super) fn lower_try_stmt(
)?;
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(end, target)?;
if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(end); }
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(end);
}
(end, catch_vars)
} else {
(try_end, base_vars.clone())
@ -98,21 +132,30 @@ pub(super) fn lower_try_stmt(
if let Some(finally_block) = finally_bb {
// Compute merged var map from try_end + catch_end (if has_catch)
let branch_vars: Vec<(BasicBlockId, HashMap<String, ValueId>)> = if has_catch {
vec![(try_end, try_branch_vars.clone()), (catch_end, catch_branch_vars.clone())]
vec![
(try_end, try_branch_vars.clone()),
(catch_end, catch_branch_vars.clone()),
]
} else {
vec![(try_end, try_branch_vars.clone())]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars { names.extend(map.keys().cloned()); }
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) { inputs.push((*bbid, v)); }
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) { merged_vars.insert(name.clone(), b); }
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
@ -126,12 +169,23 @@ pub(super) fn lower_try_stmt(
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = super::lower_stmt_list_with_vars(f, finally_block, finally, &mut finally_vars, loop_stack, env)?;
let final_end = super::lower_stmt_list_with_vars(
f,
finally_block,
finally,
&mut finally_vars,
loop_stack,
env,
)?;
f.set_jump_terminator(final_end, exit_bb)?;
if let Some(succ) = f.get_block_mut(exit_bb) { succ.add_predecessor(final_end); }
if let Some(succ) = f.get_block_mut(exit_bb) {
succ.add_predecessor(final_end);
}
*vars = finally_vars;
return Ok(exit_bb);
} else {
@ -142,38 +196,49 @@ pub(super) fn lower_try_stmt(
vec![(try_end, try_branch_vars)]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars { names.extend(map.keys().cloned()); }
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars { if let Some(&v) = map.get(&name) { inputs.push((*bbid, v)); } }
if inputs.is_empty() { if let Some(&b) = base_vars.get(&name) { merged_vars.insert(name.clone(), b); } continue; }
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if uniq.len() == 1 { merged_vars.insert(name.clone(), inputs[0].1); continue; }
if uniq.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
}
}
*vars = merged_vars;
return Ok(exit_bb);
}
} else if !try_enabled || catches.is_empty() || catches.len() > 1 {
let mut tmp_vars = vars.clone();
let mut next_bb = lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
let mut next_bb =
lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
if !finally.is_empty() {
next_bb = lower_stmt_list_with_vars(
f,
next_bb,
finally,
&mut tmp_vars,
loop_stack,
env,
)?;
next_bb =
lower_stmt_list_with_vars(f, next_bb, finally, &mut tmp_vars, loop_stack, env)?;
}
*vars = tmp_vars;
return Ok(next_bb);
@ -260,7 +325,9 @@ pub(super) fn lower_try_stmt(
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = lower_stmt_list_with_vars(
@ -309,7 +376,9 @@ pub(super) fn lower_try_stmt(
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
}
}
*vars = merged_vars;
Ok(exit_bb)