core: Add LLVM options to WorkerRegistry

This commit is contained in:
David Mak 2023-09-06 17:50:17 +08:00
parent 39724de598
commit 3993a5cf3f
4 changed files with 61 additions and 14 deletions
nac3artiq/src
nac3core/src/codegen
nac3standalone/src

View File

@ -12,7 +12,7 @@ use inkwell::{
targets::*, targets::*,
OptimizationLevel, OptimizationLevel,
}; };
use nac3core::codegen::gen_func_impl; use nac3core::codegen::{CodeGenLLVMOptions, gen_func_impl};
use nac3core::toplevel::builtins::get_exn_constructor; use nac3core::toplevel::builtins::get_exn_constructor;
use nac3core::typecheck::typedef::{TypeEnum, Unifier}; use nac3core::typecheck::typedef::{TypeEnum, Unifier};
use nac3parser::{ use nac3parser::{
@ -97,7 +97,9 @@ struct Nac3 {
top_levels: Vec<TopLevelComponent>, top_levels: Vec<TopLevelComponent>,
string_store: Arc<RwLock<HashMap<String, i32>>>, string_store: Arc<RwLock<HashMap<String, i32>>>,
exception_ids: Arc<RwLock<HashMap<usize, usize>>>, exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
deferred_eval_store: DeferredEvaluationStore deferred_eval_store: DeferredEvaluationStore,
/// LLVM-related options for code generation.
llvm_options: CodeGenLLVMOptions,
} }
create_exception!(nac3artiq, CompileError, exceptions::PyException); create_exception!(nac3artiq, CompileError, exceptions::PyException);
@ -588,7 +590,12 @@ impl Nac3 {
let membuffer = membuffers.clone(); let membuffer = membuffers.clone();
py.allow_threads(|| { py.allow_threads(|| {
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f); let (registry, handles) = WorkerRegistry::create_workers(
threads,
top_level.clone(),
&self.llvm_options,
f
);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
@ -681,7 +688,7 @@ impl Nac3 {
&triple, &triple,
"", "",
&features, &features,
OptimizationLevel::Default, self.llvm_options.opt_level,
RelocMode::PIC, RelocMode::PIC,
CodeModel::Default, CodeModel::Default,
) )
@ -885,6 +892,10 @@ impl Nac3 {
string_store: Default::default(), string_store: Default::default(),
exception_ids: Default::default(), exception_ids: Default::default(),
deferred_eval_store: DeferredEvaluationStore::new(), deferred_eval_store: DeferredEvaluationStore::new(),
llvm_options: CodeGenLLVMOptions {
opt_level: OptimizationLevel::Default,
emit_llvm: false,
}
}) })
} }

View File

