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::{MirInstruction, MirType, ValueId};
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
use crate::ast::{ASTNode, BinaryOperator};
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
use crate::mir::{BinaryOp, CompareOp, TypeOpKind, UnaryOp};
// Internal classification for binary operations
@ -38,7 +38,10 @@ impl super::MirBuilder {
let mir_op = self.convert_binary_operator(operator)?;
let all_call = std::env::var("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL").ok().as_deref() == Some("1");
let all_call = std::env::var("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL")
.ok()
.as_deref()
== Some("1");
match mir_op {
// Arithmetic operations
@ -51,11 +54,19 @@ impl super::MirBuilder {
.unwrap_or(false);
if matches!(op, crate::mir::BinaryOp::Add)
&& !in_add_op
&& (all_call || std::env::var("NYASH_BUILDER_OPERATOR_BOX_ADD_CALL").ok().as_deref() == Some("1"))
&& (all_call
|| std::env::var("NYASH_BUILDER_OPERATOR_BOX_ADD_CALL")
.ok()
.as_deref()
== Some("1"))
{
// AddOperator.apply/2(lhs, rhs)
let name = "AddOperator.apply/2".to_string();
self.emit_legacy_call(Some(dst), super::builder_calls::CallTarget::Global(name), vec![lhs, rhs])?;
self.emit_legacy_call(
Some(dst),
super::builder_calls::CallTarget::Global(name),
vec![lhs, rhs],
)?;
// 型注釈(従来と同等)
let lhs_is_str = match self.value_types.get(&lhs) {
Some(MirType::String) => true,
@ -81,21 +92,39 @@ impl super::MirBuilder {
crate::mir::BinaryOp::Mod => ("ModOperator.apply/2", "ModOperator.apply/"),
crate::mir::BinaryOp::Shl => ("ShlOperator.apply/2", "ShlOperator.apply/"),
crate::mir::BinaryOp::Shr => ("ShrOperator.apply/2", "ShrOperator.apply/"),
crate::mir::BinaryOp::BitAnd => ("BitAndOperator.apply/2", "BitAndOperator.apply/"),
crate::mir::BinaryOp::BitOr => ("BitOrOperator.apply/2", "BitOrOperator.apply/"),
crate::mir::BinaryOp::BitXor => ("BitXorOperator.apply/2", "BitXorOperator.apply/"),
crate::mir::BinaryOp::BitAnd => {
("BitAndOperator.apply/2", "BitAndOperator.apply/")
}
crate::mir::BinaryOp::BitOr => {
("BitOrOperator.apply/2", "BitOrOperator.apply/")
}
crate::mir::BinaryOp::BitXor => {
("BitXorOperator.apply/2", "BitXorOperator.apply/")
}
_ => ("", ""),
};
if !name.is_empty() {
let in_guard = self.current_function.as_ref().map(|f| f.signature.name.starts_with(guard_prefix)).unwrap_or(false);
let in_guard = self
.current_function
.as_ref()
.map(|f| f.signature.name.starts_with(guard_prefix))
.unwrap_or(false);
if !in_guard {
self.emit_legacy_call(Some(dst), super::builder_calls::CallTarget::Global(name.to_string()), vec![lhs, rhs])?;
self.emit_legacy_call(
Some(dst),
super::builder_calls::CallTarget::Global(name.to_string()),
vec![lhs, rhs],
)?;
// 型注釈: 算術はおおむね整数Addは上で注釈済み
self.value_types.insert(dst, MirType::Integer);
} else {
// guard中は従来のBinOp
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
crate::mir::ssot::binop_lower::emit_binop_to_dst(func, cur_bb, dst, op, lhs, rhs);
if let (Some(func), Some(cur_bb)) =
(self.current_function.as_mut(), self.current_block)
{
crate::mir::ssot::binop_lower::emit_binop_to_dst(
func, cur_bb, dst, op, lhs, rhs,
);
} else {
self.emit_instruction(MirInstruction::BinOp { dst, op, lhs, rhs })?;
}
@ -103,8 +132,12 @@ impl super::MirBuilder {
}
} else {
// 既存の算術経路
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
crate::mir::ssot::binop_lower::emit_binop_to_dst(func, cur_bb, dst, op, lhs, rhs);
if let (Some(func), Some(cur_bb)) =
(self.current_function.as_mut(), self.current_block)
{
crate::mir::ssot::binop_lower::emit_binop_to_dst(
func, cur_bb, dst, op, lhs, rhs,
);
} else {
self.emit_instruction(MirInstruction::BinOp { dst, op, lhs, rhs })?;
}
@ -130,8 +163,12 @@ impl super::MirBuilder {
}
} else {
// 既存の算術経路
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
crate::mir::ssot::binop_lower::emit_binop_to_dst(func, cur_bb, dst, op, lhs, rhs);
if let (Some(func), Some(cur_bb)) =
(self.current_function.as_mut(), self.current_block)
{
crate::mir::ssot::binop_lower::emit_binop_to_dst(
func, cur_bb, dst, op, lhs, rhs,
);
} else {
self.emit_instruction(MirInstruction::BinOp { dst, op, lhs, rhs })?;
}
@ -165,7 +202,12 @@ impl super::MirBuilder {
.map(|f| f.signature.name.starts_with("CompareOperator.apply/"))
.unwrap_or(false);
if !in_cmp_op
&& (all_call || std::env::var("NYASH_BUILDER_OPERATOR_BOX_COMPARE_CALL").ok().as_deref() == Some("1")) {
&& (all_call
|| std::env::var("NYASH_BUILDER_OPERATOR_BOX_COMPARE_CALL")
.ok()
.as_deref()
== Some("1"))
{
// op名の文字列化
let opname = match op {
CompareOp::Eq => "Eq",
@ -175,10 +217,15 @@ impl super::MirBuilder {
CompareOp::Gt => "Gt",
CompareOp::Ge => "Ge",
};
let op_const = crate::mir::builder::emission::constant::emit_string(self, opname);
let op_const =
crate::mir::builder::emission::constant::emit_string(self, opname);
// そのまま値を渡す(型変換/slot化は演算子内orVMで行う
let name = "CompareOperator.apply/3".to_string();
self.emit_legacy_call(Some(dst), super::builder_calls::CallTarget::Global(name), vec![op_const, lhs, rhs])?;
self.emit_legacy_call(
Some(dst),
super::builder_calls::CallTarget::Global(name),
vec![op_const, lhs, rhs],
)?;
self.value_types.insert(dst, MirType::Bool);
} else {
// 既存の比較経路(安全のための型注釈/slot化含む
@ -245,7 +292,9 @@ impl super::MirBuilder {
// Branch on LHS truthiness (runtime to_bool semantics in interpreter/LLVM)
let mut lhs_cond = self.local_cond(lhs_val);
crate::mir::builder::ssa::local::finalize_branch_cond(self, &mut lhs_cond);
crate::mir::builder::emission::branch::emit_conditional(self, lhs_cond, then_block, else_block)?;
crate::mir::builder::emission::branch::emit_conditional(
self, lhs_cond, then_block, else_block,
)?;
// Record predecessor block for branch (for single-pred PHI materialization)
let pre_branch_bb = self.current_block()?;
@ -273,7 +322,9 @@ impl super::MirBuilder {
let rhs_val = self.build_expression(right.clone())?;
let mut rhs_cond = self.local_cond(rhs_val);
crate::mir::builder::ssa::local::finalize_branch_cond(self, &mut rhs_cond);
crate::mir::builder::emission::branch::emit_conditional(self, rhs_cond, rhs_true, rhs_false)?;
crate::mir::builder::emission::branch::emit_conditional(
self, rhs_cond, rhs_true, rhs_false,
)?;
// true path
self.start_new_block(rhs_true)?;
let t_id = crate::mir::builder::emission::constant::emit_bool(self, true);
@ -286,7 +337,9 @@ impl super::MirBuilder {
let rhs_false_exit = self.current_block()?;
// join rhs result into a single bool
self.start_new_block(rhs_join)?;
if let Some(func) = self.current_function.as_mut() { func.update_cfg(); }
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
let rhs_bool = self.insert_phi_binary(rhs_true_exit, t_id, rhs_false_exit, f_id)?;
self.value_types.insert(rhs_bool, MirType::Bool);
rhs_bool
@ -323,7 +376,9 @@ impl super::MirBuilder {
let rhs_val = self.build_expression(right)?;
let mut rhs_cond = self.local_cond(rhs_val);
crate::mir::builder::ssa::local::finalize_branch_cond(self, &mut rhs_cond);
crate::mir::builder::emission::branch::emit_conditional(self, rhs_cond, rhs_true, rhs_false)?;
crate::mir::builder::emission::branch::emit_conditional(
self, rhs_cond, rhs_true, rhs_false,
)?;
// true path
self.start_new_block(rhs_true)?;
let t_id = crate::mir::builder::emission::constant::emit_bool(self, true);
@ -336,7 +391,9 @@ impl super::MirBuilder {
let rhs_false_exit = self.current_block()?;
// join rhs result into a single bool
self.start_new_block(rhs_join)?;
if let Some(func) = self.current_function.as_mut() { func.update_cfg(); }
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
let rhs_bool = self.insert_phi_binary(rhs_true_exit, t_id, rhs_false_exit, f_id)?;
self.value_types.insert(rhs_bool, MirType::Bool);
rhs_bool
@ -357,10 +414,16 @@ impl super::MirBuilder {
// Result PHI (bool) — consider only reachable predecessors
let mut inputs: Vec<(crate::mir::BasicBlockId, ValueId)> = Vec::new();
if then_reaches_merge { inputs.push((then_exit_block, then_value_raw)); }
if else_reaches_merge { inputs.push((else_exit_block, else_value_raw)); }
if then_reaches_merge {
inputs.push((then_exit_block, then_value_raw));
}
if else_reaches_merge {
inputs.push((else_exit_block, else_value_raw));
}
let result_val = if inputs.len() >= 2 {
if let Some(func) = self.current_function.as_mut() { func.update_cfg(); }
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
let dst = self.insert_phi(inputs)?;
self.value_types.insert(dst, MirType::Bool);
dst
@ -375,8 +438,16 @@ impl super::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,
&Some(else_var_map_end),
@ -394,19 +465,38 @@ impl super::MirBuilder {
operand: ASTNode,
) -> Result<ValueId, String> {
let operand_val = self.build_expression(operand)?;
let all_call = std::env::var("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL").ok().as_deref() == Some("1");
let all_call = std::env::var("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL")
.ok()
.as_deref()
== Some("1");
if all_call {
let (name, guard_prefix, rett) = match operator.as_str() {
"-" => ("NegOperator.apply/1", "NegOperator.apply/", MirType::Integer),
"-" => (
"NegOperator.apply/1",
"NegOperator.apply/",
MirType::Integer,
),
"!" | "not" => ("NotOperator.apply/1", "NotOperator.apply/", MirType::Bool),
"~" => ("BitNotOperator.apply/1", "BitNotOperator.apply/", MirType::Integer),
"~" => (
"BitNotOperator.apply/1",
"BitNotOperator.apply/",
MirType::Integer,
),
_ => ("", "", MirType::Integer),
};
if !name.is_empty() {
let in_guard = self.current_function.as_ref().map(|f| f.signature.name.starts_with(guard_prefix)).unwrap_or(false);
let in_guard = self
.current_function
.as_ref()
.map(|f| f.signature.name.starts_with(guard_prefix))
.unwrap_or(false);
let dst = self.next_value_id();
if !in_guard {
self.emit_legacy_call(Some(dst), super::builder_calls::CallTarget::Global(name.to_string()), vec![operand_val])?;
self.emit_legacy_call(
Some(dst),
super::builder_calls::CallTarget::Global(name.to_string()),
vec![operand_val],
)?;
self.value_types.insert(dst, rett);
return Ok(dst);
}