📋 Phase 15セルフホスティング戦略整理 & LLVM改善
## Phase 15戦略整理 - セルフホスティング戦略2025年9月版を作成 - Phase 15.2-15.5の段階的実装計画を明確化 - 15.2: LLVM独立化(nyash-llvm-compiler crate) - 15.3: Nyashコンパイラ実装でセルフホスト達成 - 15.4: VM層のNyash化(革新的アプローチ) - 15.5: ABI移行(LLVM完成後) - ROADMAP.mdの優先順位調整、README.md更新 ## LLVM改善(ChatGPT5協力) - BuilderCursor::with_block改善(状態の適切な保存/復元) - seal_blockでの挿入位置管理を厳密化 - 前任ブロックのみ処理、重複PHI incoming防止 - defined_in_blockトラッキングで値のスコープ管理 ## 洞察 - コンパイル不要のセルフホスティング実現可能 - VM層をNyashで書けば即座実行可能 - Phase 22(Nyash LLVMコンパイラ)への道筋 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -26,6 +26,8 @@ impl<'ctx, 'b> BuilderCursor<'ctx, 'b> {
|
||||
let prev_bb = self.cur_llbb;
|
||||
// Preserve previous closed state
|
||||
let prev_closed = prev_bid.and_then(|id| self.closed_by_bid.get(&id).copied());
|
||||
// Preserve target block closed state and restore after
|
||||
let tgt_closed_before = self.closed_by_bid.get(&bid).copied();
|
||||
|
||||
self.at_end(bid, bb);
|
||||
let r = body(self);
|
||||
@ -39,6 +41,13 @@ impl<'ctx, 'b> BuilderCursor<'ctx, 'b> {
|
||||
if let (Some(pid), Some(closed)) = (prev_bid, prev_closed) {
|
||||
self.closed_by_bid.insert(pid, closed);
|
||||
}
|
||||
if let Some(closed) = tgt_closed_before {
|
||||
self.closed_by_bid.insert(bid, closed);
|
||||
} else {
|
||||
// If previously unknown, keep it marked as closed if a terminator exists
|
||||
let has_term = unsafe { bb.get_terminator() }.is_some();
|
||||
self.closed_by_bid.insert(bid, has_term);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
||||
@ -250,8 +250,9 @@ fn coerce_to_type<'ctx>(
|
||||
}
|
||||
|
||||
/// Sealed-SSA style: when a block is finalized, add PHI incoming for all successor blocks.
|
||||
pub(in super::super) fn seal_block<'ctx>(
|
||||
pub(in super::super) fn seal_block<'ctx, 'b>(
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
func: &MirFunction,
|
||||
bid: BasicBlockId,
|
||||
succs: &HashMap<BasicBlockId, Vec<BasicBlockId>>,
|
||||
@ -269,11 +270,12 @@ pub(in super::super) fn seal_block<'ctx>(
|
||||
for sb in slist {
|
||||
if let Some(pl) = phis_by_block.get(sb) {
|
||||
for (_dst, phi, inputs) in pl {
|
||||
if let Some((_, in_vid)) = inputs.iter().find(|(pred, _)| pred == &bid) {
|
||||
// Handle only the current predecessor (bid)
|
||||
if let Some((_, in_vid)) = inputs.iter().find(|(p, _)| p == &bid) {
|
||||
// Prefer the predecessor's block-end snapshot; fall back to current vmap
|
||||
let snap_opt = block_end_values
|
||||
.get(&bid)
|
||||
.and_then(|m| m.get(in_vid).copied());
|
||||
.get(&bid)
|
||||
.and_then(|m| m.get(in_vid).copied());
|
||||
let mut val = if let Some(sv) = snap_opt {
|
||||
sv
|
||||
} else {
|
||||
@ -298,72 +300,69 @@ pub(in super::super) fn seal_block<'ctx>(
|
||||
BT::FloatType(ft) => ft.const_zero().into(),
|
||||
BT::PointerType(pt) => pt.const_zero().into(),
|
||||
_ => return Err(format!(
|
||||
"phi incoming (seal) missing: pred={} succ_bb={} in_vid={} (no snapshot)",
|
||||
bid.as_u32(), sb.as_u32(), in_vid.as_u32()
|
||||
)),
|
||||
"phi incoming (seal) missing: pred={} succ_bb={} in_vid={} (no snapshot)",
|
||||
bid.as_u32(), sb.as_u32(), in_vid.as_u32()
|
||||
)),
|
||||
}
|
||||
}
|
||||
};
|
||||
// Ensure any required casts are inserted BEFORE the predecessor's terminator
|
||||
// Save and restore current insertion point around coercion
|
||||
let saved_block = codegen.builder.get_insert_block();
|
||||
if let Some(pred_llbb) = bb_map.get(&bid) {
|
||||
let term = unsafe { pred_llbb.get_terminator() };
|
||||
if let Some(t) = term {
|
||||
// Insert casts right before the terminator of predecessor
|
||||
codegen.builder.position_before(&t);
|
||||
} else {
|
||||
codegen.builder.position_at_end(*pred_llbb);
|
||||
// Insert any required casts in the predecessor block, right before its terminator
|
||||
let saved_block = codegen.builder.get_insert_block();
|
||||
if let Some(pred_llbb) = bb_map.get(&bid) {
|
||||
let term = unsafe { pred_llbb.get_terminator() };
|
||||
if let Some(t) = term {
|
||||
codegen.builder.position_before(&t);
|
||||
} else {
|
||||
codegen.builder.position_at_end(*pred_llbb);
|
||||
}
|
||||
}
|
||||
val = coerce_to_type(codegen, phi, val)?;
|
||||
if let Some(bb) = saved_block { codegen.builder.position_at_end(bb); }
|
||||
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
let tys = phi
|
||||
.as_basic_value()
|
||||
.get_type()
|
||||
.print_to_string()
|
||||
.to_string();
|
||||
eprintln!(
|
||||
"[PHI] sealed add pred_bb={} val={} ty={}{}",
|
||||
bid.as_u32(),
|
||||
in_vid.as_u32(),
|
||||
tys,
|
||||
if snap_opt.is_some() { " (snapshot)" } else { " (vmap)" }
|
||||
);
|
||||
}
|
||||
match val {
|
||||
BasicValueEnum::IntValue(iv) => phi.add_incoming(&[(&iv, pred_bb)]),
|
||||
BasicValueEnum::FloatValue(fv) => phi.add_incoming(&[(&fv, pred_bb)]),
|
||||
BasicValueEnum::PointerValue(pv) => phi.add_incoming(&[(&pv, pred_bb)]),
|
||||
_ => return Err("unsupported phi incoming value (seal)".to_string()),
|
||||
}
|
||||
}
|
||||
val = coerce_to_type(codegen, phi, val)?;
|
||||
if let Some(bb) = saved_block { codegen.builder.position_at_end(bb); }
|
||||
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
let tys = phi
|
||||
.as_basic_value()
|
||||
.get_type()
|
||||
.print_to_string()
|
||||
.to_string();
|
||||
eprintln!(
|
||||
"[PHI] sealed add pred_bb={} val={} ty={}{}",
|
||||
bid.as_u32(),
|
||||
in_vid.as_u32(),
|
||||
tys,
|
||||
if snap_opt.is_some() { " (snapshot)" } else { " (vmap)" }
|
||||
);
|
||||
}
|
||||
match val {
|
||||
BasicValueEnum::IntValue(iv) => phi.add_incoming(&[(&iv, pred_bb)]),
|
||||
BasicValueEnum::FloatValue(fv) => phi.add_incoming(&[(&fv, pred_bb)]),
|
||||
BasicValueEnum::PointerValue(pv) => phi.add_incoming(&[(&pv, pred_bb)]),
|
||||
_ => return Err("unsupported phi incoming value (seal)".to_string()),
|
||||
}
|
||||
} else {
|
||||
// inputs に pred が見つからない場合でも、検証器は「各predに1エントリ」を要求する。
|
||||
// ゼロ(型に応じた null/0)を合成して追加する(ログ付)
|
||||
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
||||
use inkwell::types::BasicTypeEnum as BT;
|
||||
let bt = phi.as_basic_value().get_type();
|
||||
let z: BasicValueEnum = match bt {
|
||||
BT::IntType(it) => it.const_zero().into(),
|
||||
BT::FloatType(ft) => ft.const_zero().into(),
|
||||
BT::PointerType(pt) => pt.const_zero().into(),
|
||||
_ => return Err("unsupported phi type for zero synth (seal)".to_string()),
|
||||
};
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
"[PHI] sealed add (synth) pred_bb={} zero-ty={}",
|
||||
bid.as_u32(),
|
||||
bt.print_to_string().to_string()
|
||||
);
|
||||
}
|
||||
match z {
|
||||
BasicValueEnum::IntValue(iv) => phi.add_incoming(&[(&iv, pred_bb)]),
|
||||
BasicValueEnum::FloatValue(fv) => phi.add_incoming(&[(&fv, pred_bb)]),
|
||||
BasicValueEnum::PointerValue(pv) => phi.add_incoming(&[(&pv, pred_bb)]),
|
||||
_ => return Err("unsupported phi incoming (synth)".to_string()),
|
||||
}
|
||||
// Missing mapping for this predecessor: synthesize a typed zero
|
||||
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
||||
use inkwell::types::BasicTypeEnum as BT;
|
||||
let bt = phi.as_basic_value().get_type();
|
||||
let z: BasicValueEnum = match bt {
|
||||
BT::IntType(it) => it.const_zero().into(),
|
||||
BT::FloatType(ft) => ft.const_zero().into(),
|
||||
BT::PointerType(pt) => pt.const_zero().into(),
|
||||
_ => return Err("unsupported phi type for zero synth (seal)".to_string()),
|
||||
};
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
"[PHI] sealed add (synth) pred_bb={} zero-ty={}",
|
||||
bid.as_u32(),
|
||||
bt.print_to_string().to_string()
|
||||
);
|
||||
}
|
||||
match z {
|
||||
BasicValueEnum::IntValue(iv) => phi.add_incoming(&[(&iv, pred_bb)]),
|
||||
BasicValueEnum::FloatValue(fv) => phi.add_incoming(&[(&fv, pred_bb)]),
|
||||
BasicValueEnum::PointerValue(pv) => phi.add_incoming(&[(&pv, pred_bb)]),
|
||||
_ => return Err("unsupported phi incoming (synth)".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user