use crate::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel;
use crate::optimizer::settings::Settings as OptimizerSettings;
use self::target::Target;
pub mod target;
#[derive(Debug)]
pub struct TargetMachine {
target: Target,
target_machine: inkwell::targets::TargetMachine,
optimizer_settings: OptimizerSettings,
}
impl TargetMachine {
pub const VM_TARGET_NAME: &'static str = "riscv64";
pub const VM_TARGET_TRIPLE: &'static str = "riscv64-unknown-unknown-elf";
pub const VM_TARGET_CPU: &'static str = "generic-rv64";
pub const VM_FEATURES: &'static str =
"+e,+m,+a,+c,+zbb,+auipc-addi-fusion,+ld-add-fusion,+lui-addi-fusion,+xtheadcondmov,+relax";
pub fn new(target: Target, optimizer_settings: &OptimizerSettings) -> anyhow::Result<Self> {
let target_machine = inkwell::targets::Target::from_name(target.name())
.ok_or_else(|| anyhow::anyhow!("LLVM target machine `{}` not found", target.name()))?
.create_target_machine(
&inkwell::targets::TargetTriple::create(target.triple()),
Self::VM_TARGET_CPU,
Self::VM_FEATURES,
optimizer_settings.level_back_end,
inkwell::targets::RelocMode::PIC,
inkwell::targets::CodeModel::Default,
)
.ok_or_else(|| {
anyhow::anyhow!(
"LLVM target machine `{}` initialization error",
target.name(),
)
})?;
Ok(Self {
target,
target_machine,
optimizer_settings: optimizer_settings.to_owned(),
})
}
pub fn write_to_memory_buffer(
&self,
module: &inkwell::module::Module,
) -> Result<inkwell::memory_buffer::MemoryBuffer<'static>, inkwell::support::LLVMString> {
match self.target {
Target::PVM => self
.target_machine
.write_to_memory_buffer(module, inkwell::targets::FileType::Object),
}
}
pub fn run_optimization_passes(
&self,
module: &inkwell::module::Module,
passes: &str,
) -> Result<(), inkwell::support::LLVMString> {
let pass_builder_options = inkwell::passes::PassBuilderOptions::create();
pass_builder_options.set_verify_each(self.optimizer_settings.is_verify_each_enabled);
pass_builder_options.set_debug_logging(self.optimizer_settings.is_debug_logging_enabled);
pass_builder_options.set_loop_unrolling(
self.optimizer_settings.level_middle_end_size == OptimizerSettingsSizeLevel::Zero,
);
pass_builder_options.set_merge_functions(true);
module.run_passes(passes, &self.target_machine, pass_builder_options)
}
pub fn get_triple(&self) -> inkwell::targets::TargetTriple {
self.target_machine.get_triple()
}
pub fn get_target_data(&self) -> inkwell::targets::TargetData {
self.target_machine.get_target_data()
}
}