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:
@ -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,
|
||||
|
||||
Reference in New Issue
Block a user