diff --git a/examples/basic/broken0001.ngr b/examples/basic/broken0001.ngr index 360380a..76008d0 100644 --- a/examples/basic/broken0001.ngr +++ b/examples/basic/broken0001.ngr @@ -3,6 +3,8 @@ struct Point { y: u64; } +v = 1u64; + function getX(p: Point) -> u64 p.x; diff --git a/examples/basic/broken0003.ngr b/examples/basic/broken0003.ngr new file mode 100644 index 0000000..7fe0600 --- /dev/null +++ b/examples/basic/broken0003.ngr @@ -0,0 +1,13 @@ +struct Point { + x: u64; + y: u64; +} + +test = Point { + x: 1; + y: 2; +}; + +foo = test.x; + +print foo; \ No newline at end of file diff --git a/runtime/rts.c b/runtime/rts.c index dbcd759..7649ca8 100644 --- a/runtime/rts.c +++ b/runtime/rts.c @@ -1,7 +1,13 @@ #include #include +#include +#include #include +#define HEAP_SIZE (1024 * 1024) + +void *__global_allocation_pointer__ = NULL; + void print(char *_ignore, char *variable_name, int64_t vtype, int64_t value) { switch(vtype) { case /* U8 = */ 10: @@ -39,6 +45,18 @@ void print(char *_ignore, char *variable_name, int64_t vtype, int64_t value) { extern void gogogo(); int main(int argc, char **argv) { + __global_allocation_pointer__ = malloc(HEAP_SIZE); + if(__global_allocation_pointer__ == NULL) { + printf("ERROR: Couldn't allocation heap space."); + return 1; + } + + if(memset(__global_allocation_pointer__, 0, HEAP_SIZE) != __global_allocation_pointer__) { + printf("ERROR: Weird return trying to zero out heap."); + return 2; + } + gogogo(); + return 0; } \ No newline at end of file diff --git a/src/backend.rs b/src/backend.rs index 6047134..2b475e4 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -89,7 +89,7 @@ impl Backend { let mut module = JITModule::new(builder); let runtime_functions = RuntimeFunctions::new(&platform, &mut module)?; - Ok(Backend { + let mut retval = Backend { module, data_ctx: DataDescription::new(), runtime_functions, @@ -99,7 +99,18 @@ impl Backend { output_buffer, platform: Triple::host(), next_variable: 23, - }) + }; + + let alloc = "__global_allocation_pointer__".to_string(); + let id = retval + .module + .declare_data(&alloc, Linkage::Import, true, false)?; + retval.defined_symbols.insert( + ArcIntern::new(alloc), + (id, retval.module.target_config().pointer_type()), + ); + + Ok(retval) } /// Given a compiled function ID, get a pointer to where that function was written @@ -130,7 +141,7 @@ impl Backend { let mut module = ObjectModule::new(object_builder); let runtime_functions = RuntimeFunctions::new(&platform, &mut module)?; - Ok(Backend { + let mut retval = Backend { module, data_ctx: DataDescription::new(), runtime_functions, @@ -140,7 +151,18 @@ impl Backend { output_buffer: None, platform, next_variable: 23, - }) + }; + + let alloc = "__global_allocation_pointer__".to_string(); + let id = retval + .module + .declare_data(&alloc, Linkage::Import, true, false)?; + retval.defined_symbols.insert( + ArcIntern::new(alloc), + (id, retval.module.target_config().pointer_type()), + ); + + Ok(retval) } /// Given all the functions defined, return the bytes the object file should contain. diff --git a/src/backend/into_crane.rs b/src/backend/into_crane.rs index a3aa10f..8e9456f 100644 --- a/src/backend/into_crane.rs +++ b/src/backend/into_crane.rs @@ -406,12 +406,53 @@ impl Backend { } } - Expression::Construct(_, ty, name, fields) => { - let Type::Structure(fields) = ty else { + Expression::Construct(_, ty, _, fields) => { + let Type::Structure(type_fields) = ty else { panic!("Got to backend with non-structure type in structure construction?!"); }; - unimplemented!() + let global_allocator = ArcIntern::new("__global_allocation_pointer__".to_string()); + let Some(ReferenceBuilder::Global(_, allocator_variable)) = + variables.get(&global_allocator) + else { + panic!("Couldn't find global allocation pointer"); + }; + + let pointer_to = self.module.target_config().pointer_type(); + let allocator_pointer = builder.ins().symbol_value(pointer_to, *allocator_variable); + let structure = + builder + .ins() + .load(pointer_to, MemFlags::new(), allocator_pointer, 0); + let structure_size = builder + .ins() + .iconst(pointer_to, type_fields.object_size() as i64); + let updated_allocator_value = builder.ins().iadd(structure, structure_size); + builder.ins().store( + MemFlags::new(), + updated_allocator_value, + allocator_pointer, + 0, + ); + + for (field_name, field_value) in fields.into_iter() { + let (field_value, field_cranelift_type) = + self.compile_value_or_ref(field_value, variables, builder)?; + let Some((field_internal_type, offset)) = + type_fields.field_type_and_offset(&field_name) + else { + panic!("Got to backend with mismatched construction and type definition"); + }; + assert_eq!( + field_cranelift_type, + self.translate_type(field_internal_type).value_type + ); + builder + .ins() + .store(MemFlags::new(), field_value, structure, offset); + } + + Ok((structure, self.module.target_config().pointer_type())) } Expression::FieldRef(_, _, struct_type, val, field) => { @@ -427,7 +468,10 @@ impl Backend { let field_cranelift_type = self.translate_type(field_type).value_type; - let value = builder.ins().load(field_cranelift_type, MemFlags::new(), structure, offset); + let value = + builder + .ins() + .load(field_cranelift_type, MemFlags::new(), structure, offset); Ok((value, field_cranelift_type)) } diff --git a/src/backend/runtime.rs b/src/backend/runtime.rs index 6362176..6e4b437 100644 --- a/src/backend/runtime.rs +++ b/src/backend/runtime.rs @@ -91,7 +91,14 @@ impl RuntimeFunctions { /// one; both to reduce the chance that they deviate, and to reduce overall /// maintenance burden. pub fn register_jit_implementations(builder: &mut JITBuilder) { + let allocation_pointer = unsafe { + std::alloc::alloc_zeroed( + std::alloc::Layout::from_size_align(1024 * 1024, 1024 * 1024) + .expect("reasonable layout is reasonable"), + ) + }; builder.symbol("print", runtime_print as *const u8); + builder.symbol("__global_allocation_pointer__", allocation_pointer); } } diff --git a/src/ir/fields.rs b/src/ir/fields.rs index adc624d..f59ae43 100644 --- a/src/ir/fields.rs +++ b/src/ir/fields.rs @@ -133,6 +133,10 @@ impl Fields { None } + + pub fn object_size(&self) -> usize { + self.total_size + } } impl IntoIterator for Fields { diff --git a/src/type_infer/convert.rs b/src/type_infer/convert.rs index 0658d95..85f7224 100644 --- a/src/type_infer/convert.rs +++ b/src/type_infer/convert.rs @@ -183,7 +183,7 @@ fn convert_statement( let iname = ArcIntern::new(name.to_string()); let final_name = renames .get(&iname) - .map(Clone::clone) + .cloned() .unwrap_or_else(|| iname.clone()); let varty = bindings .get(&final_name)