feat(llvm): Complete function call system implementation by ChatGPT5

Major improvements to LLVM backend function call infrastructure:

## Key Changes

### Function Call System Complete
- All MIR functions now properly lowered to LLVM (not just entry)
- Function parameter binding to LLVM arguments implemented
- ny_main() wrapper added for proper entry point handling
- Callee resolution from ValueId to function symbols working

### Call Instruction Analysis
- MirInstruction::Call was implemented but system was incomplete
- Fixed "rhs missing" errors caused by undefined Call return values
- Function calls now properly return values through the system

### Code Modularization (Ongoing)
- BoxCall → instructions/boxcall.rs ✓
- ExternCall → instructions/externcall.rs ✓
- Call remains in mod.rs (to be refactored)

### Phase 21 Documentation
- Added comprehensive AI evaluation from Gemini and Codex
- Both AIs confirm academic paper potential for self-parsing AST DB approach
- "Code as Database" concept validated as novel contribution

Co-authored-by: ChatGPT5 <noreply@openai.com>

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-12 01:45:00 +09:00
parent 4f4c6397a9
commit 40d0cac0f1
17 changed files with 2219 additions and 608 deletions

View File

@ -3,19 +3,92 @@ use std::collections::HashMap;
use inkwell::values::BasicValueEnum;
use crate::backend::llvm::context::CodegenContext;
use crate::mir::{CompareOp, ValueId};
use crate::mir::{function::MirFunction, CompareOp, ValueId};
/// Compare lowering: return the resulting BasicValueEnum (i1)
pub(in super::super) fn lower_compare<'ctx>(
codegen: &CodegenContext<'ctx>,
func: &MirFunction,
vmap: &HashMap<ValueId, BasicValueEnum<'ctx>>,
op: &CompareOp,
lhs: &ValueId,
rhs: &ValueId,
) -> Result<BasicValueEnum<'ctx>, String> {
use crate::backend::llvm::compiler::helpers::{as_float, as_int};
let lv = *vmap.get(lhs).ok_or("lhs missing")?;
let rv = *vmap.get(rhs).ok_or("rhs missing")?;
let lv = *vmap
.get(lhs)
.ok_or_else(|| format!("lhs missing: {}", lhs.as_u32()))?;
let rv = *vmap
.get(rhs)
.ok_or_else(|| format!("rhs missing: {}", rhs.as_u32()))?;
// String equality/inequality by content when annotated as String/StringBox
if matches!(op, CompareOp::Eq | CompareOp::Ne) {
let l_is_str = match func.metadata.value_types.get(lhs) {
Some(crate::mir::MirType::String) => true,
Some(crate::mir::MirType::Box(b)) if b == "StringBox" => true,
_ => false,
};
let r_is_str = match func.metadata.value_types.get(rhs) {
Some(crate::mir::MirType::String) => true,
Some(crate::mir::MirType::Box(b)) if b == "StringBox" => true,
_ => false,
};
if l_is_str && r_is_str {
let i64t = codegen.context.i64_type();
// Convert both sides to handles if needed
let to_handle = |v: BasicValueEnum<'ctx>| -> Result<inkwell::values::IntValue<'ctx>, String> {
match v {
BasicValueEnum::IntValue(iv) => {
if iv.get_type() == i64t { Ok(iv) } else { codegen.builder.build_int_s_extend(iv, i64t, "i2i64").map_err(|e| e.to_string()) }
}
BasicValueEnum::PointerValue(pv) => {
let fnty = i64t.fn_type(&[codegen.context.ptr_type(inkwell::AddressSpace::from(0)).into()], false);
let callee = codegen
.module
.get_function("nyash.box.from_i8_string")
.unwrap_or_else(|| codegen.module.add_function("nyash.box.from_i8_string", fnty, None));
let call = codegen
.builder
.build_call(callee, &[pv.into()], "str_ptr_to_handle_cmp")
.map_err(|e| e.to_string())?;
let rv = call
.try_as_basic_value()
.left()
.ok_or("from_i8_string returned void".to_string())?;
Ok(rv.into_int_value())
}
_ => Err("unsupported value for string compare".to_string()),
}
};
let lh = to_handle(lv)?;
let rh = to_handle(rv)?;
let fnty = i64t.fn_type(&[i64t.into(), i64t.into()], false);
let callee = codegen
.module
.get_function("nyash.string.eq_hh")
.unwrap_or_else(|| codegen.module.add_function("nyash.string.eq_hh", fnty, None));
let call = codegen
.builder
.build_call(callee, &[lh.into(), rh.into()], "str_eq_hh")
.map_err(|e| e.to_string())?;
let iv = call
.try_as_basic_value()
.left()
.ok_or("eq_hh returned void".to_string())?
.into_int_value();
let zero = i64t.const_zero();
let pred = if matches!(op, CompareOp::Eq) {
inkwell::IntPredicate::NE
} else {
inkwell::IntPredicate::EQ
};
let b = codegen
.builder
.build_int_compare(pred, iv, zero, "str_eq_to_bool")
.map_err(|e| e.to_string())?;
return Ok(b.into());
}
}
let out = if let (Some(li), Some(ri)) = (as_int(lv), as_int(rv)) {
use CompareOp as C;
let pred = match op {