(broken) add part 1 of mutability

This commit is contained in:
Sofia 2025-07-12 02:38:31 +03:00
parent 85b2ebf04a
commit 14e0dcbe15
13 changed files with 148 additions and 24 deletions

View File

@ -3,6 +3,8 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use llvm_sys::core::{LLVMBuildAlloca, LLVMBuildLoad2, LLVMBuildStore};
use crate::{ use crate::{
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type, BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
util::match_types, util::match_types,
@ -250,6 +252,29 @@ impl Builder {
} }
Ok(()) 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) .function_data(&self.0.0)
.params .params
.get(*nth) .get(*nth)
.copied() .cloned()
.ok_or(()), .ok_or(()),
Constant(c) => Ok(c.get_type()), Constant(c) => Ok(c.get_type()),
Add(lhs, rhs) => match_types(lhs, rhs, &builder), Add(lhs, rhs) => match_types(lhs, rhs, &builder),
@ -308,6 +333,9 @@ impl InstructionValue {
ICmp(_, _, _) => Ok(Type::Bool), ICmp(_, _, _) => Ok(Type::Bool),
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret), FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)), 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::U128 => true,
Type::Bool => true, Type::Bool => true,
Type::Void => false, Type::Void => false,
Type::Ptr(_) => false,
} }
} }
@ -364,6 +393,7 @@ impl Type {
Type::U128 => false, Type::U128 => false,
Type::Bool => false, Type::Bool => false,
Type::Void => false, Type::Void => false,
Type::Ptr(_) => false,
} }
} }
} }

View File

@ -333,6 +333,22 @@ impl InstructionHolder {
); );
phi 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 { LLVMValue {
@ -428,6 +444,7 @@ impl Type {
I128 | U128 => LLVMInt128TypeInContext(context), I128 | U128 => LLVMInt128TypeInContext(context),
Bool => LLVMInt1TypeInContext(context), Bool => LLVMInt1TypeInContext(context),
Void => LLVMVoidType(), Void => LLVMVoidType(),
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
} }
} }
} }

View File

@ -97,6 +97,9 @@ impl Debug for Instr {
Self::Phi(val) => fmt_call(f, &"Phi", &val), Self::Phi(val) => fmt_call(f, &"Phi", &val),
Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
Self::FunctionCall(fun, params) => fmt_call(f, fun, params), 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),
} }
} }
} }

View File

