@@ -34,6 +34,12 @@ pub struct JIT {
3434
3535 defined_functions : HashSet < Name > ,
3636
37+ /// Global variable offsets from base pointer.
38+ globals : HashMap < Name , i32 > ,
39+
40+ /// Total size of global memory needed.
41+ globals_size : usize ,
42+
3743 pub print_ir : bool ,
3844}
3945
@@ -63,14 +69,20 @@ impl Default for JIT {
6369 ctx : module. make_context ( ) ,
6470 module,
6571 defined_functions : HashSet :: new ( ) ,
72+ globals : HashMap :: new ( ) ,
73+ globals_size : 0 ,
6674 print_ir : false ,
6775 }
6876 }
6977}
7078
7179impl JIT {
7280 /// Compile our AST into native code.
73- pub fn compile ( & mut self , decls : & DeclTable ) -> Result < * const u8 , String > {
81+ /// Returns (code_ptr, globals_size).
82+ pub fn compile ( & mut self , decls : & DeclTable ) -> Result < ( * const u8 , usize ) , String > {
83+ // First, declare all global variables.
84+ self . declare_globals ( decls) ;
85+
7486 let name = "main" ;
7587
7688 let main_decls = & decls. find ( Name :: new ( name. into ( ) ) ) ;
@@ -86,7 +98,7 @@ impl JIT {
8698 panic ! ( "no main function found" ) ;
8799 } ;
88100
89- let id = self . compile_function ( decls, main_decl) ?;
101+ let id = self . compile_function ( decls, main_decl, true ) ?;
90102
91103 // Finalize the functions which we just defined, which resolves any
92104 // outstanding relocations (patching in addresses, now that they're
@@ -98,18 +110,25 @@ impl JIT {
98110 // We can now retrieve a pointer to the machine code.
99111 let code = self . module . get_finalized_function ( id) ;
100112
101- Ok ( code)
113+ Ok ( ( code, self . globals_size ) )
102114 }
103115
104116 fn compile_function (
105117 & mut self ,
106118 decls : & DeclTable ,
107119 decl : & FuncDecl ,
120+ is_main : bool ,
108121 ) -> Result < cranelift_module:: FuncId , String > {
109122 self . ctx . func . signature = fn_sig ( & self . module ,
110123 decl. domain ( ) ,
111124 decl. ret ) ;
112125
126+ // For main function, add globals base pointer as first parameter.
127+ let has_globals = is_main && self . globals_size > 0 ;
128+ if has_globals {
129+ self . ctx . func . signature . params . insert ( 0 , AbiParam :: new ( I64 ) ) ;
130+ }
131+
113132 // Declare the function first, before generating its body.
114133 // This ensures that any functions called within the body get
115134 // different func IDs than the function being compiled.
@@ -118,7 +137,7 @@ impl JIT {
118137 . declare_function ( & * decl. name , Linkage :: Export , & self . ctx . func . signature )
119138 . map_err ( |e| e. to_string ( ) ) ?;
120139
121- let called_functions = self . function_body ( decls, decl) ;
140+ let called_functions = self . function_body ( decls, decl, has_globals ) ;
122141
123142 // Print the generated IR
124143 if self . print_ir {
@@ -154,13 +173,24 @@ impl JIT {
154173 panic ! ( )
155174 } ;
156175
157- self . compile_function ( decls, decl) ?;
176+ self . compile_function ( decls, decl, false ) ?;
158177 }
159178
160179 Ok ( id)
161180 }
162181
163- fn function_body ( & mut self , decls : & DeclTable , decl : & FuncDecl ) -> HashSet < Name > {
182+ fn declare_globals ( & mut self , decls : & DeclTable ) {
183+ let mut offset: i32 = 0 ;
184+ for decl in & decls. decls {
185+ if let Decl :: Global { name, ty } = decl {
186+ self . globals . insert ( * name, offset) ;
187+ offset += ty. size ( decls) as i32 ;
188+ }
189+ }
190+ self . globals_size = offset as usize ;
191+ }
192+
193+ fn function_body ( & mut self , decls : & DeclTable , decl : & FuncDecl , has_globals : bool ) -> HashSet < Name > {
164194 // Translate into cranelift IR.
165195 // Create the builder to build a function.
166196 let mut builder = FunctionBuilder :: new ( & mut self . ctx . func , & mut self . builder_context ) ;
@@ -177,13 +207,20 @@ impl JIT {
177207 // Get the block parameters (function arguments).
178208 let block_params: Vec < _ > = builder. block_params ( entry_block) . to_vec ( ) ;
179209
180- let mut trans = FunctionTranslator :: new ( builder, & mut self . module ) ;
210+ // If this function has globals, the first block param is the globals base pointer.
211+ let ( globals_base, param_offset) = if has_globals {
212+ ( Some ( block_params[ 0 ] ) , 1 )
213+ } else {
214+ ( None , 0 )
215+ } ;
216+
217+ let mut trans = FunctionTranslator :: new ( builder, & mut self . module , & self . globals , globals_base) ;
181218
182219 // Add variables for the function parameters and define them with block param values.
183220 for ( i, param) in decl. params . iter ( ) . enumerate ( ) {
184221 let ty = param. ty . expect ( "expected type" ) . cranelift_type ( ) ;
185222 let var = trans. declare_variable ( & param. name , ty) ;
186- trans. builder . def_var ( var, block_params[ i] ) ;
223+ trans. builder . def_var ( var, block_params[ i + param_offset ] ) ;
187224 // Function parameters are like let bindings - they hold values directly.
188225 trans. let_bindings . insert ( param. name . to_string ( ) ) ;
189226 }
@@ -289,10 +326,16 @@ struct FunctionTranslator<'a> {
289326 /// Tracks which variables are `let` bindings (hold values directly)
290327 /// vs `var` bindings (hold pointers to stack slots).
291328 let_bindings : HashSet < String > ,
329+
330+ /// Global variable offsets from base pointer.
331+ globals : & ' a HashMap < Name , i32 > ,
332+
333+ /// Base pointer for globals (passed as first param to main).
334+ globals_base : Option < Value > ,
292335}
293336
294337impl < ' a > FunctionTranslator < ' a > {
295- fn new ( builder : FunctionBuilder < ' a > , module : & ' a mut JITModule ) -> Self {
338+ fn new ( builder : FunctionBuilder < ' a > , module : & ' a mut JITModule , globals : & ' a HashMap < Name , i32 > , globals_base : Option < Value > ) -> Self {
296339 Self {
297340 builder,
298341 variables : HashMap :: new ( ) ,
@@ -301,6 +344,8 @@ impl<'a> FunctionTranslator<'a> {
301344 current_instance : Instance :: new ( ) ,
302345 called_functions : HashSet :: new ( ) ,
303346 let_bindings : HashSet :: new ( ) ,
347+ globals,
348+ globals_base,
304349 }
305350 }
306351
@@ -311,8 +356,15 @@ impl<'a> FunctionTranslator<'a> {
311356 fn translate_lvalue ( & mut self , expr : ExprID , decl : & FuncDecl , decls : & DeclTable ) -> Value {
312357 match & decl. arena [ expr] {
313358 Expr :: Id ( name) => {
314- let var = * self . variables . get ( & * * name) . unwrap ( ) ;
315- self . builder . use_var ( var)
359+ if let Some ( variable) = self . variables . get ( & * * name) {
360+ self . builder . use_var ( * variable)
361+ } else if let Some ( & offset) = self . globals . get ( name) {
362+ // Global variable - compute address from base + offset.
363+ let base = self . globals_base . expect ( "globals_base not set" ) ;
364+ self . builder . ins ( ) . iadd_imm ( base, offset as i64 )
365+ } else {
366+ panic ! ( "unknown lvalue: {:?}" , name) ;
367+ }
316368 }
317369 Expr :: Field ( lhs, name) => {
318370 let lhs_ty = decl. types [ * lhs] ;
@@ -371,6 +423,11 @@ impl<'a> FunctionTranslator<'a> {
371423 . ins ( )
372424 . load ( ty. cranelift_type ( ) , MemFlags :: new ( ) , val, 0 )
373425 }
426+ } else if let Some ( & offset) = self . globals . get ( name) {
427+ // Global variable - load from base + offset.
428+ let base = self . globals_base . expect ( "globals_base not set" ) ;
429+ let addr = self . builder . ins ( ) . iadd_imm ( base, offset as i64 ) ;
430+ self . builder . ins ( ) . load ( ty. cranelift_type ( ) , MemFlags :: new ( ) , addr, 0 )
374431 } else {
375432 self . translate_func ( name, & * ty)
376433 }
0 commit comments