126 lines
4.6 KiB
Rust
126 lines
4.6 KiB
Rust
|
|
use super::sanitize_symbol;
|
||
|
|
use crate::backend::llvm::context::CodegenContext;
|
||
|
|
use inkwell::values::BasicValueEnum;
|
||
|
|
|
||
|
|
pub(super) fn emit_wrapper_and_object<'ctx>(
|
||
|
|
codegen: &CodegenContext<'ctx>,
|
||
|
|
entry_name: &str,
|
||
|
|
output_path: &str,
|
||
|
|
) -> Result<(), String> {
|
||
|
|
let i64t = codegen.context.i64_type();
|
||
|
|
let ny_main_ty = i64t.fn_type(&[], false);
|
||
|
|
let ny_main = codegen.module.add_function("ny_main", ny_main_ty, None);
|
||
|
|
let entry_bb = codegen.context.append_basic_block(ny_main, "entry");
|
||
|
|
codegen.builder.position_at_end(entry_bb);
|
||
|
|
let entry_sym = format!("ny_f_{}", sanitize_symbol(entry_name));
|
||
|
|
let entry_fn = codegen
|
||
|
|
.module
|
||
|
|
.get_function(&entry_sym)
|
||
|
|
.ok_or_else(|| format!("entry function symbol not found: {}", entry_sym))?;
|
||
|
|
let call = codegen
|
||
|
|
.builder
|
||
|
|
.build_call(entry_fn, &[], "call_main")
|
||
|
|
.map_err(|e| e.to_string())?;
|
||
|
|
let rv = call.try_as_basic_value().left();
|
||
|
|
let ret_v = if let Some(v) = rv {
|
||
|
|
match v {
|
||
|
|
BasicValueEnum::IntValue(iv) => {
|
||
|
|
if iv.get_type().get_bit_width() == 64 {
|
||
|
|
iv
|
||
|
|
} else {
|
||
|
|
codegen
|
||
|
|
.builder
|
||
|
|
.build_int_z_extend(iv, i64t, "ret_zext")
|
||
|
|
.map_err(|e| e.to_string())?
|
||
|
|
}
|
||
|
|
}
|
||
|
|
BasicValueEnum::PointerValue(pv) => codegen
|
||
|
|
.builder
|
||
|
|
.build_ptr_to_int(pv, i64t, "ret_p2i")
|
||
|
|
.map_err(|e| e.to_string())?,
|
||
|
|
BasicValueEnum::FloatValue(fv) => codegen
|
||
|
|
.builder
|
||
|
|
.build_float_to_signed_int(fv, i64t, "ret_f2i")
|
||
|
|
.map_err(|e| e.to_string())?,
|
||
|
|
_ => i64t.const_zero(),
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
i64t.const_zero()
|
||
|
|
};
|
||
|
|
codegen
|
||
|
|
.builder
|
||
|
|
.build_return(Some(&ret_v))
|
||
|
|
.map_err(|e| e.to_string())?;
|
||
|
|
if !ny_main.verify(true) {
|
||
|
|
return Err("ny_main verification failed".to_string());
|
||
|
|
}
|
||
|
|
let verbose = std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1");
|
||
|
|
if verbose {
|
||
|
|
eprintln!("[LLVM] emitting object to {} (begin)", output_path);
|
||
|
|
}
|
||
|
|
match codegen.target_machine.write_to_file(
|
||
|
|
&codegen.module,
|
||
|
|
inkwell::targets::FileType::Object,
|
||
|
|
std::path::Path::new(output_path),
|
||
|
|
) {
|
||
|
|
Ok(_) => {
|
||
|
|
if std::fs::metadata(output_path).is_err() {
|
||
|
|
let buf = codegen
|
||
|
|
.target_machine
|
||
|
|
.write_to_memory_buffer(&codegen.module, inkwell::targets::FileType::Object)
|
||
|
|
.map_err(|e| format!("Failed to get object buffer: {}", e))?;
|
||
|
|
std::fs::write(output_path, buf.as_slice())
|
||
|
|
.map_err(|e| format!("Failed to write object to '{}': {}", output_path, e))?;
|
||
|
|
if verbose {
|
||
|
|
eprintln!(
|
||
|
|
"[LLVM] wrote object via memory buffer fallback: {} ({} bytes)",
|
||
|
|
output_path,
|
||
|
|
buf.get_size()
|
||
|
|
);
|
||
|
|
}
|
||
|
|
} else if verbose {
|
||
|
|
if let Ok(meta) = std::fs::metadata(output_path) {
|
||
|
|
eprintln!(
|
||
|
|
"[LLVM] wrote object via file API: {} ({} bytes)",
|
||
|
|
output_path,
|
||
|
|
meta.len()
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if verbose {
|
||
|
|
eprintln!("[LLVM] emit complete (Ok branch) for {}", output_path);
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
Err(e) => {
|
||
|
|
let buf = codegen
|
||
|
|
.target_machine
|
||
|
|
.write_to_memory_buffer(&codegen.module, inkwell::targets::FileType::Object)
|
||
|
|
.map_err(|ee| {
|
||
|
|
format!(
|
||
|
|
"Failed to write object ({}); and memory buffer failed: {}",
|
||
|
|
e, ee
|
||
|
|
)
|
||
|
|
})?;
|
||
|
|
std::fs::write(output_path, buf.as_slice()).map_err(|ee| {
|
||
|
|
format!(
|
||
|
|
"Failed to write object to '{}': {} (original error: {})",
|
||
|
|
output_path, ee, e
|
||
|
|
)
|
||
|
|
})?;
|
||
|
|
if verbose {
|
||
|
|
eprintln!(
|
||
|
|
"[LLVM] wrote object via error fallback: {} ({} bytes)",
|
||
|
|
output_path,
|
||
|
|
buf.get_size()
|
||
|
|
);
|
||
|
|
eprintln!(
|
||
|
|
"[LLVM] emit complete (Err branch handled) for {}",
|
||
|
|
output_path
|
||
|
|
);
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|