@ -174,13 +174,17 @@ pub enum Instr {
And(InstructionValue, InstructionValue), And(InstructionValue, InstructionValue),
Phi(Vec<InstructionValue>), Phi(Vec<InstructionValue>),
Alloca(String, Type),
Load(InstructionValue, Type),
Store(InstructionValue, InstructionValue),
/// Integer Comparison /// Integer Comparison
ICmp(CmpPredicate, InstructionValue, InstructionValue), ICmp(CmpPredicate, InstructionValue, InstructionValue),
FunctionCall(FunctionValue, Vec<InstructionValue>), FunctionCall(FunctionValue, Vec<InstructionValue>),
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Type { pub enum Type {
I8, I8,
I16, I16,
@ -194,6 +198,7 @@ pub enum Type {
U128, U128,
Bool, Bool,
Void, Void,
Ptr(Box<Type>),
} }
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]

View File

@ -133,7 +133,7 @@ pub struct Block(
pub enum BlockLevelStatement { pub enum BlockLevelStatement {
Let(LetStatement), Let(LetStatement),
/// Try to set a variable to a specified expression value /// Try to set a variable to a specified expression value
Set(String, Expression), Set(String, Expression, TokenRange),
Import { Import {
_i: ImportStatement, _i: ImportStatement,
}, },

View File

@ -363,8 +363,8 @@ impl Parse for BlockLevelStatement {
Stmt::Return(ReturnType::Hard, exp) Stmt::Return(ReturnType::Hard, exp)
} }
_ => { _ => {
if let Ok(SetStatement(ident, expr)) = stream.parse() { if let Ok(SetStatement(ident, expr, range)) = stream.parse() {
Stmt::Set(ident, expr) Stmt::Set(ident, expr, range)
} else { } else {
if let Ok(e) = stream.parse() { if let Ok(e) = stream.parse() {
if stream.expect(Token::Semi).is_ok() { if stream.expect(Token::Semi).is_ok() {
@ -382,7 +382,7 @@ impl Parse for BlockLevelStatement {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct SetStatement(String, Expression); pub struct SetStatement(String, Expression, TokenRange);
impl Parse for SetStatement { impl Parse for SetStatement {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
@ -390,7 +390,7 @@ impl Parse for SetStatement {
stream.expect(Token::Equals)?; stream.expect(Token::Equals)?;
let expr = stream.parse()?; let expr = stream.parse()?;
stream.expect(Token::Semi)?; stream.expect(Token::Semi)?;
Ok(Self(ident, expr)) Ok(Self(ident, expr, stream.get_range().unwrap()))
} else { } else {
Err(stream.expected_err("identifier")?)? Err(stream.expected_err("identifier")?)?
} }

View File

@ -70,11 +70,22 @@ impl ast::Block {
s_let.0.clone(), s_let.0.clone(),
s_let.4.into(), s_let.4.into(),
), ),
s_let.2,
s_let.3.process(), s_let.3.process(),
), ),
s_let.4, 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::Import { _i } => todo!(),
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1), ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1), ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),

View File

@ -1,11 +1,12 @@
use std::{collections::HashMap, mem}; use std::{collections::HashMap, mem};
use llvm_sys::core::LLVMBuildStore;
use reid_lib::{ use reid_lib::{
Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term, builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
Type, builder::InstructionValue, 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 /// Context that contains all of the given modules as complete codegenerated
/// LLIR that can then be finally compiled into LLVM IR. /// 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 entry = function.block("entry");
let mut stack_values = HashMap::new(); let mut stack_values = HashMap::new();
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() { for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap()); stack_values.insert(
p_name.clone(),
StackValue(
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
p_ty.get_type(),
),
);
} }
let mut scope = Scope { let mut scope = Scope {
@ -114,7 +121,16 @@ pub struct Scope<'ctx, 'a> {
function: &'ctx Function<'ctx>, function: &'ctx Function<'ctx>,
block: Block<'ctx>, block: Block<'ctx>,
functions: &'a HashMap<String, Function<'ctx>>, functions: &'a HashMap<String, Function<'ctx>>,
stack_values: HashMap<String, InstructionValue>, stack_values: HashMap<String, StackValue>,
}
#[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> { impl<'ctx, 'a> Scope<'ctx, 'a> {
@ -141,11 +157,33 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
impl mir::Statement { impl mir::Statement {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
match &self.0 { match &self.0 {
mir::StmtKind::Let(VariableReference(_, name, _), expression) => { mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => {
let value = expression.codegen(scope).unwrap(); 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 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::If(if_expression) => if_expression.codegen(scope),
mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Import(_) => todo!(),
mir::StmtKind::Expression(expression) => expression.codegen(scope), mir::StmtKind::Expression(expression) => expression.codegen(scope),
@ -218,7 +256,12 @@ impl mir::Expression {
.stack_values .stack_values
.get(&varref.1) .get(&varref.1)
.expect("Variable reference not found?!"); .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::Literal(lit) => Some(lit.as_const(&mut scope.block)),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => { mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {

View File

@ -94,7 +94,16 @@ impl Display for Statement {
impl Display for StmtKind { impl Display for StmtKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { 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::Import(n) => write!(f, "import {}", n),
Self::Expression(exp) => Display::fmt(exp, f), Self::Expression(exp) => Display::fmt(exp, f),
} }

View File

@ -257,8 +257,9 @@ pub struct Statement(pub StmtKind, pub Metadata);
#[derive(Debug)] #[derive(Debug)]
pub enum StmtKind { pub enum StmtKind {
/// Variable name+type, evaluation /// Variable name++mutability+type, evaluation
Let(VariableReference, Expression), Let(VariableReference, bool, Expression),
Set(VariableReference, Expression),
Import(Import), Import(Import),
Expression(Expression), Expression(Expression),
} }

View File

@ -253,9 +253,10 @@ impl Block {
impl Statement { impl Statement {
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
match &mut self.0 { match &mut self.0 {
StmtKind::Let(_, expression) => { StmtKind::Let(_, mutable, expression) => {
expression.pass(pass, state, scope); expression.pass(pass, state, scope);
} }
StmtKind::Set(variable_reference, expression) => {} // TODO
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => { StmtKind::Expression(expression) => {
expression.pass(pass, state, scope); expression.pass(pass, state, scope);
@ -265,10 +266,11 @@ impl Statement {
pass.stmt(self, PassState::from(state, scope)); pass.stmt(self, PassState::from(state, scope));
match &mut self.0 { match &mut self.0 {
StmtKind::Let(variable_reference, _) => scope StmtKind::Let(variable_reference, mutable, _) => scope
.variables .variables
.set(variable_reference.1.clone(), variable_reference.0) .set(variable_reference.1.clone(), variable_reference.0)
.ok(), .ok(),
StmtKind::Set(variable_reference, expression) => None, // TODO
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(_) => None, StmtKind::Expression(_) => None,
}; };

View File

@ -93,7 +93,8 @@ impl Block {
for statement in &mut self.statements { for statement in &mut self.statements {
let ret = match &mut statement.0 { 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)); let res = expression.typecheck(&mut state, Some(variable_reference.0));
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
@ -125,6 +126,7 @@ impl Block {
state.ok(res, variable_reference.2); state.ok(res, variable_reference.2);
None None
} }
StmtKind::Set(variable_reference, expression) => None, // TODO
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => { StmtKind::Expression(expression) => {
let res = expression.typecheck(&mut state, None); let res = expression.typecheck(&mut state, None);

View File

@ -26,8 +26,9 @@ impl ReturnType for Statement {
use StmtKind::*; use StmtKind::*;
match &self.0 { match &self.0 {
Expression(e) => e.return_type(), Expression(e) => e.return_type(),
Set(_, _) => todo!(),
Import(_) => Err(ReturnTypeOther::Import(self.1.range)), Import(_) => Err(ReturnTypeOther::Import(self.1.range)),
Let(_, _) => Err(ReturnTypeOther::Let(self.1.range)), Let(_, _, _) => Err(ReturnTypeOther::Let(self.1.range)),
} }
} }
} }