From 297d07f116fb40264c9fb4193937cebe455ef668 Mon Sep 17 00:00:00 2001 From: David Mak Date: Wed, 6 Sep 2023 17:50:17 +0800 Subject: [PATCH] core: Add LLVM options to CodeGen options --- nac3artiq/src/lib.rs | 11 ++++++-- nac3core/src/codegen/expr.rs | 1 + nac3core/src/codegen/mod.rs | 49 ++++++++++++++++++++++++++---------- nac3core/src/codegen/test.rs | 13 ++++++++-- nac3standalone/src/main.rs | 8 ++++-- 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 049fdeb..9e11ebc 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -12,7 +12,7 @@ use inkwell::{ targets::*, OptimizationLevel, }; -use nac3core::codegen::gen_func_impl; +use nac3core::codegen::{CodeGenLLVMOptions, gen_func_impl}; use nac3core::toplevel::builtins::get_exn_constructor; use nac3core::typecheck::typedef::{TypeEnum, Unifier}; use nac3parser::{ @@ -97,7 +97,8 @@ struct Nac3 { top_levels: Vec, string_store: Arc>>, exception_ids: Arc>>, - deferred_eval_store: DeferredEvaluationStore + deferred_eval_store: DeferredEvaluationStore, + llvm_options: CodeGenLLVMOptions, } create_exception!(nac3artiq, CompileError, exceptions::PyException); @@ -551,6 +552,7 @@ impl Nac3 { unifier_index: instance.unifier_id, calls: instance.calls, id: 0, + llvm_options: self.llvm_options, }; let mut store = ConcreteTypeStore::new(); @@ -568,6 +570,7 @@ impl Nac3 { unifier_index: instance.unifier_id, calls: Arc::new(Default::default()), id: 0, + llvm_options: self.llvm_options, }; let membuffers: Arc>>> = Default::default(); @@ -885,6 +888,10 @@ impl Nac3 { string_store: Default::default(), exception_ids: Default::default(), deferred_eval_store: DeferredEvaluationStore::new(), + llvm_options: CodeGenLLVMOptions { + opt_level: OptimizationLevel::Default, + emit_llvm: false, + } }) } diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index b713c15..7f9537f 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -601,6 +601,7 @@ pub fn gen_func_instance<'ctx, 'a>( store, unifier_index: instance.unifier_id, id, + llvm_options: ctx.llvm_options, }); Ok(symbol) } else { diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 72ba85e..fc2e7ed 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -59,6 +59,15 @@ lazy_static!( static ref PASSES_INIT_LOCK: Mutex = Mutex::new(AtomicBool::new(true)); ); +/// Additional options for LLVM during codegen. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct CodeGenLLVMOptions { + /// The optimization level to apply on the generated LLVM IR. + pub opt_level: OptimizationLevel, + /// Whether to output the LLVM IR after generation is complete. + pub emit_llvm: bool, +} + pub struct CodeGenContext<'ctx, 'a> { pub ctx: &'ctx Context, pub builder: Builder<'ctx>, @@ -89,6 +98,8 @@ pub struct CodeGenContext<'ctx, 'a> { Option<(Vec>>, BasicBlock<'ctx>, PhiValue<'ctx>)>, pub need_sret: bool, pub current_loc: Location, + /// Additional LLVM options for Codegen + pub llvm_options: CodeGenLLVMOptions, } impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { @@ -225,24 +236,32 @@ 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(OptimizationLevel::Default); - pass_builder.populate_function_pass_manager(&passes); - } - let mut errors = HashSet::new(); while let Some(task) = self.receiver.recv().unwrap() { + 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(task.llvm_options.opt_level); + pass_builder.populate_function_pass_manager(&passes); + } + + let emit_llvm = task.llvm_options.emit_llvm; + match gen_func(&context, generator, self, builder, module, task) { Ok(result) => { builder = result.0; passes.run_on(&result.2); module = result.1; + + if emit_llvm { + println!("LLVM IR for {}", module.get_name().to_str().unwrap()); + println!("{}", module.to_string()); + println!(); + } } Err((old_builder, e)) => { builder = old_builder; @@ -264,6 +283,7 @@ impl WorkerRegistry { println!("{}", err.to_string()); panic!() } + f.run(&module); let mut lock = self.task_count.lock(); *lock += 1; @@ -281,6 +301,8 @@ pub struct CodeGenTask { pub unifier_index: usize, pub resolver: Arc, pub id: usize, + /// Additional LLVM options for Codegen + pub llvm_options: CodeGenLLVMOptions, } fn get_llvm_type<'ctx>( @@ -624,7 +646,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte ), /* directory */ "", /* producer */ "NAC3", - /* is_optimized */ true, + /* is_optimized */ task.llvm_options.opt_level != OptimizationLevel::None, /* compiler command line flags */ "", /* runtime_ver */ 0, /* split_name */ "", @@ -659,7 +681,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte /* is_definition */ true, /* scope_line */ row as u32, /* flags */ inkwell::debug_info::DIFlags::PUBLIC, - /* is_optimized */ true, + /* is_optimized */ task.llvm_options.opt_level != OptimizationLevel::None, ); fn_val.set_subprogram(func_scope); @@ -686,6 +708,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte need_sret: has_sret, current_loc: Default::default(), debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()), + llvm_options: task.llvm_options, }; let loc = code_gen_context.debug_info.0.create_debug_location( diff --git a/nac3core/src/codegen/test.rs b/nac3core/src/codegen/test.rs index 97498d1..bb90bdb 100644 --- a/nac3core/src/codegen/test.rs +++ b/nac3core/src/codegen/test.rs @@ -1,7 +1,7 @@ use crate::{ codegen::{ - concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenTask, DefaultCodeGenerator, - WithCall, WorkerRegistry, + concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenLLVMOptions, CodeGenTask, + DefaultCodeGenerator, WithCall, WorkerRegistry, }, symbol_resolver::{SymbolResolver, ValueEnum}, toplevel::{ @@ -13,6 +13,7 @@ use crate::{ }, }; use indoc::indoc; +use inkwell::OptimizationLevel; use nac3parser::{ ast::{fold::Fold, StrRef}, parser::parse_program, @@ -157,6 +158,10 @@ fn test_primitives() { store, signature, id: 0, + llvm_options: CodeGenLLVMOptions { + opt_level: OptimizationLevel::Default, + emit_llvm: false, + }, }; let f = Arc::new(WithCall::new(Box::new(|module| { // the following IR is equivalent to @@ -355,6 +360,10 @@ fn test_simple_call() { signature, store, id: 0, + llvm_options: CodeGenLLVMOptions { + opt_level: OptimizationLevel::Default, + emit_llvm: false, + }, }; let f = Arc::new(WithCall::new(Box::new(|module| { let expected = indoc! {" diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index 0faedc8..14083b8 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -10,8 +10,8 @@ use std::{borrow::Borrow, collections::HashMap, fs, path::Path, sync::Arc}; use nac3core::{ codegen::{ - concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenTask, DefaultCodeGenerator, - WithCall, WorkerRegistry, + concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions, CodeGenTask, + DefaultCodeGenerator, WithCall, WorkerRegistry, }, symbol_resolver::SymbolResolver, toplevel::{ @@ -265,6 +265,10 @@ fn main() { unifier_index: instance.unifier_id, calls: instance.calls, id: 0, + llvm_options: CodeGenLLVMOptions { + opt_level: OptimizationLevel::Default, + emit_llvm: false, + }, }; let membuffers: Arc>>> = Default::default();