From 192f23bc4401e10f4b12cb07238634df564bcdbc Mon Sep 17 00:00:00 2001 From: ychenfo Date: Tue, 31 May 2022 23:03:05 +0800 Subject: [PATCH 1/3] nac3core: codegen fix call parameter type error --- nac3core/src/codegen/expr.rs | 1 + nac3core/src/codegen/mod.rs | 118 ++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index ff4a1292..92cc28a8 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -165,6 +165,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { ) -> BasicTypeEnum<'ctx> { get_llvm_type( self.ctx, + &self.module, generator, &mut self.unifier, self.top_level, diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index fbd70150..1418e400 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -205,7 +205,7 @@ impl WorkerRegistry { fn worker_thread(&self, generator: &mut G, f: Arc) { let context = Context::create(); 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( "Debug Info Version", @@ -225,16 +225,17 @@ impl WorkerRegistry { let mut errors = HashSet::new(); while let Some(task) = self.receiver.recv().unwrap() { - let tmp_module = context.create_module("tmp"); - match gen_func(&context, generator, self, builder, tmp_module, task) { + let prev_module = module.write_bitcode_to_memory(); + match gen_func(&context, generator, self, builder, module, task) { Ok(result) => { builder = result.0; passes.run_on(&result.2); - module.link_in_module(result.1).unwrap(); + module = result.1; } Err((old_builder, e)) => { builder = old_builder; errors.insert(e); + module = context.create_module_from_ir(prev_module).unwrap(); } } *self.task_count.lock() -= 1; @@ -271,6 +272,7 @@ pub struct CodeGenTask { fn get_llvm_type<'ctx>( ctx: &'ctx Context, + module: &Module<'ctx>, generator: &mut dyn CodeGenerator, unifier: &mut Unifier, top_level: &TopLevelContext, @@ -295,6 +297,7 @@ fn get_llvm_type<'ctx>( ) if *obj_id == *opt_id => { return get_llvm_type( ctx, + module, generator, unifier, top_level, @@ -311,27 +314,37 @@ fn get_llvm_type<'ctx>( // a struct with fields in the order of declaration let top_level_defs = top_level.definitions.read(); 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() { - let struct_type = ctx.opaque_struct_type(&name.to_string()); - type_cache.insert(unifier.get_representative(ty), struct_type.ptr_type(AddressSpace::Generic).into()); - let fields = fields_list - .iter() - .map(|f| { - get_llvm_type( - ctx, - generator, - unifier, - top_level, - type_cache, - primitives, - fields[&f.0].0, - ) - }) - .collect_vec(); - struct_type.set_body(&fields, false); - struct_type.ptr_type(AddressSpace::Generic).into() + let name = unifier.stringify(ty); + 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 + .iter() + .map(|f| { + get_llvm_type( + ctx, + module, + generator, + unifier, + top_level, + type_cache, + primitives, + fields[&f.0].0, + ) + }) + .collect_vec(); + struct_type.set_body(&fields, false); + struct_type.ptr_type(AddressSpace::Generic).into() + } + } } else { unreachable!() }; @@ -341,14 +354,19 @@ fn get_llvm_type<'ctx>( // a struct with fields in the order present in the tuple let fields = ty .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(); ctx.struct_type(&fields, false).into() } TList { ty } => { // a struct with an integer and a pointer to an array - let element_type = - get_llvm_type(ctx, generator, unifier, top_level, type_cache, primitives, *ty); + let element_type = get_llvm_type( + ctx, module, generator, unifier, top_level, type_cache, primitives, *ty, + ); let fields = [ element_type.ptr_type(AddressSpace::Generic).into(), generator.get_size_type(ctx).into(), @@ -434,28 +452,40 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte (primitives.float, context.f64_type().into()), (primitives.bool, context.bool_type().into()), (primitives.str, { - let str_type = context.opaque_struct_type("str"); - let fields = [ - context.i8_type().ptr_type(AddressSpace::Generic).into(), - generator.get_size_type(context).into(), - ]; - str_type.set_body(&fields, false); - str_type.into() + let name = "str"; + match module.get_struct_type(name) { + None => { + let str_type = context.opaque_struct_type("str"); + let fields = [ + context.i8_type().ptr_type(AddressSpace::Generic).into(), + generator.get_size_type(context).into(), + ]; + str_type.set_body(&fields, false); + str_type.into() + } + Some(t) => t.as_basic_type_enum() + } }), (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() .cloned() .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, // handled inside get_llvm_type instead @@ -478,7 +508,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte let ret_type = if unifier.unioned(ret, primitives.none) { None } 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)); @@ -487,6 +517,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte .map(|arg| { get_llvm_type( context, + &module, generator, &mut unifier, top_level_ctx.as_ref(), @@ -535,6 +566,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte let alloca = builder.build_alloca( get_llvm_type( context, + &module, generator, &mut unifier, top_level_ctx.as_ref(), -- 2.44.2 From 8edcb226a52bd17245212e39902730d2c098ff86 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Tue, 31 May 2022 23:05:39 +0800 Subject: [PATCH 2/3] nac3core: fix codegen error of inheritance --- nac3core/src/codegen/expr.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 92cc28a8..5c09297a 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -362,17 +362,31 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } } } - let params = if loc_params.is_empty() { - params - } else { - &loc_params - }; + let params = if loc_params.is_empty() { params } else { &loc_params }; + let params = fun + .get_type() + .get_param_types() + .into_iter() + .zip(params.iter()) + .map(|(ty, val)| match (ty, val.get_type()) { + (BasicTypeEnum::PointerType(arg_ty), BasicTypeEnum::PointerType(val_ty)) + if { + ty != val.get_type() + && arg_ty.get_element_type().is_struct_type() + && val_ty.get_element_type().is_struct_type() + } => + { + self.builder.build_bitcast(*val, arg_ty, "call_arg_cast") + } + _ => *val, + }) + .collect_vec(); let result = if let Some(target) = self.unwind_target { let current = self.builder.get_insert_block().unwrap().get_parent().unwrap(); let then_block = self.ctx.append_basic_block(current, &format!("after.{}", call_name)); let result = self .builder - .build_invoke(fun, params, then_block, target, call_name) + .build_invoke(fun, ¶ms, then_block, target, call_name) .try_as_basic_value() .left(); self.builder.position_at_end(then_block); -- 2.44.2 From 0966adca74cba449c235fb56860f1a746263ada6 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Wed, 1 Jun 2022 04:27:18 +0800 Subject: [PATCH 3/3] nac3standalone: add more tests --- nac3standalone/demo/src/inheritance.py | 32 ++++++++++++++++++++ nac3standalone/demo/src/recursive_type.py | 36 +++++++++++++++++++++++ nac3standalone/demo/src/typevar.py | 4 +++ 3 files changed, 72 insertions(+) create mode 100644 nac3standalone/demo/src/inheritance.py create mode 100644 nac3standalone/demo/src/recursive_type.py diff --git a/nac3standalone/demo/src/inheritance.py b/nac3standalone/demo/src/inheritance.py new file mode 100644 index 00000000..d280e3a5 --- /dev/null +++ b/nac3standalone/demo/src/inheritance.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +@extern +def output_int32(x: int32): + ... + +class A: + a: int32 + + def __init__(self, a: int32): + self.a = a + + def f1(self): + self.f2() + + def f2(self): + output_int32(self.a) + +class B(A): + b: int32 + + def __init__(self, b: int32): + self.a = b + 1 + self.b = b + + +def run() -> int32: + aaa = A(5) + bbb = B(2) + aaa.f1() + bbb.f1() + return 0 diff --git a/nac3standalone/demo/src/recursive_type.py b/nac3standalone/demo/src/recursive_type.py new file mode 100644 index 00000000..1444f5ac --- /dev/null +++ b/nac3standalone/demo/src/recursive_type.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +@extern +def output_int32(a: int32): + ... + +class A: + d: int32 + a: list[B] + def __init__(self, b: list[B]): + self.d = 123 + self.a = b + + def f(self): + output_int32(self.d) + +class B: + a: A + def __init__(self, a: A): + self.a = a + + def ff(self): + self.a.f() + +class Demo: + a: A + def __init__(self, a: A): + self.a = a + +def run() -> int32: + aa = A([]) + bb = B(aa) + aa.a = [bb] + d = Demo(aa) + d.a.a[0].ff() + return 0 \ No newline at end of file diff --git a/nac3standalone/demo/src/typevar.py b/nac3standalone/demo/src/typevar.py index e9def8b3..9b062214 100644 --- a/nac3standalone/demo/src/typevar.py +++ b/nac3standalone/demo/src/typevar.py @@ -34,5 +34,9 @@ def run() -> int32: insta = A() inst = C(insta) inst.foo() + + insta2 = B() + inst2 = C(insta2) + inst2.foo() return 0 -- 2.44.2