diff --git a/src/backend/llvm/compiler/codegen/instructions/flow.rs b/src/backend/llvm/compiler/codegen/instructions/flow.rs index 29209557..eaa8e158 100644 --- a/src/backend/llvm/compiler/codegen/instructions/flow.rs +++ b/src/backend/llvm/compiler/codegen/instructions/flow.rs @@ -54,6 +54,8 @@ pub(in super::super) fn emit_jump<'ctx>( >, vmap: &HashMap>, ) -> Result<(), String> { + let sealed = std::env::var("NYASH_LLVM_PHI_SEALED").ok().as_deref() == Some("1"); + if !sealed { if let Some(list) = phis_by_block.get(target) { for (_dst, phi, inputs) in list { if let Some((_, in_vid)) = inputs.iter().find(|(pred, _)| pred == &bid) { @@ -83,6 +85,7 @@ pub(in super::super) fn emit_jump<'ctx>( } } } + } let tbb = *bb_map.get(target).ok_or("target bb missing")?; codegen .builder @@ -106,7 +109,9 @@ pub(in super::super) fn emit_branch<'ctx>( ) -> Result<(), String> { let cond_v = *vmap.get(condition).ok_or("cond missing")?; let b = to_bool(codegen.context, cond_v, &codegen.builder)?; + let sealed = std::env::var("NYASH_LLVM_PHI_SEALED").ok().as_deref() == Some("1"); // then + if !sealed { if let Some(list) = phis_by_block.get(then_bb) { for (_dst, phi, inputs) in list { if let Some((_, in_vid)) = inputs.iter().find(|(pred, _)| pred == &bid) { @@ -137,7 +142,9 @@ pub(in super::super) fn emit_branch<'ctx>( } } } + } // else + if !sealed { if let Some(list) = phis_by_block.get(else_bb) { for (_dst, phi, inputs) in list { if let Some((_, in_vid)) = inputs.iter().find(|(pred, _)| pred == &bid) { @@ -168,6 +175,7 @@ pub(in super::super) fn emit_branch<'ctx>( } } } + } let tbb = *bb_map.get(then_bb).ok_or("then bb missing")?; let ebb = *bb_map.get(else_bb).ok_or("else bb missing")?; codegen @@ -233,3 +241,50 @@ fn coerce_to_type<'ctx>( (_, v) => Ok(v), } } + +/// Sealed-SSA style: when a block is finalized, add PHI incoming for all successor blocks. +pub(in super::super) fn seal_block<'ctx>( + codegen: &CodegenContext<'ctx>, + bid: BasicBlockId, + succs: &HashMap>, + bb_map: &HashMap>, + phis_by_block: &HashMap< + BasicBlockId, + Vec<(ValueId, PhiValue<'ctx>, Vec<(BasicBlockId, ValueId)>)>, + >, + vmap: &HashMap>, +) -> Result<(), String> { + if let Some(slist) = succs.get(&bid) { + 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) { + let mut val = *vmap.get(in_vid).ok_or("phi incoming (seal) value missing")?; + let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?; + val = coerce_to_type(codegen, phi, val)?; + 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 + ); + } + 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()), + } + } + } + } + } + } + Ok(()) +} diff --git a/src/backend/llvm/compiler/codegen/instructions/mod.rs b/src/backend/llvm/compiler/codegen/instructions/mod.rs index aae9d5d5..964b36ca 100644 --- a/src/backend/llvm/compiler/codegen/instructions/mod.rs +++ b/src/backend/llvm/compiler/codegen/instructions/mod.rs @@ -1,5 +1,5 @@ mod blocks; -mod flow; +pub mod flow; mod externcall; mod newbox; mod boxcall; diff --git a/src/backend/llvm/compiler/codegen/mod.rs b/src/backend/llvm/compiler/codegen/mod.rs index 85f35b77..ed47aac2 100644 --- a/src/backend/llvm/compiler/codegen/mod.rs +++ b/src/backend/llvm/compiler/codegen/mod.rs @@ -122,6 +122,12 @@ impl LLVMCompiler { crate::mir::BasicBlockId, Vec<(ValueId, PhiValue, Vec<(crate::mir::BasicBlockId, ValueId)>)>, > = HashMap::new(); + // Build successors map (for optional sealed-SSA PHI wiring) + let mut succs: HashMap> = HashMap::new(); + for (bid, block) in &func.blocks { + let v: Vec = block.successors.iter().copied().collect(); + succs.insert(*bid, v); + } // Bind parameters for (i, pid) in func.params.iter().enumerate() { if let Some(av) = llvm_func.get_nth_param(i as u32) { @@ -160,6 +166,25 @@ impl LLVMCompiler { .entry(*bid) .or_default() .push((*dst, phi, inputs.clone())); + if std::env::var("NYASH_LLVM_TRACE_PHI").ok().as_deref() == Some("1") { + let ty_str = phi + .as_basic_value() + .get_type() + .print_to_string() + .to_string(); + let mut pairs: Vec = Vec::new(); + for (pb, vid) in inputs { + pairs.push(format!("({}->{})", pb.as_u32(), vid.as_u32())); + } + eprintln!( + "[PHI:new] fn={} bb={} dst={} ty={} inputs={}", + fn_label, + bid.as_u32(), + dst.as_u32(), + ty_str, + pairs.join(",") + ); + } } } } @@ -168,6 +193,7 @@ impl LLVMCompiler { let const_strs = build_const_str_map(func); // Lower body + let sealed_mode = std::env::var("NYASH_LLVM_PHI_SEALED").ok().as_deref() == Some("1"); for (bi, bid) in block_ids.iter().enumerate() { let bb = *bb_map.get(bid).unwrap(); if codegen @@ -319,7 +345,10 @@ impl LLVMCompiler { instructions::emit_jump(&codegen, *bid, &entry_first, &bb_map, &phis_by_block, &vmap)?; } } - } + if sealed_mode { + instructions::flow::seal_block(&codegen, *bid, &succs, &bb_map, &phis_by_block, &vmap)?; + } + } // Verify the fully-lowered function once, after all blocks if !llvm_func.verify(true) { return Err(format!("Function verification failed: {}", name));