Compare commits

...

5 Commits

5 changed files with 111 additions and 47 deletions

1
Cargo.lock generated
View File

@ -521,6 +521,7 @@ dependencies = [
"inkwell", "inkwell",
"insta", "insta",
"itertools", "itertools",
"lazy_static",
"nac3parser", "nac3parser",
"parking_lot 0.11.2", "parking_lot 0.11.2",
"rayon", "rayon",

View File

@ -10,6 +10,7 @@ crossbeam = "0.8.1"
parking_lot = "0.11.1" parking_lot = "0.11.1"
rayon = "1.5.1" rayon = "1.5.1"
nac3parser = { path = "../nac3parser" } nac3parser = { path = "../nac3parser" }
lazy_static = "1.4.0"
[dependencies.inkwell] [dependencies.inkwell]
git = "https://github.com/TheDan64/inkwell.git" git = "https://github.com/TheDan64/inkwell.git"

View File

@ -165,6 +165,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
) -> BasicTypeEnum<'ctx> { ) -> BasicTypeEnum<'ctx> {
get_llvm_type( get_llvm_type(
self.ctx, self.ctx,
&self.module,
generator, generator,
&mut self.unifier, &mut self.unifier,
self.top_level, self.top_level,

View File

@ -31,6 +31,7 @@ use std::sync::{
Arc, Arc,
}; };
use std::thread; use std::thread;
use lazy_static::lazy_static;
pub mod concrete_type; pub mod concrete_type;
pub mod expr; pub mod expr;
@ -52,6 +53,12 @@ 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);
lazy_static!(
// HACK: The Mutex is a work-around for issue
// https://git.m-labs.hk/M-Labs/nac3/issues/275
static ref PASSES_INIT_LOCK: Mutex<AtomicBool> = Mutex::new(AtomicBool::new(true));
);
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>,
@ -205,7 +212,7 @@ impl WorkerRegistry {
fn worker_thread<G: CodeGenerator>(&self, generator: &mut G, f: Arc<WithCall>) { fn worker_thread<G: CodeGenerator>(&self, generator: &mut G, f: Arc<WithCall>) {
let context = Context::create(); let context = Context::create();
let mut builder = context.create_builder(); let mut builder = context.create_builder();
let module = context.create_module(generator.get_name()); let mut module = context.create_module(generator.get_name());
module.add_basic_value_flag( module.add_basic_value_flag(
"Debug Info Version", "Debug Info Version",
@ -218,23 +225,30 @@ 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(); let pass_builder = PassManagerBuilder::create();
pass_builder.set_optimization_level(OptimizationLevel::Default); pass_builder.set_optimization_level(OptimizationLevel::Default);
let passes = PassManager::create(&module);
pass_builder.populate_function_pass_manager(&passes); 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 tmp_module = context.create_module("tmp"); match gen_func(&context, generator, self, builder, module, task) {
match gen_func(&context, generator, self, builder, tmp_module, task) {
Ok(result) => { Ok(result) => {
builder = result.0; builder = result.0;
passes.run_on(&result.2); passes.run_on(&result.2);
module.link_in_module(result.1).unwrap(); module = result.1;
} }
Err((old_builder, e)) => { Err((old_builder, e)) => {
builder = old_builder; builder = old_builder;
errors.insert(e); errors.insert(e);
// create a new empty module just to continue codegen and collect errors
module = context.create_module(&format!("{}_recover", generator.get_name()));
} }
} }
*self.task_count.lock() -= 1; *self.task_count.lock() -= 1;
@ -271,6 +285,7 @@ pub struct CodeGenTask {
fn get_llvm_type<'ctx>( fn get_llvm_type<'ctx>(
ctx: &'ctx Context, ctx: &'ctx Context,
module: &Module<'ctx>,
generator: &mut dyn CodeGenerator, generator: &mut dyn CodeGenerator,
unifier: &mut Unifier, unifier: &mut Unifier,
top_level: &TopLevelContext, top_level: &TopLevelContext,
@ -295,6 +310,7 @@ fn get_llvm_type<'ctx>(
) if *obj_id == *opt_id => { ) if *obj_id == *opt_id => {
return get_llvm_type( return get_llvm_type(
ctx, ctx,
module,
generator, generator,
unifier, unifier,
top_level, top_level,
@ -311,16 +327,24 @@ fn get_llvm_type<'ctx>(
// a struct with fields in the order of declaration // a struct with fields in the order of declaration
let top_level_defs = top_level.definitions.read(); let top_level_defs = top_level.definitions.read();
let definition = top_level_defs.get(obj_id.0).unwrap(); let definition = top_level_defs.get(obj_id.0).unwrap();
let ty = if let TopLevelDef::Class { name, fields: fields_list, .. } = let ty = if let TopLevelDef::Class { fields: fields_list, .. } =
&*definition.read() &*definition.read()
{ {
let struct_type = ctx.opaque_struct_type(&name.to_string()); let name = unifier.stringify(ty);
type_cache.insert(unifier.get_representative(ty), struct_type.ptr_type(AddressSpace::Generic).into()); match module.get_struct_type(&name) {
Some(t) => t.ptr_type(AddressSpace::Generic).into(),
None => {
let struct_type = ctx.opaque_struct_type(&name);
type_cache.insert(
unifier.get_representative(ty),
struct_type.ptr_type(AddressSpace::Generic).into()
);
let fields = fields_list let fields = fields_list
.iter() .iter()
.map(|f| { .map(|f| {
get_llvm_type( get_llvm_type(
ctx, ctx,
module,
generator, generator,
unifier, unifier,
top_level, top_level,
@ -332,6 +356,8 @@ fn get_llvm_type<'ctx>(
.collect_vec(); .collect_vec();
struct_type.set_body(&fields, false); struct_type.set_body(&fields, false);
struct_type.ptr_type(AddressSpace::Generic).into() struct_type.ptr_type(AddressSpace::Generic).into()
}
}
} else { } else {
unreachable!() unreachable!()
}; };
@ -341,14 +367,19 @@ fn get_llvm_type<'ctx>(
// a struct with fields in the order present in the tuple // a struct with fields in the order present in the tuple
let fields = ty let fields = ty
.iter() .iter()
.map(|ty| get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty)) .map(|ty| {
get_llvm_type(
ctx, module, generator, unifier, top_level, type_cache, primitives, *ty,
)
})
.collect_vec(); .collect_vec();
ctx.struct_type(&fields, false).into() ctx.struct_type(&fields, false).into()
} }
TList { ty } => { TList { ty } => {
// a struct with an integer and a pointer to an array // a struct with an integer and a pointer to an array
let element_type = let element_type = get_llvm_type(
get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty); ctx, module, generator, unifier, top_level, type_cache, primitives, *ty,
);
let fields = [ let fields = [
element_type.ptr_type(AddressSpace::Generic).into(), element_type.ptr_type(AddressSpace::Generic).into(),
generator.get_size_type(ctx).into(), generator.get_size_type(ctx).into(),
@ -434,6 +465,9 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
(primitives.float, context.f64_type().into()), (primitives.float, context.f64_type().into()),
(primitives.bool, context.bool_type().into()), (primitives.bool, context.bool_type().into()),
(primitives.str, { (primitives.str, {
let name = "str";
match module.get_struct_type(name) {
None => {
let str_type = context.opaque_struct_type("str"); let str_type = context.opaque_struct_type("str");
let fields = [ let fields = [
context.i8_type().ptr_type(AddressSpace::Generic).into(), context.i8_type().ptr_type(AddressSpace::Generic).into(),
@ -441,21 +475,30 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
]; ];
str_type.set_body(&fields, false); str_type.set_body(&fields, false);
str_type.into() str_type.into()
}
Some(t) => t.as_basic_type_enum()
}
}), }),
(primitives.range, context.i32_type().array_type(3).ptr_type(AddressSpace::Generic).into()), (primitives.range, context.i32_type().array_type(3).ptr_type(AddressSpace::Generic).into()),
(primitives.exception, {
let name = "Exception";
match module.get_struct_type(name) {
Some(t) => t.ptr_type(AddressSpace::Generic).as_basic_type_enum(),
None => {
let exception = context.opaque_struct_type("Exception");
let int32 = context.i32_type().into();
let int64 = context.i64_type().into();
let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum();
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
exception.set_body(&fields, false);
exception.ptr_type(AddressSpace::Generic).as_basic_type_enum()
}
}
})
] ]
.iter() .iter()
.cloned() .cloned()
.collect(); .collect();
type_cache.insert(primitives.exception, {
let exception = context.opaque_struct_type("Exception");
let int32 = context.i32_type().into();
let int64 = context.i64_type().into();
let str_ty = *type_cache.get(&primitives.str).unwrap();
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
exception.set_body(&fields, false);
exception.ptr_type(AddressSpace::Generic).into()
});
// NOTE: special handling of option cannot use this type cache since it contains type var, // NOTE: special handling of option cannot use this type cache since it contains type var,
// handled inside get_llvm_type instead // handled inside get_llvm_type instead
@ -478,7 +521,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
let ret_type = if unifier.unioned(ret, primitives.none) { let ret_type = if unifier.unioned(ret, primitives.none) {
None None
} else { } else {
Some(get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret)) Some(get_llvm_type(context, &module, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, &primitives, ret))
}; };
let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty)); let has_sret = ret_type.map_or(false, |ty| need_sret(context, ty));
@ -487,6 +530,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
.map(|arg| { .map(|arg| {
get_llvm_type( get_llvm_type(
context, context,
&module,
generator, generator,
&mut unifier, &mut unifier,
top_level_ctx.as_ref(), top_level_ctx.as_ref(),
@ -535,6 +579,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
let alloca = builder.build_alloca( let alloca = builder.build_alloca(
get_llvm_type( get_llvm_type(
context, context,
&module,
generator, generator,
&mut unifier, &mut unifier,
top_level_ctx.as_ref(), top_level_ctx.as_ref(),

View File

@ -105,7 +105,7 @@ impl SymbolResolver for Resolver {
def __init__(self): def __init__(self):
self.c: int32 = 4 self.c: int32 = 4
self.a: bool = True self.a: bool = True
"} "},
]; ];
"register" "register"
)] )]
@ -120,6 +120,22 @@ fn test_simple_register(source: Vec<&str>) {
} }
} }
#[test_case(
indoc! {"
class A:
def foo(self):
pass
"};
"register"
)]
fn test_simple_register_without_constructor(source: &str) {
let mut composer: TopLevelComposer = Default::default();
let ast = parse_program(source, Default::default()).unwrap();
let ast = ast[0].clone();
composer.register_top_level(ast, None, "".into(), false).unwrap();
}
#[test_case( #[test_case(
vec![ vec![
indoc! {" indoc! {"