Skip to content

Commit

Permalink
Compile to binary file; improve type checker error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
nameoverflow committed Sep 14, 2017
1 parent 12d6839 commit 7d59d62
Show file tree
Hide file tree
Showing 14 changed files with 460 additions and 118 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ build = "build.rs"

[dependencies]
bytecount = "0.1.4"
llvm-sys = "39"
argparse = "*"
libllvm = { path="./libllvm" }

[features]
Expand Down
34 changes: 27 additions & 7 deletions libllvm/src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use llvm_sys::prelude::{LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef,
pub use llvm_sys::prelude::{LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef,
LLVMTypeRef, LLVMValueRef, LLVMBasicBlockRef};
use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGenericValueRef,
LLVMGenericValueToFloat, LLVMRunFunction};
use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction};
use llvm_sys::LLVMRealPredicate;
pub use llvm_sys::core::*;
pub use llvm_sys::{ LLVMIntPredicate, LLVMRealPredicate };
use llvm_sys::transforms;

use std::ptr;
use libc::{c_char, c_uint, c_ulonglong};
use std::ffi::CString;

pub use llvm_sys::core::*;


pub trait LLVMWrapper<T> {
Expand Down Expand Up @@ -179,6 +179,8 @@ impl LLVMFunctionPassManager {
transforms::scalar::LLVMAddCFGSimplificationPass(llfpm);
// transforms::scalar::LLVMAddDeadStoreEliminationPass(llfpm);
transforms::scalar::LLVMAddMergedLoadStoreMotionPass(llfpm);
transforms::scalar::LLVMAddConstantPropagationPass(llfpm);
transforms::scalar::LLVMAddPromoteMemoryToRegisterPass(llfpm);
LLVMInitializeFunctionPassManager(llfpm);
LLVMFunctionPassManager(llfpm)
}
Expand Down Expand Up @@ -266,15 +268,33 @@ impl LLVMBuilder {
unsafe { LLVMPositionBuilderAtEnd(self.raw_ptr(), block.raw_ptr()) }
}

pub fn insert_block(&self) -> LLVMBasicBlock {
pub fn get_insert_block(&self) -> LLVMBasicBlock {
unsafe { LLVMBasicBlock::from_ref(LLVMGetInsertBlock(self.raw_ptr())) }
}

method_build_instr!(alloca, LLVMBuildAlloca, ty: &LLVMType => target: &str);
method_build_instr!(load, LLVMBuildLoad, ptr: &LLVMValue => target: &str);
method_build_instr!(alloca, LLVMBuildAlloca, ty: &LLVMType => dest: &str);
method_build_instr!(phi, LLVMBuildPhi, ty: &LLVMType => dest: &str);
method_build_instr!(load, LLVMBuildLoad, ptr: &LLVMValue => dest: &str);
method_build_instr!(store, LLVMBuildStore, val: &LLVMValue, ptr: &LLVMValue);
method_build_instr!(ret, LLVMBuildRet, val: &LLVMValue);
method_build_instr!(bit_cast, LLVMBuildBitCast, val: &LLVMValue, dest_ty: &LLVMType => name: &str);
method_build_instr!(cond_br, LLVMBuildCondBr, cond: &LLVMValue, then: &LLVMBasicBlock, el: &LLVMBasicBlock);
method_build_instr!(br, LLVMBuildBr, cont: &LLVMBasicBlock);
method_build_instr!(bit_cast, LLVMBuildBitCast, val: &LLVMValue, dest_ty: &LLVMType => dest: &str);

pub fn phi_node<'a, I>(&self, ty: &LLVMType, incoming: I, dest: &str) -> LLVMValue
where I: IntoIterator<Item=&'a (&'a LLVMValue, &'a LLVMBasicBlock)>
{
unsafe {
let phi = LLVMBuildPhi(self.raw_ptr(), ty.raw_ptr(), raw_string(dest));
let (mut vals, mut blks): (Vec<_>, Vec<_>) = incoming
.into_iter()
.map(|&(val, blk)| (val.raw_ptr(), blk.raw_ptr()))
.unzip();
let count = vals.len();
LLVMAddIncoming(phi, vals.as_mut_ptr(), blks.as_mut_ptr(), count as c_uint);
LLVMValue::from_ref(phi)
}
}

pub fn ret_void(&self) -> LLVMValue {
unsafe {
Expand Down
111 changes: 78 additions & 33 deletions src/codegen/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ pub trait EmitProvider {
}

pub struct LLVMEmit<'i> {
generator: LLVMCodegen,
pub generator: LLVMCodegen,
interner: &'i mut Interner,
}

pub type VarEnv<'a> = SymTable<'a, Id, LLVMValue>;

fn with_var<'a, 'b: 'a, F, R>(sym: &mut VarEnv<'a>, var: Id, val: LLVMValue, mut cb: F) -> R
where F: FnMut(&mut VarEnv<'a>) -> R
{
let old = sym.insert(var, val);
let res = cb(sym);
if let Some(o) = old {
sym.insert(var, o);
} else {
sym.remove(&var);
}
res
}
//fn with_var<'a, 'b: 'a, F, R>(sym: &mut VarEnv<'a>, var: Id, val: LLVMValue, mut cb: F) -> R
// where F: FnMut(&mut VarEnv<'a>) -> R
//{
// let old = sym.insert(var, val);
// let res = cb(sym);
// if let Some(o) = old {
// sym.insert(var, o);
// } else {
// sym.remove(&var);
// }
// res
//}


impl<'i> LLVMEmit<'i> {
Expand All @@ -53,15 +53,15 @@ impl<'i> LLVMEmit<'i> {
};
let llvm_fun_type = self.generator.get_llvm_type(fun_type);
let def_name = def.name();
let fun = self.generator.module.get_or_add_function(def_name, &llvm_fun_type);
let fun = self.module().get_or_add_function(def_name, &llvm_fun_type);
let arg_count = fun.count_params();

// Check redefinition

if fun.count_basic_blocks() != 0 {
panic!("Redefinition of function");
panic!("Redefine function");
}
let block = self.generator.context.append_basic_block(&fun, "entry");
let block = self.context().append_basic_block(&fun, "entry");

self.builder().set_position_at_end(&block);

Expand Down Expand Up @@ -106,13 +106,12 @@ impl<'i> LLVMEmit<'i> {
let formal_fvs = def.fv();
let fv_allocas = self.alloca_for_vars(&fun, formal_fvs);
let fv_tys = fv_allocas.iter().map(|v| v.get_type().get_element()).collect();
let fv_ty_actual = self.generator.context.get_struct_type(&fv_tys, false);
let fv_ty_actual = self.context().get_struct_type(&fv_tys, false);
let fv_ptr_actual = self.builder().bit_cast(&p_fvs, &fv_ty_actual.get_ptr(0), "fv");
for (i, fv) in fv_allocas.into_iter().enumerate() {
let fv_id = formal_fvs[i].name();
let fv_name = self.interner.trace(fv_id);
let fv_val_ptr =
self.builder().struct_field_ptr(&fv_ptr_actual, i, "tmp");
let fv_val_ptr = self.builder().struct_field_ptr(&fv_ptr_actual, i, "tmp");
let fv_val = self.builder().load(&fv_val_ptr, fv_name);
self.builder().store(&fv_val, &fv);
symtbl.insert(fv_id, fv);
Expand All @@ -126,7 +125,23 @@ impl<'i> LLVMEmit<'i> {
fun.verify(LLVMVerifierFailureAction::LLVMPrintMessageAction);
self.generator.passer.run(&fun);
}
pub fn gen_expr<'a: 'b, 'b>(&mut self,

pub fn gen_main(&mut self, def: &FunDef, prelude: &VarEnv) {
let main_ty = self.generator.get_main_type();
let fun = self.module().get_or_add_function("main", &main_ty);
let block = self.context().append_basic_block(&fun, "entry");
self.builder().set_position_at_end(&block);
let zero = self.context().get_int32_const(0);
let mut symtbl = prelude.sub_env();
let res = self.gen_expr(def.body(), &mut symtbl);
let alloca = self.builder().alloca(&res.get_type(), "res");
self.builder().store(&res, &alloca);
self.builder().ret(&zero);
fun.verify(LLVMVerifierFailureAction::LLVMPrintMessageAction);
self.generator.passer.run(&fun);
}
/// Long bull shit
fn gen_expr<'a: 'b, 'b>(&mut self,
term: &'a TaggedTerm,
symbols: &mut VarEnv<'b>)
-> LLVMValue {
Expand All @@ -151,7 +166,7 @@ impl<'i> LLVMEmit<'i> {
}
Let(ref var_decl, ref val, ref exp) => {
let &VarDecl(var, ref tyvar) = var_decl;
let block = self.builder().insert_block();
let block = self.builder().get_insert_block();
let fun = block.get_parent();

let init = self.gen_expr(val, symbols);
Expand All @@ -162,7 +177,7 @@ impl<'i> LLVMEmit<'i> {
self.builder().store(&init, &alloca);


with_var(symbols, var, alloca, |sym| self.gen_expr(exp.deref(), sym))
symbols.with_var(var, alloca, |sym| self.gen_expr(exp.deref(), sym))
}
ApplyCls(ref callee, ref args) => {
// get the pointer to closure struct
Expand Down Expand Up @@ -223,14 +238,8 @@ impl<'i> LLVMEmit<'i> {

// set function entry
let elm_ptr_fun = self.builder().struct_field_ptr(&cls_ptr, 0, "cls.fn");
let fn_ent = self.generator
.module
.get_or_add_function(cls.entry(), &fun_ty)
.into_value();
let ptr_ty = self.generator
.context
.get_int8_type()
.get_ptr(0);
let fn_ent = self.module().get_or_add_function(cls.entry(), &fun_ty).into_value();
let ptr_ty = self.context().get_int8_type().get_ptr(0);
let fn_ent_ptr = self.builder().bit_cast(&fn_ent, &ptr_ty, "fn");
self.builder().store(&fn_ent_ptr, &elm_ptr_fun);

Expand All @@ -254,21 +263,57 @@ impl<'i> LLVMEmit<'i> {
self.get_value_ptr(&val)
};

with_var(symbols,
var_decl.name(),
symbols.with_var(var_decl.name(),
cls_var,
|sym| self.gen_expr(exp, sym))
}
If(box ref c, box ref t, box ref f) => {
// unimplemented!()
let cond = self.gen_expr(c, symbols);
let zero = self.context().get_int1_const(0);

let blk = self.builder().get_insert_block();
let parent = blk.get_parent();
let then_blk = self.context().append_basic_block(&parent, "if.then");;
let else_blk = self.context().append_basic_block(&parent, "if.else");
let cont_blk = self.context().append_basic_block(&parent, "if.cont");

self.builder().cond_br(&cond, &then_blk, &else_blk);
self.builder().set_position_at_end(&then_blk);

let then = self.gen_expr(t, symbols);
self.builder().br(&cont_blk);

let then_end = self.builder().get_insert_block();

self.builder().set_position_at_end(&else_blk);

let els = self.gen_expr(f, symbols);
self.builder().br(&cont_blk);

let els_end = self.builder().get_insert_block();

self.builder().set_position_at_end(&cont_blk);

let ret_ty = then.get_type();
self.builder().phi_node(&ret_ty, &[(&then, &then_blk), (&els, &else_blk)], "if.res")
},
List(_) => unimplemented!(),
Unary(_, _) => unimplemented!(),
If(_, _, _) => unimplemented!(),
}
}

fn builder(&self) -> &LLVMBuilder {
&self.generator.builder
}

fn module(&self) -> &LLVMModule {
&self.generator.module
}

fn context(&self) -> &LLVMContext {
&self.generator.context
}
fn alloca_for_var(&mut self, fun: &LLVMFunction, var: &VarDecl) -> LLVMValue {
let &VarDecl(pname, ref ptype) = var;
let name = self.interner.trace(pname);
Expand Down
57 changes: 40 additions & 17 deletions src/codegen/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,43 @@ pub struct LLVMCodegen {
unique: usize,
}


pub fn get_llvm_op(op: BinOp, operand_ty: &Type) -> LLVMOperateBuild {
type LLVMOpBuilder<'a> = Fn(LLVMBuilderRef,
LLVMValueRef,
LLVMValueRef,
*const ::libc::c_char)
-> LLVMValueRef + 'a;
pub fn get_llvm_op<'a>(op: BinOp, operand_ty: &'a Type) -> Box<LLVMOpBuilder<'a>> {
use self::BinOp::*;
use self::Type::*;
if let &Con(ref ty_name) = operand_ty {
let name_ref = ty_name.as_str();
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!(),
box move |builder, lhs, rhs, dest|
if let &Con(ref ty_name) = operand_ty {
let name_ref = ty_name.as_str();
unsafe {
match (op, name_ref) {
(Add, "Int") => LLVMBuildAdd(builder, lhs, rhs, dest),
(Add, "Float") => LLVMBuildFAdd(builder, lhs, rhs, dest),
(Sub, "Int") => LLVMBuildSub(builder, lhs, rhs, dest),
(Sub, "Float") => LLVMBuildFSub(builder, lhs, rhs, dest),
(Mul, "Int") => LLVMBuildMul(builder, lhs, rhs, dest),
(Mul, "Float") => LLVMBuildFMul(builder, lhs, rhs, dest),
(Eq, "Int") => LLVMBuildICmp(builder, LLVMIntPredicate::LLVMIntEQ, lhs, rhs, dest),
(Lt, "Int") => LLVMBuildICmp(builder, LLVMIntPredicate::LLVMIntSLT, lhs, rhs, dest),
(Le, "Int") => LLVMBuildICmp(builder, LLVMIntPredicate::LLVMIntSLE, lhs, rhs, dest),
(Gt, "Int") => LLVMBuildICmp(builder, LLVMIntPredicate::LLVMIntSGT, lhs, rhs, dest),
(Ge, "Int") => LLVMBuildICmp(builder, LLVMIntPredicate::LLVMIntSGE, lhs, rhs, dest),
(Eq, "Double") => LLVMBuildFCmp(builder, LLVMRealPredicate::LLVMRealOEQ, lhs, rhs, dest),
(Lt, "Double") => LLVMBuildFCmp(builder, LLVMRealPredicate::LLVMRealOLT, lhs, rhs, dest),
(Le, "Double") => LLVMBuildFCmp(builder, LLVMRealPredicate::LLVMRealOLE, lhs, rhs, dest),
(Gt, "Double") => LLVMBuildFCmp(builder, LLVMRealPredicate::LLVMRealOGT, lhs, rhs, dest),
(Ge, "Double") => LLVMBuildFCmp(builder, LLVMRealPredicate::LLVMRealOGE, lhs, rhs, dest),
(Div, _) => LLVMBuildFDiv(builder, lhs, rhs, dest), // TODO: I dont know exactly which builder
(Rem, _) => LLVMBuildURem(builder, lhs, rhs, dest), // should I use for these two
_ => unimplemented!(),
}
}
} else {
unreachable!()
}
} else {
unreachable!()
}
}

pub fn is_primitive_type(t: &Type) -> bool {
Expand Down Expand Up @@ -108,6 +125,12 @@ impl LLVMCodegen {
}
}

pub fn get_main_type(&self) -> LLVMType {
let retty = self.context.get_int32_type();
let pty = self.context.get_void_type();
LLVMContext::get_function_type(&retty, &vec![pty], false)
}

pub fn get_llvm_type(&self, ty: &Type) -> LLVMType {
use self::Type::*;
match ty {
Expand Down
11 changes: 9 additions & 2 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
pub mod emit;
pub mod llvm;
mod emit;
mod llvm;

mod target;

pub use self::emit::*;
pub use self::llvm::*;
pub use self::target::*;

Loading

0 comments on commit 7d59d62

Please sign in to comment.