Implement codegen for binops

This commit is contained in:
Sofia 2025-07-24 15:52:46 +03:00
parent b12e0a18a9
commit d448c8b9f1

View File

@ -18,9 +18,12 @@ use crate::{
allocator::{Allocator, AllocatorScope}, allocator::{Allocator, AllocatorScope},
lexer::{FullToken, Position}, lexer::{FullToken, Position},
mir::{ mir::{
self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind, self,
Metadata, NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinition, implement::TypeCategory,
TypeDefinitionKind, TypeKind, VagueLiteral, WhileStatement, pass::{ScopeBinopDef, ScopeBinopKey},
CustomTypeKey, FunctionDefinitionKind, Metadata, NamedVariableRef, SourceModuleId,
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral,
WhileStatement,
}, },
util::try_all, util::try_all,
}; };
@ -77,12 +80,13 @@ pub struct Scope<'ctx, 'scope> {
modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>, modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
tokens: &'ctx Vec<FullToken>, tokens: &'ctx Vec<FullToken>,
module: &'ctx Module<'ctx>, module: &'ctx Module<'ctx>,
pub(super) module_id: SourceModuleId, module_id: SourceModuleId,
function: &'ctx Function<'ctx>, function: &'ctx Function<'ctx>,
pub(super) block: Block<'ctx>, pub(super) block: Block<'ctx>,
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>, types: &'scope HashMap<TypeValue, TypeDefinition>,
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>, type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
functions: &'scope HashMap<String, Function<'ctx>>, functions: &'scope HashMap<String, Function<'ctx>>,
binops: &'scope HashMap<ScopeBinopKey, StackBinopDefinition<'ctx>>,
stack_values: HashMap<String, StackValue>, stack_values: HashMap<String, StackValue>,
debug: Option<Debug<'ctx>>, debug: Option<Debug<'ctx>>,
allocator: Rc<RefCell<Allocator>>, allocator: Rc<RefCell<Allocator>>,
@ -104,6 +108,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
stack_values: self.stack_values.clone(), stack_values: self.stack_values.clone(),
debug: self.debug.clone(), debug: self.debug.clone(),
allocator: self.allocator.clone(), allocator: self.allocator.clone(),
binops: self.binops,
} }
} }
@ -186,6 +191,29 @@ pub struct StackBinopDefinition<'ctx> {
ir: Function<'ctx>, ir: Function<'ctx>,
} }
impl<'ctx> StackBinopDefinition<'ctx> {
fn codegen<'a>(
&self,
lhs: &StackValue,
rhs: &StackValue,
scope: &mut Scope<'ctx, 'a>,
) -> StackValue {
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
(lhs, rhs)
} else {
(rhs, lhs)
};
let instr = scope
.block
.build(Instr::FunctionCall(
self.ir.value(),
vec![lhs.instr(), rhs.instr()],
))
.unwrap();
StackValue(StackValueKind::Immutable(instr), self.return_ty.clone())
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
struct State { struct State {
should_load: bool, should_load: bool,
@ -376,6 +404,7 @@ impl mir::Module {
scope: compile_unit, scope: compile_unit,
types: &debug_types, types: &debug_types,
}), }),
binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
}; };
@ -442,6 +471,7 @@ impl mir::Module {
scope: compile_unit, scope: compile_unit,
types: &debug_types, types: &debug_types,
}), }),
binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
}; };
@ -832,85 +862,102 @@ impl mir::Expression {
lit.as_type(), lit.as_type(),
)), )),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => { mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
let lhs = lhs_exp let lhs_val = lhs_exp
.codegen(scope, state)? .codegen(scope, state)?
.expect("lhs has no return value") .expect("lhs has no return value");
.instr(); let rhs_val = rhs_exp
let rhs = rhs_exp
.codegen(scope, state)? .codegen(scope, state)?
.expect("rhs has no return value") .expect("rhs has no return value");
.instr(); let lhs = lhs_val.instr();
let lhs_type = lhs_exp let rhs = rhs_val.instr();
.return_type(&Default::default(), scope.module_id)
.unwrap() let operation = scope.binops.get(&ScopeBinopKey {
.1; params: (lhs_val.1.clone(), rhs_val.1.clone()),
let instr = match ( operator: *binop,
binop, });
lhs_type.signed(),
lhs_type.category() == TypeCategory::Real, if let Some(operation) = operation {
) { Some(operation.codegen(&lhs_val, &rhs_val, scope))
(mir::BinaryOperator::Add, _, false) => Instr::Add(lhs, rhs), } else {
(mir::BinaryOperator::Add, _, true) => Instr::FAdd(lhs, rhs), dbg!((lhs_val.1.clone(), rhs_val.1.clone()));
(mir::BinaryOperator::Minus, _, false) => Instr::Sub(lhs, rhs), dbg!(&operation.map(|b| &b.return_ty));
(mir::BinaryOperator::Minus, _, true) => Instr::FSub(lhs, rhs),
(mir::BinaryOperator::Mult, _, false) => Instr::Mul(lhs, rhs), let lhs_type = lhs_exp
(mir::BinaryOperator::Mult, _, true) => Instr::FMul(lhs, rhs), .return_type(&Default::default(), scope.module_id)
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs), .unwrap()
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs), .1;
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs), let instr = match (
(mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs), binop,
(mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs), lhs_type.signed(),
(mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs), lhs_type.category() == TypeCategory::Real,
(mir::BinaryOperator::Mod, false, false) => { ) {
let div = scope (mir::BinaryOperator::Add, _, false) => Instr::Add(lhs, rhs),
.block (mir::BinaryOperator::Add, _, true) => Instr::FAdd(lhs, rhs),
.build(Instr::UDiv(lhs, rhs)) (mir::BinaryOperator::Minus, _, false) => Instr::Sub(lhs, rhs),
.unwrap() (mir::BinaryOperator::Minus, _, true) => Instr::FSub(lhs, rhs),
.maybe_location(&mut scope.block, location); (mir::BinaryOperator::Mult, _, false) => Instr::Mul(lhs, rhs),
let mul = scope (mir::BinaryOperator::Mult, _, true) => Instr::FMul(lhs, rhs),
.block (mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
.build(Instr::Mul(rhs, div)) (mir::BinaryOperator::Cmp(i), _, false) => {
.unwrap() Instr::ICmp(i.predicate(), lhs, rhs)
.maybe_location(&mut scope.block, location); }
Instr::Sub(lhs, mul) (mir::BinaryOperator::Cmp(i), _, true) => {
} Instr::FCmp(i.predicate(), lhs, rhs)
(mir::BinaryOperator::Mod, true, false) => { }
let div = scope (mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs),
.block (mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs),
.build(Instr::SDiv(lhs, rhs)) (mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs),
.unwrap() (mir::BinaryOperator::Mod, false, false) => {
.maybe_location(&mut scope.block, location); let div = scope
let mul = scope .block
.block .build(Instr::UDiv(lhs, rhs))
.build(Instr::Mul(rhs, div)) .unwrap()
.unwrap() .maybe_location(&mut scope.block, location);
.maybe_location(&mut scope.block, location); let mul = scope
Instr::Sub(lhs, mul) .block
} .build(Instr::Mul(rhs, div))
(mir::BinaryOperator::Mod, _, true) => { .unwrap()
let div = scope .maybe_location(&mut scope.block, location);
.block Instr::Sub(lhs, mul)
.build(Instr::FDiv(lhs, rhs)) }
.unwrap() (mir::BinaryOperator::Mod, true, false) => {
.maybe_location(&mut scope.block, location); let div = scope
let mul = scope .block
.block .build(Instr::SDiv(lhs, rhs))
.build(Instr::Mul(rhs, div)) .unwrap()
.unwrap() .maybe_location(&mut scope.block, location);
.maybe_location(&mut scope.block, location); let mul = scope
Instr::Sub(lhs, mul) .block
} .build(Instr::Mul(rhs, div))
}; .unwrap()
Some(StackValue( .maybe_location(&mut scope.block, location);
StackValueKind::Immutable( Instr::Sub(lhs, mul)
scope }
.block (mir::BinaryOperator::Mod, _, true) => {
.build(instr) let div = scope
.unwrap() .block
.maybe_location(&mut scope.block, location), .build(Instr::FDiv(lhs, rhs))
), .unwrap()
lhs_type, .maybe_location(&mut scope.block, location);
)) let mul = scope
.block
.build(Instr::Mul(rhs, div))
.unwrap()
.maybe_location(&mut scope.block, location);
Instr::Sub(lhs, mul)
}
};
Some(StackValue(
StackValueKind::Immutable(
scope
.block
.build(instr)
.unwrap()
.maybe_location(&mut scope.block, location),
),
lhs_type,
))
}
} }
mir::ExprKind::FunctionCall(call) => { mir::ExprKind::FunctionCall(call) => {
let ret_type_kind = call let ret_type_kind = call