diff --git a/cli/src/pipeline.rs b/cli/src/pipeline.rs index c81434fc..286fb79a 100644 --- a/cli/src/pipeline.rs +++ b/cli/src/pipeline.rs @@ -37,12 +37,8 @@ pub enum ExecutionBackend { /// Helper to resolve target triple. pub fn get_host_target_triple() -> String { #[cfg(feature = "llvm")] - unsafe { - let raw = llvm_sys::target_machine::LLVMGetDefaultTargetTriple(); - let cstr = std::ffi::CStr::from_ptr(raw); - let s = cstr.to_string_lossy().into_owned(); - llvm_sys::core::LLVMDisposeMessage(raw); - s + { + techscript_llvm_backend::get_host_target_triple() } #[cfg(not(feature = "llvm"))] { diff --git a/compiler/llvm_backend/src/codegen.rs b/compiler/llvm_backend/src/codegen.rs index 5c0ed8ab..769ce51e 100644 --- a/compiler/llvm_backend/src/codegen.rs +++ b/compiler/llvm_backend/src/codegen.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use std::ffi::CString; use techscript_ast::LiteralVal; use techscript_ir::types::{BlockId, GlobalId, IRType, ValueId}; -use techscript_ir::{BasicBlock, Function, Instruction, Module, Op, TerminatorKind, Value}; +use techscript_ir::{Function, Instruction, Module, Op, TerminatorKind, Value}; use techscript_syntax::TokenKind; use crate::context::CodegenContext; @@ -44,7 +44,7 @@ impl<'a> CodegenEngine<'a> { llvm_ty, CString::new(name.as_str()).unwrap().as_ptr(), ); - self.ctx.register_value(*global_id, global_var); + self.ctx.register_global(*global_id, global_var); self.global_names.insert(*global_id, name.clone()); } @@ -95,7 +95,7 @@ impl<'a> CodegenEngine<'a> { // Register function parameter variables for (idx, &(local_id, _, _)) in func.params.iter().enumerate() { let param_val = LLVMGetParam(llvm_func, idx as u32); - self.ctx.register_value(local_id, param_val); + self.ctx.register_local(local_id, param_val); } // Allocate basic blocks @@ -124,6 +124,10 @@ impl<'a> CodegenEngine<'a> { let dest_block = self.ctx.get_block(*dest).unwrap(); LLVMBuildBr(self.ctx.builder, dest_block); } + TerminatorKind::Throw(_) => { + // TODO: Implement exception handling or unwind + LLVMBuildUnreachable(self.ctx.builder); + } TerminatorKind::ConditionalJump { cond, then_block, @@ -695,14 +699,17 @@ impl<'a> CodegenEngine<'a> { // Handle direct calls to global/user/standard functions let mut resolved_func = None; if let Value::Global(global_id) = callee { - if let Some(global_name) = self.global_names.get(global_id) { - resolved_func = self.resolve_function_by_name(global_name); + let name = self.global_names.get(global_id).cloned(); + if let Some(n) = name { + resolved_func = self.resolve_function_by_name(&n); } } else if let Value::Temp(temp_id) = callee { + let mut name = None; if let Some(global_id) = self.temp_to_global.get(temp_id) { - if let Some(global_name) = self.global_names.get(global_id) { - resolved_func = self.resolve_function_by_name(global_name); - } + name = self.global_names.get(global_id).cloned(); + } + if let Some(n) = name { + resolved_func = self.resolve_function_by_name(&n); } } @@ -1030,6 +1037,7 @@ impl<'a> CodegenEngine<'a> { map_val } Op::Cast { value, target_type } => { + let _double_ty = double_ty; // avoid unused warning let val_val = self.codegen_val(value)?; let boxed_val = self.box_val(val_val)?; let tag = match target_type { @@ -1050,7 +1058,7 @@ impl<'a> CodegenEngine<'a> { CString::new("cast").unwrap().as_ptr(), ) } - Op::NoOp => return Ok(()), + Op::Try { .. } | Op::EndTry | Op::MakeDslBlock { .. } | Op::NoOp => return Ok(()), }; if let Some(res_id) = inst.result { @@ -1068,14 +1076,14 @@ impl<'a> CodegenEngine<'a> { .ok_or_else(|| format!("ValueId {:?} not found", id)), Value::Local(id) => self .ctx - .get_value(*id) + .get_local(*id) .ok_or_else(|| format!("LocalId {:?} not found", id)), Value::Global(id) => self .ctx - .get_value(*id) + .get_global(*id) .ok_or_else(|| format!("GlobalId {:?} not found", id)), Value::Const(lit) => self.codegen_literal(lit), - Value::Null => Ok(LLVMConstNull(LLVMPointerType( + Value::Null | Value::DslBlock { .. } => Ok(LLVMConstNull(LLVMPointerType( LLVMInt8TypeInContext(self.ctx.context), 0, ))), @@ -1106,7 +1114,7 @@ impl<'a> CodegenEngine<'a> { name.as_ptr(), )) } - LiteralVal::Null => Ok(LLVMConstNull(LLVMPointerType( + LiteralVal::None => Ok(LLVMConstNull(LLVMPointerType( LLVMInt8TypeInContext(self.ctx.context), 0, ))), @@ -1274,7 +1282,7 @@ impl TypeInfo for Value { LiteralVal::Float(_) => IRType::Float64, LiteralVal::Bool(_) => IRType::Bool, LiteralVal::Str(_) => IRType::String, - LiteralVal::Null => IRType::Any, + LiteralVal::None => IRType::Any, }, _ => IRType::Any, } diff --git a/compiler/llvm_backend/src/jit.rs b/compiler/llvm_backend/src/jit.rs index bb3b8c23..9005daa3 100644 --- a/compiler/llvm_backend/src/jit.rs +++ b/compiler/llvm_backend/src/jit.rs @@ -6,10 +6,9 @@ use llvm_sys::core::*; use llvm_sys::orc2::*; -use llvm_sys::prelude::*; +use llvm_sys::orc2::lljit::*; use std::collections::HashMap; use std::ffi::CString; -use std::os::raw::c_void; use std::ptr; use crate::codegen::CodegenEngine; @@ -32,7 +31,7 @@ impl LLVMJitEngine { return Err("Failed to create LLVMOrcLLJITRef".to_string()); } - let ts_ctx = LLVMOrcCreateThreadSafeContext(); + let ts_ctx = LLVMOrcCreateNewThreadSafeContext(); Ok(Self { jit, @@ -54,17 +53,17 @@ impl LLVMJitEngine { // 2. Set target triple and data layout matching LLJIT let jd = LLVMOrcLLJITGetMainJITDylib(self.jit); - let layout = LLVMOrcLLJITGetDataLayout(self.jit); - let layout_str = LLVMCopyStringRepOfTargetData(layout); - LLVMSetDataLayout(ctx.module, layout_str); - LLVMDisposeTargetString(layout_str); + let layout_str = LLVMOrcLLJITGetDataLayoutStr(self.jit); + llvm_sys::core::LLVMSetDataLayout(ctx.module, layout_str); + // Do not dispose layout_str directly as LLVMOrcLLJITGetDataLayoutStr returns a borrowed const char* + // string tied to the DataLayout of the JIT instance. // 3. Set host target triple - let host_triple = LLVMOrcLLJITGetExecutionSession(self.jit); // session triple fallback + let _host_triple = LLVMOrcLLJITGetExecutionSession(self.jit); // session triple fallback // We can just keep the default LLVM target triple // 4. Wrap Module in ThreadSafeModule - let tsm = LLVMOrcCreateThreadSafeModule(ctx.module, self.ts_ctx); + let tsm = LLVMOrcCreateNewThreadSafeModule(ctx.module, self.ts_ctx); // Relinquish ownership of ctx.module because LLVMOrcCreateThreadSafeModule takes it ctx.module = ptr::null_mut(); @@ -112,7 +111,7 @@ impl LLVMJitEngine { impl Drop for LLVMJitEngine { fn drop(&mut self) { unsafe { - LLVMOrcLLJITDispose(self.jit); + LLVMOrcDisposeLLJIT(self.jit); LLVMOrcDisposeThreadSafeContext(self.ts_ctx); } } diff --git a/compiler/llvm_backend/src/lib.rs b/compiler/llvm_backend/src/lib.rs index 37ca667f..b76a24a4 100644 --- a/compiler/llvm_backend/src/lib.rs +++ b/compiler/llvm_backend/src/lib.rs @@ -44,6 +44,17 @@ pub struct LLVMBackendOptions { pub debug_symbols: bool, } +#[cfg(feature = "llvm")] +pub fn get_host_target_triple() -> String { + unsafe { + let raw = llvm_sys::target_machine::LLVMGetDefaultTargetTriple(); + let cstr = std::ffi::CStr::from_ptr(raw); + let s = cstr.to_string_lossy().into_owned(); + llvm_sys::core::LLVMDisposeMessage(raw); + s + } +} + pub struct LLVMBackend; impl LLVMBackend { @@ -54,12 +65,14 @@ impl LLVMBackend { options: &LLVMBackendOptions, out_path: &Path, ) -> Result<(), LLVMCodegenError> { - Self::emit_to_file( - ir_module, - options, - out_path, - llvm_sys::target_machine::LLVMCodeGenFileType::LLVMObjectFile, - ) + unsafe { + Self::emit_to_file( + ir_module, + options, + out_path, + llvm_sys::target_machine::LLVMCodeGenFileType::LLVMObjectFile, + ) + } } /// Compiles a TechScript IR Module to a native assembly file (`.s` or `.asm`) at the given output path. @@ -69,12 +82,14 @@ impl LLVMBackend { options: &LLVMBackendOptions, out_path: &Path, ) -> Result<(), LLVMCodegenError> { - Self::emit_to_file( - ir_module, - options, - out_path, - llvm_sys::target_machine::LLVMCodeGenFileType::LLVMAssemblyFile, - ) + unsafe { + Self::emit_to_file( + ir_module, + options, + out_path, + llvm_sys::target_machine::LLVMCodeGenFileType::LLVMAssemblyFile, + ) + } } /// Emits textual LLVM IR representation (`.ll`) at the given output path. @@ -117,7 +132,6 @@ impl LLVMBackend { use crate::context::CodegenContext; use llvm_sys::target::*; use llvm_sys::target_machine::*; - use llvm_sys::transforms::pass_manager_builder::*; use std::ffi::{CStr, CString}; // 1. Initialize LLVM targets @@ -172,48 +186,37 @@ impl LLVMBackend { // Set module target triple and data layout let layout = LLVMCreateTargetDataLayout(target_machine); - let layout_str = LLVMCopyStringRepOfTargetData(layout); - LLVMSetDataLayout(ctx.module, layout_str); - LLVMSetTarget(ctx.module, triple_cstr.as_ptr()); + let layout_str = llvm_sys::target::LLVMCopyStringRepOfTargetData(layout); + llvm_sys::core::LLVMSetDataLayout(ctx.module, layout_str); + llvm_sys::core::LLVMSetTarget(ctx.module, triple_cstr.as_ptr()); // 5. Setup Pass Manager Optimizations - let opt_level_u32 = match options.opt_level { - LLVMCodeGenOptLevel::LLVMCodeGenLevelNone => 0, - LLVMCodeGenOptLevel::LLVMCodeGenLevelLess => 1, - LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault => 2, - LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive => 3, - }; + let pb_options = llvm_sys::transforms::pass_builder::LLVMCreatePassBuilderOptions(); - let pm_builder = LLVMPassManagerBuilderCreate(); - LLVMPassManagerBuilderSetOptLevel(pm_builder, opt_level_u32); - LLVMPassManagerBuilderSetSizeLevel(pm_builder, if opt_level_u32 == 2 { 1 } else { 0 }); // Os equivalent - LLVMPassManagerBuilderUseInlinerWithThreshold( - pm_builder, - if opt_level_u32 > 0 { 275 } else { 0 }, - ); - - let mpm = llvm_sys::core::LLVMCreatePassManager(); - LLVMPassManagerBuilderPopulateModulePassManager(pm_builder, mpm); - - let fpm = llvm_sys::core::LLVMCreateFunctionPassManagerForModule(ctx.module); - LLVMPassManagerBuilderPopulateFunctionPassManager(pm_builder, fpm); - - LLVMPassManagerBuilderDispose(pm_builder); - - // Run function-level optimizations - llvm_sys::core::LLVMInitializeFunctionPassManager(fpm); - let mut func = llvm_sys::core::LLVMGetFirstFunction(ctx.module); - while !func.is_null() { - llvm_sys::core::LLVMRunFunctionPassManager(fpm, func); - func = llvm_sys::core::LLVMGetNextFunction(func); + let passes = match options.opt_level { + LLVMCodeGenOptLevel::LLVMCodeGenLevelNone => "default", + LLVMCodeGenOptLevel::LLVMCodeGenLevelLess => "default", + LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault => "default", + LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive => "default", + }; + let passes_cstr = CString::new(passes).unwrap(); + + if let LLVMCodeGenOptLevel::LLVMCodeGenLevelNone = options.opt_level { + // No extra options + } else { + llvm_sys::transforms::pass_builder::LLVMPassBuilderOptionsSetInlinerThreshold( + pb_options, 275, + ); } - llvm_sys::core::LLVMFinalizeFunctionPassManager(fpm); - // Run module-level optimizations - llvm_sys::core::LLVMRunPassManager(mpm, ctx.module); + llvm_sys::transforms::pass_builder::LLVMRunPasses( + ctx.module, + passes_cstr.as_ptr(), + target_machine, + pb_options, + ); - llvm_sys::core::LLVMDisposePassManager(fpm); - llvm_sys::core::LLVMDisposePassManager(mpm); + llvm_sys::transforms::pass_builder::LLVMDisposePassBuilderOptions(pb_options); // 6. Emit target file (object or assembly) let out_str = CString::new(out_path.to_string_lossy().to_string()).unwrap(); @@ -228,8 +231,7 @@ impl LLVMBackend { ); // Clean up target layouts and machines - LLVMDisposeTargetString(layout_str); - LLVMDisposeTargetData(layout); + llvm_sys::target::LLVMDisposeTargetData(layout); LLVMDisposeTargetMachine(target_machine); if status != 0 { diff --git a/compiler/llvm_backend/src/type_map.rs b/compiler/llvm_backend/src/type_map.rs index ab397955..5b1038b5 100644 --- a/compiler/llvm_backend/src/type_map.rs +++ b/compiler/llvm_backend/src/type_map.rs @@ -25,6 +25,7 @@ pub unsafe fn to_llvm_type(context: LLVMContextRef, ty: &IRType) -> LLVMTypeRef IRType::Struct(_) => LLVMPointerType(LLVMInt8TypeInContext(context), 0), IRType::Enum(_) => LLVMPointerType(LLVMInt8TypeInContext(context), 0), IRType::Model(_) => LLVMPointerType(LLVMInt8TypeInContext(context), 0), + IRType::DslBlock(_) => LLVMPointerType(LLVMInt8TypeInContext(context), 0), IRType::Any => LLVMPointerType(LLVMInt8TypeInContext(context), 0), } }