use crate::{CodegenConfig, CodegenError, CodegenResult};
use bhc_target::TargetSpec;
use inkwell::context::Context;
use inkwell::targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple};
use super::module::LlvmModule;
pub struct LlvmContext {
context: Context,
target_machine: TargetMachine,
config: CodegenConfig,
}
impl LlvmContext {
pub fn new(config: CodegenConfig) -> CodegenResult<Self> {
let context = Context::create();
let target_machine = Self::create_target_machine(&config)?;
Ok(Self {
context,
target_machine,
config,
})
}
fn create_target_machine(config: &CodegenConfig) -> CodegenResult<TargetMachine> {
let triple_str = config.target.triple();
let triple = TargetTriple::create(&triple_str);
let target = Target::from_triple(&triple).map_err(|e| {
CodegenError::UnsupportedTarget(format!("{}: {}", triple_str, e.to_string()))
})?;
let opt_level = match config.opt_level {
bhc_session::OptLevel::None => inkwell::OptimizationLevel::None,
bhc_session::OptLevel::Less => inkwell::OptimizationLevel::Less,
bhc_session::OptLevel::Default => inkwell::OptimizationLevel::Default,
bhc_session::OptLevel::Aggressive => inkwell::OptimizationLevel::Aggressive,
bhc_session::OptLevel::Size | bhc_session::OptLevel::SizeMin => {
inkwell::OptimizationLevel::Less
}
};
let reloc_mode = if config.pic {
RelocMode::PIC
} else {
RelocMode::Default
};
let code_model = CodeModel::Default;
let cpu = &config.cpu;
let features = "";
target
.create_target_machine(&triple, cpu, features, opt_level, reloc_mode, code_model)
.ok_or_else(|| {
CodegenError::Internal(format!(
"failed to create target machine for {}",
triple_str
))
})
}
#[must_use]
pub fn llvm_context(&self) -> &Context {
&self.context
}
#[must_use]
pub fn target_machine(&self) -> &TargetMachine {
&self.target_machine
}
#[must_use]
pub fn data_layout(&self) -> String {
self.target_machine
.get_target_data()
.get_data_layout()
.as_str()
.to_str()
.unwrap_or("")
.to_string()
}
pub fn create_module(&self, name: &str) -> CodegenResult<LlvmModule<'_>> {
LlvmModule::new(self, name)
}
#[must_use]
pub fn target(&self) -> &TargetSpec {
&self.config.target
}
#[must_use]
pub fn config(&self) -> &CodegenConfig {
&self.config
}
}