@@ -26,7 +26,6 @@ use inkwell::{
2626 execution_engine:: ExecutionEngine ,
2727 targets:: { InitializationConfig , Target } ,
2828} ;
29-
3029use crate :: { CompilerError , CompilerResult } ;
3130use crate :: hir:: { HirModule , HirFunction , HirId } ;
3231use crate :: llvm_backend:: LLVMBackend ;
@@ -47,6 +46,10 @@ pub struct LLVMJitBackend<'ctx> {
4746
4847 /// Optimization level
4948 opt_level : OptimizationLevel ,
49+
50+ /// Runtime symbols to register with the execution engine
51+ /// Maps function name to function pointer address
52+ runtime_symbols : IndexMap < String , usize > ,
5053}
5154
5255impl < ' ctx > LLVMJitBackend < ' ctx > {
@@ -69,9 +72,24 @@ impl<'ctx> LLVMJitBackend<'ctx> {
6972 execution_engine : None ,
7073 function_pointers : IndexMap :: new ( ) ,
7174 opt_level,
75+ runtime_symbols : IndexMap :: new ( ) ,
7276 } )
7377 }
7478
79+ /// Register a runtime symbol that will be available to JIT-compiled code
80+ ///
81+ /// Call this before `compile_module` to make external functions available.
82+ pub fn register_symbol ( & mut self , name : impl Into < String > , ptr : * const u8 ) {
83+ self . runtime_symbols . insert ( name. into ( ) , ptr as usize ) ;
84+ }
85+
86+ /// Register multiple runtime symbols at once
87+ pub fn register_symbols ( & mut self , symbols : & [ ( & str , * const u8 ) ] ) {
88+ for ( name, ptr) in symbols {
89+ self . runtime_symbols . insert ( ( * name) . to_string ( ) , * ptr as usize ) ;
90+ }
91+ }
92+
7593 /// Compile a full HIR module
7694 ///
7795 /// Translates all functions to LLVM IR and JIT compiles them.
@@ -84,21 +102,46 @@ impl<'ctx> LLVMJitBackend<'ctx> {
84102 let mut backend = LLVMBackend :: new ( self . context , "zyntax_jit" ) ;
85103 let _llvm_ir = backend. compile_module ( hir_module) ?;
86104
87- // Step 2: Create execution engine from the FULLY POPULATED module
88- // This is critical - MCJIT takes ownership of the module and compiles it
89- let execution_engine = backend. into_module ( )
105+ // Step 2: Collect external function declarations from the module BEFORE consuming it
106+ // We need the function values for add_global_mapping
107+ let mut external_functions: Vec < ( String , inkwell:: values:: FunctionValue < ' ctx > ) > = Vec :: new ( ) ;
108+ for ( _, function) in & hir_module. functions {
109+ if function. is_external {
110+ if let Some ( name) = function. name . resolve_global ( ) {
111+ if let Some ( llvm_func) = backend. module ( ) . get_function ( & name) {
112+ external_functions. push ( ( name, llvm_func) ) ;
113+ }
114+ }
115+ }
116+ }
117+
118+ // Step 3: Consume the module and create execution engine
119+ let module = backend. into_module ( ) ;
120+ let execution_engine = module
90121 . create_jit_execution_engine ( self . opt_level )
91122 . map_err ( |e| CompilerError :: Backend ( format ! ( "Failed to create JIT execution engine: {}" , e) ) ) ?;
92123
93- // Step 3: Extract function pointers from the execution engine
124+ // Step 4: Register runtime symbols with the execution engine using add_global_mapping
125+ for ( name, llvm_func) in & external_functions {
126+ if let Some ( addr) = self . runtime_symbols . get ( name) {
127+ execution_engine. add_global_mapping ( llvm_func, * addr) ;
128+ log:: debug!( "Registered runtime symbol '{}' at address 0x{:x}" , name, addr) ;
129+ }
130+ }
131+
132+ // Step 5: Extract function pointers from the execution engine
94133 for ( id, function) in & hir_module. functions {
134+ // Skip external functions - they don't have compiled code in this module
135+ if function. is_external {
136+ continue ;
137+ }
138+
95139 // Must match naming logic in llvm_backend.rs:
96- // - External functions use their actual name for linking
97140 // - Main function uses actual name for entry point
98141 // - Other functions use mangled name with HirId
99142 let actual_name = function. name . resolve_global ( )
100143 . unwrap_or_else ( || format ! ( "{:?}" , function. name) ) ;
101- let fn_name = if function . is_external || actual_name == "main" {
144+ let fn_name = if actual_name == "main" {
102145 actual_name
103146 } else {
104147 format ! ( "func_{:?}" , id)
0 commit comments