docs: Create AI-assisted compiler development paper structure
Added paper-g-ai-assisted-compiler folder documenting: - Week-long LLVM backend development with AI assistance - Key insights from PHI/SSA struggles to Resolver API solution - Development log capturing the chaotic reality - Abstract in both English and Japanese Key quote: 'I don't remember anymore' - capturing the authentic experience of intensive AI-assisted development where the process itself becomes the research data. This represents potentially the first fully documented case of building a compiler backend primarily through AI assistance.
This commit is contained in:
@ -10,6 +10,7 @@ use super::builder_cursor::BuilderCursor;
|
||||
pub(super) fn try_handle_array_method<'ctx, 'b>(
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
resolver: &mut super::Resolver<'ctx>,
|
||||
cur_bid: BasicBlockId,
|
||||
func: &MirFunction,
|
||||
vmap: &mut HashMap<ValueId, inkwell::values::BasicValueEnum<'ctx>>,
|
||||
@ -18,6 +19,9 @@ pub(super) fn try_handle_array_method<'ctx, 'b>(
|
||||
method: &str,
|
||||
args: &[ValueId],
|
||||
recv_h: inkwell::values::IntValue<'ctx>,
|
||||
bb_map: &std::collections::HashMap<crate::mir::BasicBlockId, inkwell::basic_block::BasicBlock<'ctx>>,
|
||||
preds: &std::collections::HashMap<crate::mir::BasicBlockId, Vec<crate::mir::BasicBlockId>>,
|
||||
block_end_values: &std::collections::HashMap<crate::mir::BasicBlockId, std::collections::HashMap<ValueId, inkwell::values::BasicValueEnum<'ctx>>>,
|
||||
) -> Result<bool, String> {
|
||||
// Only when receiver is ArrayBox
|
||||
let is_array = matches!(func.metadata.value_types.get(box_val), Some(crate::mir::MirType::Box(b)) if b == "ArrayBox")
|
||||
@ -34,12 +38,7 @@ pub(super) fn try_handle_array_method<'ctx, 'b>(
|
||||
if args.len() != 1 {
|
||||
return Err("ArrayBox.get expects 1 arg".to_string());
|
||||
}
|
||||
let idx_v = *vmap.get(&args[0]).ok_or("array.get index missing")?;
|
||||
let idx_i = if let BVE::IntValue(iv) = idx_v {
|
||||
iv
|
||||
} else {
|
||||
return Err("array.get index must be int".to_string());
|
||||
};
|
||||
let idx_i = resolver.resolve_i64(codegen, cursor, cur_bid, args[0], bb_map, preds, block_end_values, vmap)?;
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into()], false);
|
||||
let callee = codegen
|
||||
.module
|
||||
@ -64,18 +63,8 @@ pub(super) fn try_handle_array_method<'ctx, 'b>(
|
||||
if args.len() != 2 {
|
||||
return Err("ArrayBox.set expects 2 arg".to_string());
|
||||
}
|
||||
let idx_v = *vmap.get(&args[0]).ok_or("array.set index missing")?;
|
||||
let val_v = *vmap.get(&args[1]).ok_or("array.set value missing")?;
|
||||
let idx_i = if let BVE::IntValue(iv) = idx_v {
|
||||
iv
|
||||
} else {
|
||||
return Err("array.set index must be int".to_string());
|
||||
};
|
||||
let val_i = if let BVE::IntValue(iv) = val_v {
|
||||
iv
|
||||
} else {
|
||||
return Err("array.set value must be int".to_string());
|
||||
};
|
||||
let idx_i = resolver.resolve_i64(codegen, cursor, cur_bid, args[0], bb_map, preds, block_end_values, vmap)?;
|
||||
let val_i = resolver.resolve_i64(codegen, cursor, cur_bid, args[1], bb_map, preds, block_end_values, vmap)?;
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into(), i64t.into()], false);
|
||||
let callee = codegen
|
||||
.module
|
||||
@ -93,14 +82,7 @@ pub(super) fn try_handle_array_method<'ctx, 'b>(
|
||||
if args.len() != 1 {
|
||||
return Err("ArrayBox.push expects 1 arg".to_string());
|
||||
}
|
||||
let val_v = *vmap.get(&args[0]).ok_or("array.push value missing")?;
|
||||
let val_i = match val_v {
|
||||
BVE::IntValue(iv) => iv,
|
||||
BVE::PointerValue(pv) => cursor
|
||||
.emit_instr(cur_bid, |b| b.build_ptr_to_int(pv, i64t, "val_p2i"))
|
||||
.map_err(|e| e.to_string())?,
|
||||
_ => return Err("array.push value must be int or handle ptr".to_string()),
|
||||
};
|
||||
let val_i = resolver.resolve_i64(codegen, cursor, cur_bid, args[0], bb_map, preds, block_end_values, vmap)?;
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into()], false);
|
||||
let callee = codegen
|
||||
.module
|
||||
|
||||
@ -67,12 +67,12 @@ pub(in super::super) fn lower_boxcall<'ctx, 'b>(
|
||||
}
|
||||
|
||||
// Delegate Map methods first (to avoid Array fallback catching get/set ambiguously)
|
||||
if super::maps::try_handle_map_method(codegen, cursor, cur_bid, func, vmap, dst, box_val, method, args, recv_h)? {
|
||||
if super::maps::try_handle_map_method(codegen, cursor, resolver, cur_bid, func, vmap, dst, box_val, method, args, recv_h)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Delegate Array methods
|
||||
if super::arrays::try_handle_array_method(codegen, cursor, cur_bid, func, vmap, dst, box_val, method, args, recv_h)? {
|
||||
if super::arrays::try_handle_array_method(codegen, cursor, resolver, cur_bid, func, vmap, dst, box_val, method, args, recv_h, bb_map, preds, block_end_values)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ use crate::backend::llvm::compiler::codegen::instructions::builder_cursor::Build
|
||||
pub(in super::super) fn lower_call<'ctx, 'b>(
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
resolver: &mut super::Resolver<'ctx>,
|
||||
cur_bid: BasicBlockId,
|
||||
_func: &MirFunction,
|
||||
vmap: &mut HashMap<ValueId, BVE<'ctx>>,
|
||||
@ -22,6 +23,9 @@ pub(in super::super) fn lower_call<'ctx, 'b>(
|
||||
args: &[ValueId],
|
||||
const_strs: &HashMap<ValueId, String>,
|
||||
llvm_funcs: &HashMap<String, FunctionValue<'ctx>>,
|
||||
bb_map: &std::collections::HashMap<crate::mir::BasicBlockId, inkwell::basic_block::BasicBlock<'ctx>>,
|
||||
preds: &std::collections::HashMap<crate::mir::BasicBlockId, Vec<crate::mir::BasicBlockId>>,
|
||||
block_end_values: &std::collections::HashMap<crate::mir::BasicBlockId, std::collections::HashMap<ValueId, BVE<'ctx>>>,
|
||||
) -> Result<(), String> {
|
||||
let name_s = const_strs
|
||||
.get(callee)
|
||||
@ -43,11 +47,43 @@ pub(in super::super) fn lower_call<'ctx, 'b>(
|
||||
}
|
||||
let mut params: Vec<BasicMetadataValueEnum> = Vec::with_capacity(args.len());
|
||||
for (i, a) in args.iter().enumerate() {
|
||||
let v = *vmap
|
||||
.get(a)
|
||||
.ok_or_else(|| format!("call arg missing: {}", a.as_u32()))?;
|
||||
let tv = coerce_to_type_cursor(codegen, cursor, cur_bid, v, exp_tys[i])?;
|
||||
params.push(tv.into());
|
||||
use inkwell::types::BasicMetadataTypeEnum as BMTy;
|
||||
let coerced: BVE<'ctx> = match exp_tys[i] {
|
||||
BMTy::IntType(it) => {
|
||||
// Localize as i64, then adjust width to callee expectation
|
||||
let iv = resolver.resolve_i64(codegen, cursor, cur_bid, *a, bb_map, preds, block_end_values, vmap)?;
|
||||
let bw_dst = it.get_bit_width();
|
||||
let bw_src = iv.get_type().get_bit_width();
|
||||
if bw_src == bw_dst { iv.into() }
|
||||
else if bw_src < bw_dst { cursor.emit_instr(cur_bid, |b| b.build_int_z_extend(iv, it, "call_arg_zext")).map_err(|e| e.to_string())?.into() }
|
||||
else if bw_dst == 1 { super::super::types::to_bool(codegen.context, iv.into(), &codegen.builder)?.into() }
|
||||
else { cursor.emit_instr(cur_bid, |b| b.build_int_truncate(iv, it, "call_arg_trunc")).map_err(|e| e.to_string())?.into() }
|
||||
}
|
||||
BMTy::PointerType(pt) => {
|
||||
// Localize as i64 handle and convert to expected pointer type
|
||||
let iv = resolver.resolve_i64(codegen, cursor, cur_bid, *a, bb_map, preds, block_end_values, vmap)?;
|
||||
let p = cursor
|
||||
.emit_instr(cur_bid, |b| b.build_int_to_ptr(iv, pt, "call_arg_i2p"))
|
||||
.map_err(|e| e.to_string())?;
|
||||
p.into()
|
||||
}
|
||||
BMTy::FloatType(ft) => {
|
||||
// Localize as f64, then adjust to callee expectation width if needed
|
||||
let fv = resolver.resolve_f64(codegen, cursor, cur_bid, *a, bb_map, preds, block_end_values, vmap)?;
|
||||
if fv.get_type() == ft { fv.into() }
|
||||
else {
|
||||
// Cast f64<->f32 as needed
|
||||
cursor
|
||||
.emit_instr(cur_bid, |b| b.build_float_cast(fv, ft, "call_arg_fcast"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err("call: unsupported parameter type (expected int/ptr/float)".to_string());
|
||||
}
|
||||
};
|
||||
params.push(coerced.into());
|
||||
}
|
||||
let call = cursor
|
||||
.emit_instr(cur_bid, |b| b.build_call(*target, ¶ms, "call"))
|
||||
@ -59,53 +95,3 @@ pub(in super::super) fn lower_call<'ctx, 'b>(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn coerce_to_type_cursor<'ctx, 'b>(
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
cur_bid: BasicBlockId,
|
||||
val: BVE<'ctx>,
|
||||
target: BMT<'ctx>,
|
||||
) -> Result<BVE<'ctx>, String> {
|
||||
use inkwell::types::BasicMetadataTypeEnum as BMTy;
|
||||
match (val, target) {
|
||||
(BVE::IntValue(iv), BMTy::IntType(it)) => {
|
||||
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(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_int_z_extend(iv, it, "call_zext"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into())
|
||||
} else if bw_dst == 1 {
|
||||
Ok(super::super::types::to_bool(codegen.context, iv.into(), &codegen.builder)?.into())
|
||||
} else {
|
||||
Ok(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_int_truncate(iv, it, "call_trunc"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into())
|
||||
}
|
||||
}
|
||||
(BVE::PointerValue(pv), BMTy::IntType(it)) => Ok(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_ptr_to_int(pv, it, "call_p2i"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into()),
|
||||
(BVE::FloatValue(fv), BMTy::IntType(it)) => Ok(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_float_to_signed_int(fv, it, "call_f2i"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into()),
|
||||
(BVE::IntValue(iv), BMTy::PointerType(pt)) => Ok(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_int_to_ptr(iv, pt, "call_i2p"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into()),
|
||||
(BVE::PointerValue(pv), BMTy::PointerType(_)) => Ok(pv.into()),
|
||||
(BVE::IntValue(iv), BMTy::FloatType(ft)) => Ok(cursor
|
||||
.emit_instr(cur_bid, |b| b.build_signed_int_to_float(iv, ft, "call_i2f"))
|
||||
.map_err(|e| e.to_string())?
|
||||
.into()),
|
||||
(BVE::FloatValue(fv), BMTy::FloatType(_)) => Ok(fv.into()),
|
||||
(v, _) => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,17 +221,14 @@ pub(in super::super) fn seal_block<'ctx, 'b>(
|
||||
}
|
||||
};
|
||||
// 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);
|
||||
}
|
||||
cursor.with_block(bid, *pred_llbb, |c| {
|
||||
let term = unsafe { pred_llbb.get_terminator() };
|
||||
if let Some(t) = term { codegen.builder.position_before(&t); }
|
||||
else { c.position_at_end(*pred_llbb); }
|
||||
val = coerce_to_type(codegen, phi, val).expect("coerce_to_type in seal_block");
|
||||
});
|
||||
}
|
||||
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
|
||||
@ -341,14 +338,14 @@ pub(in super::super) fn finalize_phis<'ctx, 'b>(
|
||||
}
|
||||
};
|
||||
// Insert casts in pred block, just before its terminator
|
||||
let saved_block = codegen.builder.get_insert_block();
|
||||
if let Some(pred_llbb) = bb_map.get(pred) {
|
||||
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); }
|
||||
cursor.with_block(*pred, *pred_llbb, |c| {
|
||||
let term = unsafe { pred_llbb.get_terminator() };
|
||||
if let Some(t) = term { codegen.builder.position_before(&t); }
|
||||
else { c.position_at_end(*pred_llbb); }
|
||||
val = coerce_to_type(codegen, phi, val).expect("coerce_to_type finalize_phis");
|
||||
});
|
||||
}
|
||||
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(pred).ok_or("pred bb missing")?;
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
|
||||
@ -16,6 +16,7 @@ use super::super::types::to_bool;
|
||||
|
||||
/// LoopForm scaffolding — fixed block layout for while/loop normalization
|
||||
pub struct LoopFormContext<'ctx> {
|
||||
pub preheader: BasicBlock<'ctx>,
|
||||
pub header: BasicBlock<'ctx>,
|
||||
pub body: BasicBlock<'ctx>,
|
||||
pub dispatch: BasicBlock<'ctx>,
|
||||
@ -32,6 +33,9 @@ impl<'ctx> LoopFormContext<'ctx> {
|
||||
loop_id: u32,
|
||||
prefix: &str,
|
||||
) -> Self {
|
||||
let preheader = codegen
|
||||
.context
|
||||
.append_basic_block(function, &format!("{}_lf{}_preheader", prefix, loop_id));
|
||||
let header = codegen
|
||||
.context
|
||||
.append_basic_block(function, &format!("{}_lf{}_header", prefix, loop_id));
|
||||
@ -47,7 +51,7 @@ impl<'ctx> LoopFormContext<'ctx> {
|
||||
let exit = codegen
|
||||
.context
|
||||
.append_basic_block(function, &format!("{}_lf{}_exit", prefix, loop_id));
|
||||
Self { header, body, dispatch, latch, exit, loop_id }
|
||||
Self { preheader, header, body, dispatch, latch, exit, loop_id }
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,6 +82,13 @@ pub fn lower_while_loopform<'ctx, 'b>(
|
||||
|
||||
// Create LoopForm fixed blocks under the same function
|
||||
let lf = LoopFormContext::new(codegen, llvm_func, loop_id, prefix);
|
||||
// Preheader: currently a pass-through to header (Phase 1)
|
||||
codegen.builder.position_at_end(lf.preheader);
|
||||
codegen
|
||||
.builder
|
||||
.build_unconditional_branch(lf.header)
|
||||
.map_err(|e| e.to_string())
|
||||
.unwrap();
|
||||
|
||||
// Header: evaluate condition and branch to body (for true) or dispatch (for false)
|
||||
let cond_v = *vmap.get(condition).ok_or("loopform: condition value missing")?;
|
||||
|
||||
@ -10,6 +10,7 @@ use super::builder_cursor::BuilderCursor;
|
||||
pub(super) fn try_handle_map_method<'ctx, 'b>(
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
resolver: &mut super::Resolver<'ctx>,
|
||||
cur_bid: BasicBlockId,
|
||||
func: &MirFunction,
|
||||
vmap: &mut HashMap<ValueId, inkwell::values::BasicValueEnum<'ctx>>,
|
||||
@ -59,10 +60,7 @@ pub(super) fn try_handle_map_method<'ctx, 'b>(
|
||||
}
|
||||
let key_v = *vmap.get(&args[0]).ok_or("map.has key missing")?;
|
||||
let key_i = match key_v {
|
||||
BVE::IntValue(iv) => iv,
|
||||
BVE::PointerValue(pv) => cursor
|
||||
.emit_instr(cur_bid, |b| b.build_ptr_to_int(pv, i64t, "key_p2i"))
|
||||
.map_err(|e| e.to_string())?,
|
||||
BVE::IntValue(_) | BVE::PointerValue(_) => resolver.resolve_i64(codegen, cursor, cur_bid, args[0], &std::collections::HashMap::new(), &std::collections::HashMap::new(), &std::collections::HashMap::new(), vmap).map_err(|e| e.to_string())?,
|
||||
_ => return Err("map.has key must be int or handle ptr".to_string()),
|
||||
};
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into()], false);
|
||||
@ -91,7 +89,8 @@ pub(super) fn try_handle_map_method<'ctx, 'b>(
|
||||
}
|
||||
let key_v = *vmap.get(&args[0]).ok_or("map.get key missing")?;
|
||||
let call = match key_v {
|
||||
BVE::IntValue(iv) => {
|
||||
BVE::IntValue(_) => {
|
||||
let iv = resolver.resolve_i64(codegen, cursor, cur_bid, args[0], &std::collections::HashMap::new(), &std::collections::HashMap::new(), &std::collections::HashMap::new(), vmap)?;
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into()], false);
|
||||
let callee = codegen
|
||||
.module
|
||||
@ -147,17 +146,11 @@ pub(super) fn try_handle_map_method<'ctx, 'b>(
|
||||
let key_v = *vmap.get(&args[0]).ok_or("map.set key missing")?;
|
||||
let val_v = *vmap.get(&args[1]).ok_or("map.set value missing")?;
|
||||
let key_i = match key_v {
|
||||
BVE::IntValue(iv) => iv,
|
||||
BVE::PointerValue(pv) => cursor
|
||||
.emit_instr(cur_bid, |b| b.build_ptr_to_int(pv, i64t, "key_p2i"))
|
||||
.map_err(|e| e.to_string())?,
|
||||
BVE::IntValue(_) | BVE::PointerValue(_) => resolver.resolve_i64(codegen, cursor, cur_bid, args[0], &std::collections::HashMap::new(), &std::collections::HashMap::new(), &std::collections::HashMap::new(), vmap).map_err(|e| e.to_string())?,
|
||||
_ => return Err("map.set key must be int or handle ptr".to_string()),
|
||||
};
|
||||
let val_i = match val_v {
|
||||
BVE::IntValue(iv) => iv,
|
||||
BVE::PointerValue(pv) => cursor
|
||||
.emit_instr(cur_bid, |b| b.build_ptr_to_int(pv, i64t, "val_p2i"))
|
||||
.map_err(|e| e.to_string())?,
|
||||
BVE::IntValue(_) | BVE::PointerValue(_) => resolver.resolve_i64(codegen, cursor, cur_bid, args[1], &std::collections::HashMap::new(), &std::collections::HashMap::new(), &std::collections::HashMap::new(), vmap).map_err(|e| e.to_string())?,
|
||||
_ => return Err("map.set value must be int or handle ptr".to_string()),
|
||||
};
|
||||
let fnty = i64t.fn_type(&[i64t.into(), i64t.into(), i64t.into()], false);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use inkwell::values::{BasicValueEnum as BVE, IntValue};
|
||||
use inkwell::values::PointerValue;
|
||||
|
||||
use crate::backend::llvm::context::CodegenContext;
|
||||
use crate::mir::{BasicBlockId, ValueId};
|
||||
@ -12,11 +13,13 @@ use super::flow::localize_to_i64;
|
||||
/// redundant PHIs and casts when multiple users in the same block request the same MIR value.
|
||||
pub struct Resolver<'ctx> {
|
||||
i64_locals: HashMap<(BasicBlockId, ValueId), IntValue<'ctx>>,
|
||||
ptr_locals: HashMap<(BasicBlockId, ValueId), PointerValue<'ctx>>,
|
||||
f64_locals: HashMap<(BasicBlockId, ValueId), inkwell::values::FloatValue<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> Resolver<'ctx> {
|
||||
pub fn new() -> Self {
|
||||
Self { i64_locals: HashMap::new() }
|
||||
Self { i64_locals: HashMap::new(), ptr_locals: HashMap::new(), f64_locals: HashMap::new() }
|
||||
}
|
||||
|
||||
/// Resolve a MIR value as an i64 dominating the current block.
|
||||
@ -39,5 +42,112 @@ impl<'ctx> Resolver<'ctx> {
|
||||
self.i64_locals.insert((cur_bid, vid), iv);
|
||||
Ok(iv)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a MIR value as an i8* pointer dominating the current block.
|
||||
pub fn resolve_ptr<'b>(
|
||||
&mut self,
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
cur_bid: BasicBlockId,
|
||||
vid: ValueId,
|
||||
bb_map: &std::collections::HashMap<BasicBlockId, inkwell::basic_block::BasicBlock<'ctx>>,
|
||||
preds: &std::collections::HashMap<BasicBlockId, Vec<BasicBlockId>>,
|
||||
block_end_values: &std::collections::HashMap<BasicBlockId, std::collections::HashMap<ValueId, BVE<'ctx>>>,
|
||||
vmap: &std::collections::HashMap<ValueId, BVE<'ctx>>,
|
||||
) -> Result<PointerValue<'ctx>, String> {
|
||||
if let Some(pv) = self.ptr_locals.get(&(cur_bid, vid)).copied() {
|
||||
return Ok(pv);
|
||||
}
|
||||
let i8p = codegen.context.ptr_type(inkwell::AddressSpace::from(0));
|
||||
let cur_llbb = *bb_map.get(&cur_bid).ok_or("cur bb missing")?;
|
||||
let pred_list = preds.get(&cur_bid).cloned().unwrap_or_default();
|
||||
// Insert PHI at block start
|
||||
let saved_ip = codegen.builder.get_insert_block();
|
||||
if let Some(first) = cur_llbb.get_first_instruction() { codegen.builder.position_before(&first); }
|
||||
else { codegen.builder.position_at_end(cur_llbb); }
|
||||
let phi = codegen.builder.build_phi(i8p, &format!("loc_p_{}", vid.as_u32())).map_err(|e| e.to_string())?;
|
||||
if pred_list.is_empty() {
|
||||
// Entry-like block: derive from vmap or zero
|
||||
let base = vmap.get(&vid).copied().unwrap_or_else(|| i8p.const_zero().into());
|
||||
let coerced = match base {
|
||||
BVE::PointerValue(pv) => pv,
|
||||
BVE::IntValue(iv) => cursor.emit_instr(cur_bid, |b| b.build_int_to_ptr(iv, i8p, "loc_i2p")).map_err(|e| e.to_string())?,
|
||||
BVE::FloatValue(_) => i8p.const_zero(),
|
||||
_ => i8p.const_zero(),
|
||||
};
|
||||
phi.add_incoming(&[(&coerced, cur_llbb)]);
|
||||
} else {
|
||||
for p in &pred_list {
|
||||
let pred_bb = *bb_map.get(p).ok_or("pred bb missing")?;
|
||||
let base = block_end_values
|
||||
.get(p)
|
||||
.and_then(|m| m.get(&vid).copied())
|
||||
.unwrap_or_else(|| i8p.const_zero().into());
|
||||
let coerced = match base {
|
||||
BVE::PointerValue(pv) => pv,
|
||||
BVE::IntValue(iv) => codegen.builder.build_int_to_ptr(iv, i8p, "loc_i2p_p").map_err(|e| e.to_string())?,
|
||||
BVE::FloatValue(_) => i8p.const_zero(),
|
||||
_ => i8p.const_zero(),
|
||||
};
|
||||
phi.add_incoming(&[(&coerced, pred_bb)]);
|
||||
}
|
||||
}
|
||||
if let Some(bb) = saved_ip { codegen.builder.position_at_end(bb); }
|
||||
let out = phi.as_basic_value().into_pointer_value();
|
||||
self.ptr_locals.insert((cur_bid, vid), out);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Resolve a MIR value as an f64 dominating the current block.
|
||||
pub fn resolve_f64<'b>(
|
||||
&mut self,
|
||||
codegen: &CodegenContext<'ctx>,
|
||||
cursor: &mut BuilderCursor<'ctx, 'b>,
|
||||
cur_bid: BasicBlockId,
|
||||
vid: ValueId,
|
||||
bb_map: &std::collections::HashMap<BasicBlockId, inkwell::basic_block::BasicBlock<'ctx>>,
|
||||
preds: &std::collections::HashMap<BasicBlockId, Vec<BasicBlockId>>,
|
||||
block_end_values: &std::collections::HashMap<BasicBlockId, std::collections::HashMap<ValueId, BVE<'ctx>>>,
|
||||
vmap: &std::collections::HashMap<ValueId, BVE<'ctx>>,
|
||||
) -> Result<inkwell::values::FloatValue<'ctx>, String> {
|
||||
if let Some(fv) = self.f64_locals.get(&(cur_bid, vid)).copied() {
|
||||
return Ok(fv);
|
||||
}
|
||||
let f64t = codegen.context.f64_type();
|
||||
let cur_llbb = *bb_map.get(&cur_bid).ok_or("cur bb missing")?;
|
||||
let pred_list = preds.get(&cur_bid).cloned().unwrap_or_default();
|
||||
let saved_ip = codegen.builder.get_insert_block();
|
||||
if let Some(first) = cur_llbb.get_first_instruction() { codegen.builder.position_before(&first); }
|
||||
else { codegen.builder.position_at_end(cur_llbb); }
|
||||
let phi = codegen.builder.build_phi(f64t, &format!("loc_f64_{}", vid.as_u32())).map_err(|e| e.to_string())?;
|
||||
if pred_list.is_empty() {
|
||||
let base = vmap.get(&vid).copied().unwrap_or_else(|| f64t.const_zero().into());
|
||||
let coerced = match base {
|
||||
BVE::FloatValue(fv) => fv,
|
||||
BVE::IntValue(iv) => codegen.builder.build_signed_int_to_float(iv, f64t, "loc_i2f").map_err(|e| e.to_string())?,
|
||||
BVE::PointerValue(_) => f64t.const_zero(),
|
||||
_ => f64t.const_zero(),
|
||||
};
|
||||
phi.add_incoming(&[(&coerced, cur_llbb)]);
|
||||
} else {
|
||||
for p in &pred_list {
|
||||
let pred_bb = *bb_map.get(p).ok_or("pred bb missing")?;
|
||||
let base = block_end_values
|
||||
.get(p)
|
||||
.and_then(|m| m.get(&vid).copied())
|
||||
.unwrap_or_else(|| f64t.const_zero().into());
|
||||
let coerced = match base {
|
||||
BVE::FloatValue(fv) => fv,
|
||||
BVE::IntValue(iv) => codegen.builder.build_signed_int_to_float(iv, f64t, "loc_i2f_p").map_err(|e| e.to_string())?,
|
||||
BVE::PointerValue(_) => f64t.const_zero(),
|
||||
_ => f64t.const_zero(),
|
||||
};
|
||||
phi.add_incoming(&[(&coerced, pred_bb)]);
|
||||
}
|
||||
}
|
||||
if let Some(bb) = saved_ip { codegen.builder.position_at_end(bb); }
|
||||
let out = phi.as_basic_value().into_float_value();
|
||||
self.f64_locals.insert((cur_bid, vid), out);
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user