@ -132,12 +132,15 @@ pub struct WorkerRegistry {
wait_condvar: Condvar, wait_condvar: Condvar,
top_level_ctx: Arc<TopLevelContext>, top_level_ctx: Arc<TopLevelContext>,
static_value_store: Arc<Mutex<StaticValueStore>>, static_value_store: Arc<Mutex<StaticValueStore>>,
/// LLVM-related options for code generation.
llvm_options: CodeGenLLVMOptions,
} }
impl WorkerRegistry { impl WorkerRegistry {
pub fn create_workers<G: CodeGenerator + Send + 'static>( pub fn create_workers<G: CodeGenerator + Send + 'static>(
generators: Vec<Box<G>>, generators: Vec<Box<G>>,
top_level_ctx: Arc<TopLevelContext>, top_level_ctx: Arc<TopLevelContext>,
llvm_options: &CodeGenLLVMOptions,
f: Arc<WithCall>, f: Arc<WithCall>,
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) { ) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
@ -158,6 +161,7 @@ impl WorkerRegistry {
task_count, task_count,
wait_condvar, wait_condvar,
top_level_ctx, top_level_ctx,
llvm_options: llvm_options.clone(),
}); });
let mut handles = Vec::new(); let mut handles = Vec::new();
@ -242,7 +246,7 @@ impl WorkerRegistry {
{ {
let _data = PASSES_INIT_LOCK.lock(); let _data = PASSES_INIT_LOCK.lock();
let pass_builder = PassManagerBuilder::create(); let pass_builder = PassManagerBuilder::create();
pass_builder.set_optimization_level(OptimizationLevel::Default); pass_builder.set_optimization_level(self.llvm_options.opt_level);
pass_builder.populate_function_pass_manager(&passes); pass_builder.populate_function_pass_manager(&passes);
} }
@ -274,6 +278,13 @@ impl WorkerRegistry {
println!("{}", err.to_string()); println!("{}", err.to_string());
panic!() panic!()
} }
if self.llvm_options.emit_llvm {
println!("LLVM IR for {}", module.get_name().to_str().unwrap());
println!("{}", module.to_string());
println!();
}
f.run(&module); f.run(&module);
let mut lock = self.task_count.lock(); let mut lock = self.task_count.lock();
*lock += 1; *lock += 1;
@ -634,7 +645,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
), ),
/* directory */ "", /* directory */ "",
/* producer */ "NAC3", /* producer */ "NAC3",
/* is_optimized */ true, /* is_optimized */ registry.llvm_options.opt_level != OptimizationLevel::None,
/* compiler command line flags */ "", /* compiler command line flags */ "",
/* runtime_ver */ 0, /* runtime_ver */ 0,
/* split_name */ "", /* split_name */ "",
@ -669,7 +680,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
/* is_definition */ true, /* is_definition */ true,
/* scope_line */ row as u32, /* scope_line */ row as u32,
/* flags */ inkwell::debug_info::DIFlags::PUBLIC, /* flags */ inkwell::debug_info::DIFlags::PUBLIC,
/* is_optimized */ true, /* is_optimized */ registry.llvm_options.opt_level != OptimizationLevel::None,
); );
fn_val.set_subprogram(func_scope); fn_val.set_subprogram(func_scope);

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
codegen::{ codegen::{
concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenTask, DefaultCodeGenerator, concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenLLVMOptions, CodeGenTask,
WithCall, WorkerRegistry, DefaultCodeGenerator, WithCall, WorkerRegistry,
}, },
symbol_resolver::{SymbolResolver, ValueEnum}, symbol_resolver::{SymbolResolver, ValueEnum},
toplevel::{ toplevel::{
@ -13,6 +13,7 @@ use crate::{
}, },
}; };
use indoc::indoc; use indoc::indoc;
use inkwell::OptimizationLevel;
use nac3parser::{ use nac3parser::{
ast::{fold::Fold, StrRef}, ast::{fold::Fold, StrRef},
parser::parse_program, parser::parse_program,
@ -220,7 +221,17 @@ fn test_primitives() {
.trim(); .trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim()); assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
}))); })));
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f);
let llvm_options = CodeGenLLVMOptions {
opt_level: OptimizationLevel::Default,
emit_llvm: false,
};
let (registry, handles) = WorkerRegistry::create_workers(
threads,
top_level,
&llvm_options,
f
);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
} }
@ -395,7 +406,17 @@ fn test_simple_call() {
.trim(); .trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim()); assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
}))); })));
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f);
let llvm_options = CodeGenLLVMOptions {
opt_level: OptimizationLevel::Default,
emit_llvm: false,
};
let (registry, handles) = WorkerRegistry::create_workers(
threads,
top_level,
&llvm_options,
f
);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
} }

View File

@ -10,8 +10,8 @@ use std::{borrow::Borrow, collections::HashMap, fs, path::Path, sync::Arc};
use nac3core::{ use nac3core::{
codegen::{ codegen::{
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenTask, DefaultCodeGenerator, concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions, CodeGenTask,
WithCall, WorkerRegistry, DefaultCodeGenerator, WithCall, WorkerRegistry,
}, },
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
toplevel::{ toplevel::{
@ -255,6 +255,10 @@ fn main() {
} }
}; };
let llvm_options = CodeGenLLVMOptions {
opt_level: OptimizationLevel::Default,
emit_llvm: false,
};
let task = CodeGenTask { let task = CodeGenTask {
subst: Default::default(), subst: Default::default(),
symbol_name: "run".to_string(), symbol_name: "run".to_string(),
@ -278,7 +282,7 @@ fn main() {
let threads = (0..threads) let threads = (0..threads)
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i), 64))) .map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i), 64)))
.collect(); .collect();
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f); let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, f);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);