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,6 +1,6 @@
use super::{MirBuilder, ValueId};
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
use crate::ast::{ASTNode, BinaryOperator};
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
impl MirBuilder {
/// Lower an if/else using a structured IfForm (header→then/else→merge).
@ -17,25 +17,31 @@ impl MirBuilder {
// so that subsequent branches can safely reuse these values across blocks.
// This leverages existing variable_map merges (PHI) at the merge block.
if crate::config::env::mir_pre_pin_compare_operands() {
if let ASTNode::BinaryOp { operator, left, right, .. } = &condition {
match operator {
BinaryOperator::Equal
| BinaryOperator::NotEqual
| BinaryOperator::Less
| BinaryOperator::LessEqual
| BinaryOperator::Greater
| BinaryOperator::GreaterEqual => {
if let Ok(lhs_v) = self.build_expression((**left).clone()) {
let _ = self.pin_to_slot(lhs_v, "@if_lhs");
}
if let Ok(rhs_v) = self.build_expression((**right).clone()) {
let _ = self.pin_to_slot(rhs_v, "@if_rhs");
if let ASTNode::BinaryOp {
operator,
left,
right,
..
} = &condition
{
match operator {
BinaryOperator::Equal
| BinaryOperator::NotEqual
| BinaryOperator::Less
| BinaryOperator::LessEqual
| BinaryOperator::Greater
| BinaryOperator::GreaterEqual => {
if let Ok(lhs_v) = self.build_expression((**left).clone()) {
let _ = self.pin_to_slot(lhs_v, "@if_lhs");
}
if let Ok(rhs_v) = self.build_expression((**right).clone()) {
let _ = self.pin_to_slot(rhs_v, "@if_rhs");
}
}
_ => {}
}
_ => {}
}
}
}
let condition_val = self.build_expression(condition)?;
let condition_val = self.local_cond(condition_val);
@ -49,7 +55,12 @@ impl MirBuilder {
let pre_branch_bb = self.current_block()?;
let mut condition_val = condition_val;
crate::mir::builder::ssa::local::finalize_branch_cond(self, &mut condition_val);
crate::mir::builder::emission::branch::emit_conditional(self, condition_val, then_block, else_block)?;
crate::mir::builder::emission::branch::emit_conditional(
self,
condition_val,
then_block,
else_block,
)?;
// Snapshot variables before entering branches
let pre_if_var_map = self.variable_map.clone();
@ -93,40 +104,41 @@ impl MirBuilder {
self.debug_push_region(format!("join#{}", join_id) + "/else");
// Scope enter for else-branch
self.hint_scope_enter(0);
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) = if let Some(else_ast) = else_branch {
// Reset variable_map BEFORE materializing PHI nodes (same pattern as then-branch)
self.variable_map = pre_if_var_map.clone();
// Materialize all variables at block entry via single-pred Phi (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
name, pre_v, phi_val
);
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) =
if let Some(else_ast) = else_branch {
// Reset variable_map BEFORE materializing PHI nodes (same pattern as then-branch)
self.variable_map = pre_if_var_map.clone();
// Materialize all variables at block entry via single-pred Phi (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
name, pre_v, phi_val
);
}
}
}
let val = self.build_expression(else_ast.clone())?;
(val, Some(else_ast), Some(self.variable_map.clone()))
} else {
// No else branch: materialize PHI nodes for the empty else block
self.variable_map = pre_if_var_map.clone();
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
name, pre_v, phi_val
);
let val = self.build_expression(else_ast.clone())?;
(val, Some(else_ast), Some(self.variable_map.clone()))
} else {
// No else branch: materialize PHI nodes for the empty else block
self.variable_map = pre_if_var_map.clone();
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
name, pre_v, phi_val
);
}
}
}
let void_val = crate::mir::builder::emission::constant::emit_void(self);
// Phase 25.1c/k: Pass PHI-renamed variable_map for empty else branch
// This ensures merge_modified_vars uses correct ValueIds after PHI renaming
(void_val, None, Some(self.variable_map.clone()))
};
let void_val = crate::mir::builder::emission::constant::emit_void(self);
// Phase 25.1c/k: Pass PHI-renamed variable_map for empty else branch
// This ensures merge_modified_vars uses correct ValueIds after PHI renaming
(void_val, None, Some(self.variable_map.clone()))
};
let else_exit_block = self.current_block()?;
let else_reaches_merge = !self.is_current_block_terminated();
if else_reaches_merge {
@ -146,7 +158,8 @@ impl MirBuilder {
self.push_if_merge(merge_block);
// Pre-analysis: identify then/else assigned var for skip and hints
let assigned_then_pre = crate::mir::phi_core::if_phi::extract_assigned_var(&then_ast_for_analysis);
let assigned_then_pre =
crate::mir::phi_core::if_phi::extract_assigned_var(&then_ast_for_analysis);
let assigned_else_pre = else_ast_for_analysis
.as_ref()
.and_then(|e| crate::mir::phi_core::if_phi::extract_assigned_var(e));
@ -157,8 +170,16 @@ impl MirBuilder {
let result_val = self.normalize_if_else_phi(
then_block,
else_block,
if then_reaches_merge { Some(then_exit_block) } else { None },
if else_reaches_merge { Some(else_exit_block) } else { None },
if then_reaches_merge {
Some(then_exit_block)
} else {
None
},
if else_reaches_merge {
Some(else_exit_block)
} else {
None
},
then_value_raw,
else_value_raw,
&pre_if_var_map,
@ -172,12 +193,16 @@ impl MirBuilder {
// Hint: join result variable(s)
// 1) Primary: if both branches assign to the same variable name, emit a hint for that name
if let (Some(tn), Some(en)) = (assigned_then_pre.as_deref(), assigned_else_pre.as_deref()) {
if tn == en { self.hint_join_result(tn); }
if tn == en {
self.hint_join_result(tn);
}
}
// 2) Secondary: if both branches assign multiple variables, hint全件制限なし
if let Some(ref else_map_end) = else_var_map_end_opt {
for name in then_var_map_end.keys() {
if Some(name.as_str()) == assigned_then_pre.as_deref() { continue; }
if Some(name.as_str()) == assigned_then_pre.as_deref() {
continue;
}
if else_map_end.contains_key(name) {
self.hint_join_result(name.as_str());
}
@ -189,8 +214,16 @@ impl MirBuilder {
self.merge_modified_vars(
then_block,
else_block,
if then_reaches_merge { Some(then_exit_block) } else { None },
if else_reaches_merge { Some(else_exit_block) } else { None },
if then_reaches_merge {
Some(then_exit_block)
} else {
None
},
if else_reaches_merge {
Some(else_exit_block)
} else {
None
},
&pre_if_var_map,
&then_var_map_end,
&else_var_map_end_opt,