From 26bd7e90fdf6cf2d42ef01f273167a38d0bf6a68 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Thu, 22 Feb 2024 13:47:06 -0800 Subject: [PATCH] getting closer ... --- examples/basic/function0001.ngr | 2 + runtime/rts.c | 2 +- src/backend/into_crane.rs | 114 +++++++++++++++++++++----------- src/compiler.rs | 19 ++++++ src/ir/arbitrary.rs | 8 ++- src/ir/ast.rs | 35 ++++++---- src/ir/eval.rs | 11 +-- src/type_infer/convert.rs | 4 +- src/type_infer/finalize.rs | 7 +- 9 files changed, 137 insertions(+), 65 deletions(-) diff --git a/examples/basic/function0001.ngr b/examples/basic/function0001.ngr index 1a845d8..6cdb5c3 100644 --- a/examples/basic/function0001.ngr +++ b/examples/basic/function0001.ngr @@ -1,5 +1,7 @@ x = 1; function add_x(y) x + y a = 3; +print x; result = add_x(a); +print x; print result; \ No newline at end of file diff --git a/runtime/rts.c b/runtime/rts.c index d8eba53..dbcd759 100644 --- a/runtime/rts.c +++ b/runtime/rts.c @@ -32,7 +32,7 @@ void print(char *_ignore, char *variable_name, int64_t vtype, int64_t value) { printf("%s = \n", variable_name); break; default: - printf("%s = UNKNOWN VTYPE %d\n", variable_name, vtype); + printf("%s = UNKNOWN VTYPE %lld\n", variable_name, vtype); } } diff --git a/src/backend/into_crane.rs b/src/backend/into_crane.rs index ce1acad..2526984 100644 --- a/src/backend/into_crane.rs +++ b/src/backend/into_crane.rs @@ -24,28 +24,6 @@ pub enum ReferenceBuilder { Argument(ConstantType, entities::Value), } -impl ReferenceBuilder { - fn refer_to(&self, builder: &mut FunctionBuilder) -> (entities::Value, ConstantType) { - match self { - ReferenceBuilder::Global(ty, gv) => { - let cranelift_type = ir::Type::from(*ty); - let ptr_value = builder.ins().symbol_value(types::I64, *gv); - let value = builder - .ins() - .load(cranelift_type, MemFlags::new(), ptr_value, 0); - (value, *ty) - } - - ReferenceBuilder::Local(ty, var) => { - let value = builder.use_var(*var); - (value, *ty) - } - - ReferenceBuilder::Argument(ty, val) => (*val, *ty), - } - } -} - impl Backend { /// Translate the given IR type into an ABI parameter type for cranelift, as /// best as possible. @@ -105,6 +83,7 @@ impl Backend { true, false, )?; + println!("defining {} with primitive type {}", top_level_name, pt); self.module.define_data(data_id, &pt.blank_data())?; self.defined_symbols .insert(top_level_name, (data_id, pt.into())); @@ -146,6 +125,7 @@ impl Backend { argument_types: Vec, return_type: Type, ) -> Result { + println!("Declaring {:?} function {}", linkage, name); let basic_signature = Signature { params: argument_types .iter() @@ -176,6 +156,22 @@ impl Backend { return_type: Type, body: Expression, ) -> Result { + println!("Compiling function {}", function_name); + { + use pretty::{DocAllocator, Pretty}; + let allocator = pretty::BoxAllocator; + allocator + .text("Function body:") + .append(allocator.hardline()) + .append(body.pretty(&allocator)) + .append(allocator.hardline()) + .1 + .render_colored( + 70, + pretty::termcolor::StandardStream::stdout(pretty::termcolor::ColorChoice::Auto), + ) + .expect("rendering works"); + } // reset the next variable counter. this value shouldn't matter; hopefully // we won't be using close to 2^32 variables! self.reset_local_variable_tracker(); @@ -423,24 +419,23 @@ impl Backend { } }, - Expression::Print(ann, var) => { + Expression::Print(_, var) => { // Get the output buffer (or null) from our general compilation context. let buffer_ptr = self.output_buffer_ptr(); let buffer_ptr = builder.ins().iconst(types::I64, buffer_ptr as i64); // Get a reference to the string we want to print. - let string_data_id = self.string_reference(var.as_ref())?; + let var_name = match var { + ValueOrRef::Ref(_, _, ref name) => name.as_ref(), + ValueOrRef::Value(_, _, _) => "", + }; + let string_data_id = self.string_reference(var_name)?; let local_name_ref = self .module .declare_data_in_func(string_data_id, builder.func); let name_ptr = builder.ins().symbol_value(types::I64, local_name_ref); - // Look up the value for the variable. Because this might be a - // global variable (and that requires special logic), we just turn - // this into an `Expression` and re-use the logic in that implementation. - let fake_ref = - ValueOrRef::Ref(ann, Type::Primitive(PrimitiveType::U8), var.clone()); - let (val, vtype) = self.compile_value_or_ref(fake_ref, variables, builder)?; + let (val, vtype) = self.compile_value_or_ref(var, variables, builder)?; let vtype_repr = builder.ins().iconst(types::I64, vtype as i64); @@ -472,10 +467,30 @@ impl Backend { let ir_type = ir::Type::from(value_type); let variable = self.generate_local(); - builder.declare_var(variable, ir_type); - builder.def_var(variable, value); - variables.insert(name, ReferenceBuilder::Local(value_type, variable)); - Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void)) + match variables.get(&name) { + Some(ReferenceBuilder::Global(_, global_value)) => { + let pointer = self.module.target_config().pointer_type(); + let pointer_to = builder.ins().symbol_value(pointer, *global_value); + println!("STORE {}: cranelift_type {} origin type {:?}", name, value, value_type); + builder.ins().store(MemFlags::new(), value, pointer_to, 0); + Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void)) + } + + Some(ReferenceBuilder::Argument(_, _)) => { + panic!("Attempt to mutate an argument {}", name) + } + + Some(ReferenceBuilder::Local(_, _)) => { + panic!("Attempt to mutate local {}", name); + } + + None => { + builder.declare_var(variable, ir_type); + builder.def_var(variable, value); + variables.insert(name, ReferenceBuilder::Local(value_type, variable)); + Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void)) + } + } } Expression::Call(_, _, function, args) => { @@ -508,9 +523,11 @@ impl Backend { [result] => match result_type { Type::Primitive(ct) => Ok((*result, ct.into())), Type::Function(_, rt) => match *rt { - Type::Function(_, _) => panic!("function returns a function?"), + Type::Function(_, _) => { + panic!("function returns a function?") + } Type::Primitive(ct) => Ok((*result, ct.into())), - } + }, }, _ => panic!("don't support multi-value returns yet"), } @@ -530,6 +547,7 @@ impl Backend { variables: &HashMap, builder: &mut FunctionBuilder, ) -> Result<(entities::Value, ConstantType), BackendError> { + println!("compile_value_or_ref {:?}", valref); match valref { ValueOrRef::Value(_, _, val) => match val { Value::I8(_, v) => { @@ -575,7 +593,25 @@ impl Backend { }, ValueOrRef::Ref(_, _, name) => match variables.get(&name) { None => Err(BackendError::VariableLookupFailure(name)), - Some(x) => Ok(x.refer_to(builder)), + Some(ReferenceBuilder::Global(ty, gv)) => { + let pointer_to = self.module.target_config().pointer_type(); + let pointer_value = builder.ins().symbol_value(pointer_to, *gv); + let cranelift_type = ir::Type::from(*ty); + println!("READ {}: cranelift_type {} origin type {:?}", name, cranelift_type, ty); + let value = + builder + .ins() + .load(cranelift_type, MemFlags::new(), pointer_value, 0); + + Ok((value, *ty)) + } + + Some(ReferenceBuilder::Argument(ctype, val)) => Ok((*val, *ctype)), + + Some(ReferenceBuilder::Local(ctype, var)) => { + let value = builder.use_var(*var); + Ok((value, *ctype)) + } }, } } @@ -588,11 +624,11 @@ impl PrimitiveType { PrimitiveType::U8 => (1, 1), PrimitiveType::U16 => (2, 2), PrimitiveType::U32 => (4, 4), - PrimitiveType::U64 => (4, 4), + PrimitiveType::U64 => (8, 8), PrimitiveType::I8 => (1, 1), PrimitiveType::I16 => (2, 2), PrimitiveType::I32 => (4, 4), - PrimitiveType::I64 => (4, 4), + PrimitiveType::I64 => (8, 8), }; let mut result = DataDescription::new(); result.define_zeroinit(size); diff --git a/src/compiler.rs b/src/compiler.rs index 22c8029..388fccc 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,6 +5,7 @@ use codespan_reporting::{ files::SimpleFiles, term::{self, Config}, }; +use cranelift_module::Module; use pretty::termcolor::{ColorChoice, StandardStream}; use target_lexicon::Triple; @@ -134,7 +135,25 @@ impl Compiler { // Finally, send all this to Cranelift for conversion into an object file. let mut backend = Backend::object_file(Triple::host())?; + let unknown = "".to_string(); backend.compile_program("gogogo", ir)?; + println!("FINAL MODULE:"); + println!(" FUNCTIONS:"); + for (_, decl) in backend.module.declarations().get_functions() { + println!( + " {}: {:?}", + decl.name.as_ref().unwrap_or(&unknown), + decl.linkage + ); + } + println!(" DATA:"); + for (_, decl) in backend.module.declarations().get_data_objects() { + println!( + " {}: {:?}", + decl.name.as_ref().unwrap_or(&unknown), + decl.linkage + ); + } Ok(Some(backend.bytes()?)) } diff --git a/src/ir/arbitrary.rs b/src/ir/arbitrary.rs index 1ac45bb..71de979 100644 --- a/src/ir/arbitrary.rs +++ b/src/ir/arbitrary.rs @@ -359,19 +359,21 @@ fn generate_random_expression( .iter() .filter_map(|(variable, ty)| { if ty.is_printable() { - Some(variable.clone()) + Some((variable.clone(), ty.clone())) } else { None } }) - .collect::>(); + .collect::>(); if possible_variables.is_empty() { generate_random_binding(rng, env) } else { + let (variable, var_type) = possible_variables.choose(rng).unwrap(); + Expression::Print( Location::manufactured(), - possible_variables.choose(rng).unwrap().clone(), + ValueOrRef::Ref(Location::manufactured(), var_type.clone(), variable.clone()), ) } } diff --git a/src/ir/ast.rs b/src/ir/ast.rs index cc1d873..7480483 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -61,8 +61,9 @@ pub struct Program { impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Program where A: 'a, - D: ?Sized + DocAllocator<'a, A>, + D: ?Sized + DocAllocator<'a, A> + 'a, &'b Type: Pretty<'a, D, A>, + pretty::DocBuilder<'a, D, A>: Clone, { fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { let mut result = allocator.nil(); @@ -116,8 +117,9 @@ impl TopLevel { impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b TopLevel where A: 'a, - D: ?Sized + DocAllocator<'a, A>, + D: ?Sized + DocAllocator<'a, A> + 'a, &'b Type: Pretty<'a, D, A>, + pretty::DocBuilder<'a, D, A>: Clone, { fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { match self { @@ -159,7 +161,7 @@ pub enum Expression { Cast(Location, Type, ValueOrRef), Primitive(Location, Type, Primitive, Vec>), Block(Location, Type, Vec>), - Print(Location, Variable), + Print(Location, ValueOrRef), Call(Location, Type, Box>, Vec>), Bind(Location, Variable, Type, Box>), } @@ -197,8 +199,9 @@ impl Expression { impl<'a, 'b, D, A, Type> Pretty<'a, D, A> for &'b Expression where A: 'a, - D: ?Sized + DocAllocator<'a, A>, + D: ?Sized + DocAllocator<'a, A> + 'a, &'b Type: Pretty<'a, D, A>, + pretty::DocBuilder<'a, D, A>: Clone, { fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> { match self { @@ -235,24 +238,28 @@ where Some((last, &[])) => last.pretty(allocator), Some((last, start)) => { let mut result = allocator.text("{").append(allocator.hardline()); - - for stmt in start.iter() { - result = result - .append(stmt.pretty(allocator)) + let starts = start.iter().map(|x| { + x.pretty(allocator) .append(allocator.text(";")) - .append(allocator.hardline()); + .append(allocator.hardline()) + .indent(4) + }); + let last = last + .pretty(allocator) + .append(allocator.hardline()) + .indent(4); + + for start in starts { + result = result.append(start); } - result - .append(last.pretty(allocator)) - .append(allocator.hardline()) - .append(allocator.text("}")) + result.append(last).append(allocator.text("}")) } }, Expression::Print(_, var) => allocator .text("print") .append(allocator.space()) - .append(allocator.text(var.as_ref().to_string())), + .append(var.pretty(allocator)), Expression::Bind(_, var, ty, expr) => allocator .text(var.as_ref().to_string()) .append(allocator.space()) diff --git a/src/ir/eval.rs b/src/ir/eval.rs index 4d5841f..5b758ae 100644 --- a/src/ir/eval.rs +++ b/src/ir/eval.rs @@ -89,11 +89,12 @@ where Ok(result) } - Expression::Print(loc, n) => { - let value = env - .get(n) - .cloned() - .ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.to_string()))?; + Expression::Print(_, value) => { + let n = match value { + ValueOrRef::Ref(_, _, ref name) => name.as_str(), + ValueOrRef::Value(_, _, _) => "", + }; + let value = value.eval(env)?; stdout.push_str(&format!("{} = {}\n", n, value)); Ok(Value::Void) } diff --git a/src/type_infer/convert.rs b/src/type_infer/convert.rs index d93d811..3c11de8 100644 --- a/src/type_infer/convert.rs +++ b/src/type_infer/convert.rs @@ -150,10 +150,11 @@ fn convert_statement( .get(&final_name) .expect("print variable defined before use") .clone(); + println!("varty for {} is {}", final_name, varty); constraint_db.push(Constraint::Printable(loc.clone(), varty.clone())); - ir::Expression::Print(loc, final_name) + ir::Expression::Print(loc.clone(), ir::ValueOrRef::Ref(loc, varty, final_name)) } syntax::Statement::Binding(loc, name, expr) => { @@ -256,6 +257,7 @@ fn convert_expression( .get(&final_name) .cloned() .expect("variable bound before use"); + println!("rtype for {} is {}", final_name, rtype); let refexp = ir::Expression::Atomic(ir::ValueOrRef::Ref(loc, rtype.clone(), final_name)); diff --git a/src/type_infer/finalize.rs b/src/type_infer/finalize.rs index 4173794..12bf00b 100644 --- a/src/type_infer/finalize.rs +++ b/src/type_infer/finalize.rs @@ -89,7 +89,7 @@ fn finalize_expression( Expression::Block(loc, finalize_type(ty, resolutions), final_exprs) } - Expression::Print(loc, var) => Expression::Print(loc, var), + Expression::Print(loc, var) => Expression::Print(loc, finalize_val_or_ref(var, resolutions)), Expression::Call(loc, ty, fun, args) => Expression::Call( loc, @@ -114,7 +114,10 @@ fn finalize_type(ty: TypeOrVar, resolutions: &TypeResolutions) -> Type { TypeOrVar::Primitive(x) => Type::Primitive(x), TypeOrVar::Variable(_, tvar) => match resolutions.get(&tvar) { None => panic!("Did not resolve type for type variable {}", tvar), - Some(pt) => pt.clone(), + Some(pt) => { + println!("Finalizing {} to {}", tvar, pt); + pt.clone() + } }, TypeOrVar::Function(mut args, ret) => Type::Function( args.drain(..)