diff --git a/reid-llvm-lib/src/builder.rs b/reid-llvm-lib/src/builder.rs index 04c366d..62648a1 100644 --- a/reid-llvm-lib/src/builder.rs +++ b/reid-llvm-lib/src/builder.rs @@ -3,6 +3,8 @@ use std::{cell::RefCell, rc::Rc}; +use llvm_sys::core::{LLVMBuildAlloca, LLVMBuildLoad2, LLVMBuildStore}; + use crate::{ BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type, util::match_types, @@ -250,6 +252,29 @@ impl Builder { } Ok(()) } + Alloca(_, _) => Ok(()), + Load(ptr, _) => { + if let Ok(ty) = ptr.get_type(&self) { + if let Type::Ptr(_) = ty { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + } + Store(ptr, _) => { + if let Ok(ty) = ptr.get_type(&self) { + if let Type::Ptr(_) = ty { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + } } } } @@ -298,7 +323,7 @@ impl InstructionValue { .function_data(&self.0.0) .params .get(*nth) - .copied() + .cloned() .ok_or(()), Constant(c) => Ok(c.get_type()), Add(lhs, rhs) => match_types(lhs, rhs, &builder), @@ -308,6 +333,9 @@ impl InstructionValue { ICmp(_, _, _) => Ok(Type::Bool), FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret), Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)), + Alloca(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))), + Load(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))), + Store(_, value) => value.get_type(builder), } } } @@ -347,6 +375,7 @@ impl Type { Type::U128 => true, Type::Bool => true, Type::Void => false, + Type::Ptr(_) => false, } } @@ -364,6 +393,7 @@ impl Type { Type::U128 => false, Type::Bool => false, Type::Void => false, + Type::Ptr(_) => false, } } } diff --git a/reid-llvm-lib/src/compile.rs b/reid-llvm-lib/src/compile.rs index 9a51167..6e5088f 100644 --- a/reid-llvm-lib/src/compile.rs +++ b/reid-llvm-lib/src/compile.rs @@ -333,6 +333,22 @@ impl InstructionHolder { ); phi } + Alloca(name, ty) => LLVMBuildAlloca( + module.builder_ref, + ty.as_llvm(module.context_ref), + into_cstring(name).as_ptr(), + ), + Load(ptr, ty) => LLVMBuildLoad2( + module.builder_ref, + ty.as_llvm(module.context_ref), + module.values.get(&ptr).unwrap().value_ref, + c"load".as_ptr(), + ), + Store(ptr, val) => LLVMBuildStore( + module.builder_ref, + module.values.get(&val).unwrap().value_ref, + module.values.get(&ptr).unwrap().value_ref, + ), } }; LLVMValue { @@ -428,6 +444,7 @@ impl Type { I128 | U128 => LLVMInt128TypeInContext(context), Bool => LLVMInt1TypeInContext(context), Void => LLVMVoidType(), + Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0), } } } diff --git a/reid-llvm-lib/src/debug.rs b/reid-llvm-lib/src/debug.rs index 1592473..5a693bf 100644 --- a/reid-llvm-lib/src/debug.rs +++ b/reid-llvm-lib/src/debug.rs @@ -97,6 +97,9 @@ impl Debug for Instr { Self::Phi(val) => fmt_call(f, &"Phi", &val), Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), Self::FunctionCall(fun, params) => fmt_call(f, fun, params), + Instr::Alloca(name, ty) => write!(f, "alloca<{:?}>({})", ty, name), + Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val), + Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val), } } } diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index b07826c..f161f5a 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -174,13 +174,17 @@ pub enum Instr { And(InstructionValue, InstructionValue), Phi(Vec), + Alloca(String, Type), + Load(InstructionValue, Type), + Store(InstructionValue, InstructionValue), + /// Integer Comparison ICmp(CmpPredicate, InstructionValue, InstructionValue), FunctionCall(FunctionValue, Vec), } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum Type { I8, I16, @@ -194,6 +198,7 @@ pub enum Type { U128, Bool, Void, + Ptr(Box), } #[derive(Debug, Clone, Hash)] diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index b806347..557b73a 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -133,7 +133,7 @@ pub struct Block( pub enum BlockLevelStatement { Let(LetStatement), /// Try to set a variable to a specified expression value - Set(String, Expression), + Set(String, Expression, TokenRange), Import { _i: ImportStatement, }, diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index d0fb3e8..fa49d06 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -363,8 +363,8 @@ impl Parse for BlockLevelStatement { Stmt::Return(ReturnType::Hard, exp) } _ => { - if let Ok(SetStatement(ident, expr)) = stream.parse() { - Stmt::Set(ident, expr) + if let Ok(SetStatement(ident, expr, range)) = stream.parse() { + Stmt::Set(ident, expr, range) } else { if let Ok(e) = stream.parse() { if stream.expect(Token::Semi).is_ok() { @@ -382,7 +382,7 @@ impl Parse for BlockLevelStatement { } #[derive(Debug)] -pub struct SetStatement(String, Expression); +pub struct SetStatement(String, Expression, TokenRange); impl Parse for SetStatement { fn parse(mut stream: TokenStream) -> Result { @@ -390,7 +390,7 @@ impl Parse for SetStatement { stream.expect(Token::Equals)?; let expr = stream.parse()?; stream.expect(Token::Semi)?; - Ok(Self(ident, expr)) + Ok(Self(ident, expr, stream.get_range().unwrap())) } else { Err(stream.expected_err("identifier")?)? } diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 8b9a08b..3667bb4 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -70,11 +70,22 @@ impl ast::Block { s_let.0.clone(), s_let.4.into(), ), + s_let.2, s_let.3.process(), ), s_let.4, ), - ast::BlockLevelStatement::Set(_, expression) => todo!(), + ast::BlockLevelStatement::Set(name, expression, range) => ( + StmtKind::Set( + VariableReference( + mir::TypeKind::Vague(mir::VagueType::Unknown), + name.clone(), + (*range).into(), + ), + expression.process(), + ), + *range, + ), ast::BlockLevelStatement::Import { _i } => todo!(), ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1), ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1), diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index 95de547..6eedc50 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -1,11 +1,12 @@ use std::{collections::HashMap, mem}; +use llvm_sys::core::LLVMBuildStore; use reid_lib::{ - Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term, - Type, builder::InstructionValue, + builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, + TerminatorKind as Term, Type, }; -use crate::mir::{self, TypeKind, VariableReference, types::ReturnType}; +use crate::mir::{self, types::ReturnType, TypeKind, VariableReference}; /// Context that contains all of the given modules as complete codegenerated /// LLIR that can then be finally compiled into LLVM IR. @@ -73,8 +74,14 @@ impl mir::Module { let mut entry = function.block("entry"); let mut stack_values = HashMap::new(); - for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() { - stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap()); + for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() { + stack_values.insert( + p_name.clone(), + StackValue( + StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()), + p_ty.get_type(), + ), + ); } let mut scope = Scope { @@ -114,7 +121,16 @@ pub struct Scope<'ctx, 'a> { function: &'ctx Function<'ctx>, block: Block<'ctx>, functions: &'a HashMap>, - stack_values: HashMap, + stack_values: HashMap, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StackValue(StackValueKind, Type); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StackValueKind { + Immutable(InstructionValue), + Mutable(InstructionValue), } impl<'ctx, 'a> Scope<'ctx, 'a> { @@ -141,11 +157,33 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { impl mir::Statement { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { match &self.0 { - mir::StmtKind::Let(VariableReference(_, name, _), expression) => { + mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => { let value = expression.codegen(scope).unwrap(); - scope.stack_values.insert(name.clone(), value); + scope.stack_values.insert( + name.clone(), + StackValue( + match mutable { + true => StackValueKind::Mutable(value), + false => StackValueKind::Immutable(value), + }, + ty.get_type(), + ), + ); None } + mir::StmtKind::Set(var, val) => { + if let Some(StackValue(kind, ty)) = scope.stack_values.get(&var.1).cloned() { + match kind { + StackValueKind::Immutable(ptr) => { + let expression = val.codegen(scope).unwrap(); + Some(scope.block.build(Instr::Store(ptr, expression)).unwrap()) + } + StackValueKind::Mutable(_) => panic!(""), + } + } else { + panic!("") + } + } // mir::StmtKind::If(if_expression) => if_expression.codegen(scope), mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Expression(expression) => expression.codegen(scope), @@ -218,7 +256,12 @@ impl mir::Expression { .stack_values .get(&varref.1) .expect("Variable reference not found?!"); - Some(v.clone()) + Some(match v.0 { + StackValueKind::Immutable(val) => val.clone(), + StackValueKind::Mutable(val) => { + scope.block.build(Instr::Load(val, v.1.clone())).unwrap() + } + }) } mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)), mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => { diff --git a/reid/src/mir/display.rs b/reid/src/mir/display.rs index fe7aea2..d24ff76 100644 --- a/reid/src/mir/display.rs +++ b/reid/src/mir/display.rs @@ -94,7 +94,16 @@ impl Display for Statement { impl Display for StmtKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Let(var, block) => write!(f, "let {} = {}", var, block), + Self::Let(var, mutable, block) => { + write!( + f, + "let{} {} = {}", + if *mutable { " mut" } else { "" }, + var, + block + ) + } + Self::Set(var, expr) => write!(f, "{} = {}", var, expr), Self::Import(n) => write!(f, "import {}", n), Self::Expression(exp) => Display::fmt(exp, f), } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 84ef2dc..82d96d8 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -257,8 +257,9 @@ pub struct Statement(pub StmtKind, pub Metadata); #[derive(Debug)] pub enum StmtKind { - /// Variable name+type, evaluation - Let(VariableReference, Expression), + /// Variable name++mutability+type, evaluation + Let(VariableReference, bool, Expression), + Set(VariableReference, Expression), Import(Import), Expression(Expression), } diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 5fb448e..90d234d 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -253,9 +253,10 @@ impl Block { impl Statement { fn pass(&mut self, pass: &mut T, state: &mut State, scope: &mut Scope) { match &mut self.0 { - StmtKind::Let(_, expression) => { + StmtKind::Let(_, mutable, expression) => { expression.pass(pass, state, scope); } + StmtKind::Set(variable_reference, expression) => {} // TODO StmtKind::Import(_) => todo!(), StmtKind::Expression(expression) => { expression.pass(pass, state, scope); @@ -265,10 +266,11 @@ impl Statement { pass.stmt(self, PassState::from(state, scope)); match &mut self.0 { - StmtKind::Let(variable_reference, _) => scope + StmtKind::Let(variable_reference, mutable, _) => scope .variables .set(variable_reference.1.clone(), variable_reference.0) .ok(), + StmtKind::Set(variable_reference, expression) => None, // TODO StmtKind::Import(_) => todo!(), StmtKind::Expression(_) => None, }; diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index ae63c95..5821d83 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -93,7 +93,8 @@ impl Block { for statement in &mut self.statements { let ret = match &mut statement.0 { - StmtKind::Let(variable_reference, expression) => { + // TODO + StmtKind::Let(variable_reference, mutable, expression) => { let res = expression.typecheck(&mut state, Some(variable_reference.0)); // If expression resolution itself was erronous, resolve as @@ -125,6 +126,7 @@ impl Block { state.ok(res, variable_reference.2); None } + StmtKind::Set(variable_reference, expression) => None, // TODO StmtKind::Import(_) => todo!(), StmtKind::Expression(expression) => { let res = expression.typecheck(&mut state, None); diff --git a/reid/src/mir/types.rs b/reid/src/mir/types.rs index b0f6fb6..369ec7f 100644 --- a/reid/src/mir/types.rs +++ b/reid/src/mir/types.rs @@ -26,8 +26,9 @@ impl ReturnType for Statement { use StmtKind::*; match &self.0 { Expression(e) => e.return_type(), + Set(_, _) => todo!(), Import(_) => Err(ReturnTypeOther::Import(self.1.range)), - Let(_, _) => Err(ReturnTypeOther::Let(self.1.range)), + Let(_, _, _) => Err(ReturnTypeOther::Let(self.1.range)), } } }