diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 80f8222..3c05d72 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use inkwell::{ memory_buffer::MemoryBuffer, module::{Linkage, Module}, - passes::PassBuilderOptions, + passes::{PassManager, PassManagerBuilder}, targets::*, OptimizationLevel, }; @@ -654,16 +654,12 @@ impl Nac3 { global_option = global.get_next_global(); } - let target_machine = self.llvm_options.target - .create_target_machine(self.llvm_options.opt_level) - .expect("couldn't create target machine"); - - let pass_options = PassBuilderOptions::create(); - pass_options.set_merge_functions(true); - let result = main.run_passes("default", &target_machine, pass_options); - if let Err(err) = result { - panic!("Failed to run optimization for module `main`: {}", err.to_string()); - } + let builder = PassManagerBuilder::create(); + builder.set_optimization_level(OptimizationLevel::Aggressive); + let passes = PassManager::create(()); + builder.set_inliner_with_threshold(255); + builder.populate_module_pass_manager(&passes); + passes.run_on(&main); link_fn(&main) } diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 0d8e3c8..c741aa6 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -15,7 +15,7 @@ use inkwell::{ builder::Builder, context::Context, module::Module, - passes::PassBuilderOptions, + passes::{PassManager, PassManagerBuilder}, targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple}, types::{AnyType, BasicType, BasicTypeEnum}, values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}, @@ -32,6 +32,7 @@ use std::sync::{ Arc, }; use std::thread; +use lazy_static::lazy_static; pub mod concrete_type; pub mod expr; @@ -53,6 +54,12 @@ pub struct StaticValueStore { pub type VarValue<'ctx> = (PointerValue<'ctx>, Option>, i64); +lazy_static!( + // HACK: The Mutex is a work-around for issue + // https://git.m-labs.hk/M-Labs/nac3/issues/275 + static ref PASSES_INIT_LOCK: Mutex = Mutex::new(AtomicBool::new(true)); +); + /// Additional options for LLVM during codegen. #[derive(Clone, Debug, Eq, PartialEq)] pub struct CodeGenLLVMOptions { @@ -298,11 +305,23 @@ impl WorkerRegistry { context.i32_type().const_int(4, false), ); + let passes = PassManager::create(&module); + + // HACK: This critical section is a work-around for issue + // https://git.m-labs.hk/M-Labs/nac3/issues/275 + { + let _data = PASSES_INIT_LOCK.lock(); + let pass_builder = PassManagerBuilder::create(); + pass_builder.set_optimization_level(self.llvm_options.opt_level); + pass_builder.populate_function_pass_manager(&passes); + } + let mut errors = HashSet::new(); while let Some(task) = self.receiver.recv().unwrap() { match gen_func(&context, generator, self, builder, module, task) { Ok(result) => { builder = result.0; + passes.run_on(&result.2); module = result.1; } Err((old_builder, e)) => { @@ -326,21 +345,9 @@ impl WorkerRegistry { panic!() } - let pass_options = PassBuilderOptions::create(); - let target_machine = self.llvm_options.target.create_target_machine( - self.llvm_options.opt_level - ).expect(format!("could not create target machine from properties {:?}", self.llvm_options.target).as_str()); - let passes = format!("default", self.llvm_options.opt_level as u32); - - let result = module.run_passes(passes.as_str(), &target_machine, pass_options); - if let Err(err) = result { - panic!("Failed to run optimization for module `{}`: {}", - module.get_name().to_str().unwrap(), - err.to_string()); - } - if self.llvm_options.emit_llvm { - println!("LLVM IR for {}\n{}", module.get_name().to_str().unwrap(), module.to_string()); + println!("LLVM IR for {}", module.get_name().to_str().unwrap()); + println!("{}", module.to_string()); println!(); } diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index f1a2160..732fca1 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -1,7 +1,7 @@ use clap::Parser; use inkwell::{ memory_buffer::MemoryBuffer, - passes::PassBuilderOptions, + passes::{PassManager, PassManagerBuilder}, targets::*, OptimizationLevel, }; @@ -357,17 +357,16 @@ fn main() { function_iter = func.get_next_function(); } + let builder = PassManagerBuilder::create(); + builder.set_optimization_level(OptimizationLevel::Aggressive); + let passes = PassManager::create(()); + builder.set_inliner_with_threshold(255); + builder.populate_module_pass_manager(&passes); + passes.run_on(&main); + let target_machine = llvm_options.target .create_target_machine(llvm_options.opt_level) .expect("couldn't create target machine"); - - let pass_options = PassBuilderOptions::create(); - pass_options.set_merge_functions(true); - let result = main.run_passes("default", &target_machine, pass_options); - if let Err(err) = result { - panic!("Failed to run optimization for module `main`: {}", err.to_string()); - } - target_machine .write_to_file(&main, FileType::Object, Path::new("module.o")) .expect("couldn't write module to file");