Compare commits

...

3 Commits

Author SHA1 Message Date
David Mak 1d0356e3c4 meta: Update run_demo.sh
- Allow more than one argument to nac3standalone executable
- Abort linking process if standalone executable exits with error
2023-09-06 20:25:37 +08:00
David Mak 95222331b6 standalone: Expose flags in command-line 2023-09-06 20:25:35 +08:00
David Mak 5165e61507 core: Add opt_level and emit_llvm to CodeGen options 2023-09-06 20:25:23 +08:00
4 changed files with 50 additions and 17 deletions

View File

@ -601,6 +601,8 @@ pub fn gen_func_instance<'ctx, 'a>(
store, store,
unifier_index: instance.unifier_id, unifier_index: instance.unifier_id,
id, id,
opt_level: ctx.opt_level,
emit_llvm: ctx.emit_llvm,
}); });
Ok(symbol) Ok(symbol)
} else { } else {

View File

@ -89,6 +89,10 @@ pub struct CodeGenContext<'ctx, 'a> {
Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>, Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>,
pub need_sret: bool, pub need_sret: bool,
pub current_loc: Location, pub current_loc: Location,
/// 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,
} }
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
@ -225,6 +229,8 @@ impl WorkerRegistry {
context.i32_type().const_int(4, false), context.i32_type().const_int(4, false),
); );
let mut errors = HashSet::new();
while let Some(task) = self.receiver.recv().unwrap() {
let passes = PassManager::create(&module); let passes = PassManager::create(&module);
// HACK: This critical section is a work-around for issue // HACK: This critical section is a work-around for issue
@ -232,17 +238,23 @@ 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(task.opt_level);
pass_builder.populate_function_pass_manager(&passes); pass_builder.populate_function_pass_manager(&passes);
} }
let mut errors = HashSet::new(); let emit_llvm = task.emit_llvm;
while let Some(task) = self.receiver.recv().unwrap() {
match gen_func(&context, generator, self, builder, module, task) { match gen_func(&context, generator, self, builder, module, task) {
Ok(result) => { Ok(result) => {
builder = result.0; builder = result.0;
passes.run_on(&result.2); passes.run_on(&result.2);
module = result.1; 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)) => { Err((old_builder, e)) => {
builder = old_builder; builder = old_builder;
@ -264,6 +276,7 @@ impl WorkerRegistry {
println!("{}", err.to_string()); println!("{}", err.to_string());
panic!() panic!()
} }
f.run(&module); f.run(&module);
let mut lock = self.task_count.lock(); let mut lock = self.task_count.lock();
*lock += 1; *lock += 1;
@ -281,6 +294,10 @@ pub struct CodeGenTask {
pub unifier_index: usize, pub unifier_index: usize,
pub resolver: Arc<dyn SymbolResolver + Send + Sync>, pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
pub id: usize, pub id: usize,
/// 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,
} }
fn get_llvm_type<'ctx>( fn get_llvm_type<'ctx>(
@ -624,7 +641,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 */ task.opt_level != OptimizationLevel::None,
/* compiler command line flags */ "", /* compiler command line flags */ "",
/* runtime_ver */ 0, /* runtime_ver */ 0,
/* split_name */ "", /* split_name */ "",
@ -659,7 +676,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 */ task.opt_level != OptimizationLevel::None,
); );
fn_val.set_subprogram(func_scope); fn_val.set_subprogram(func_scope);
@ -686,6 +703,8 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
need_sret: has_sret, need_sret: has_sret,
current_loc: Default::default(), current_loc: Default::default(),
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()), debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
opt_level: task.opt_level,
emit_llvm: task.emit_llvm,
}; };
let loc = code_gen_context.debug_info.0.create_debug_location( let loc = code_gen_context.debug_info.0.create_debug_location(

View File

@ -15,6 +15,6 @@ else
fi fi
rm -f *.o rm -f *.o
$nac3standalone $1 $nac3standalone "$@" || exit $?
rustc -o demo demo.rs -Crelocation-model=static -Clink-arg=./module.o rustc -o demo demo.rs -Crelocation-model=static -Clink-arg=./module.o || exit $?
./demo ./demo

View File

@ -7,6 +7,7 @@ use inkwell::{
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use std::{borrow::Borrow, collections::HashMap, fs, path::Path, sync::Arc}; use std::{borrow::Borrow, collections::HashMap, fs, path::Path, sync::Arc};
use std::mem::transmute;
use nac3core::{ use nac3core::{
codegen::{ codegen::{
@ -41,6 +42,14 @@ struct CommandLineArgs {
/// The number of threads allocated to processing the source file. /// The number of threads allocated to processing the source file.
#[arg(default_value_t = 1)] #[arg(default_value_t = 1)]
threads: u32, threads: u32,
/// The level to optimize the LLVM IR.
#[arg(short = 'O', default_value_t = 2, value_parser = clap::value_parser!(u32).range(0..=3))]
opt_level: u32,
/// Whether to emit LLVM IR at the end of every module.
#[arg(long, default_value_t = false)]
emit_llvm: bool,
} }
fn handle_typevar_definition( fn handle_typevar_definition(
@ -169,7 +178,8 @@ fn handle_assignment_pattern(
fn main() { fn main() {
let cli = CommandLineArgs::parse(); let cli = CommandLineArgs::parse();
let CommandLineArgs { file_name, threads } = cli; let CommandLineArgs { file_name, threads, opt_level, emit_llvm } = cli;
let opt_level: OptimizationLevel = unsafe { transmute(opt_level) };
Target::initialize_all(&InitializationConfig::default()); Target::initialize_all(&InitializationConfig::default());
@ -265,6 +275,8 @@ fn main() {
unifier_index: instance.unifier_id, unifier_index: instance.unifier_id,
calls: instance.calls, calls: instance.calls,
id: 0, id: 0,
opt_level,
emit_llvm,
}; };
let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default(); let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default();
@ -318,7 +330,7 @@ fn main() {
&triple, &triple,
"", "",
"", "",
OptimizationLevel::Default, opt_level,
RelocMode::Default, RelocMode::Default,
CodeModel::Default, CodeModel::Default,
) )