2025-09-11 23:58:10 +09:00
|
|
|
|
use inkwell::basic_block::BasicBlock;
|
|
|
|
|
|
use inkwell::values::{BasicValueEnum, PhiValue};
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::backend::llvm::context::CodegenContext;
|
|
|
|
|
|
use crate::mir::{function::MirFunction, BasicBlockId, ValueId};
|
|
|
|
|
|
|
2025-09-12 05:48:59 +09:00
|
|
|
|
use super::super::types::{to_bool, map_mirtype_to_basic};
|
2025-09-12 14:12:54 +09:00
|
|
|
|
use super::builder_cursor::BuilderCursor;
|
2025-09-11 23:58:10 +09:00
|
|
|
|
|
2025-09-12 14:12:54 +09:00
|
|
|
|
pub(in super::super) fn emit_return<'ctx, 'b>(
|
2025-09-11 23:58:10 +09:00
|
|
|
|
codegen: &CodegenContext<'ctx>,
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
|
|
|
|
|
_bid: BasicBlockId,
|
2025-09-11 23:58:10 +09:00
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
|
value: &Option<ValueId>,
|
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
|
match (&func.signature.return_type, value) {
|
|
|
|
|
|
(crate::mir::MirType::Void, _) => {
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor.emit_term(_bid, |b| { b.build_return(None).unwrap(); });
|
2025-09-11 23:58:10 +09:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
(_t, Some(vid)) => {
|
|
|
|
|
|
let v = *vmap.get(vid).ok_or("ret value missing")?;
|
2025-09-12 05:48:59 +09:00
|
|
|
|
// If function expects a pointer but we have an integer handle, convert i64 -> ptr
|
|
|
|
|
|
let expected = map_mirtype_to_basic(codegen.context, &func.signature.return_type);
|
|
|
|
|
|
use inkwell::types::BasicTypeEnum as BT;
|
|
|
|
|
|
let v_adj = match (expected, v) {
|
|
|
|
|
|
(BT::PointerType(pt), BasicValueEnum::IntValue(iv)) => {
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor.emit_instr(_bid, |b| b
|
|
|
|
|
|
.build_int_to_ptr(iv, pt, "ret_i2p"))
|
2025-09-12 05:48:59 +09:00
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into()
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => v,
|
|
|
|
|
|
};
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor.emit_term(_bid, |b| {
|
|
|
|
|
|
b.build_return(Some(&v_adj)).map_err(|e| e.to_string()).unwrap();
|
|
|
|
|
|
});
|
2025-09-11 23:58:10 +09:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
(_t, None) => Err("non-void function missing return value".to_string()),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 14:12:54 +09:00
|
|
|
|
pub(in super::super) fn emit_jump<'ctx, 'b>(
|
2025-09-11 23:58:10 +09:00
|
|
|
|
codegen: &CodegenContext<'ctx>,
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
2025-09-11 23:58:10 +09:00
|
|
|
|
bid: BasicBlockId,
|
|
|
|
|
|
target: &BasicBlockId,
|
|
|
|
|
|
bb_map: &HashMap<BasicBlockId, BasicBlock<'ctx>>,
|
|
|
|
|
|
phis_by_block: &HashMap<
|
|
|
|
|
|
BasicBlockId,
|
|
|
|
|
|
Vec<(ValueId, PhiValue<'ctx>, Vec<(BasicBlockId, ValueId)>)>,
|
|
|
|
|
|
>,
|
|
|
|
|
|
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
|
) -> Result<(), String> {
|
2025-09-12 12:30:42 +09:00
|
|
|
|
let sealed = std::env::var("NYASH_LLVM_PHI_SEALED").ok().as_deref() == Some("1");
|
|
|
|
|
|
if !sealed {
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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) {
|
2025-09-12 12:07:07 +09:00
|
|
|
|
let mut val = *vmap.get(in_vid).ok_or("phi incoming value missing")?;
|
2025-09-11 23:58:10 +09:00
|
|
|
|
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
2025-09-12 12:07:07 +09:00
|
|
|
|
// Coerce incoming to PHI type when needed
|
|
|
|
|
|
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] incoming add pred_bb={} val={} ty={}",
|
|
|
|
|
|
bid.as_u32(),
|
|
|
|
|
|
in_vid.as_u32(),
|
|
|
|
|
|
tys
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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".to_string()),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
let tbb = *bb_map.get(target).ok_or("target bb missing")?;
|
2025-09-12 13:20:59 +09:00
|
|
|
|
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[LLVM] emit_jump: {} -> {}", bid.as_u32(), target.as_u32());
|
|
|
|
|
|
}
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor.emit_term(bid, |b| {
|
|
|
|
|
|
b.build_unconditional_branch(tbb).map_err(|e| e.to_string()).unwrap();
|
|
|
|
|
|
});
|
2025-09-11 23:58:10 +09:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 14:12:54 +09:00
|
|
|
|
pub(in super::super) fn emit_branch<'ctx, 'b>(
|
2025-09-11 23:58:10 +09:00
|
|
|
|
codegen: &CodegenContext<'ctx>,
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
2025-09-11 23:58:10 +09:00
|
|
|
|
bid: BasicBlockId,
|
|
|
|
|
|
condition: &ValueId,
|
|
|
|
|
|
then_bb: &BasicBlockId,
|
|
|
|
|
|
else_bb: &BasicBlockId,
|
|
|
|
|
|
bb_map: &HashMap<BasicBlockId, BasicBlock<'ctx>>,
|
|
|
|
|
|
phis_by_block: &HashMap<
|
|
|
|
|
|
BasicBlockId,
|
|
|
|
|
|
Vec<(ValueId, PhiValue<'ctx>, Vec<(BasicBlockId, ValueId)>)>,
|
|
|
|
|
|
>,
|
|
|
|
|
|
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
|
let cond_v = *vmap.get(condition).ok_or("cond missing")?;
|
|
|
|
|
|
let b = to_bool(codegen.context, cond_v, &codegen.builder)?;
|
2025-09-12 12:30:42 +09:00
|
|
|
|
let sealed = std::env::var("NYASH_LLVM_PHI_SEALED").ok().as_deref() == Some("1");
|
2025-09-11 23:58:10 +09:00
|
|
|
|
// then
|
2025-09-12 12:30:42 +09:00
|
|
|
|
if !sealed {
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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) {
|
2025-09-12 12:07:07 +09:00
|
|
|
|
let mut val = *vmap
|
2025-09-11 23:58:10 +09:00
|
|
|
|
.get(in_vid)
|
|
|
|
|
|
.ok_or("phi incoming (then) value missing")?;
|
|
|
|
|
|
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
2025-09-12 12:07:07 +09:00
|
|
|
|
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] incoming add (then) pred_bb={} val={} ty={}",
|
|
|
|
|
|
bid.as_u32(),
|
|
|
|
|
|
in_vid.as_u32(),
|
|
|
|
|
|
tys
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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 (then)".to_string()),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
// else
|
2025-09-12 12:30:42 +09:00
|
|
|
|
if !sealed {
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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) {
|
2025-09-12 12:07:07 +09:00
|
|
|
|
let mut val = *vmap
|
2025-09-11 23:58:10 +09:00
|
|
|
|
.get(in_vid)
|
|
|
|
|
|
.ok_or("phi incoming (else) value missing")?;
|
|
|
|
|
|
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
2025-09-12 12:07:07 +09:00
|
|
|
|
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] incoming add (else) pred_bb={} val={} ty={}",
|
|
|
|
|
|
bid.as_u32(),
|
|
|
|
|
|
in_vid.as_u32(),
|
|
|
|
|
|
tys
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
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 (else)".to_string()),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
}
|
2025-09-11 23:58:10 +09:00
|
|
|
|
let tbb = *bb_map.get(then_bb).ok_or("then bb missing")?;
|
|
|
|
|
|
let ebb = *bb_map.get(else_bb).ok_or("else bb missing")?;
|
2025-09-12 13:20:59 +09:00
|
|
|
|
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[LLVM] emit_branch: {} -> then {} / else {}", bid.as_u32(), then_bb.as_u32(), else_bb.as_u32());
|
|
|
|
|
|
}
|
2025-09-12 14:12:54 +09:00
|
|
|
|
cursor.emit_term(bid, |bd| {
|
|
|
|
|
|
bd.build_conditional_branch(b, tbb, ebb).map_err(|e| e.to_string()).unwrap();
|
|
|
|
|
|
});
|
2025-09-11 23:58:10 +09:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
2025-09-12 12:07:07 +09:00
|
|
|
|
|
|
|
|
|
|
// Coerce a value to the PHI node's type, inserting casts in the current block if necessary.
|
|
|
|
|
|
fn coerce_to_type<'ctx>(
|
|
|
|
|
|
codegen: &CodegenContext<'ctx>,
|
|
|
|
|
|
phi: &PhiValue<'ctx>,
|
|
|
|
|
|
val: BasicValueEnum<'ctx>,
|
|
|
|
|
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
|
|
|
|
|
use inkwell::types::BasicTypeEnum as BT;
|
|
|
|
|
|
match (phi.as_basic_value().get_type(), val) {
|
|
|
|
|
|
(BT::IntType(it), BasicValueEnum::IntValue(iv)) => {
|
|
|
|
|
|
let bw_src = iv.get_type().get_bit_width();
|
|
|
|
|
|
let bw_dst = it.get_bit_width();
|
|
|
|
|
|
if bw_src == bw_dst {
|
|
|
|
|
|
Ok(iv.into())
|
|
|
|
|
|
} else if bw_src < bw_dst {
|
|
|
|
|
|
Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_int_z_extend(iv, it, "phi_zext")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into())
|
|
|
|
|
|
} else if bw_dst == 1 {
|
|
|
|
|
|
// Narrow to i1 via != 0
|
|
|
|
|
|
Ok(super::super::types::to_bool(codegen.context, iv.into(), &codegen.builder)?.into())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_int_truncate(iv, it, "phi_trunc")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
(BT::IntType(it), BasicValueEnum::PointerValue(pv)) => Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_ptr_to_int(pv, it, "phi_p2i")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into()),
|
|
|
|
|
|
(BT::IntType(it), BasicValueEnum::FloatValue(fv)) => Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_float_to_signed_int(fv, it, "phi_f2i")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into()),
|
|
|
|
|
|
(BT::PointerType(pt), BasicValueEnum::IntValue(iv)) => Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_int_to_ptr(iv, pt, "phi_i2p")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into()),
|
|
|
|
|
|
(BT::PointerType(_), BasicValueEnum::PointerValue(pv)) => Ok(pv.into()),
|
|
|
|
|
|
(BT::FloatType(ft), BasicValueEnum::IntValue(iv)) => Ok(codegen
|
|
|
|
|
|
.builder
|
|
|
|
|
|
.build_signed_int_to_float(iv, ft, "phi_i2f")
|
|
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
|
|
.into()),
|
|
|
|
|
|
(BT::FloatType(_), BasicValueEnum::FloatValue(fv)) => Ok(fv.into()),
|
|
|
|
|
|
// Already matching or unsupported combination
|
|
|
|
|
|
(_, v) => Ok(v),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
|
|
|
|
|
|
/// 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>,
|
2025-09-12 14:34:13 +09:00
|
|
|
|
func: &MirFunction,
|
2025-09-12 12:30:42 +09:00
|
|
|
|
bid: BasicBlockId,
|
|
|
|
|
|
succs: &HashMap<BasicBlockId, Vec<BasicBlockId>>,
|
|
|
|
|
|
bb_map: &HashMap<BasicBlockId, BasicBlock<'ctx>>,
|
|
|
|
|
|
phis_by_block: &HashMap<
|
|
|
|
|
|
BasicBlockId,
|
|
|
|
|
|
Vec<(ValueId, PhiValue<'ctx>, Vec<(BasicBlockId, ValueId)>)>,
|
|
|
|
|
|
>,
|
2025-09-12 13:20:59 +09:00
|
|
|
|
// Snapshot of value map at end of each predecessor block
|
|
|
|
|
|
block_end_values: &HashMap<BasicBlockId, HashMap<ValueId, BasicValueEnum<'ctx>>>,
|
|
|
|
|
|
// Fallback: current vmap (used only if snapshot missing)
|
2025-09-12 12:30:42 +09:00
|
|
|
|
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
|
) -> 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) {
|
2025-09-12 13:20:59 +09:00
|
|
|
|
// 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());
|
|
|
|
|
|
let mut val = if let Some(sv) = snap_opt {
|
|
|
|
|
|
sv
|
|
|
|
|
|
} else {
|
2025-09-12 14:34:13 +09:00
|
|
|
|
// Trust vmap only when the value is a function parameter (dominates all paths)
|
|
|
|
|
|
if func.params.contains(in_vid) {
|
|
|
|
|
|
vmap.get(in_vid).copied().unwrap_or_else(|| {
|
2025-09-12 14:12:54 +09:00
|
|
|
|
let bt = phi.as_basic_value().get_type();
|
2025-09-12 14:34:13 +09:00
|
|
|
|
use inkwell::types::BasicTypeEnum as BT;
|
2025-09-12 14:12:54 +09:00
|
|
|
|
match bt {
|
|
|
|
|
|
BT::IntType(it) => it.const_zero().into(),
|
|
|
|
|
|
BT::FloatType(ft) => ft.const_zero().into(),
|
|
|
|
|
|
BT::PointerType(pt) => pt.const_zero().into(),
|
2025-09-12 14:34:13 +09:00
|
|
|
|
_ => unreachable!(),
|
2025-09-12 14:12:54 +09:00
|
|
|
|
}
|
2025-09-12 14:34:13 +09:00
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Synthesize zero to avoid dominance violations
|
|
|
|
|
|
let bt = phi.as_basic_value().get_type();
|
|
|
|
|
|
use inkwell::types::BasicTypeEnum as BT;
|
|
|
|
|
|
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(format!(
|
|
|
|
|
|
"phi incoming (seal) missing: pred={} succ_bb={} in_vid={} (no snapshot)",
|
|
|
|
|
|
bid.as_u32(), sb.as_u32(), in_vid.as_u32()
|
|
|
|
|
|
)),
|
2025-09-12 13:20:59 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-09-12 14:12:54 +09:00
|
|
|
|
// 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
val = coerce_to_type(codegen, phi, val)?;
|
2025-09-12 14:12:54 +09:00
|
|
|
|
if let Some(bb) = saved_block { codegen.builder.position_at_end(bb); }
|
|
|
|
|
|
let pred_bb = *bb_map.get(&bid).ok_or("pred bb missing")?;
|
2025-09-12 12:30:42 +09:00
|
|
|
|
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!(
|
2025-09-12 13:20:59 +09:00
|
|
|
|
"[PHI] sealed add pred_bb={} val={} ty={}{}",
|
2025-09-12 12:30:42 +09:00
|
|
|
|
bid.as_u32(),
|
|
|
|
|
|
in_vid.as_u32(),
|
2025-09-12 13:20:59 +09:00
|
|
|
|
tys,
|
|
|
|
|
|
if snap_opt.is_some() { " (snapshot)" } else { " (vmap)" }
|
2025-09-12 12:30:42 +09:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
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()),
|
|
|
|
|
|
}
|
2025-09-12 14:12:54 +09:00
|
|
|
|
} 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()),
|
|
|
|
|
|
}
|
2025-09-12 12:30:42 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|