2025-09-11 23:58:10 +09:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
use inkwell::values::BasicValueEnum;
|
|
|
|
|
|
2025-09-17 02:50:39 +09:00
|
|
|
use super::builder_cursor::BuilderCursor;
|
2025-09-11 23:58:10 +09:00
|
|
|
use crate::backend::llvm::context::CodegenContext;
|
2025-09-12 19:23:16 +09:00
|
|
|
use crate::mir::{BasicBlockId, ValueId};
|
2025-09-11 23:58:10 +09:00
|
|
|
|
|
|
|
|
// Lower Store: handle allocas with element type tracking and integer width adjust
|
2025-09-12 19:23:16 +09:00
|
|
|
pub(in super::super) fn lower_store<'ctx, 'b>(
|
2025-09-11 23:58:10 +09:00
|
|
|
codegen: &CodegenContext<'ctx>,
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
2025-09-12 20:40:48 +09:00
|
|
|
resolver: &mut super::Resolver<'ctx>,
|
2025-09-12 19:23:16 +09:00
|
|
|
cur_bid: BasicBlockId,
|
2025-09-11 23:58:10 +09:00
|
|
|
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
allocas: &mut HashMap<ValueId, inkwell::values::PointerValue<'ctx>>,
|
|
|
|
|
alloca_elem_types: &mut HashMap<ValueId, inkwell::types::BasicTypeEnum<'ctx>>,
|
|
|
|
|
value: &ValueId,
|
|
|
|
|
ptr: &ValueId,
|
2025-09-17 02:50:39 +09:00
|
|
|
bb_map: &std::collections::HashMap<
|
|
|
|
|
crate::mir::BasicBlockId,
|
|
|
|
|
inkwell::basic_block::BasicBlock<'ctx>,
|
|
|
|
|
>,
|
2025-09-12 20:40:48 +09:00
|
|
|
preds: &std::collections::HashMap<crate::mir::BasicBlockId, Vec<crate::mir::BasicBlockId>>,
|
2025-09-17 02:50:39 +09:00
|
|
|
block_end_values: &std::collections::HashMap<
|
|
|
|
|
crate::mir::BasicBlockId,
|
|
|
|
|
std::collections::HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
>,
|
2025-09-11 23:58:10 +09:00
|
|
|
) -> Result<(), String> {
|
|
|
|
|
use inkwell::types::BasicTypeEnum;
|
2025-09-12 20:40:48 +09:00
|
|
|
// Resolve value preferring native kind; try i64, then f64, else pointer
|
|
|
|
|
let i64t = codegen.context.i64_type();
|
2025-09-17 02:50:39 +09:00
|
|
|
let val: BasicValueEnum = if let Ok(iv) = resolver.resolve_i64(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*value,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
) {
|
2025-09-12 20:40:48 +09:00
|
|
|
iv.into()
|
2025-09-17 02:50:39 +09:00
|
|
|
} else if let Ok(fv) = resolver.resolve_f64(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*value,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
) {
|
2025-09-12 20:40:48 +09:00
|
|
|
fv.into()
|
2025-09-17 02:50:39 +09:00
|
|
|
} else if let Ok(pv) = resolver.resolve_ptr(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*value,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
) {
|
2025-09-12 20:40:48 +09:00
|
|
|
pv.into()
|
|
|
|
|
} else {
|
|
|
|
|
// Fallback: zero i64
|
|
|
|
|
i64t.const_zero().into()
|
|
|
|
|
};
|
2025-09-11 23:58:10 +09:00
|
|
|
let elem_ty = match val {
|
|
|
|
|
BasicValueEnum::IntValue(iv) => BasicTypeEnum::IntType(iv.get_type()),
|
|
|
|
|
BasicValueEnum::FloatValue(fv) => BasicTypeEnum::FloatType(fv.get_type()),
|
|
|
|
|
BasicValueEnum::PointerValue(pv) => BasicTypeEnum::PointerType(pv.get_type()),
|
|
|
|
|
_ => return Err("unsupported store value type".to_string()),
|
|
|
|
|
};
|
|
|
|
|
if let Some(existing) = allocas.get(ptr).copied() {
|
2025-09-17 02:50:39 +09:00
|
|
|
let existing_elem = *alloca_elem_types
|
|
|
|
|
.get(ptr)
|
|
|
|
|
.ok_or("alloca elem type missing")?;
|
2025-09-11 23:58:10 +09:00
|
|
|
if existing_elem != elem_ty {
|
|
|
|
|
match (val, existing_elem) {
|
|
|
|
|
(BasicValueEnum::IntValue(iv), BasicTypeEnum::IntType(t)) => {
|
|
|
|
|
let bw_src = iv.get_type().get_bit_width();
|
|
|
|
|
let bw_dst = t.get_bit_width();
|
|
|
|
|
if bw_src < bw_dst {
|
2025-09-12 19:23:16 +09:00
|
|
|
let adj = cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_int_z_extend(iv, t, "zext"))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, adj))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
} else if bw_src > bw_dst {
|
2025-09-12 19:23:16 +09:00
|
|
|
let adj = cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_int_truncate(iv, t, "trunc"))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, adj))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
} else {
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, iv))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(BasicValueEnum::PointerValue(pv), BasicTypeEnum::PointerType(pt)) => {
|
2025-09-12 19:23:16 +09:00
|
|
|
let adj = cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_pointer_cast(pv, pt, "pcast"))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, adj))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
}
|
|
|
|
|
(BasicValueEnum::FloatValue(fv), BasicTypeEnum::FloatType(ft)) => {
|
|
|
|
|
// Only f64 currently expected
|
|
|
|
|
if fv.get_type() != ft {
|
|
|
|
|
return Err("float width mismatch in store".to_string());
|
|
|
|
|
}
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, fv))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
}
|
|
|
|
|
_ => return Err("store type mismatch".to_string()),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(existing, val))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-09-12 19:23:16 +09:00
|
|
|
let slot = cursor
|
2025-09-17 02:50:39 +09:00
|
|
|
.emit_instr(cur_bid, |b| {
|
|
|
|
|
b.build_alloca(elem_ty, &format!("slot_{}", ptr.as_u32()))
|
|
|
|
|
})
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor
|
|
|
|
|
.emit_instr(cur_bid, |b| b.build_store(slot, val))
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
allocas.insert(*ptr, slot);
|
|
|
|
|
alloca_elem_types.insert(*ptr, elem_ty);
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-12 19:23:16 +09:00
|
|
|
pub(in super::super) fn lower_load<'ctx, 'b>(
|
2025-09-11 23:58:10 +09:00
|
|
|
codegen: &CodegenContext<'ctx>,
|
2025-09-12 19:23:16 +09:00
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
|
|
|
|
cur_bid: BasicBlockId,
|
2025-09-11 23:58:10 +09:00
|
|
|
vmap: &mut HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
allocas: &mut HashMap<ValueId, inkwell::values::PointerValue<'ctx>>,
|
|
|
|
|
alloca_elem_types: &mut HashMap<ValueId, inkwell::types::BasicTypeEnum<'ctx>>,
|
|
|
|
|
dst: &ValueId,
|
|
|
|
|
ptr: &ValueId,
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
use inkwell::types::BasicTypeEnum;
|
|
|
|
|
let (slot, elem_ty) = if let Some(s) = allocas.get(ptr).copied() {
|
2025-09-17 02:50:39 +09:00
|
|
|
let et = *alloca_elem_types
|
|
|
|
|
.get(ptr)
|
|
|
|
|
.ok_or("alloca elem type missing")?;
|
2025-09-11 23:58:10 +09:00
|
|
|
(s, et)
|
|
|
|
|
} else {
|
|
|
|
|
// Default new slot as i64 for uninitialized loads
|
|
|
|
|
let i64t = codegen.context.i64_type();
|
2025-09-12 19:23:16 +09:00
|
|
|
let slot = cursor
|
2025-09-17 02:50:39 +09:00
|
|
|
.emit_instr(cur_bid, |b| {
|
|
|
|
|
b.build_alloca(i64t, &format!("slot_{}", ptr.as_u32()))
|
|
|
|
|
})
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
allocas.insert(*ptr, slot);
|
|
|
|
|
alloca_elem_types.insert(*ptr, i64t.into());
|
|
|
|
|
(slot, i64t.into())
|
|
|
|
|
};
|
2025-09-12 19:23:16 +09:00
|
|
|
let lv = cursor
|
2025-09-17 02:50:39 +09:00
|
|
|
.emit_instr(cur_bid, |b| {
|
|
|
|
|
b.build_load(elem_ty, slot, &format!("load_{}", dst.as_u32()))
|
|
|
|
|
})
|
2025-09-11 23:58:10 +09:00
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
vmap.insert(*dst, lv);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
|
|
|
// Lower Copy: define dst in the current block by localizing src via Resolver
|
|
|
|
|
pub(in super::super) fn lower_copy<'ctx, 'b>(
|
|
|
|
|
codegen: &CodegenContext<'ctx>,
|
|
|
|
|
cursor: &mut BuilderCursor<'ctx, 'b>,
|
|
|
|
|
resolver: &mut super::Resolver<'ctx>,
|
|
|
|
|
cur_bid: BasicBlockId,
|
|
|
|
|
func: &crate::mir::function::MirFunction,
|
|
|
|
|
vmap: &mut HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
dst: &ValueId,
|
|
|
|
|
src: &ValueId,
|
2025-09-17 02:50:39 +09:00
|
|
|
bb_map: &std::collections::HashMap<
|
|
|
|
|
crate::mir::BasicBlockId,
|
|
|
|
|
inkwell::basic_block::BasicBlock<'ctx>,
|
|
|
|
|
>,
|
2025-09-16 23:49:36 +09:00
|
|
|
preds: &std::collections::HashMap<crate::mir::BasicBlockId, Vec<crate::mir::BasicBlockId>>,
|
2025-09-17 02:50:39 +09:00
|
|
|
block_end_values: &std::collections::HashMap<
|
|
|
|
|
crate::mir::BasicBlockId,
|
|
|
|
|
std::collections::HashMap<ValueId, BasicValueEnum<'ctx>>,
|
|
|
|
|
>,
|
2025-09-16 23:49:36 +09:00
|
|
|
) -> Result<(), String> {
|
|
|
|
|
// Choose resolution kind based on metadata type preference
|
|
|
|
|
use inkwell::types::BasicTypeEnum as BT;
|
|
|
|
|
let expected_bt: Option<BT> = func
|
|
|
|
|
.metadata
|
|
|
|
|
.value_types
|
|
|
|
|
.get(dst)
|
|
|
|
|
.or_else(|| func.metadata.value_types.get(src))
|
|
|
|
|
.map(|mt| super::super::types::map_mirtype_to_basic(codegen.context, mt));
|
|
|
|
|
let out: BasicValueEnum<'ctx> = match expected_bt {
|
|
|
|
|
Some(BT::IntType(_)) | None => {
|
|
|
|
|
// Prefer i64 for unknown
|
2025-09-17 02:50:39 +09:00
|
|
|
let iv = resolver.resolve_i64(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*src,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
)?;
|
2025-09-16 23:49:36 +09:00
|
|
|
iv.into()
|
|
|
|
|
}
|
|
|
|
|
Some(BT::PointerType(_)) => {
|
2025-09-17 02:50:39 +09:00
|
|
|
let pv = resolver.resolve_ptr(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*src,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
)?;
|
2025-09-16 23:49:36 +09:00
|
|
|
pv.into()
|
|
|
|
|
}
|
|
|
|
|
Some(BT::FloatType(_)) => {
|
2025-09-17 02:50:39 +09:00
|
|
|
let fv = resolver.resolve_f64(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*src,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
)?;
|
2025-09-16 23:49:36 +09:00
|
|
|
fv.into()
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
// Fallback i64
|
2025-09-17 02:50:39 +09:00
|
|
|
let iv = resolver.resolve_i64(
|
|
|
|
|
codegen,
|
|
|
|
|
cursor,
|
|
|
|
|
cur_bid,
|
|
|
|
|
*src,
|
|
|
|
|
bb_map,
|
|
|
|
|
preds,
|
|
|
|
|
block_end_values,
|
|
|
|
|
vmap,
|
|
|
|
|
)?;
|
2025-09-16 23:49:36 +09:00
|
|
|
iv.into()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
vmap.insert(*dst, out);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|