Make codegen return StackValues instead of instructions

This commit is contained in:
Sofia 2025-07-19 15:46:34 +03:00
parent bcad156ef0
commit d64cf750b1

View File

@ -99,21 +99,42 @@ pub struct StackFunction<'ctx> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StackValue(StackValueKind, TypeKind);
impl StackValue {
fn instr(&self) -> InstructionValue {
self.0.instr()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StackValueKind {
Immutable(InstructionValue),
Mutable(InstructionValue),
Any(InstructionValue),
Literal(InstructionValue),
}
impl StackValueKind {
unsafe fn get_inner(&self) -> InstructionValue {
fn instr(&self) -> InstructionValue {
match &self {
StackValueKind::Immutable(val) => *val,
StackValueKind::Mutable(val) => *val,
StackValueKind::Any(val) => *val,
StackValueKind::Literal(val) => *val,
}
}
fn derive(&self, instr: InstructionValue) -> StackValueKind {
match &self {
StackValueKind::Immutable(_) => StackValueKind::Immutable(instr),
StackValueKind::Mutable(_) => StackValueKind::Mutable(instr),
StackValueKind::Literal(_) => StackValueKind::Literal(instr),
}
}
fn map<F>(&self, lambda: F) -> StackValueKind
where
F: FnOnce(InstructionValue) -> InstructionValue,
{
self.derive(lambda(self.instr()))
}
}
impl<'ctx, 'a> Scope<'ctx, 'a> {
@ -369,7 +390,7 @@ impl mir::Module {
mir::FunctionDefinitionKind::Local(block, _) => {
let state = State::default();
if let Some(ret) = block.codegen(&mut scope, &state) {
scope.block.terminate(Term::Ret(ret)).unwrap();
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
} else {
if !scope.block.delete_if_unused().unwrap() {
// Add a void return just in case if the block
@ -397,13 +418,13 @@ impl mir::Block {
&self,
mut scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Option<InstructionValue> {
) -> Option<StackValue> {
for stmt in &self.statements {
stmt.codegen(&mut scope, state).map(|s| {
if let Some(debug) = &scope.debug {
let location = stmt.1.into_debug(scope.tokens).unwrap();
let loc_val = debug.info.location(&debug.scope, location);
s.with_location(&mut scope.block, loc_val);
s.instr().with_location(&mut scope.block, loc_val);
}
});
}
@ -412,7 +433,7 @@ impl mir::Block {
match kind {
mir::ReturnKind::Hard => {
let ret = expr.codegen(&mut scope, &state)?;
scope.block.terminate(Term::Ret(ret)).unwrap();
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
None
}
mir::ReturnKind::Soft => expr.codegen(&mut scope, state),
@ -424,11 +445,7 @@ impl mir::Block {
}
impl mir::Statement {
fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Option<InstructionValue> {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
let location = self.1.into_debug(scope.tokens).unwrap();
let location = scope
.debug
@ -450,7 +467,7 @@ impl mir::Statement {
let store = scope
.block
.build(Instr::Store(alloca, value))
.build(Instr::Store(alloca, value.instr()))
.unwrap()
.maybe_location(&mut scope.block, location);
@ -483,12 +500,12 @@ impl mir::Statement {
InstructionDebugRecordData {
variable: var,
location,
kind: DebugRecordKind::Declare(value),
kind: DebugRecordKind::Declare(value.instr()),
scope: debug.scope,
},
);
}
StackValueKind::Any(_) => {}
StackValueKind::Literal(_) => {}
}
}
None
@ -500,13 +517,23 @@ impl mir::Statement {
let rhs_value = rhs.codegen(scope, state)?;
Some(
match lhs_value.0 {
StackValueKind::Immutable(_) => {
panic!("Tried to assign to immutable!")
}
StackValueKind::Mutable(instr) => {
scope
.block
.build(Instr::Store(lhs_value, rhs_value))
.build(Instr::Store(instr, rhs_value.instr()))
.unwrap()
.maybe_location(&mut scope.block, location),
)
.maybe_location(&mut scope.block, location);
}
StackValueKind::Literal(_) => {
panic!("Tried to assign to a literal!")
}
};
None
}
mir::StmtKind::Import(_) => todo!(),
mir::StmtKind::Expression(expression) => expression.codegen(scope, state),
@ -515,11 +542,7 @@ impl mir::Statement {
}
impl mir::Expression {
fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Option<InstructionValue> {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
let location = if let Some(debug) = &scope.debug {
Some(
debug
@ -530,7 +553,7 @@ impl mir::Expression {
None
};
match &self.0 {
let value = match &self.0 {
mir::ExprKind::Variable(varref) => {
varref.0.known().expect("variable type unknown");
let v = scope
@ -538,18 +561,23 @@ impl mir::Expression {
.get(&varref.1)
.expect("Variable reference not found?!");
dbg!(varref);
Some(match v.0 {
StackValueKind::Immutable(val) | StackValueKind::Mutable(val) => scope
Some(StackValue(
v.0.map(|val| {
scope
.block
.build(Instr::Load(
val,
v.1.get_type(scope.type_values, scope.types),
))
.unwrap(),
_ => panic!("Found an unknown-mutable variable!"),
})
.unwrap()
}),
varref.0.clone(),
))
}
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
mir::ExprKind::Literal(lit) => Some(StackValue(
StackValueKind::Literal(lit.as_const(&mut scope.block)),
lit.as_type(),
)),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
lhs_exp
.return_type()
@ -566,41 +594,58 @@ impl mir::Expression {
let lhs = lhs_exp
.codegen(scope, state)
.expect("lhs has no return value");
.expect("lhs has no return value")
.instr();
let rhs = rhs_exp
.codegen(scope, state)
.expect("rhs has no return value");
Some(match binop {
mir::BinaryOperator::Add => scope.block.build(Instr::Add(lhs, rhs)).unwrap(),
mir::BinaryOperator::Minus => scope.block.build(Instr::Sub(lhs, rhs)).unwrap(),
mir::BinaryOperator::Mult => scope.block.build(Instr::Mult(lhs, rhs)).unwrap(),
mir::BinaryOperator::And => scope.block.build(Instr::And(lhs, rhs)).unwrap(),
.expect("rhs has no return value")
.instr();
Some(StackValue(
StackValueKind::Immutable(match binop {
mir::BinaryOperator::Add => {
scope.block.build(Instr::Add(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Minus => {
scope.block.build(Instr::Sub(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Mult => {
scope.block.build(Instr::Mult(lhs, rhs)).unwrap()
}
mir::BinaryOperator::And => {
scope.block.build(Instr::And(lhs, rhs)).unwrap()
}
mir::BinaryOperator::Cmp(l) => scope
.block
.build(Instr::ICmp(l.int_predicate(), lhs, rhs))
.unwrap(),
})
}),
TypeKind::U32,
))
}
mir::ExprKind::FunctionCall(call) => {
call.return_type
let ret_type = call
.return_type
.known()
.expect("function return type unknown");
let params = call
.parameters
.iter()
.map(|e| e.codegen(scope, state).unwrap())
.map(|e| e.codegen(scope, state).unwrap().instr())
.collect();
let callee = scope
.functions
.get(&call.name)
.expect("function not found!");
Some(
Some(StackValue(
StackValueKind::Immutable(
scope
.block
.build(Instr::FunctionCall(callee.ir.value(), params))
.unwrap(),
)
),
ret_type,
))
}
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state),
mir::ExprKind::Block(block) => {
@ -616,16 +661,17 @@ impl mir::Expression {
}
}
mir::ExprKind::Indexed(expression, val_t, idx_expr) => {
let array = expression
let StackValue(kind, ty) = expression
.codegen(scope, &state.load(true))
.expect("array returned none!");
let idx = idx_expr
.codegen(scope, &state.load(true))
.expect("index returned none!");
.expect("index returned none!")
.instr();
let mut ptr = scope
.block
.build(Instr::GetElemPtr(array, vec![idx]))
.build(Instr::GetElemPtr(kind.instr(), vec![idx]))
.unwrap()
.maybe_location(&mut scope.block, location);
@ -640,16 +686,25 @@ impl mir::Expression {
.maybe_location(&mut scope.block, location);
}
Some(ptr)
let TypeKind::Array(elem_ty, _) = ty else {
panic!();
};
Some(StackValue(kind.derive(ptr), *elem_ty))
}
mir::ExprKind::Array(expressions) => {
let instr_list = expressions
let stack_value_list = expressions
.iter()
.map(|e| e.codegen(scope, state).unwrap())
.collect::<Vec<_>>();
let instr_t = expressions
let instr_list = stack_value_list
.iter()
.map(|e| e.return_type().unwrap().1)
.map(|s| s.instr())
.collect::<Vec<_>>();
let instr_t = stack_value_list
.iter()
.map(|s| s.1.clone())
.next()
.unwrap_or(TypeKind::Void);
@ -679,28 +734,27 @@ impl mir::Expression {
.maybe_location(&mut scope.block, location);
}
Some(array)
Some(StackValue(
StackValueKind::Literal(array),
TypeKind::Array(Box::new(instr_t), instr_list.len() as u64),
))
}
mir::ExprKind::Accessed(expression, type_kind, field) => {
let struct_val = expression.codegen(scope, &mut state.load(true)).unwrap();
let struct_ty = expression
.return_type()
.map(|r| r.1.known())
.unwrap()
.unwrap();
let TypeKind::CustomType(name) = struct_ty.deref_borrow() else {
let TypeKind::CustomType(name) = struct_val.1.deref_borrow() else {
panic!("tried accessing non-custom-type");
};
let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&name).unwrap();
let TypeDefinitionKind::Struct(struct_ty) =
scope.get_typedef(&name).unwrap().clone();
let idx = struct_ty.find_index(field).unwrap();
let mut value = scope
.block
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
.unwrap()
.maybe_location(&mut scope.block, location);
.build(Instr::GetStructElemPtr(struct_val.instr(), idx as u32))
.unwrap();
// value.maybe_location(&mut scope.block, location);
if state.should_load {
value = scope
@ -712,7 +766,10 @@ impl mir::Expression {
.unwrap();
}
Some(value)
Some(StackValue(
struct_val.0.derive(value),
struct_ty.get_field_ty(&field).unwrap().clone(),
))
}
mir::ExprKind::Struct(name, items) => {
let struct_ptr = scope
@ -733,25 +790,27 @@ impl mir::Expression {
if let Some(val) = exp.codegen(scope, state) {
scope
.block
.build(Instr::Store(elem_ptr, val))
.build(Instr::Store(elem_ptr, val.instr()))
.unwrap()
.maybe_location(&mut scope.block, location);
}
}
Some(struct_ptr)
Some(StackValue(
StackValueKind::Literal(struct_ptr),
TypeKind::CustomType(name.clone()),
))
}
};
if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location);
}
.map(|i| i.maybe_location(&mut scope.block, location))
value
}
}
impl mir::IfExpression {
fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Option<InstructionValue> {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
let condition = self.0.codegen(scope, state).unwrap();
// Create blocks
@ -792,7 +851,7 @@ impl mir::IfExpression {
scope
.block
.terminate(Term::CondBr(condition, then_bb, else_bb))
.terminate(Term::CondBr(condition.instr(), then_bb, else_bb))
.unwrap();
let opt = else_block.codegen(&mut else_scope, state);
@ -807,7 +866,7 @@ impl mir::IfExpression {
else_b.terminate(Term::Br(after_bb)).unwrap();
scope
.block
.terminate(Term::CondBr(condition, then_bb, after_bb))
.terminate(Term::CondBr(condition.instr(), then_bb, after_bb))
.unwrap();
None
};
@ -819,8 +878,29 @@ impl mir::IfExpression {
None
} else {
let mut incoming = Vec::from(then_res.as_slice());
incoming.extend(else_res);
Some(scope.block.build(Instr::Phi(incoming)).unwrap())
incoming.extend(else_res.clone());
let instr = scope
.block
.build(Instr::Phi(incoming.iter().map(|i| i.instr()).collect()))
.unwrap();
use StackValueKind::*;
let value = match (then_res, else_res) {
(None, None) => StackValue(StackValueKind::Immutable(instr), TypeKind::Void),
(Some(val), None) | (None, Some(val)) => StackValue(val.0.derive(instr), val.1),
(Some(lhs_val), Some(rhs_val)) => match (lhs_val.0, rhs_val.0) {
(Immutable(_), Immutable(_))
| (Immutable(_), Mutable(_))
| (Mutable(_), Immutable(_))
| (Immutable(_), Literal(_))
| (Literal(_), Immutable(_))
| (Mutable(_), Literal(_))
| (Literal(_), Mutable(_))
| (Literal(_), Literal(_)) => StackValue(Immutable(instr), lhs_val.1),
(Mutable(_), Mutable(_)) => StackValue(Mutable(instr), lhs_val.1),
},
};
Some(value)
}
}
}