Compare commits
3 Commits
1d0356e3c4
...
5668fd9254
Author | SHA1 | Date |
---|---|---|
David Mak | 5668fd9254 | |
David Mak | 6db0157b79 | |
David Mak | 297d07f116 |
|
@ -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,8 @@ 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_options: CodeGenLLVMOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
||||||
|
@ -551,6 +552,7 @@ impl Nac3 {
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
calls: instance.calls,
|
calls: instance.calls,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
llvm_options: self.llvm_options,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut store = ConcreteTypeStore::new();
|
let mut store = ConcreteTypeStore::new();
|
||||||
|
@ -568,6 +570,7 @@ impl Nac3 {
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
calls: Arc::new(Default::default()),
|
calls: Arc::new(Default::default()),
|
||||||
id: 0,
|
id: 0,
|
||||||
|
llvm_options: self.llvm_options,
|
||||||
};
|
};
|
||||||
|
|
||||||
let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default();
|
let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default();
|
||||||
|
@ -885,6 +888,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,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -601,6 +601,7 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
store,
|
store,
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
id,
|
id,
|
||||||
|
llvm_options: ctx.llvm_options,
|
||||||
});
|
});
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -59,6 +59,15 @@ lazy_static!(
|
||||||
static ref PASSES_INIT_LOCK: Mutex<AtomicBool> = Mutex::new(AtomicBool::new(true));
|
static ref PASSES_INIT_LOCK: Mutex<AtomicBool> = 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 struct CodeGenContext<'ctx, 'a> {
|
||||||
pub ctx: &'ctx Context,
|
pub ctx: &'ctx Context,
|
||||||
pub builder: Builder<'ctx>,
|
pub builder: Builder<'ctx>,
|
||||||
|
@ -89,6 +98,8 @@ 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,
|
||||||
|
/// Additional LLVM options for Codegen
|
||||||
|
pub llvm_options: CodeGenLLVMOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
|
@ -225,24 +236,32 @@ impl WorkerRegistry {
|
||||||
context.i32_type().const_int(4, false),
|
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();
|
let mut errors = HashSet::new();
|
||||||
while let Some(task) = self.receiver.recv().unwrap() {
|
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) {
|
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 +283,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 +301,8 @@ 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,
|
||||||
|
/// Additional LLVM options for Codegen
|
||||||
|
pub llvm_options: CodeGenLLVMOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_llvm_type<'ctx>(
|
fn get_llvm_type<'ctx>(
|
||||||
|
@ -624,7 +646,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.llvm_options.opt_level != OptimizationLevel::None,
|
||||||
/* compiler command line flags */ "",
|
/* compiler command line flags */ "",
|
||||||
/* runtime_ver */ 0,
|
/* runtime_ver */ 0,
|
||||||
/* split_name */ "",
|
/* split_name */ "",
|
||||||
|
@ -659,7 +681,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.llvm_options.opt_level != OptimizationLevel::None,
|
||||||
);
|
);
|
||||||
fn_val.set_subprogram(func_scope);
|
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,
|
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()),
|
||||||
|
llvm_options: task.llvm_options,
|
||||||
};
|
};
|
||||||
|
|
||||||
let loc = code_gen_context.debug_info.0.create_debug_location(
|
let loc = code_gen_context.debug_info.0.create_debug_location(
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -157,6 +158,10 @@ fn test_primitives() {
|
||||||
store,
|
store,
|
||||||
signature,
|
signature,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
llvm_options: CodeGenLLVMOptions {
|
||||||
|
opt_level: OptimizationLevel::Default,
|
||||||
|
emit_llvm: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||||
// the following IR is equivalent to
|
// the following IR is equivalent to
|
||||||
|
@ -355,6 +360,10 @@ fn test_simple_call() {
|
||||||
signature,
|
signature,
|
||||||
store,
|
store,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
llvm_options: CodeGenLLVMOptions {
|
||||||
|
opt_level: OptimizationLevel::Default,
|
||||||
|
emit_llvm: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||||
let expected = indoc! {"
|
let expected = indoc! {"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -7,11 +7,12 @@ 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::{
|
||||||
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::{
|
||||||
|
@ -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,10 @@ fn main() {
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
calls: instance.calls,
|
calls: instance.calls,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
llvm_options: CodeGenLLVMOptions {
|
||||||
|
opt_level,
|
||||||
|
emit_llvm,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default();
|
let membuffers: Arc<Mutex<Vec<Vec<u8>>>> = Default::default();
|
||||||
|
@ -318,7 +332,7 @@ fn main() {
|
||||||
&triple,
|
&triple,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
OptimizationLevel::Default,
|
opt_level,
|
||||||
RelocMode::Default,
|
RelocMode::Default,
|
||||||
CodeModel::Default,
|
CodeModel::Default,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue