reid-llvm/reid/src/codegen/scope.rs
2025-08-05 22:00:11 +03:00

247 lines
10 KiB
Rust

use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
use reid_lib::{
builder::{FunctionValue, GlobalValue, InstructionValue, TypeValue},
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
intrinsics::LLVMIntrinsic,
Block, Context, Function, Instr, Module,
};
use crate::{
codegen::intrinsics::LLVMIntrinsicKind,
lexer::FullToken,
mir::{
self,
pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind,
},
};
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction};
pub struct Scope<'ctx, 'scope> {
pub(super) context: &'ctx Context,
pub(super) modules: &'scope HashMap<SourceModuleId, &'ctx mir::Module>,
pub(super) tokens: &'ctx Vec<FullToken>,
pub(super) module: &'ctx Module<'ctx>,
pub(super) module_id: SourceModuleId,
pub(super) function: &'ctx Function<'ctx>,
pub(super) block: Block<'ctx>,
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
pub(super) type_map: &'scope HashMap<CustomTypeKey, TypeDefinition>,
pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>,
pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>,
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
pub(super) stack_values: HashMap<String, StackValue>,
pub(super) globals: &'scope HashMap<String, GlobalValue>,
pub(super) debug: Option<Debug<'ctx>>,
pub(super) allocator: Rc<RefCell<Allocator>>,
pub(super) llvm_intrinsics: Rc<RefCell<HashMap<LLVMIntrinsicKind, FunctionValue>>>,
}
impl<'ctx, 'a> Scope<'ctx, 'a> {
pub fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
Scope {
block,
modules: self.modules,
tokens: self.tokens,
function: self.function,
context: self.context,
module: self.module,
module_id: self.module_id,
assoc_functions: self.assoc_functions,
functions: self.functions,
types: self.types,
type_values: self.type_values,
type_map: self.type_map,
stack_values: self.stack_values.clone(),
debug: self.debug.clone(),
allocator: self.allocator.clone(),
globals: self.globals,
binops: self.binops,
llvm_intrinsics: self.llvm_intrinsics.clone(),
}
}
/// Takes the block out from this scope, swaps the given block in it's place
/// and returns the old block.
pub fn swap_block(&mut self, block: Block<'ctx>) -> Block<'ctx> {
let mut old_block = block;
mem::swap(&mut self.block, &mut old_block);
old_block
}
pub fn get_typedef(&self, key: &CustomTypeKey) -> Option<&TypeDefinition> {
self.type_values.get(key).and_then(|v| self.types.get(v))
}
pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
self.allocator.borrow_mut().allocate(meta, ty)
}
pub fn get_intrinsic(&self, kind: LLVMIntrinsicKind) -> FunctionValue {
let mut intrinsics = self.llvm_intrinsics.borrow_mut();
if let Some(fun) = intrinsics.get(&kind) {
*fun
} else {
let intrinsic = self
.module
.intrinsic(match &kind {
LLVMIntrinsicKind::Max(ty) => LLVMIntrinsic::Max(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Min(ty) => LLVMIntrinsic::Min(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Abs(ty) => LLVMIntrinsic::Abs(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Memcpy(ty) => LLVMIntrinsic::Memcpy(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sqrt(ty) => LLVMIntrinsic::Sqrt(ty.get_type(self.type_values)),
LLVMIntrinsicKind::PowI(lhs, rhs) => {
LLVMIntrinsic::PowI(lhs.get_type(self.type_values), rhs.get_type(self.type_values))
}
LLVMIntrinsicKind::Pow(ty) => LLVMIntrinsic::Pow(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sin(ty) => LLVMIntrinsic::Sin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Cos(ty) => LLVMIntrinsic::Cos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Tan(ty) => LLVMIntrinsic::Tan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ASin(ty) => LLVMIntrinsic::ASin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ACos(ty) => LLVMIntrinsic::ACos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan(ty) => LLVMIntrinsic::ATan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan2(ty) => LLVMIntrinsic::ATan2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::SinH(ty) => LLVMIntrinsic::SinH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::CosH(ty) => LLVMIntrinsic::CosH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::TanH(ty) => LLVMIntrinsic::TanH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log(ty) => LLVMIntrinsic::Log(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log2(ty) => LLVMIntrinsic::Log2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log10(ty) => LLVMIntrinsic::Log10(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Copysign(ty) => LLVMIntrinsic::Copysign(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Floor(ty) => LLVMIntrinsic::Floor(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Ceil(ty) => LLVMIntrinsic::Ceil(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Trunc(ty) => LLVMIntrinsic::Trunc(ty.get_type(self.type_values)),
LLVMIntrinsicKind::RoundEven(ty) => LLVMIntrinsic::RoundEven(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Round(ty) => LLVMIntrinsic::Round(ty.get_type(self.type_values)),
})
.unwrap();
intrinsics.insert(kind, intrinsic.clone());
intrinsic
}
}
}
#[derive(Debug, Clone)]
pub struct Debug<'ctx> {
pub(super) info: &'ctx DebugInformation,
pub(super) scope: DebugScopeValue,
pub(super) types: &'ctx HashMap<TypeKind, DebugTypeValue>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StackValue(pub(super) StackValueKind, pub(super) TypeKind);
impl StackValue {
pub fn instr(&self) -> InstructionValue {
self.0.instr()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StackValueKind {
Immutable(InstructionValue),
Mutable(InstructionValue),
Literal(InstructionValue),
}
impl StackValueKind {
pub fn mutable(mutable: bool, instr: InstructionValue) -> StackValueKind {
match mutable {
true => StackValueKind::Mutable(instr),
false => StackValueKind::Immutable(instr),
}
}
pub fn instr(&self) -> InstructionValue {
match &self {
StackValueKind::Immutable(val) => *val,
StackValueKind::Mutable(val) => *val,
StackValueKind::Literal(val) => *val,
}
}
pub fn derive(&self, instr: InstructionValue) -> StackValueKind {
match &self {
StackValueKind::Immutable(_) => StackValueKind::Immutable(instr),
StackValueKind::Mutable(_) => StackValueKind::Mutable(instr),
StackValueKind::Literal(_) => StackValueKind::Literal(instr),
}
}
#[allow(dead_code)]
fn map<F>(&self, lambda: F) -> StackValueKind
where
F: FnOnce(InstructionValue) -> InstructionValue,
{
self.derive(lambda(self.instr()))
}
}
pub struct StackBinopDefinition<'ctx> {
pub(super) parameters: (FunctionParam, FunctionParam),
pub(super) return_ty: TypeKind,
pub(super) kind: ScopeFunctionKind<'ctx>,
}
pub enum ScopeFunctionKind<'ctx> {
UserGenerated(Function<'ctx>),
Intrinsic(&'ctx Box<dyn IntrinsicFunction>),
IntrinsicOwned(Box<dyn IntrinsicFunction>),
}
impl<'ctx> StackBinopDefinition<'ctx> {
pub fn codegen<'a>(
&self,
lhs: StackValue,
rhs: StackValue,
scope: &mut Scope<'ctx, 'a>,
) -> Result<StackValue, ErrorKind> {
let (lhs, rhs) = if lhs.1 == self.parameters.0.ty && rhs.1 == self.parameters.1.ty {
(lhs, rhs)
} else {
(rhs, lhs)
};
let name = format!(
"binop.{}.{}.{}.call",
self.parameters.0.ty, self.parameters.1.ty, self.return_ty
);
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
}
}
impl<'ctx> ScopeFunctionKind<'ctx> {
pub fn codegen<'a>(
&self,
name: &str,
params: &[StackValue],
return_ty: &TypeKind,
location: Option<DebugLocation>,
scope: &mut Scope<'ctx, 'a>,
) -> Result<StackValue, ErrorKind> {
match self {
ScopeFunctionKind::UserGenerated(function) => {
let val = scope
.block
.build_named(
name,
Instr::FunctionCall(function.value(), params.iter().map(|p| p.instr()).collect()),
)
.unwrap();
if let Some(debug) = &scope.debug {
if let Some(location) = location {
let location_val = debug.info.location(&debug.scope, location);
val.with_location(&mut scope.block, location_val);
}
}
Ok(StackValue(StackValueKind::Immutable(val), return_ty.clone()))
}
ScopeFunctionKind::Intrinsic(fun) => fun.codegen(scope, params),
ScopeFunctionKind::IntrinsicOwned(fun) => fun.codegen(scope, params),
}
}
}