diff --git a/nac3artiq/src/codegen.rs b/nac3artiq/src/codegen.rs index 7c43d88..8bec23b 100644 --- a/nac3artiq/src/codegen.rs +++ b/nac3artiq/src/codegen.rs @@ -990,11 +990,12 @@ fn rpc_codegen_callback_fn<'ctx>( } } -pub fn attributes_writeback( - ctx: &mut CodeGenContext<'_, '_>, +pub fn attributes_writeback<'ctx>( + ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut dyn CodeGenerator, inner_resolver: &InnerResolver, host_attributes: &PyObject, + return_obj: Option<(Type, ValueEnum<'ctx>)>, ) -> Result<(), String> { Python::with_gil(|py| -> PyResult> { let host_attributes: &PyList = host_attributes.downcast(py)?; @@ -1004,6 +1005,11 @@ pub fn attributes_writeback( let zero = int32.const_zero(); let mut values = Vec::new(); let mut scratch_buffer = Vec::new(); + + if let Some((ty, obj)) = return_obj { + values.push((ty, obj.to_basic_value_enum(ctx, generator, ty).unwrap())); + } + for val in (*globals).values() { let val = val.as_ref(py); let ty = inner_resolver.get_obj_type( @@ -1082,7 +1088,7 @@ pub fn attributes_writeback( let args: Vec<_> = values.into_iter().map(|(_, val)| (None, ValueEnum::Dynamic(val))).collect(); if let Err(e) = - rpc_codegen_callback_fn(ctx, None, (&fun, PrimDef::Int32.id()), args, generator, false) + rpc_codegen_callback_fn(ctx, None, (&fun, PrimDef::Int32.id()), args, generator, true) { return Ok(Err(e)); } diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 6e80fd0..e66c9d7 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -37,12 +37,12 @@ use tempfile::{self, TempDir}; use nac3core::{ codegen::{ concrete_type::ConcreteTypeStore, gen_func_impl, irrt::load_irrt, CodeGenLLVMOptions, - CodeGenTargetMachineOptions, CodeGenTask, WithCall, WorkerRegistry, + CodeGenTargetMachineOptions, CodeGenTask, CodeGenerator, WithCall, WorkerRegistry, }, inkwell::{ context::Context, memory_buffer::MemoryBuffer, - module::{Linkage, Module}, + module::{FlagBehavior, Linkage, Module}, passes::PassBuilderOptions, support::is_multithreaded, targets::*, @@ -673,33 +673,12 @@ impl Nac3 { let task = CodeGenTask { subst: Vec::default(), symbol_name: "__modinit__".to_string(), - body: instance.body, - signature, - resolver: resolver.clone(), - store, - unifier_index: instance.unifier_id, - calls: instance.calls, - id: 0, - }; - - let mut store = ConcreteTypeStore::new(); - let mut cache = HashMap::new(); - let signature = store.from_signature( - &mut composer.unifier, - &self.primitive, - &fun_signature, - &mut cache, - ); - let signature = store.add_cty(signature); - let attributes_writeback_task = CodeGenTask { - subst: Vec::default(), - symbol_name: "attributes_writeback".to_string(), body: Arc::new(Vec::default()), signature, resolver, store, unifier_index: instance.unifier_id, - calls: Arc::new(HashMap::default()), + calls: instance.calls, id: 0, }; @@ -723,19 +702,27 @@ impl Nac3 { .collect(); let membuffer = membuffers.clone(); + let mut has_return = false; py.allow_threads(|| { let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), &self.llvm_options, &f); - registry.add_task(task); - registry.wait_tasks_complete(handles); - let mut generator = - ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns); + let mut generator = ArtiqCodeGenerator::new("main".to_string(), size_t, self.time_fns); let context = Context::create(); - let module = context.create_module("attributes_writeback"); + let module = context.create_module("main"); let target_machine = self.llvm_options.create_target_machine().unwrap(); module.set_data_layout(&target_machine.get_target_data().get_data_layout()); module.set_triple(&target_machine.get_triple()); + module.add_basic_value_flag( + "Debug Info Version", + FlagBehavior::Warning, + context.i32_type().const_int(3, false), + ); + module.add_basic_value_flag( + "Dwarf Version", + FlagBehavior::Warning, + context.i32_type().const_int(4, false), + ); let builder = context.create_builder(); let (_, module, _) = gen_func_impl( &context, @@ -743,9 +730,27 @@ impl Nac3 { ®istry, builder, module, - attributes_writeback_task, + task, |generator, ctx| { - attributes_writeback(ctx, generator, inner_resolver.as_ref(), &host_attributes) + assert_eq!(instance.body.len(), 1, "toplevel module should have 1 statement"); + let StmtKind::Expr { value: ref expr, .. } = instance.body[0].node else { + unreachable!("toplevel statement must be an expression") + }; + let ExprKind::Call { .. } = expr.node else { + unreachable!("toplevel expression must be a function call") + }; + + let return_obj = + generator.gen_expr(ctx, &expr)?.map(|value| (expr.custom.unwrap(), value)); + has_return = return_obj.is_some(); + registry.wait_tasks_complete(handles); + attributes_writeback( + ctx, + generator, + inner_resolver.as_ref(), + &host_attributes, + return_obj, + ) }, ) .unwrap(); @@ -754,35 +759,23 @@ impl Nac3 { membuffer.lock().push(buffer); }); + embedding_map.setattr("expects_return", has_return).unwrap(); + // Link all modules into `main`. let buffers = membuffers.lock(); let main = context - .create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main")) + .create_module_from_ir(MemoryBuffer::create_from_memory_range( + &buffers.last().unwrap(), + "main", + )) .unwrap(); - for buffer in buffers.iter().skip(1) { + for buffer in buffers.iter().rev().skip(1) { let other = context .create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main")) .unwrap(); main.link_in_module(other).map_err(|err| CompileError::new_err(err.to_string()))?; } - let builder = context.create_builder(); - let modinit_return = main - .get_function("__modinit__") - .unwrap() - .get_last_basic_block() - .unwrap() - .get_terminator() - .unwrap(); - builder.position_before(&modinit_return); - builder - .build_call( - main.get_function("attributes_writeback").unwrap(), - &[], - "attributes_writeback", - ) - .unwrap(); - main.link_in_module(irrt).map_err(|err| CompileError::new_err(err.to_string()))?; let mut function_iter = main.get_first_function();