Skip to content
Snippets Groups Projects
Commit 2926fcb8 authored by Per Lindgren's avatar Per Lindgren
Browse files

Code generation for basic block

parent 97ec6d48
No related branches found
No related tags found
No related merge requests found
#![allow(unused_imports)]
#![allow(dead_code)]
use crust::{
ast::{Block, Cmd, Expr, Func, Op, Span, SpanExpr},
parse::{parse_block, parse_expr},
......@@ -10,10 +13,7 @@ use inkwell::{
module::Module,
passes::PassManager,
types::BasicTypeEnum,
values::{
BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue,
PointerValue,
},
values::{BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue},
FloatPredicate, OptimizationLevel,
};
use std::collections::HashMap;
......@@ -23,23 +23,23 @@ type ExprFunc = unsafe extern "C" fn() -> i32;
fn main() -> Result<(), Box<dyn Error>> {
let context = Context::create();
let mut module = context.create_module("expr");
let module = context.create_module("expr");
let builder = context.create_builder();
let fpm = PassManager::create(&module);
fpm.initialize();
let execution_engine =
module.create_jit_execution_engine(OptimizationLevel::None)?;
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;
match parse_block(Span::new(
"
{
let abba : i32 = 7;
let abba : mut i32 = 7;
abba = 5;
return 2 + abba
}
",
)) {
Ok((_, prog)) => {
println!("{:?}", &prog);
println!("ast : {:?}", &prog);
let u32_type = context.i32_type();
let fn_type = u32_type.fn_type(&[], false);
let function = module.add_function("expr", fn_type, None);
......@@ -54,18 +54,17 @@ fn main() -> Result<(), Box<dyn Error>> {
variables: HashMap::new(),
//&fpm,
};
let res = compiler.compile_block(prog);
// builder.build_return(Some(&res));
compiler.compile_block(prog);
let fun_expr: JitFunction<ExprFunc> =
unsafe { execution_engine.get_function("expr").ok().unwrap() };
unsafe {
println!("{}", fun_expr.call());
println!("\nexecution result : {}", fun_expr.call());
}
}
_ => panic!(),
}
println!("module: {}", module.print_to_string());
module.print_to_stderr();
Ok(())
}
......@@ -87,24 +86,33 @@ impl<'a> Compiler<'a> {
self.module.get_function(name)
}
/// Returns the `PointerValue` representing the variable `id`.
#[inline]
fn get_variable(&self, id: &str) -> &PointerValue {
match self.variables.get(id) {
Some(var) => var,
None => panic!(
"Could not find a matching variable, {} in {:?}",
id, self.variables
),
}
}
/// Returns the `FunctionValue` representing the function being compiled.
#[inline]
fn fn_value(&self) -> FunctionValue {
self.fn_value_opt.unwrap()
}
/// For now, returns an IntValue
/// Boolean is i1, single bit integers in LLVM
/// However we might to choose to store them as i8 or i32
fn compile_expr(&self, expr: &SpanExpr) -> IntValue {
match expr.1.clone() {
Expr::Id(id) => match self.variables.get(&id) {
Some(var) => {
Expr::Id(id) => {
let var = self.get_variable(&id);
self.builder.build_load(*var, &id).into_int_value()
}
None => panic!(
"Could not find a matching variable.
{} in {:?}",
id, self.variables
),
},
Expr::Num(i) => self.context.i32_type().const_int(i as u64, false),
Expr::BinOp(op, l, r) => {
......@@ -115,6 +123,7 @@ impl<'a> Compiler<'a> {
_ => unimplemented!(),
}
}
// Todo: Binop, Unop, Booleans, Function calls
_ => unimplemented!(),
}
}
......@@ -134,19 +143,20 @@ impl<'a> Compiler<'a> {
alloca
}
/// Compiles a command into (InstructionValue, b:bool)
/// `b` indicates that its a return value of the basic block
fn compile_cmd(&mut self, cmd: &Cmd) -> (InstructionValue, bool) {
// println!("{:?}", cmd);
match cmd {
// Cmd::Assign(lexp, rexp) => {
// let rval = eval_expr(rexp, mem, venv, fenv);
// println!("val {:?}", rval);
// let addr = eval_lvalue(lexp, mem, venv, fenv);
// // println!("lval {:?}", lval);
// // let addr = venv.get(&lval).unwrap();
// mem.Menv.insert(addr, rval);
// None
// }
Cmd::Assign((_, lexp), rexp) => match lexp {
Expr::Id(id) => {
let var = self.get_variable(id);
let rexp = self.compile_expr(rexp);
(self.builder.build_store(*var, rexp), false)
}
_ => panic!("we are bad"),
},
// -- TODO: This is code from my `old` interpreter
// Cmd::If(exp, then_block, opt_else) => {
// if get_bool(eval_expr(exp, mem, venv, fenv)) {
// eval_body(then_block.to_vec(), mem, venv, fenv)
......@@ -158,10 +168,12 @@ impl<'a> Compiler<'a> {
// }
// }
// }
// -- TODO: While
Cmd::Let(_, id, _, exp) => {
let exp = self.compile_expr(exp);
println!("\n-- let id.fragment {}\n", id.fragment);
// allocate a local variable (on the stack)
let alloca = self.create_entry_block_alloca(id.fragment);
// store the (initial) value
let store = self.builder.build_store(alloca, exp);
(store, false)
}
......@@ -176,28 +188,18 @@ impl<'a> Compiler<'a> {
pub fn compile_block(&mut self, cmds: Vec<Cmd>) -> InstructionValue {
for c in &cmds {
let (cmd, ret) = self.compile_cmd(c);
// early return (e.g., inside a loop/conditional)
if ret {
return cmd;
}
}
panic!();
}
}
// fn main() {
// let p = parse_prog(Span::new(
// "
// fn main() -> i32
// {
// let a : i32 = 1 + 2;
// a = a + 1;
// return a
// }
// ",
// ));
// println!("{:?}", &p);
// }
// TODO, function declarations
}
// SHAMELESSLY STOLEN FROM inkwell!!!!
// // ======================================================================================
// // COMPILER =============================================================================
// // ======================================================================================
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment