diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 7df32aa..79e0525 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -12,7 +12,7 @@ use inkwell::{ targets::*, OptimizationLevel, }; -use nac3core::codegen::{CodeGenLLVMOptions, gen_func_impl}; +use nac3core::codegen::{CodeGenLLVMOptions, CodeGenTargetMachineOptions, gen_func_impl}; use nac3core::toplevel::builtins::get_exn_constructor; use nac3core::typecheck::typedef::{TypeEnum, Unifier}; use nac3parser::{ @@ -664,34 +664,42 @@ impl Nac3 { link_fn(&main) } - fn get_llvm_target_machine( - &self, - ) -> TargetMachine { - let (triple, features) = match self.isa { - Isa::Host => ( - TargetMachine::get_default_triple(), - TargetMachine::get_host_cpu_features().to_string(), - ), - Isa::RiscV32G => { - (TargetTriple::create("riscv32-unknown-linux"), "+a,+m,+f,+d".to_string()) - } - Isa::RiscV32IMA => (TargetTriple::create("riscv32-unknown-linux"), "+a,+m".to_string()), - Isa::CortexA9 => ( - TargetTriple::create("armv7-unknown-linux-gnueabihf"), - "+dsp,+fp16,+neon,+vfp3,+long-calls".to_string(), - ), - }; - let target = - Target::from_triple(&triple).expect("couldn't create target from target triple"); - target - .create_target_machine( - &triple, - "", - &features, - self.llvm_options.opt_level, - RelocMode::PIC, - CodeModel::Default, - ) + /// Returns the [TargetTriple] used for compiling to [isa]. + fn get_llvm_target_triple(isa: Isa) -> TargetTriple { + match isa { + Isa::Host => TargetMachine::get_default_triple(), + Isa::RiscV32G | Isa::RiscV32IMA => TargetTriple::create("riscv32-unknown-linux"), + Isa::CortexA9 => TargetTriple::create("armv7-unknown-linux-gnueabihf"), + } + } + + /// Returns the [String] representing the target features used for compiling to [isa]. + fn get_llvm_target_features(isa: Isa) -> String { + match isa { + Isa::Host => TargetMachine::get_host_cpu_features().to_string(), + Isa::RiscV32G => "+a,+m,+f,+d".to_string(), + Isa::RiscV32IMA => "+a,+m".to_string(), + Isa::CortexA9 => "+dsp,+fp16,+neon,+vfp3,+long-calls".to_string(), + } + } + + /// Returns an instance of [CodeGenTargetMachineOptions] representing the target machine + /// options used for compiling to [isa]. + fn get_llvm_target_options(isa: Isa) -> CodeGenTargetMachineOptions { + CodeGenTargetMachineOptions { + triple: Nac3::get_llvm_target_triple(isa).as_str().to_string_lossy().into_owned(), + cpu: String::default(), + features: Nac3::get_llvm_target_features(isa), + reloc_mode: RelocMode::PIC, + ..CodeGenTargetMachineOptions::from_host() + } + } + + /// Returns an instance of [TargetMachine] used in compiling and linking of a program to the + /// target [isa]. + fn get_llvm_target_machine(&self) -> TargetMachine { + Nac3::get_llvm_target_options(self.isa) + .create_target_machine(self.llvm_options.opt_level) .expect("couldn't create target machine") } } diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 0bb6c90..32891ce 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -16,6 +16,7 @@ use inkwell::{ context::Context, module::Module, passes::{PassManager, PassManagerBuilder}, + targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple}, types::{AnyType, BasicType, BasicTypeEnum}, values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}, debug_info::{ @@ -68,6 +69,67 @@ pub struct CodeGenLLVMOptions { pub emit_llvm: bool, } +/// Additional options for code generation for the target machine. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CodeGenTargetMachineOptions { + /// The target machine triple. + pub triple: String, + /// The target machine CPU. + pub cpu: String, + /// Additional target machine features. + pub features: String, + /// Relocation mode for code generation. + pub reloc_mode: RelocMode, + /// Code model for code generation. + pub code_model: CodeModel, +} + +impl CodeGenTargetMachineOptions { + + /// Creates an instance of [CodeGenTargetMachineOptions] using the triple of the host machine. + /// Other options are set to defaults. + pub fn from_host_triple() -> CodeGenTargetMachineOptions { + CodeGenTargetMachineOptions { + triple: TargetMachine::get_default_triple().as_str().to_string_lossy().into_owned(), + cpu: String::default(), + features: String::default(), + reloc_mode: RelocMode::Default, + code_model: CodeModel::Default, + } + } + + /// Creates an instance of [CodeGenTargetMachineOptions] using the properties of the host + /// machine. Other options are set to defaults. + pub fn from_host() -> CodeGenTargetMachineOptions { + CodeGenTargetMachineOptions { + cpu: TargetMachine::get_host_cpu_name().to_string(), + features: TargetMachine::get_host_cpu_features().to_string(), + ..CodeGenTargetMachineOptions::from_host_triple() + } + } + + /// Creates a [TargetMachine] using the target options specified by this struct. + /// + /// See [Target::create_target_machine]. + pub fn create_target_machine( + &self, + level: OptimizationLevel, + ) -> Option { + let triple = TargetTriple::create(self.triple.as_str()); + let target = Target::from_triple(&triple) + .expect(format!("could not create target from target triple {}", self.triple).as_str()); + + target.create_target_machine( + &triple, + self.cpu.as_str(), + self.features.as_str(), + level, + self.reloc_mode, + self.code_model + ) + } +} + pub struct CodeGenContext<'ctx, 'a> { pub ctx: &'ctx Context, pub builder: Builder<'ctx>,