λ Support functions! #5
@@ -3,6 +3,8 @@ struct Point {
|
||||
y: u64;
|
||||
}
|
||||
|
||||
v = 1u64;
|
||||
|
||||
function getX(p: Point) -> u64
|
||||
p.x;
|
||||
|
||||
|
||||
13
examples/basic/broken0003.ngr
Normal file
13
examples/basic/broken0003.ngr
Normal file
@@ -0,0 +1,13 @@
|
||||
struct Point {
|
||||
x: u64;
|
||||
y: u64;
|
||||
}
|
||||
|
||||
test = Point {
|
||||
x: 1;
|
||||
y: 2;
|
||||
};
|
||||
|
||||
foo = test.x;
|
||||
|
||||
print foo;
|
||||
@@ -1,7 +1,13 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ impl Backend<JITModule> {
|
||||
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<JITModule> {
|
||||
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<ObjectModule> {
|
||||
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<ObjectModule> {
|
||||
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.
|
||||
|
||||
@@ -406,12 +406,53 @@ impl<M: Module> Backend<M> {
|
||||
}
|
||||
}
|
||||
|
||||
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<M: Module> Backend<M> {
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,10 @@ impl<T> Fields<T> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn object_size(&self) -> usize {
|
||||
self.total_size
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for Fields<T> {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user