diff --git a/Cargo.toml b/Cargo.toml index 27675ef..1218873 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,8 @@ authors = ["nameoverflow "] [dependencies] pest = "0.4" llvm-sys = "39" +bytecount = "0.1.4" + +[features] +avx-accel = ["bytecount/avx-accel"] +simd-accel = ["bytecount/simd-accel"] diff --git a/src/codegen/emit.rs b/src/codegen/emit.rs index edd50f2..0a3c80a 100644 --- a/src/codegen/emit.rs +++ b/src/codegen/emit.rs @@ -1,7 +1,202 @@ -use syntax::form::*; +use core::*; +use types::*; +use internal::*; + +use codegen::llvm::*; +pub use codegen::llvm::{ VarEnv }; + +use std::ops::Deref; + + +pub trait EmitProvider { + fn gen_module(&mut self, module: T) + where T: IntoIterator; +} + +pub struct LLVMEmit(LLVMCodegen); + +impl LLVMEmit { + pub fn new(name: &str) -> Self { + LLVMEmit(LLVMCodegen::new(name)) + } + pub fn dump(&mut self) { + unsafe { + LLVMDumpModule(self.0.module); + } + } + pub fn gen_top_level(&mut self, def: &Definition, prelude: &VarEnv) { + unsafe { + // A global function definition + let fun_type = def.ref_type(); + let fun = self.0.get_or_add_function(def.name(), fun_type); + println!("{:?}", fun_type); + + // Check redefinition + if LLVMCountBasicBlocks(fun) != 0 { + panic!("Redefinition of function"); + } + + let bb = LLVMAppendBasicBlockInContext(self.0.context, fun, raw_string("entry")); + + LLVMPositionBuilderAtEnd(self.0.builder, bb); + + // Create a sub environment for current function generating + let mut symtbl = prelude.sub_env(); + + let mut params_ref: Vec<_> = def.parameters().iter().collect(); + + let last_param: Option<&VarDecl> = if let Some(&VarDecl(_, ref _last_type)) = def.parameters().last() { + match _last_type.body() { + &Type::Prod(..) => { + params_ref.pop() + }, + _ => None + } + } else { None }; + + + // Spread length + let len_head = params_ref.len(); + +// let paramc = LLVMCountParams(fun) as usize; + // LLVM parameter counts should be the sum +// if paramc != len_head + last_type_flat.len() + 1 { +// eprintln!("expected {:?}, found {:?}", paramc, len_head + last_type_flat.len() + 1); +// panic!("Redefinition of function with different argument count"); +// } + // For each parameter, set argument name, + // create store instruction, add to + // symbol table. + for (i, &VarDecl(ref pname, ref ptype)) in params_ref.into_iter().enumerate() { + let llarg = LLVMGetParam(fun, i as c_uint); + // let lltype = self.get_llvm_type(ptype.body()); + LLVMSetValueName(llarg, raw_string(pname.as_str())); + + let alloca = self.0.create_entry_block_alloca(fun, pname.as_str(), ptype.body()); + + LLVMBuildStore(self.0.builder, llarg, alloca); + symtbl.insert(pname.as_str(), alloca); + } + + if let Some(&VarDecl(ref last_name, ref _last_type)) = last_param { +// let last_type = + let last_type_flat = _last_type.body().prod_to_vec(); + // Handle the last parameter + let last_alloca = self.0.create_entry_block_alloca(fun, last_name.as_str(), _last_type.body()); + println!("fuck: {:?}", last_type_flat.clone()); + for (i, ty) in last_type_flat.into_iter().enumerate() { + let idx_name = i.to_string(); + let llarg = LLVMGetParam(fun, (i + len_head) as c_uint); + let argname = last_name.clone() + idx_name.as_str(); + LLVMSetValueName(llarg, raw_string(argname.as_str())); + + let field = LLVMBuildStructGEP(self.0.builder, last_alloca, i as c_uint, raw_string(idx_name.as_str())); + LLVMBuildStore(self.0.builder, llarg, field); + } + } + + + + + // TODO: Make closure pointer a parameter + // TODO: return pointer instead of stack value for structure type + + let fun_body = self.gen_expr(def.body(), &mut symtbl); + LLVMBuildRet(self.0.builder, fun_body); + + if LLVMVerifyFunction(fun, LLVMVerifierFailureAction::LLVMPrintMessageAction) != 0 { + println!("Function verify failed"); + } + } + } + pub unsafe fn gen_expr<'a: 'b, 'b>(&mut self, + term: &'a TaggedTerm, + symbols: &mut VarEnv<'b>) + -> LLVMValueRef { + use self::Term::*; + match *term.body() { + Lit(ref lit) => self.0.gen_lit(lit), + Var(ref vn) => { + let var_name = vn.as_str(); + match symbols.lookup(&var_name) { + Some(v) => { + LLVMBuildLoad(self.0.builder, *v, raw_string(var_name)) + } + // It must be a global definition because of type check + None => self.0.get_or_add_function(var_name, term.ref_scheme().body()), + } + } + Binary(op, ref lhs, ref rhs) => { + let lval = self.gen_expr(lhs, symbols); + let rval = self.gen_expr(rhs, symbols); + let instr = get_llvm_op(op, lhs.ref_scheme().body()); + + instr(self.0.builder, lval, rval, self.0.new_symbol().unwrap().into_raw()) + } + Let(ref var_decl, ref val, ref exp) => { + let &VarDecl(ref var, ref tyvar) = var_decl; + let var_name = var.as_str(); + + let blk = LLVMGetInsertBlock(self.0.builder); + let fun = LLVMGetBasicBlockParent(blk); + + let init = self.gen_expr(val, symbols); + let alloca = self.0.create_entry_block_alloca(fun, var_name, tyvar.body()); + LLVMBuildStore(self.0.builder, init, alloca); + + let old = symbols.insert(var_name, alloca); + + let res = self.gen_expr(exp.deref(), symbols); + + if let Some(o) = old { + symbols.insert(var_name, o); + } else { + symbols.remove(&var_name); + } + res + } + ApplyCls(ref callee, ref args) => { + // let funty = self.get_fun_type(callee.deref().tag.ref_scheme()); + let callee_ref = self.gen_expr(callee, symbols); + + let mut argsv = vec![]; + for arg in args.iter() { + // TODO: unpack tuple + argsv.push(self.gen_expr(arg, symbols)); + } + + LLVMBuildCall(self.0.builder, + callee_ref, + argsv.as_mut_ptr(), + argsv.len() as c_uint, + self.0.new_symbol().unwrap().into_raw()) + } + Block(ref fs) => { + let mut it = fs.iter(); + if let Some(v) = it.next() { + let mut ret = self.gen_expr(v, symbols); + for n in it { + ret = self.gen_expr(n, symbols); + } + ret + } else { + panic!("Empty block") + } + } + MakeCls(ref var_decl, ref cls, ref exp) => unimplemented!(), + List(_) => unimplemented!(), + Unary(_, _) => unimplemented!(), + If(_, _, _) => unimplemented!(), + } + } -pub trait ModuleProvider { - fn gen_module(&mut self, modu: T) - where T: IntoIterator; } + +impl EmitProvider for LLVMCodegen { + fn gen_module(&mut self, module: T) + where T: IntoIterator + { + + } +} \ No newline at end of file diff --git a/src/codegen/llvm.rs b/src/codegen/llvm.rs index 76633aa..998b7ab 100644 --- a/src/codegen/llvm.rs +++ b/src/codegen/llvm.rs @@ -1,70 +1,172 @@ use std::char; use std::ffi::{CString, NulError}; -use std::io::{self, Read, Write, BufReader}; +use std::io::{self, BufReader, Read, Write}; use std::ptr; use std::collections::HashMap; use std::iter::*; use std::ops::Deref; -use libc::{c_uint, c_ulonglong, c_char}; +pub use libc::{c_char, c_uint, c_ulonglong}; -use llvm_sys::prelude::{LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef, LLVMTypeRef, LLVMValueRef}; -use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGenericValueToFloat, LLVMRunFunction, LLVMGenericValueRef}; -use llvm_sys::analysis::{LLVMVerifyFunction, LLVMVerifierFailureAction}; -use llvm_sys::LLVMRealPredicate; -use llvm_sys::core::*; +pub use llvm_sys::prelude::{LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef, + LLVMTypeRef, LLVMValueRef}; +pub use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGenericValueRef, + LLVMGenericValueToFloat, LLVMRunFunction}; +pub use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction}; +pub use llvm_sys::LLVMRealPredicate; +pub use llvm_sys::core::*; // use codegen::llvm::*; -use syntax::interm::*; -use core::term::*; +use core::*; +use internal::*; use types::*; use utils::*; + +#[derive(Debug)] +pub struct LLVMModule(LLVMModuleRef); +#[derive(Debug)] +pub struct LLVMContext(LLVMContextRef); +#[derive(Debug)] +pub struct LLVMValue(LLVMValueRef); +#[derive(Debug)] +pub struct LLVMFunction(LLVMValueRef); +#[derive(Debug)] +pub struct LLVMType(LLVMTypeRef); +#[derive(Debug)] +pub struct LLVMBuilder(LLVMBuilderRef); + +macro_rules! method_raw_ptr { + ($raw_type: ty) => { + pub fn raw_ptr(&mut self) -> $raw_type { + self.0 + } + }; +} +macro_rules! method_get_type { + ($name: ident, $fun: ident) => { + pub fn $name(&self) -> LLVMType { + unsafe { + LLVMType::from_ref($fun(self.0)) + } + } + }; +} + +impl LLVMContext { + pub fn new() -> Self { + unsafe { + LLVMContext(LLVMContextCreate()) + } + } + method_raw_ptr!(LLVMContextRef); + method_get_type!(get_int1_type, LLVMInt1TypeInContext); + method_get_type!(get_int8_type, LLVMInt8TypeInContext); + method_get_type!(get_int32_type, LLVMInt32TypeInContext); + method_get_type!(get_double_type, LLVMDoubleTypeInContext); + method_get_type!(get_void_type, LLVMVoidTypeInContext); + + pub fn get_function_type(ret: &mut LLVMType, param: &mut Vec, is_var_arg: bool) -> LLVMType { + let mut ps: Vec<_> = param.iter_mut().map(|t| t.raw_ptr()).collect(); + let pc = ps.len() as c_uint; + let flag = if is_var_arg { 1 } else { 0 }; + let fun = unsafe { + LLVMFunctionType(ret.raw_ptr(), ps.as_mut_ptr(), pc, flag) + }; + LLVMType::from_ref(fun) + } + + pub fn get_struct_type(&mut self, types: &mut Vec, packed: bool) -> LLVMType { + let mut mems: Vec<_> = types.iter_mut().map(|t| t.raw_ptr()).collect(); + let flag = if packed { 1 } else { 0 }; + let t = unsafe { + LLVMStructTypeInContext(self.0, mems.as_mut_ptr(), mems.len() as c_uint, flag) + }; + LLVMType(t) + } +} + +impl LLVMType { + pub fn from_ref(ptr: LLVMTypeRef) -> Self { + LLVMType(ptr) + } + method_raw_ptr!(LLVMTypeRef); +} + +impl Drop for LLVMModule { + fn drop(&mut self) { + unsafe { + LLVMDisposeModule(self.0); + } + } +} +impl Drop for LLVMContext { + fn drop(&mut self) { + unsafe { + LLVMContextDispose(self.0); + } + } +} +impl Drop for LLVMBuilder { + fn drop(&mut self) { + unsafe { + LLVMDisposeBuilder(self.0); + } + } +} + #[derive(Debug, Clone)] pub struct LLVMCodegen { - module: LLVMModuleRef, - builder: LLVMBuilderRef, - context: LLVMContextRef, + pub module: LLVMModuleRef, + pub builder: LLVMBuilderRef, + pub context: LLVMContextRef, unique: usize, } pub type VarEnv<'a> = SymTable<'a, &'a str, LLVMValueRef>; -fn get_llvm_op(op: BinOp, p_type: &Type) - -> unsafe extern "C" - fn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, *const ::libc::c_char) -> LLVMValueRef -{ +type LLVMOperateBuild = unsafe extern "C" fn(LLVMBuilderRef, + LLVMValueRef, + LLVMValueRef, + *const ::libc::c_char) + -> LLVMValueRef; + +pub fn get_llvm_op(op: BinOp, + operand_ty: &Type) + -> LLVMOperateBuild { use self::BinOp::*; use self::Type::*; - if let &Con(ref ty_name) = p_type { + if let &Con(ref ty_name) = operand_ty { let name_ref = ty_name.as_str(); - match op { - Add => match name_ref { - "Int" => LLVMBuildAdd, - "Float" => LLVMBuildFAdd, - _ => unreachable!() - }, - Sub => match name_ref { - "Int" => LLVMBuildSub, - "Float" => LLVMBuildFSub, - _ => unreachable!() - }, - Mul => match name_ref { - "Int" => LLVMBuildMul, - "Float" => LLVMBuildFMul, - _ => unreachable!() - }, - Div => LLVMBuildFDiv, - Rem => LLVMBuildURem, // TODO: WTF LLVM builder ??? - _ => unreachable!() + match (op, name_ref) { + (Add, "Int") => LLVMBuildAdd, + (Add, "Float") => LLVMBuildFAdd, + (Sub, "Int") => LLVMBuildSub, + (Sub, "Float") => LLVMBuildFSub, + (Mul, "Int") => LLVMBuildMul, + (Mul, "Float") => LLVMBuildFMul, + (Div, _) => LLVMBuildFDiv, // TODO: I dont know exactly which builder + (Rem, _) => LLVMBuildURem, // should I use for these two + _ => unimplemented!(), } } else { unreachable!() } } -unsafe fn raw_string(s: &str) -> *mut c_char { +pub fn is_primitive_type(t: &Type) -> bool { + if let &Type::Con(ref n) = t { + match n.as_str() { + "Int" | "Float" | "Char" => true, + _ => false + } + } else { + false + } +} + +pub unsafe fn raw_string(s: &str) -> *mut c_char { CString::new(s).unwrap().into_raw() } @@ -72,125 +174,94 @@ impl LLVMCodegen { pub fn new(name: &str) -> LLVMCodegen { unsafe { let ctx = LLVMContextCreate(); - let modu = LLVMModuleCreateWithNameInContext(CString::new(name).unwrap().into_raw(), ctx); + let modu = LLVMModuleCreateWithNameInContext(raw_string(name), ctx); let builder = LLVMCreateBuilderInContext(ctx); LLVMCodegen { module: modu, context: ctx, builder: builder, - unique: 0 + unique: 0, } } } - pub fn gen_top_level(&mut self, def: &Definition, prelude: &VarEnv) { - unsafe { - // A global function definition - let fun_type = def.ref_type(); - let fun = self.get_or_add_function(def.name(), fun_type); - - // Check redefinition - if LLVMCountBasicBlocks(fun) != 0 { - panic!("Redefinition of function"); // TODO: Error return - } - let paramc = LLVMCountParams(fun) as usize; - if paramc != def.parameters().len() { - // TODO: Error return - // self.dump(); - panic!("Redefinition of function with different argument count"); - } - - let mut symtbl = prelude.sub_env(); - let bb = LLVMAppendBasicBlockInContext( - self.context, - fun, - CString::new("entry").unwrap().into_raw()); - - LLVMPositionBuilderAtEnd(self.builder, bb); - - // For each parameter, set argument name, - // create store instruction, add to - // symbol table. - for (i, &VarDecl(ref pname, ref ptype)) in def.parameters().iter().enumerate() { - let llarg = LLVMGetParam(fun, i as c_uint); - // let lltype = self.get_llvm_type(ptype.body()); - LLVMSetValueName(llarg, raw_string(pname.as_str())); - - let alloca = self.create_entry_block_alloca(fun, pname.as_str(), ptype.body()); - - LLVMBuildStore(self.builder, llarg, alloca); - symtbl.insert(pname.as_str(), alloca); - } - - // TODO: Make closure pointer a parameter - // make free var symbols point to free var allocas - - let fun_body = self.gen_expr(def.body(), &mut symtbl); - LLVMBuildRet(self.builder, fun_body); - - if LLVMVerifyFunction(fun, LLVMVerifierFailureAction::LLVMPrintMessageAction) != 0 { - println!("Function verify failed"); - } - } - } - - pub fn dump(&mut self) { - unsafe { - LLVMDumpModule(self.module); - } - } - - fn gensym(&mut self) -> Result { + pub fn new_symbol(&mut self) -> Result { let mut f = String::new(); f.push_str(self.unique.to_string().as_str()); self.unique = self.unique + 1; CString::new(f) } - unsafe fn get_fun_type(&mut self, scm: &Scheme) -> LLVMTypeRef { + pub unsafe fn get_fun_type(&mut self, scm: &Scheme) -> LLVMTypeRef { match scm { &Scheme::Mono(ref ty) => self.get_llvm_type(ty.deref()), - _ => unreachable!() + _ => unreachable!(), + } + } + + fn get_closure_type(&mut self) -> LLVMTypeRef { + unsafe { + let ptr = LLVMPointerType(LLVMInt8TypeInContext(self.context), 0); + let mut mem = vec![LLVMInt16TypeInContext(self.context), ptr]; + LLVMStructTypeInContext(self.context, mem.as_mut_ptr(), mem.len() as c_uint, 0) + } + } + + pub unsafe fn get_llvm_type_or_ptr(&mut self, ty: &Type) -> LLVMTypeRef { + let ret = self.get_llvm_type(ty); + if !is_primitive_type(ty) { + LLVMPointerType(ret, 0 as c_uint) + } else { + ret } } - unsafe fn get_llvm_type(&mut self, ty: &Type) -> LLVMTypeRef { + pub unsafe fn get_llvm_type(&mut self, ty: &Type) -> LLVMTypeRef { use self::Type::*; match ty { - &Con(ref n) => match n.as_str() { - // Primary types - "Int" => LLVMInt32TypeInContext(self.context), - "Float" => LLVMDoubleTypeInContext(self.context), - "Char" => LLVMInt8TypeInContext(self.context), - - // User defined types - t => self.gen_user_type(t) - }, - &Arr(ref p, ref ret) => { - let mut psty: Vec = vec![]; - let mut r: &Type = p.deref(); - loop { - if let &Prod(ref t, ref rest) = r { - psty.push(self.get_llvm_type(t.deref())); - r = rest; - } else { - psty.push(self.get_llvm_type(r.deref())); - break; - } + &Con(ref n) => { + match n.as_str() { + // Primary types + "Int" => LLVMInt32TypeInContext(self.context), + "Float" => LLVMDoubleTypeInContext(self.context), + "Char" => LLVMInt8TypeInContext(self.context), + + // User defined types + t => self.gen_user_type(t), } - let argc = psty.len(); - LLVMFunctionType(self.get_llvm_type(ret.deref()), psty.as_mut_ptr(), argc as c_uint, 0) - }, + } + &Arr(box ref p, box ref ret) => { + // type of parameters and returned value should be pointer if not primitive + let cls_type = LLVMPointerType(self.get_closure_type(), 0); + let mut retty = self.get_llvm_type_or_ptr(ret); + let psty = p.prod_to_vec(); + let mut llvm_psty: Vec<_> = + psty.into_iter().map(|t| self.get_llvm_type_or_ptr(t)).collect(); + llvm_psty.push(cls_type); + let argc = llvm_psty.len(); + println!("{:?}", llvm_psty); + LLVMFunctionType(retty, llvm_psty.as_mut_ptr(), argc as c_uint, 0) + } &Void => LLVMVoidTypeInContext(self.context), - &Prod(ref l, ref r) => unimplemented!(), // TODO: make a struct represent tuple + &Prod(..) => { + // let ty_name = ty.to_string().as_str(); + + // let llvm_t = LLVMGetStructName(); + let mut tys: Vec<_> = ty.prod_to_vec() + .iter() + .map(|t| self.get_llvm_type(t)) + .collect(); + let count = tys.len(); + LLVMStructTypeInContext(self.context, tys.as_mut_ptr(), count as c_uint, 0) + } // TODO: make a struct represent tuple &Comp(ref c, ref p) => unimplemented!(), // TODO: determine the type &Var(..) => panic!("Unmaterized type"), } } - unsafe fn gen_lit(&mut self, lit: &Lit) -> LLVMValueRef { + pub unsafe fn gen_lit(&mut self, lit: &Lit) -> LLVMValueRef { use self::Lit::*; match lit { &Float(f) => LLVMConstReal(LLVMDoubleTypeInContext(self.context), f), @@ -202,29 +273,30 @@ impl LLVMCodegen { } } - unsafe fn get_or_add_function(&mut self, fname: &str, fty: &Type) -> LLVMValueRef { + pub unsafe fn get_or_add_function(&mut self, fname: &str, fty: &Type) -> LLVMValueRef { // TODO: make closure pointer a parameter - let n = CString::new(fname).unwrap().into_raw(); + let n = raw_string(fname); let f = LLVMGetNamedFunction(self.module, n); if f.is_null() { let llvm_ty = self.get_llvm_type(fty); - LLVMAddFunction( - self.module, - raw_string(fname), - llvm_ty) + LLVMAddFunction(self.module, raw_string(fname), llvm_ty) } else { f } } - unsafe fn gen_user_type(&mut self, tyname: &str) -> LLVMTypeRef { + pub unsafe fn gen_user_type(&mut self, tyname: &str) -> LLVMTypeRef { // TODO: make a user defined type definition unimplemented!() } - unsafe fn create_entry_block_alloca(&mut self, fun: LLVMValueRef, var_name: &str, ty: &Type) -> LLVMValueRef { + pub unsafe fn create_entry_block_alloca(&mut self, + fun: LLVMValueRef, + var_name: &str, + ty: &Type) + -> LLVMValueRef { let builder = LLVMCreateBuilderInContext(self.context); let bb = LLVMGetEntryBasicBlock(fun); let fi = LLVMGetFirstInstruction(bb); @@ -234,94 +306,7 @@ impl LLVMCodegen { } - unsafe fn gen_expr<'a: 'b, 'b>( - &mut self, - term: &'a TaggedTerm, - symbols: &mut VarEnv<'b>) - -> LLVMValueRef - { - // TODO: fix variable ref - // change `form` code to `term` code - // get var type from environment - // instead of form attribute - use self::Term::*; - // println!("{:?}", form); - match *term.body() { - Lit(ref lit) => self.gen_lit(lit), - Var(ref vn) => { - let var_name = vn.as_str(); - match symbols.lookup(&var_name) { - Some(v) => { - LLVMBuildLoad(self.builder, *v, raw_string(var_name)) - // *v - }, - // Impossible because of type check - None => self.get_or_add_function(var_name, term.ref_scheme().body()) - } - } - Binary(op, ref lhs, ref rhs) => { - let lval = self.gen_expr(lhs, symbols); - let rval = self.gen_expr(rhs, symbols); - let instr = get_llvm_op(op, lhs.ref_scheme().body()); - - instr(self.builder, lval, rval, self.gensym().unwrap().into_raw()) - } - Let(ref var_decl, ref val, ref exp) => { - let &VarDecl(ref var, ref tyvar) = var_decl; - let var_name = var.as_str(); - - let blk = LLVMGetInsertBlock(self.builder); - let fun = LLVMGetBasicBlockParent(blk); - - let init = self.gen_expr(val, symbols); - let alloca = self.create_entry_block_alloca(fun, var_name, tyvar.body()); - LLVMBuildStore(self.builder, init, alloca); - - let old = symbols.insert(var_name, alloca); - - let res = self.gen_expr(exp.deref(), symbols); +} - if let Some(o) = old { - symbols.insert(var_name, o); - } else { - symbols.remove(&var_name); - } - res - } - ApplyCls(ref callee, ref args) => { - // let funty = self.get_fun_type(callee.deref().tag.ref_scheme()); - let callee_ref = self.gen_expr(callee, symbols); - - let mut argsv = vec![]; - for arg in args.iter() { - // TODO: unpack tuple - argsv.push(self.gen_expr(arg, symbols)); - } - LLVMBuildCall( - self.builder, - callee_ref, - argsv.as_mut_ptr(), - argsv.len() as c_uint, - self.gensym().unwrap().into_raw()) - } - Block(ref fs) => { - let mut it = fs.iter(); - if let Some(v) = it.next() { - let mut ret = self.gen_expr(v, symbols); - for n in it { - ret = self.gen_expr(n, symbols); - } - ret - } else { - panic!("Empty block") - } - }, - MakeCls(ref var_decl, ref cls, ref exp) => unimplemented!(), - List(_) => unimplemented!(), - Unary(_, _) => unimplemented!(), - If(_, _, _) => unimplemented!() - } - } -} diff --git a/src/core/convert.rs b/src/core/convert.rs index e6e21d3..66b6cc3 100644 --- a/src/core/convert.rs +++ b/src/core/convert.rs @@ -9,7 +9,7 @@ use std::ops::DerefMut; use utils::*; use types::*; use syntax::form::*; -use syntax::interm::*; +use internal::*; use core::term::*; @@ -26,13 +26,13 @@ impl K { /// Do transformation on a syntax module, /// generate core term representation pub fn go(module: I) -> HashMap> - where I: IntoIterator> + where I: IntoIterator> { let mut runner = K { count: 0, env: HashMap::new(), global: HashMap::new(), - cur_name: "".to_string() + cur_name: "".to_string(), }; { let b = &mut runner; @@ -71,7 +71,7 @@ impl K { let ty = tag.ty; self.cur_name = ident; let def_name = self.cur_name.clone(); - + match node { Expr::Abs(lambda) => { // We can ignore fvs (global definitions) there @@ -79,28 +79,29 @@ impl K { let (ps, _, bd) = self.trans_lambda(lambda); self.define_fn(def_name, ty, ps, vec![], bd); } - _ => unreachable!() + _ => unreachable!(), } - }, + } _ => {} } } /// Add a function in top level definitions - fn define_fn<'c: 'b, 'b>( - &'c mut self, - name: String, - ty: Scheme, - params: Vec, - freevars: Vec, - body: TaggedTerm) - -> (&'b str, Vec<&'b str>) - { + fn define_fn<'c: 'b, 'b>(&'c mut self, + name: String, + ty: Scheme, + params: Vec, + freevars: Vec, + body: TaggedTerm) + -> (&'b str, Vec<&'b str>) { let fun = Definition::new(name.clone(), ty, params, freevars, body); let ent = self.global.entry(name).or_insert(P(fun)); - (&(*ent).name(), (*ent).fv().iter() - .map(|ref v| { v.name() }) - .collect()) + (&(*ent).name(), + (*ent) + .fv() + .iter() + .map(|ref v| v.name()) + .collect()) } @@ -112,15 +113,15 @@ impl K { Var(ref v) => { let mut hs = HashSet::new(); hs.insert(v.as_str()); - return hs - }, + return hs; + } List(ref lst) | Block(ref lst) => { lst.iter().fold(HashSet::new(), |mut res, v| { res.extend(self.fv(v.deref())); res }) - }, + } // The new binding name should not be visible // in binding value. @@ -129,13 +130,13 @@ impl K { res.remove(var.name()); res.extend(&self.fv(val.deref())); res - }, + } MakeCls(ref var, ref cls, ref exp) => { let mut r = self.fv(exp.deref()); r.extend(cls.deref().fv()); r.remove(var.name()); r - }, + } ApplyCls(ref n, ref args) => { let mut r = args.iter().fold(HashSet::new(), |mut res, v| { res.extend(self.fv(v.deref())); @@ -143,19 +144,19 @@ impl K { }); r.extend(self.fv(n.deref())); r - }, + } Binary(_, ref lhs, ref rhs) => { let mut r = self.fv(lhs.deref()); r.extend(self.fv(rhs.deref())); r - }, + } Unary(_, ref e) => self.fv(e.deref()), If(ref c, ref t, ref f) => { let mut r = self.fv(c.deref()); r.extend(self.fv(t.deref())); r.extend(self.fv(f.deref())); r - }, + } } } @@ -174,9 +175,7 @@ impl K { } /// Get parameters, free variables, function body term from lambda - fn trans_lambda(&mut self, lambda: Lambda) - -> (Vec, Vec, TaggedTerm) - { + fn trans_lambda(&mut self, lambda: Lambda) -> (Vec, Vec, TaggedTerm) { let params = lambda.param; let bd = *lambda.body; @@ -203,9 +202,9 @@ impl K { for &VarDecl(ref n, _) in params.iter() { _fvs.remove(n.as_str()); } - _fvs.iter().map(|vn| { - VarDecl(vn.to_string(), self.env[&vn.to_string()].to_owned()) - }).collect() + _fvs.iter() + .map(|vn| VarDecl(vn.to_string(), self.env[&vn.to_string()].to_owned())) + .collect() }; // Reset env for bname in present { @@ -234,27 +233,22 @@ impl K { // A global definition should not be in scope env if self.find_var(n.as_str()) == None && tform.is_fn() { // For global function name, make a closure - Term::MakeCls( - VarDecl(n.clone(), tform.clone()), - box Closure::new(n.as_str(), vec![]), - box TaggedTerm::new(tform.clone(), Term::Var(n))) + Term::MakeCls(VarDecl(n.clone(), tform.clone()), + box Closure::new(n.as_str(), vec![]), + box TaggedTerm::new(tform.clone(), Term::Var(n))) } else { Term::Var(n) } - }, + } List(e) | Block(e) => Term::List(self.transform_list(e)), Unary(op, e) => Term::Unary(op, box self.transform(*e)), If(cond, tr, fl) => { - Term::If( - box self.transform(*cond), - box self.transform(*tr), - box self.transform(*fl)) + Term::If(box self.transform(*cond), + box self.transform(*tr), + box self.transform(*fl)) } Binary(op, left, right) => { - Term::Binary( - op, - box self.transform(*left), - box self.transform(*right)) + Term::Binary(op, box self.transform(*left), box self.transform(*right)) } Let(v, val, exp) => { let exp_term = self.transform(*exp); @@ -273,24 +267,19 @@ impl K { } let _cls_name = self.make_cls_name(bound); - self.define_fn( - _cls_name, - var_ty.clone(), - ps, fv, bd) + self.define_fn(_cls_name, var_ty.clone(), ps, fv, bd) }; - - let cls = Closure::new( - cls_name, - cls_fv); - + + let cls = Closure::new(cls_name, cls_fv); + Term::MakeCls(v, box cls, box exp_term) } else { // Normal variable bingding let val_term = self.transform(*val); Term::Let(v, box val_term, box exp_term) } - }, - + } + Apply(callee, params) => { let callee_term = self.transform(*callee); let params_term = self.transform_list(params); @@ -308,14 +297,11 @@ impl K { let (cls_name, cls_fv) = self.define_fn(tmp_name.clone(), ty.clone(), ps, fv, bd); let cls = Closure::new(cls_name, cls_fv); - Term::MakeCls( - VarDecl(tmp_name.clone(), ty.clone()), - box cls, - box TaggedTerm::new(ty, Term::Var(tmp_name))) - }, + Term::MakeCls(VarDecl(tmp_name.clone(), ty.clone()), + box cls, + box TaggedTerm::new(ty, Term::Var(tmp_name))) + } }; TaggedTerm::new(tform, t) } - } - diff --git a/src/core/mod.rs b/src/core/mod.rs index c28faa5..b810e95 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,2 +1,5 @@ -pub mod term; -pub mod convert; \ No newline at end of file +mod term; +mod convert; + +pub use core::term::*; +pub use core::convert::*; diff --git a/src/core/term.rs b/src/core/term.rs index 7791665..50ee854 100644 --- a/src/core/term.rs +++ b/src/core/term.rs @@ -7,7 +7,7 @@ use std::ops::DerefMut; use std::iter::IntoIterator; use std::iter::DoubleEndedIterator; -use syntax::interm::*; +use internal::*; use types::*; use utils::*; diff --git a/src/syntax/interm.rs b/src/internal.rs similarity index 97% rename from src/syntax/interm.rs rename to src/internal.rs index 9c31c89..4b8d4e7 100644 --- a/src/syntax/interm.rs +++ b/src/internal.rs @@ -131,8 +131,8 @@ pub enum UnOp { } impl UnOp { - pub fn to_string(op: UnOp) -> &'static str { - match op { + pub fn to_string(&self) -> &'static str { + match *self { UnOp::Not => "!", UnOp::Neg => "-", } diff --git a/src/lib.rs b/src/lib.rs index 367627b..0b7c235 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,10 @@ #![feature(libc)] #![feature(box_syntax, box_patterns)] +extern crate bytecount; +#[macro_use] +// extern crate nom; +// extern crate regex; #[macro_use] extern crate pest; extern crate llvm_sys; @@ -20,3 +24,4 @@ pub mod typeinfer; pub mod codegen; pub mod types; pub mod core; +pub mod internal; diff --git a/src/main.rs b/src/main.rs index 9e1574d..ff3d257 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,8 @@ use miko::utils::*; use miko::syntax::parser::*; use miko::types::*; use miko::typeinfer::*; -use miko::codegen::llvm::*; -use miko::core::convert::*; +use miko::codegen::emit::*; +use miko::core::*; use std::io; use std::io::Write; @@ -15,7 +15,7 @@ fn repl() { let mut stdout = io::stdout(); let mut input = String::new(); - let mut generator = LLVMCodegen::new("repl"); + let mut generator = LLVMEmit::new("repl"); 'main: loop { print!("> "); @@ -31,10 +31,10 @@ fn repl() { let ty_op = Scheme::Poly(vec!["a".to_string()], Type::Arr(P(Type::Prod(P(Type::Var("a".to_string())), - P(Type::Var("a".to_string())))), - P(Type::Var("a".to_string())))); + P(Type::Var("a".to_string())))), + P(Type::Var("a".to_string())))); + - let mut ty_infer = infer::Infer::new(); let mut ty_env = infer::Infer::new_env(); @@ -54,8 +54,8 @@ fn repl() { generator.gen_top_level(def.deref(), &VarEnv::new()); } generator.dump(); - }, - Err(e) => println!("{:?}", e) + } + Err(e) => println!("{:?}", e), } diff --git a/src/runtime/gsvalue.h b/src/runtime/gsvalue.h new file mode 100644 index 0000000..28a036d --- /dev/null +++ b/src/runtime/gsvalue.h @@ -0,0 +1,46 @@ +/** + * Geisha value representation definitions + */ + +#ifndef GSVALUE_H +#define GSVALUE_H + +#include + +/* Representations + + Currently for 64-bit arch only. + + primitive values: int32 / char / double + + struct: A struct has a header first, subsequent pointers and + primitive values fields. Structs should be allocated in + GC heap and managed by GC. + + closure: A closure also has a head, and contains a pointer to a function, + a collection of pointers to free variables. + + structure of the head: + +-------+-------+--------------------------+ + | type | mark | count of pointer fields | + +-------+-------+--------------------------+ + low 1 1 14 high + + So we could hold 2^14 pointers, which means 16MB data + in single structure lol +*/ + +typedef uint32_t header_t; + +// `type` field values 1 means this is a closure type +#define Is_struct(h) (((h) & 1) == 0) +#define Is_closure(h) (((h) & 1) != 0) + +#define Set_fields_count(h, c) (((h) & 3) | (c << 2)) +#define Fields_count(h) (h >> 2) + +// mark operations +#define Mark(h) ((h) | (1 << 1)) +#define Unmark(h) ((h) & ~(1 << 1)) + +#endif \ No newline at end of file diff --git a/src/syntax/form.rs b/src/syntax/form.rs index ec6ad58..29ab958 100644 --- a/src/syntax/form.rs +++ b/src/syntax/form.rs @@ -9,7 +9,7 @@ use std::iter::DoubleEndedIterator; use utils::*; use types::*; -use syntax::interm::*; +use internal::*; pub type E = P
; diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 5ebe56f..5b2d802 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -1,3 +1,2 @@ pub mod parser; pub mod form; -pub mod interm; \ No newline at end of file diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index c386777..a30cce7 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -3,7 +3,7 @@ use pest::*; use types::*; use utils::*; use syntax::form::*; -use syntax::interm::*; +use internal::*; use std::str::FromStr; use std::collections::LinkedList; use std::borrow::BorrowMut; diff --git a/src/typeinfer/infer.rs b/src/typeinfer/infer.rs index e948a63..0c9c25e 100644 --- a/src/typeinfer/infer.rs +++ b/src/typeinfer/infer.rs @@ -1,7 +1,7 @@ use typeinfer::typeenv::*; use typeinfer::subst::*; use syntax::form::*; -use syntax::interm::*; +use internal::*; use types::*; use utils::*; diff --git a/src/typeinfer/subst.rs b/src/typeinfer/subst.rs index d550f4d..345941c 100644 --- a/src/typeinfer/subst.rs +++ b/src/typeinfer/subst.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::ops::DerefMut; use syntax::form::*; -use syntax::interm::*; +use internal::*; use utils::*; use types::*; diff --git a/src/types.rs b/src/types.rs index f403ca9..8396f54 100644 --- a/src/types.rs +++ b/src/types.rs @@ -115,6 +115,35 @@ impl Type { } res } + + pub fn prod_to_vec(&self) -> Vec<&Type> { + use self::Type::*; + let mut v = vec![]; + let mut r: &Type = self; + loop { + if let &Prod(box ref t, box ref rest) = r { + v.push(t); + r = rest; + } else { + v.push(r); + break; + } + } + v + } +} + +impl ToString for Type { + fn to_string(&self) -> String { + use self::Type::*; + match self { + &Void => String::from("Void"), + &Var(ref n) | &Con(ref n) => n.clone(), + &Arr(box ref l, box ref r) => l.to_string() + "->" + r.to_string().as_str(), + &Prod(box ref l, box ref r) => l.to_string() + "*" + r.to_string().as_str(), + &Comp(box ref l, box ref r) => l.to_string() + "+" + r.to_string().as_str(), + } + } }