Skip to content

Commit

Permalink
LLVM code refactor; add type definition convert
Browse files Browse the repository at this point in the history
  • Loading branch information
nameoverflow committed Sep 14, 2017
1 parent 92dac93 commit 2db3111
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 287 deletions.
16 changes: 8 additions & 8 deletions src/codegen/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::ops::Deref;


pub trait EmitProvider {
fn gen_module<T>(&mut self, module: T) where T: IntoIterator<Item = Definition>;
fn gen_module<T>(&mut self, module: T) where T: IntoIterator<Item =FunDef>;
}

pub struct LLVMEmit(LLVMCodegen);
Expand All @@ -22,7 +22,7 @@ impl LLVMEmit {
pub fn dump(&mut self) {
self.0.module.dump()
}
pub fn gen_top_level(&mut self, def: &Definition, prelude: &VarEnv) {
pub fn gen_top_level(&mut self, def: &FunDef, prelude: &VarEnv) {
unsafe {
// A global function definition
let fun_type = def.ref_type();
Expand Down Expand Up @@ -70,13 +70,13 @@ impl LLVMEmit {
symtbl.insert(pname.as_str(), alloca);
}

if let Some(&VarDecl(ref last_name, ref _last_type)) = last_param {
let last_type_flat = _last_type.body().prod_to_vec();
if let Some(&VarDecl(ref last_name, ref last_type)) = last_param {
let flatten_count = last_type.body().prod_to_vec().len();
// 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() {
self.0.create_entry_block_alloca(&fun, last_name.as_str(), last_type.body());
// println!("fuck: {:?}", last_type_flat.clone());
for i in 0..flatten_count {
let idx_name = i.to_string();
let arg = fun.get_param(i + len_head);
let arg_name = last_name.clone() + idx_name.as_str();
Expand Down Expand Up @@ -179,5 +179,5 @@ impl LLVMEmit {
}

impl EmitProvider for LLVMCodegen {
fn gen_module<T>(&mut self, module: T) where T: IntoIterator<Item = Definition> {}
fn gen_module<T>(&mut self, module: T) where T: IntoIterator<Item =FunDef> {}
}
183 changes: 183 additions & 0 deletions src/codegen/llvm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
mod wrapper;

use std::char;
use std::ffi::{CString, NulError};
use std::io::{self, BufReader, Read, Write};
use std::ptr;
use std::collections::HashMap;
use std::iter::*;

use std::ops::Deref;

use core::*;
use internal::*;
use types::*;
use utils::*;

pub use codegen::llvm::wrapper::*;


#[derive(Debug, Clone)]
pub struct LLVMCodegen {
pub module: LLVMModule,
pub builder: LLVMBuilder,
pub context: LLVMContext,
unique: usize,
}


pub fn get_llvm_op(op: BinOp, operand_ty: &Type) -> LLVMOperateBuild {
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!(),
}
} else {
unreachable!()
}
}

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
}
}

impl LLVMCodegen {
pub fn new(name: &str) -> LLVMCodegen {
unsafe {
let context = LLVMContext::new();
let module = LLVMModule::in_ctx(name, &context);
let builder = LLVMBuilder::in_ctx(&context);
LLVMCodegen { module, context, builder, unique: 0 }
}
}


pub fn new_symbol(&mut self) -> Result<CString, NulError> {
let f = String::new() + self.unique.to_string().as_str();
self.unique = self.unique + 1;
CString::new(f)
}

pub fn new_symbol_string(&mut self) -> String {
let f = String::new() + self.unique.to_string().as_str();
self.unique = self.unique + 1;
f
}

fn get_closure_type(&self) -> LLVMType {
let ptr = self.context.get_int8_type().get_ptr(0);
let mem = vec![self.context.get_int16_type(), ptr];
self.context.get_struct_type(&mem, false)
}

/// Get a pointer type if the type is not primitive
pub fn get_llvm_type_or_ptr(&self, ty: &Type) -> LLVMType {
let ret = self.get_llvm_type(ty);
if !is_primitive_type(ty) {
ret.get_ptr(0)
} else {
ret
}
}

pub fn get_llvm_type(&self, ty: &Type) -> LLVMType {
use self::Type::*;
match ty {
&Con(ref n) => {
match n.as_str() {

// Primary types
"Int" => self.context.get_int32_type(),
"Float" => self.context.get_double_type(),
"Char" => self.context.get_int8_type(),

// User defined types
t => self.gen_user_type(t),
}
}
&Arr(box ref p, box ref ret) => {
// Type of parameters and returned value should be pointer if not primitive
let mut cls_type = self.get_closure_type().get_ptr(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);
LLVMContext::get_function_type(&retty, &llvm_psty, false)
}
&Void => self.context.get_void_type(),
&Prod(..) => {
let mut tys: Vec<_> = ty.prod_to_vec()
.iter()
.map(|t| self.get_llvm_type(t))
.collect();
self.context.get_struct_type(&tys, true)
}
&Comp(ref c, ref p) => unimplemented!(), // TODO: determine the type

&Var(..) => panic!("Unmaterized type"),
}
}

pub fn gen_lit(&mut self, lit: &Lit) -> LLVMValue {
use self::Lit::*;
match lit {
&Float(f) => self.context.get_double_const(f),
&Int(i) => self.context.get_int32_const(i),
&Bool(true) => self.context.get_int1_const(1),
&Bool(false) => self.context.get_int1_const(0),
// TODO: String represent
&Str(ref s) => unimplemented!(),
}
}

pub fn gen_user_type(&self, tyname: &str) -> LLVMType {
// TODO: make a user defined type definition
unimplemented!()
}

pub unsafe fn create_entry_block_alloca(&self,
fun: &LLVMFunction,
var_name: &str,
ty: &Type)
-> LLVMValue {
let builder = LLVMBuilder::in_ctx(&self.context);
let block = fun.get_entry_basic_block();
let fi = block.get_first_instr();
let llvm_ty = self.get_llvm_type(ty);
builder.set_position(&block, &fi);
builder.alloca(&llvm_ty, var_name)
}

pub fn bin_operator(&mut self,
op: BinOp,
lhs: LLVMValue,
rhs: LLVMValue,
operand_ty: &Type)
-> LLVMValue {
let fun = get_llvm_op(op, operand_ty);
unsafe {
LLVMValue::from_ref(fun(self.builder.raw_ptr(),
lhs.raw_ptr(),
rhs.raw_ptr(),
self.new_symbol().unwrap().into_raw()))
}
}
}
Loading

0 comments on commit 2db3111

Please sign in to comment.