From 612b4d63a8d47d8bded0f438ebb859d155093733 Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 2 Aug 2023 18:19:30 +0300 Subject: [PATCH] Reorganize code --- src/codegen.rs | 188 ++++++++++++++----------------------------------- src/llvm_ir.rs | 150 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 67 +----------------- 3 files changed, 206 insertions(+), 199 deletions(-) create mode 100644 src/llvm_ir.rs diff --git a/src/codegen.rs b/src/codegen.rs index 89cf4e2..836cb07 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,147 +1,65 @@ -use std::ffi::CString; -use std::mem; +use std::collections::HashMap; -use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule}; +use crate::{ + llvm_ir::{IRBlock, IRModule, Value, ValueType}, + parser::{ + BinaryOperator, BlockLevelStatement, Expression, FunctionDefinition, Literal, + TopLevelStatement, + }, +}; -use crate::parser::Literal; +pub fn codegen(statements: Vec) { + let mut c = IRModule::new(); + for statement in statements { + match statement { + TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { + let mut named_vars: HashMap = HashMap::new(); -macro_rules! cstr { - ($string:expr) => { - core::ffi::CStr::from_bytes_with_nul_unchecked(concat!($string, "\0").as_bytes()).as_ptr() - }; -} + let func = c.create_func(sig.name, ValueType::I32); + let mut c_block = c.create_block(); -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ValueType { - I32, -} + for stmt in block.0 { + match stmt { + BlockLevelStatement::Let(let_statement) => { + let value = codegen_exp(&mut c_block, &named_vars, let_statement.1); + named_vars.insert(let_statement.0, value); + } + BlockLevelStatement::Return(_) => panic!("Should never exist!"), + BlockLevelStatement::Import(_) => {} + BlockLevelStatement::Expression(_) => {} + } + } -impl ValueType { - unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef { - match *self { - Self::I32 => LLVMInt32TypeInContext(codegen.context), - } - } -} - -#[derive(Clone, Debug)] -#[must_use = "value contains raw pointer and must be inserted somewhere"] -pub struct Value(ValueType, LLVMValueRef); - -fn into_cstring>(value: T) -> CString { - let string = value.into(); - unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } -} - -pub struct IRModule { - context: *mut LLVMContext, - module: *mut LLVMModule, - builder: *mut LLVMBuilder, -} - -impl IRModule { - pub fn new() -> IRModule { - unsafe { - // Set up a context, module and builder in that context. - let context = LLVMContextCreate(); - let module = LLVMModuleCreateWithNameInContext(cstr!("testmodule"), context); - let builder = LLVMCreateBuilderInContext(context); - - IRModule { - context, - module, - builder, + let value = if let Some(exp) = block.1 { + codegen_exp(&mut c_block, &named_vars, exp) + } else { + c_block.get_const(&Literal::I32(0)) + }; + func.add_definition(value, c_block); } + TopLevelStatement::Import(_) => {} } } +} - pub fn create_block(&mut self) -> IRBlock { - IRBlock::create("entry", self) - } - - pub fn create_func>(&mut self, name: T, return_type: ValueType) -> IRFunction { - unsafe { - let mut argts = []; - let func_type = LLVMFunctionType( - return_type.get_llvm_type(self), - argts.as_mut_ptr(), - argts.len() as u32, - 0, - ); - - let anon_func = LLVMAddFunction(self.module, into_cstring(name).as_ptr(), func_type); - IRFunction { - value: Value(return_type, anon_func), +fn codegen_exp( + c_block: &mut IRBlock, + named_vars: &HashMap, + expression: Expression, +) -> Value { + use Expression::*; + match expression { + Binop(op, lhs, rhs) => match op { + BinaryOperator::Add => { + let lhs = codegen_exp(c_block, named_vars, *lhs); + let rhs = codegen_exp(c_block, named_vars, *rhs); + c_block.add(lhs, rhs).unwrap() } - } - } -} - -impl Drop for IRModule { - fn drop(&mut self) { - // Clean up. Values created in the context mostly get cleaned up there. - unsafe { - LLVMDisposeBuilder(self.builder); - LLVMDumpModule(self.module); - LLVMDisposeModule(self.module); - LLVMContextDispose(self.context); - } - } -} - -pub struct IRFunction { - value: Value, -} - -impl IRFunction { - pub fn add_definition(self, ret: Value, block: IRBlock) { - unsafe { - LLVMAppendExistingBasicBlock(self.value.1, block.blockref); - LLVMBuildRet(block.codegen.builder, ret.1); - } - } -} - -pub struct IRBlock<'a> { - codegen: &'a mut IRModule, - blockref: LLVMBasicBlockRef, -} - -impl<'a> IRBlock<'a> { - fn create>(name: T, codegen: &'a mut IRModule) -> IRBlock<'a> { - unsafe { - let blockref = - LLVMCreateBasicBlockInContext(codegen.context, into_cstring(name).as_ptr()); - LLVMPositionBuilderAtEnd(codegen.builder, blockref); - IRBlock { codegen, blockref } - } - } - - pub fn get_const(&mut self, literal_type: &Literal) -> Value { - unsafe { - match *literal_type { - Literal::I32(v) => Value( - ValueType::I32, - LLVMConstInt( - LLVMInt32TypeInContext(self.codegen.context), - mem::transmute(v as i64), - 1, - ), - ), - } - } - } - - pub fn add(&mut self, lhs: Value, rhs: Value) -> Result { - unsafe { - if lhs.0 == rhs.0 { - Ok(Value( - lhs.0, - LLVMBuildAdd(self.codegen.builder, lhs.1, rhs.1, cstr!("tmpadd")), - )) - } else { - Err(()) - } - } + BinaryOperator::Mult => panic!("Not implemented!"), + }, + BlockExpr(_) => panic!("Not implemented!"), + FunctionCall(_) => panic!("Not implemented!"), + VariableName(name) => named_vars.get(&name).cloned().unwrap(), + Literal(lit) => c_block.get_const(&lit), } } diff --git a/src/llvm_ir.rs b/src/llvm_ir.rs new file mode 100644 index 0000000..c23b3fe --- /dev/null +++ b/src/llvm_ir.rs @@ -0,0 +1,150 @@ +use std::ffi::CString; +use std::mem; + +use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule}; + +use crate::parser::Literal; + +macro_rules! cstr { + ($string:expr) => { + core::ffi::CStr::from_bytes_with_nul_unchecked(concat!($string, "\0").as_bytes()).as_ptr() + }; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ValueType { + I32, +} + +impl ValueType { + unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef { + match *self { + Self::I32 => LLVMInt32TypeInContext(codegen.context), + } + } +} + +#[derive(Clone, Debug)] +#[must_use = "value contains raw pointer and must be inserted somewhere"] +pub struct Value(ValueType, LLVMValueRef); + +fn into_cstring>(value: T) -> CString { + let string = value.into(); + unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } +} + +pub struct IRModule { + context: *mut LLVMContext, + module: *mut LLVMModule, + builder: *mut LLVMBuilder, +} + +impl IRModule { + pub fn new() -> IRModule { + unsafe { + // Set up a context, module and builder in that context. + let context = LLVMContextCreate(); + let module = LLVMModuleCreateWithNameInContext(cstr!("testmodule"), context); + let builder = LLVMCreateBuilderInContext(context); + + IRModule { + context, + module, + builder, + } + } + } + + pub fn create_block(&mut self) -> IRBlock { + IRBlock::create("entry", self) + } + + pub fn create_func>(&mut self, name: T, return_type: ValueType) -> IRFunction { + unsafe { + let mut argts = []; + let func_type = LLVMFunctionType( + return_type.get_llvm_type(self), + argts.as_mut_ptr(), + argts.len() as u32, + 0, + ); + + let anon_func = LLVMAddFunction(self.module, into_cstring(name).as_ptr(), func_type); + IRFunction { + value: Value(return_type, anon_func), + } + } + } +} + +impl Drop for IRModule { + fn drop(&mut self) { + // Clean up. Values created in the context mostly get cleaned up there. + unsafe { + LLVMDisposeBuilder(self.builder); + LLVMDumpModule(self.module); + LLVMDisposeModule(self.module); + LLVMContextDispose(self.context); + } + } +} + +pub struct IRFunction { + value: Value, +} + +impl IRFunction { + pub fn add_definition(self, ret: Value, block: IRBlock) { + unsafe { + LLVMAppendExistingBasicBlock(self.value.1, block.blockref); + LLVMBuildRet(block.module.builder, ret.1); + } + } +} + +pub struct IRBlock<'a> { + module: &'a mut IRModule, + blockref: LLVMBasicBlockRef, +} + +impl<'a> IRBlock<'a> { + fn create>(name: T, codegen: &'a mut IRModule) -> IRBlock<'a> { + unsafe { + let blockref = + LLVMCreateBasicBlockInContext(codegen.context, into_cstring(name).as_ptr()); + LLVMPositionBuilderAtEnd(codegen.builder, blockref); + IRBlock { + module: codegen, + blockref, + } + } + } + + pub fn get_const(&mut self, literal_type: &Literal) -> Value { + unsafe { + match *literal_type { + Literal::I32(v) => Value( + ValueType::I32, + LLVMConstInt( + LLVMInt32TypeInContext(self.module.context), + mem::transmute(v as i64), + 1, + ), + ), + } + } + } + + pub fn add(&mut self, lhs: Value, rhs: Value) -> Result { + unsafe { + if lhs.0 == rhs.0 { + Ok(Value( + lhs.0, + LLVMBuildAdd(self.module.builder, lhs.1, rhs.1, cstr!("tmpadd")), + )) + } else { + Err(()) + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 0d174f5..3a53ad3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,4 @@ -use std::collections::HashMap; - -use codegen::IRBlock; -use parser::Expression; - -use crate::{ - codegen::{IRModule, Value}, - lexer::Token, - parser::{FunctionDefinition, Literal, TopLevelStatement}, - token_stream::TokenStream, -}; +use crate::{lexer::Token, parser::TopLevelStatement, token_stream::TokenStream}; pub static EASIEST: &str = include_str!("../reid/easiest.reid"); pub static EASY: &str = include_str!("../reid/easy.reid"); @@ -17,6 +7,7 @@ pub static HARD: &str = include_str!("../reid/hard.reid"); mod codegen; mod lexer; +mod llvm_ir; mod parser; mod token_stream; @@ -41,57 +32,5 @@ fn main() { statements.push(statement); } - let mut c = IRModule::new(); - for statement in statements { - match statement { - TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { - let mut named_vars: HashMap = HashMap::new(); - - let func = c.create_func(sig.name, codegen::ValueType::I32); - let mut c_block = c.create_block(); - - for stmt in block.0 { - match stmt { - parser::BlockLevelStatement::Let(let_statement) => { - let value = codegen_exp(&mut c_block, &named_vars, let_statement.1); - named_vars.insert(let_statement.0, value); - } - parser::BlockLevelStatement::Return(_) => panic!("Should never exist!"), - parser::BlockLevelStatement::Import(_) => {} - parser::BlockLevelStatement::Expression(_) => {} - } - } - - let value = if let Some(exp) = block.1 { - codegen_exp(&mut c_block, &named_vars, exp) - } else { - c_block.get_const(&Literal::I32(0)) - }; - func.add_definition(value, c_block); - } - TopLevelStatement::Import(_) => {} - } - } -} - -fn codegen_exp( - c_block: &mut IRBlock, - named_vars: &HashMap, - expression: Expression, -) -> Value { - use parser::Expression::*; - match expression { - Binop(op, lhs, rhs) => match op { - parser::BinaryOperator::Add => { - let lhs = codegen_exp(c_block, named_vars, *lhs); - let rhs = codegen_exp(c_block, named_vars, *rhs); - c_block.add(lhs, rhs).unwrap() - } - parser::BinaryOperator::Mult => panic!("Not implemented!"), - }, - BlockExpr(_) => panic!("Not implemented!"), - FunctionCall(_) => panic!("Not implemented!"), - VariableName(name) => named_vars.get(&name).cloned().unwrap(), - Literal(lit) => c_block.get_const(&lit), - } + codegen::codegen(statements); }