Skip to content

Commit 119a0f8

Browse files
committed
globals
1 parent 237dd16 commit 119a0f8

File tree

3 files changed

+92
-20
lines changed

3 files changed

+92
-20
lines changed

src/compiler.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl Compiler {
106106
!self.decls.decls.is_empty()
107107
}
108108

109-
pub fn jit(&self) -> Result<*const u8, String> {
109+
pub fn jit(&self) -> Result<(*const u8, usize), String> {
110110
let mut jit = JIT::default();
111111
jit.print_ir = self.print_ir;
112112
if self.decls.decls.is_empty() {
@@ -117,14 +117,24 @@ impl Compiler {
117117

118118
pub fn run(&mut self) {
119119
let r = self.jit();
120-
if let Ok(code_ptr) = r {
120+
if let Ok((code_ptr, globals_size)) = r {
121121
println!("compilation successful");
122122

123-
type Entry = fn() -> ();
124-
125-
unsafe {
126-
let code_fn = mem::transmute::<_, Entry>(code_ptr);
127-
code_fn();
123+
if globals_size > 0 {
124+
// Allocate zeroed global memory and pass to main.
125+
type EntryWithGlobals = fn(*mut u8) -> ();
126+
let mut globals: Vec<u8> = vec![0u8; globals_size];
127+
unsafe {
128+
let code_fn = mem::transmute::<_, EntryWithGlobals>(code_ptr);
129+
code_fn(globals.as_mut_ptr());
130+
}
131+
} else {
132+
// No globals, call main with no arguments.
133+
type Entry = fn() -> ();
134+
unsafe {
135+
let code_fn = mem::transmute::<_, Entry>(code_ptr);
136+
code_fn();
137+
}
128138
}
129139
} else {
130140
println!("{:?}", r);

src/jit.rs

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7179
impl 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

294337
impl<'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
}

tests/cases/globals.lyte

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
1+
// args: -c
2+
// expected stdout:
3+
// compilation successful
4+
// assert(true)
5+
// assert(true)
26

37
assert(cond: bool) → void
48

59
var global: i32
610

7-
test {
11+
main {
12+
assert(global == 0)
813
global = 42
914
assert(global == 42)
1015
}

0 commit comments

Comments
 (0)