Files
wasmer/lib/compiler-llvm/src/config.rs
2020-05-02 15:17:18 -07:00

166 lines
5.2 KiB
Rust

// Allow unused imports while developing
#![allow(unused_imports, dead_code)]
use crate::compiler::LLVMCompiler;
use inkwell::targets::{
CodeModel, InitializationConfig, RelocMode, Target as LLVMTarget, TargetMachine, TargetTriple,
};
use inkwell::OptimizationLevel;
use itertools::Itertools;
use target_lexicon::Architecture;
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, Features, Target};
/// The InkWell Module type
pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>;
/// The InkWell MemoryBuffer type
pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer;
/// Callbacks to
pub trait LLVMCallbacks: std::any::Any + 'static {
fn preopt_ir_callback(&mut self, module: &InkwellModule);
fn postopt_ir_callback(&mut self, module: &InkwellModule);
fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer);
}
#[derive(Clone)]
pub struct LLVMConfig {
/// Enable NaN canonicalization.
///
/// NaN canonicalization is useful when trying to run WebAssembly
/// deterministically across different architectures.
pub enable_nan_canonicalization: bool,
/// Should the LLVM IR verifier be enabled.
///
/// The verifier assures that the generated LLVM IR is valid.
pub enable_verifier: bool,
/// The optimization levels when optimizing the IR.
pub opt_level: OptimizationLevel,
features: Features,
target: Target,
}
impl LLVMConfig {
/// Creates a new configuration object with the default configuration
/// specified.
pub fn new(features: Features, target: Target) -> Self {
Self {
enable_nan_canonicalization: true,
enable_verifier: false,
opt_level: OptimizationLevel::Aggressive,
features,
target,
}
}
fn reloc_mode(&self) -> RelocMode {
RelocMode::Static
}
fn code_model(&self) -> CodeModel {
CodeModel::Large
}
pub fn target_triple(&self) -> TargetTriple {
TargetTriple::create(&self.target().triple().to_string())
}
/// Generates the target machine for the current target
pub fn target_machine(&self) -> TargetMachine {
let target = self.target();
let triple = target.triple();
let cpu_features = &target.cpu_features();
match triple.architecture {
Architecture::X86_64 => LLVMTarget::initialize_x86(&InitializationConfig {
asm_parser: true,
asm_printer: true,
base: true,
disassembler: true,
info: true,
machine_code: true,
}),
Architecture::Arm(_) => LLVMTarget::initialize_aarch64(&InitializationConfig {
asm_parser: true,
asm_printer: true,
base: true,
disassembler: true,
info: true,
machine_code: true,
}),
_ => unimplemented!("target {} not supported", triple),
}
// The CPU features formatted as LLVM strings
let llvm_cpu_features = cpu_features
.iter()
.filter_map(|feature| match feature {
CpuFeature::SSE2 => Some("+sse2"),
CpuFeature::SSE3 => Some("+sse3"),
CpuFeature::SSSE3 => Some("+ssse3"),
CpuFeature::SSE41 => Some("+sse4.1"),
CpuFeature::SSE42 => Some("+sse4.2"),
CpuFeature::POPCNT => Some("+popcnt"),
CpuFeature::AVX => Some("+avx"),
CpuFeature::BMI1 => Some("+bmi"),
CpuFeature::BMI2 => Some("+bmi2"),
CpuFeature::AVX2 => Some("+avx2"),
CpuFeature::AVX512DQ => Some("+avx512dq"),
CpuFeature::AVX512VL => Some("+avx512vl"),
CpuFeature::LZCNT => Some("+lzcnt"),
})
.join(",");
let arch_string = triple.architecture.to_string();
let llvm_target = LLVMTarget::from_triple(&self.target_triple()).unwrap();
let target_machine = llvm_target
.create_target_machine(
&self.target_triple(),
"generic",
&llvm_cpu_features,
self.opt_level.clone(),
self.reloc_mode(),
self.code_model(),
)
.unwrap();
target_machine
}
}
impl CompilerConfig for LLVMConfig {
/// Gets the WebAssembly features
fn features(&self) -> &Features {
&self.features
}
/// Gets the WebAssembly features, mutable
fn features_mut(&mut self) -> &mut Features {
&mut self.features
}
/// Gets the target that we will use for compiling
/// the WebAssembly module
fn target(&self) -> &Target {
&self.target
}
/// Gets the target that we will use for compiling
/// the WebAssembly module, mutable
fn target_mut(&mut self) -> &mut Target {
&mut self.target
}
/// Transform it into the compiler
fn compiler(&self) -> Box<dyn Compiler> {
Box::new(LLVMCompiler::new(&self))
}
}
impl Default for LLVMConfig {
fn default() -> LLVMConfig {
Self::new(Default::default(), Default::default())
}
}