use inkwell::{module::Linkage, types::BasicTypeEnum};
use inkwell::types::FunctionType;
use inkwell::AddressSpace;
use std::{ collections::HashMap, hash::Hash };
use inkwell::{
basic_block::BasicBlock,
builder::Builder,
context::Context,
module::Module,
values::{ FunctionValue, PointerValue },
};
use crate::metair::MetaProgram;
use super::LLVMError;
use crate::ir::scope::Scope;
use crate::metair::*;
pub struct LoopFrame<'ctx> {
pub break_block: BasicBlock<'ctx>,
pub continue_block: BasicBlock<'ctx>,
}
pub struct LLVMBackend<'ctx> {
pub context: &'ctx Context,
pub module: Module<'ctx>,
pub builder: Builder<'ctx>,
pub program: &'ctx MetaProgram,
pub functions: HashMap<u32, FunctionValue<'ctx>>,
pub scopes: Vec<Scope<'ctx>>,
pub current_function: Option<FunctionValue<'ctx>>,
pub loop_stack: Vec<LoopFrame<'ctx>>,
pub builtins: HashMap<&'ctx str, FunctionValue<'ctx>>,
}
impl<'ctx> LLVMBackend<'ctx> {
pub fn new(context: &'ctx Context, program: &'ctx MetaProgram, module_name: &str) -> Self {
let mut s = Self {
context,
module: context.create_module(module_name),
builder: context.create_builder(),
program,
functions: HashMap::new(),
builtins: HashMap::new(),
scopes: Vec::new(),
loop_stack: Vec::new(),
current_function: None,
};
s.declare_builtins();
s
}
pub fn dump_ir(&self) {
self.module.print_to_stderr();
}
pub fn declare_builtin(&mut self, name: &str, ty: FunctionType<'ctx>) -> Result<(), LLVMError> {
let id = self.program.symbol_table
.iter()
.position(|s| s == name)
.ok_or_else(||
LLVMError::Message(format!("builtin '{}' not interned", name))
)? as SymbolId;
let func = self.module.add_function(name, ty, None);
self.functions.insert(id, func);
Ok(())
}
pub fn compile(&mut self) -> Result<Module<'ctx>, LLVMError> {
self.lower_program()?;
self.module.verify().map_err(|e| { LLVMError::Message(e.to_string()) })?;
Ok(self.module.clone())
}
}
impl<'ctx> LLVMBackend<'ctx> {
pub fn push_scope(&mut self) {
self.scopes.push(Scope::new());
}
pub fn pop_scope(&mut self) {
self.scopes.pop();
}
pub fn current_function(&self) -> FunctionValue<'ctx> {
self.current_function.unwrap()
}
pub fn insert_variable(
&mut self,
id: SymbolId,
ptr: PointerValue<'ctx>,
ty: BasicTypeEnum<'ctx>
) {
self.scopes.last_mut().unwrap().insert(id, ptr, ty);
}
pub fn get_variable(
&self,
id: SymbolId
) -> Result<&crate::ir::scope::Variable<'ctx>, LLVMError> {
for scope in self.scopes.iter().rev() {
if let Some(var) = scope.get(id) {
return Ok(var);
}
}
Err(LLVMError::UnknownVariable(id))
}
}