core: Add use_demo_lib option
Allows injecting calls to demo library functions for debugging.
This commit is contained in:
parent
520e1adc56
commit
4d0d4e0eae
|
@ -14,7 +14,7 @@ use inkwell::{
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nac3core::codegen::{CodeGenLLVMOptions, CodeGenTargetMachineOptions, gen_func_impl};
|
use nac3core::codegen::{CodeGenLLVMOptions, CodeGenOptions, CodeGenTargetMachineOptions, gen_func_impl};
|
||||||
use nac3core::toplevel::builtins::get_exn_constructor;
|
use nac3core::toplevel::builtins::get_exn_constructor;
|
||||||
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
|
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
|
||||||
use nac3parser::{
|
use nac3parser::{
|
||||||
|
@ -113,8 +113,8 @@ struct Nac3 {
|
||||||
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.
|
/// Options for code generation.
|
||||||
llvm_options: CodeGenLLVMOptions,
|
codegen_options: CodeGenOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
create_exception!(nac3artiq, CompileError, exceptions::PyException);
|
||||||
|
@ -607,7 +607,7 @@ impl Nac3 {
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
threads,
|
threads,
|
||||||
top_level.clone(),
|
top_level.clone(),
|
||||||
&self.llvm_options,
|
&self.codegen_options,
|
||||||
&f
|
&f
|
||||||
);
|
);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
|
@ -674,13 +674,13 @@ impl Nac3 {
|
||||||
global_option = global.get_next_global();
|
global_option = global.get_next_global();
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_machine = self.llvm_options.target
|
let target_machine = self.codegen_options.llvm.target
|
||||||
.create_target_machine(self.llvm_options.opt_level)
|
.create_target_machine(self.codegen_options.llvm.opt_level)
|
||||||
.expect("couldn't create target machine");
|
.expect("couldn't create target machine");
|
||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
pass_options.set_merge_functions(true);
|
pass_options.set_merge_functions(true);
|
||||||
let passes = format!("default<O{}>", self.llvm_options.opt_level as u32);
|
let passes = format!("default<O{}>", self.codegen_options.llvm.opt_level as u32);
|
||||||
let result = main.run_passes(passes.as_str(), &target_machine, pass_options);
|
let result = main.run_passes(passes.as_str(), &target_machine, pass_options);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||||
|
@ -733,7 +733,7 @@ impl Nac3 {
|
||||||
/// target [isa].
|
/// target [isa].
|
||||||
fn get_llvm_target_machine(&self) -> TargetMachine {
|
fn get_llvm_target_machine(&self) -> TargetMachine {
|
||||||
Nac3::get_llvm_target_options(self.isa)
|
Nac3::get_llvm_target_options(self.isa)
|
||||||
.create_target_machine(self.llvm_options.opt_level)
|
.create_target_machine(self.codegen_options.llvm.opt_level)
|
||||||
.expect("couldn't create target machine")
|
.expect("couldn't create target machine")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -908,10 +908,13 @@ impl Nac3 {
|
||||||
string_store: Arc::default(),
|
string_store: Arc::default(),
|
||||||
exception_ids: Arc::default(),
|
exception_ids: Arc::default(),
|
||||||
deferred_eval_store: DeferredEvaluationStore::new(),
|
deferred_eval_store: DeferredEvaluationStore::new(),
|
||||||
llvm_options: CodeGenLLVMOptions {
|
codegen_options: CodeGenOptions {
|
||||||
opt_level: OptimizationLevel::Default,
|
use_demo_lib: false,
|
||||||
target: Nac3::get_llvm_target_options(isa),
|
llvm: CodeGenLLVMOptions {
|
||||||
}
|
opt_level: OptimizationLevel::Default,
|
||||||
|
target: Nac3::get_llvm_target_options(isa),
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -738,7 +738,7 @@ pub fn call_numpy_min<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
|
||||||
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||||
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes());
|
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes());
|
||||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
if ctx.registry.codegen_options.llvm.opt_level == OptimizationLevel::None {
|
||||||
let n_sz_eqz = ctx.builder
|
let n_sz_eqz = ctx.builder
|
||||||
.build_int_compare(
|
.build_int_compare(
|
||||||
IntPredicate::NE,
|
IntPredicate::NE,
|
||||||
|
@ -956,7 +956,7 @@ pub fn call_numpy_max<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
|
||||||
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||||
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes());
|
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes());
|
||||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
if ctx.registry.codegen_options.llvm.opt_level == OptimizationLevel::None {
|
||||||
let n_sz_eqz = ctx.builder
|
let n_sz_eqz = ctx.builder
|
||||||
.build_int_compare(
|
.build_int_compare(
|
||||||
IntPredicate::NE,
|
IntPredicate::NE,
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||||
|
use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue, PointerValue};
|
||||||
|
use itertools::Either;
|
||||||
|
|
||||||
|
use crate::codegen::{CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
|
/// Invokes `dbl_nan` in the demo library.
|
||||||
|
pub fn call_dbl_nan<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "dbl_nan";
|
||||||
|
|
||||||
|
assert!(ctx.registry.codegen_options.use_demo_lib);
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"mustprogress",
|
||||||
|
"nofree",
|
||||||
|
"norecurse",
|
||||||
|
"nosync",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
"willreturn",
|
||||||
|
"readnone",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[], "")
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `dbl_inf` in the demo library.
|
||||||
|
pub fn call_dbl_inf<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "dbl_inf";
|
||||||
|
|
||||||
|
assert!(ctx.registry.codegen_options.use_demo_lib);
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"mustprogress",
|
||||||
|
"nofree",
|
||||||
|
"norecurse",
|
||||||
|
"nosync",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
"willreturn",
|
||||||
|
"readnone",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[], "")
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_bool` in the demo library.
|
||||||
|
pub fn call_output_bool<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_bool";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type().get_bit_width(), llvm_i1.get_bit_width());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_i1.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_int32` in the demo library.
|
||||||
|
pub fn call_output_int32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_int32";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type().get_bit_width(), llvm_i32.get_bit_width());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_i32.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_int64` in the demo library.
|
||||||
|
pub fn call_output_int64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_int64";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_i64 = ctx.ctx.i64_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type().get_bit_width(), llvm_i64.get_bit_width());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_i64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_uint32` in the demo library.
|
||||||
|
pub fn call_output_uint32<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_uint32";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type().get_bit_width(), llvm_i32.get_bit_width());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_i32.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_uint64` in the demo library.
|
||||||
|
pub fn call_output_uint64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_uint64";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_i64 = ctx.ctx.i64_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type().get_bit_width(), llvm_i64.get_bit_width());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_i64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_float64` in the demo library.
|
||||||
|
pub fn call_output_float64<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>, value: FloatValue<'ctx>) {
|
||||||
|
const FN_NAME: &str = "output_float64";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes `output_str` in the demo library.
|
||||||
|
pub fn call_output_str<'ctx>(
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
|
) {
|
||||||
|
const FN_NAME: &str = "output_str";
|
||||||
|
|
||||||
|
if ctx.registry.codegen_options.use_demo_lib {
|
||||||
|
let llvm_void = ctx.ctx.void_type();
|
||||||
|
let llvm_str = ctx.get_llvm_type(generator, ctx.primitives.str).into_pointer_type();
|
||||||
|
|
||||||
|
debug_assert_eq!(value.get_type(), llvm_str);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_void.fn_type(&[llvm_str.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in [
|
||||||
|
"nofree",
|
||||||
|
"nounwind",
|
||||||
|
"sspstrong",
|
||||||
|
] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[value.into()], "")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ use std::thread;
|
||||||
pub mod builtin_fns;
|
pub mod builtin_fns;
|
||||||
pub mod classes;
|
pub mod classes;
|
||||||
pub mod concrete_type;
|
pub mod concrete_type;
|
||||||
|
pub mod demo_fns;
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod extern_fns;
|
pub mod extern_fns;
|
||||||
mod generator;
|
mod generator;
|
||||||
|
@ -64,6 +65,16 @@ pub struct StaticValueStore {
|
||||||
|
|
||||||
pub type VarValue<'ctx> = (PointerValue<'ctx>, Option<Arc<dyn StaticValue + Send + Sync>>, i64);
|
pub type VarValue<'ctx> = (PointerValue<'ctx>, Option<Arc<dyn StaticValue + Send + Sync>>, i64);
|
||||||
|
|
||||||
|
/// Additional options for codegen.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct CodeGenOptions {
|
||||||
|
/// Whether to use the demo library during codegen.
|
||||||
|
pub use_demo_lib: bool,
|
||||||
|
|
||||||
|
/// Options related to LLVM codegen.
|
||||||
|
pub llvm: CodeGenLLVMOptions,
|
||||||
|
}
|
||||||
|
|
||||||
/// Additional options for LLVM during codegen.
|
/// Additional options for LLVM during codegen.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct CodeGenLLVMOptions {
|
pub struct CodeGenLLVMOptions {
|
||||||
|
@ -245,8 +256,8 @@ pub struct WorkerRegistry {
|
||||||
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.
|
/// Code generation options.
|
||||||
pub llvm_options: CodeGenLLVMOptions,
|
pub codegen_options: CodeGenOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerRegistry {
|
impl WorkerRegistry {
|
||||||
|
@ -256,7 +267,7 @@ 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,
|
codegen_options: &CodeGenOptions,
|
||||||
f: &Arc<WithCall>,
|
f: &Arc<WithCall>,
|
||||||
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
||||||
let (sender, receiver) = unbounded();
|
let (sender, receiver) = unbounded();
|
||||||
|
@ -277,7 +288,7 @@ impl WorkerRegistry {
|
||||||
task_count,
|
task_count,
|
||||||
wait_condvar,
|
wait_condvar,
|
||||||
top_level_ctx,
|
top_level_ctx,
|
||||||
llvm_options: llvm_options.clone(),
|
codegen_options: codegen_options.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
|
@ -382,11 +393,12 @@ impl WorkerRegistry {
|
||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
let target_machine = self
|
let target_machine = self
|
||||||
.llvm_options
|
.codegen_options
|
||||||
|
.llvm
|
||||||
.target
|
.target
|
||||||
.create_target_machine(self.llvm_options.opt_level)
|
.create_target_machine(self.codegen_options.llvm.opt_level)
|
||||||
.unwrap_or_else(|| panic!("could not create target machine from properties {:?}", self.llvm_options.target));
|
.unwrap_or_else(|| panic!("could not create target machine from properties {:?}", self.codegen_options.llvm.target));
|
||||||
let passes = format!("default<O{}>", self.llvm_options.opt_level as u32);
|
let passes = format!("default<O{}>", self.codegen_options.llvm.opt_level as u32);
|
||||||
let result = module.run_passes(passes.as_str(), &target_machine, pass_options);
|
let result = module.run_passes(passes.as_str(), &target_machine, pass_options);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
panic!("Failed to run optimization for module `{}`: {}",
|
panic!("Failed to run optimization for module `{}`: {}",
|
||||||
|
@ -828,7 +840,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
||||||
),
|
),
|
||||||
/* directory */ "",
|
/* directory */ "",
|
||||||
/* producer */ "NAC3",
|
/* producer */ "NAC3",
|
||||||
/* is_optimized */ registry.llvm_options.opt_level != OptimizationLevel::None,
|
/* is_optimized */ registry.codegen_options.llvm.opt_level != OptimizationLevel::None,
|
||||||
/* compiler command line flags */ "",
|
/* compiler command line flags */ "",
|
||||||
/* runtime_ver */ 0,
|
/* runtime_ver */ 0,
|
||||||
/* split_name */ "",
|
/* split_name */ "",
|
||||||
|
@ -863,7 +875,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 */ registry.llvm_options.opt_level != OptimizationLevel::None,
|
/* is_optimized */ registry.codegen_options.llvm.opt_level != OptimizationLevel::None,
|
||||||
);
|
);
|
||||||
fn_val.set_subprogram(func_scope);
|
fn_val.set_subprogram(func_scope);
|
||||||
|
|
||||||
|
|
|
@ -937,7 +937,7 @@ pub fn ndarray_matmul_2d<'ctx, G: CodeGenerator>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
if ctx.registry.codegen_options.llvm.opt_level == OptimizationLevel::None {
|
||||||
let lhs_dim1 = unsafe {
|
let lhs_dim1 = unsafe {
|
||||||
lhs.dim_sizes().get_typed_unchecked(ctx, generator, &llvm_usize.const_int(1, false), None)
|
lhs.dim_sizes().get_typed_unchecked(ctx, generator, &llvm_usize.const_int(1, false), None)
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions,
|
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions, CodeGenOptions,
|
||||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
|
@ -68,6 +68,11 @@ struct CommandLineArgs {
|
||||||
/// Additional target features to enable/disable, specified using the `+`/`-` prefixes.
|
/// Additional target features to enable/disable, specified using the `+`/`-` prefixes.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
target_features: Option<String>,
|
target_features: Option<String>,
|
||||||
|
|
||||||
|
/// Enables the demo library for use in compiled executables. This requires `demo.o` to be
|
||||||
|
/// present when linking the executable.
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
fuse_demo_lib: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_typevar_definition(
|
fn handle_typevar_definition(
|
||||||
|
@ -258,6 +263,7 @@ fn main() {
|
||||||
triple,
|
triple,
|
||||||
mcpu,
|
mcpu,
|
||||||
target_features,
|
target_features,
|
||||||
|
fuse_demo_lib,
|
||||||
} = cli;
|
} = cli;
|
||||||
|
|
||||||
Target::initialize_all(&InitializationConfig::default());
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
|
@ -371,14 +377,17 @@ fn main() {
|
||||||
instance_to_stmt[""].clone()
|
instance_to_stmt[""].clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let llvm_options = CodeGenLLVMOptions {
|
let codegen_options = CodeGenOptions {
|
||||||
opt_level,
|
use_demo_lib: fuse_demo_lib,
|
||||||
target: CodeGenTargetMachineOptions {
|
llvm: CodeGenLLVMOptions {
|
||||||
triple,
|
opt_level,
|
||||||
cpu: mcpu,
|
target: CodeGenTargetMachineOptions {
|
||||||
features: target_features,
|
triple,
|
||||||
reloc_mode: RelocMode::PIC,
|
cpu: mcpu,
|
||||||
..host_target_machine
|
features: target_features,
|
||||||
|
reloc_mode: RelocMode::PIC,
|
||||||
|
..host_target_machine
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -405,7 +414,7 @@ fn main() {
|
||||||
let threads = (0..threads)
|
let threads = (0..threads)
|
||||||
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), SIZE_T)))
|
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), SIZE_T)))
|
||||||
.collect();
|
.collect();
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &codegen_options, &f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
|
|
||||||
|
@ -444,8 +453,8 @@ fn main() {
|
||||||
function_iter = func.get_next_function();
|
function_iter = func.get_next_function();
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_machine = llvm_options.target
|
let target_machine = codegen_options.llvm.target
|
||||||
.create_target_machine(llvm_options.opt_level)
|
.create_target_machine(codegen_options.llvm.opt_level)
|
||||||
.expect("couldn't create target machine");
|
.expect("couldn't create target machine");
|
||||||
|
|
||||||
let pass_options = PassBuilderOptions::create();
|
let pass_options = PassBuilderOptions::create();
|
||||||
|
|
Loading…
Reference in New Issue