From 048fcb0a695a057bcb319374db7efbb457d14b3c Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 11 Sep 2023 13:14:35 +0800 Subject: [PATCH] core: Switch to LLVM New Pass Manager --- nac3artiq/src/lib.rs | 18 +++++++++++------- nac3core/src/codegen/mod.rs | 37 +++++++++++++++---------------------- nac3standalone/src/main.rs | 17 +++++++++-------- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 4705999b..b13be843 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::{PassManager, PassManagerBuilder}, + passes::PassBuilderOptions, targets::*, OptimizationLevel, }; @@ -654,12 +654,16 @@ impl Nac3 { global_option = global.get_next_global(); } - 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 = 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()); + } link_fn(&main) } diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index c741aa63..0d8e3c8c 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::{PassManager, PassManagerBuilder}, + passes::PassBuilderOptions, targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple}, types::{AnyType, BasicType, BasicTypeEnum}, values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}, @@ -32,7 +32,6 @@ use std::sync::{ Arc, }; use std::thread; -use lazy_static::lazy_static; pub mod concrete_type; pub mod expr; @@ -54,12 +53,6 @@ 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 { @@ -305,23 +298,11 @@ 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)) => { @@ -345,9 +326,21 @@ 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 {}", module.get_name().to_str().unwrap()); - println!("{}", module.to_string()); + println!("LLVM IR for {}\n{}", module.get_name().to_str().unwrap(), module.to_string()); println!(); } diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 4b6756c3..d3337c80 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -1,7 +1,7 @@ use clap::Parser; use inkwell::{ memory_buffer::MemoryBuffer, - passes::{PassManager, PassManagerBuilder}, + passes::PassBuilderOptions, targets::*, OptimizationLevel, }; @@ -325,16 +325,17 @@ 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");