This commit is contained in:
ychenfo 2022-05-27 03:02:48 +08:00
parent b04631e935
commit 258aa4c9d6
6 changed files with 381 additions and 69 deletions

View File

@ -158,7 +158,9 @@
cargo-insta
clippy
rustfmt
lldb_14
];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
};
devShells.x86_64-linux.msys2 = pkgs.mkShell {
name = "nac3-dev-shell-msys2";

View File

@ -1,5 +1,6 @@
use std::collections::{HashMap, HashSet};
use std::fs;
use std::io::Write;
use std::process::Command;
use std::rc::Rc;
use std::sync::Arc;
@ -763,34 +764,54 @@ impl Nac3 {
let membuffer = membuffers.clone();
let f = Arc::new(WithCall::new(Box::new(move |module| {
// println!("\n\n--------------\n{}\n--------------\n", module.print_to_string().to_string());
let buffer = module.write_bitcode_to_memory();
let buffer = buffer.as_slice().into();
membuffer.lock().push(buffer);
})));
let size_t = if self.isa == Isa::Host { 64 } else { 32 };
let thread_names: Vec<String> = (0..4).map(|_| "main".to_string()).collect();
print!("input number of thread: ");
std::io::stdout().flush().unwrap();
let mut buffer = String::with_capacity(2);
// std::io::stdin().read_line(&mut buffer)?;
// println!("{} as input", buffer);
let num_thread = buffer.trim().parse::<i32>().unwrap_or_else(|_| {/* println!("using default (4 thread)"); */4});
let thread_names: Vec<String> = (0..num_thread).map(|_| "main".to_string()).collect();
// println!("number of threads: {}", thread_names.len());
// let thread_names: Vec<String> = (0..4).map(|_| "main".to_string()).collect();
let threads: Vec<_> = thread_names
.iter()
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns)))
.collect();
let membuffer = membuffers.clone();
println!("------0:");
// let membuffer = membuffers.clone();
py.allow_threads(|| {
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f);
registry.add_task(task);
registry.wait_tasks_complete(handles);
println!("------1:");
let mut generator = ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns);
let context = inkwell::context::Context::create();
let module = context.create_module("attributes_writeback");
let builder = context.create_builder();
let (_, module, _) = gen_func_impl(&context, &mut generator, &registry, builder, module,
attributes_writeback_task, |generator, ctx| {
attributes_writeback(ctx, generator, inner_resolver.as_ref(), host_attributes)
}).unwrap();
let buffer = module.write_bitcode_to_memory();
let buffer = buffer.as_slice().into();
membuffer.lock().push(buffer);
// let mut generator = ArtiqCodeGenerator::new("attributes_writeback".to_string(), size_t, self.time_fns);
// let context = inkwell::context::Context::create();
// let module = context.create_module("attributes_writeback");
// module.add_basic_value_flag(
// "Debug Info Version",
// inkwell::module::FlagBehavior::Warning,
// context.i32_type().const_int(3, false),
// );
// module.add_basic_value_flag(
// "Dwarf Version",
// inkwell::module::FlagBehavior::Warning,
// context.i32_type().const_int(4, false),
// );
// let builder = context.create_builder();
// let (_, module, _) = gen_func_impl(&context, &mut generator, &registry, builder, module,
// attributes_writeback_task, |generator, ctx| {
// attributes_writeback(ctx, generator, inner_resolver.as_ref(), host_attributes)
// }).unwrap();
// let buffer = module.write_bitcode_to_memory();
// let buffer = buffer.as_slice().into();
// membuffer.lock().push(buffer);
});
let context = inkwell::context::Context::create();
@ -798,21 +819,25 @@ impl Nac3 {
let main = context
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
.unwrap();
// println!(":1: {}", buffers.len());
for buffer in buffers.iter().skip(1) {
let other = context
.create_module_from_ir(MemoryBuffer::create_from_memory_range(buffer, "main"))
.unwrap();
// println!(":2:");
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");
// 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");
main.link_in_module(load_irrt(&context))
.map_err(|err| CompileError::new_err(err.to_string()))?;
// main.link_in_module(load_irrt(&context))
// .map_err(|err| CompileError::new_err(err.to_string()))?;
// println!(":3:");
let mut function_iter = main.get_first_function();
while let Some(func) = function_iter {
@ -822,12 +847,14 @@ impl Nac3 {
function_iter = func.get_next_function();
}
let builder = PassManagerBuilder::create();
builder.set_optimization_level(OptimizationLevel::Aggressive);
let passes = PassManager::create(());
builder.set_inliner_with_threshold(255);
builder.populate_module_pass_manager(&passes);
passes.run_on(&main);
// let builder = PassManagerBuilder::create();
// builder.set_optimization_level(OptimizationLevel::Aggressive);
// let passes = PassManager::create(());
// builder.set_inliner_with_threshold(255);
// builder.populate_module_pass_manager(&passes);
// passes.run_on(&main);
// println!("\n\n==========={}\n=============", main.print_to_string().to_string());
let (triple, features) = match isa {
Isa::Host => (

View File

@ -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,
@ -460,7 +461,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let i1_true = i1.const_all_ones();
let expect_fun = self.module.get_function("llvm.expect.i1").unwrap_or_else(|| {
self.module.add_function(
"llvm.expect",
// FIXME:
"llvm.expect.i1",
i1.fn_type(&[i1.into(), i1.into()], false),
None,
)
@ -693,6 +695,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
if let Some(obj) = &obj {
args.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
}
// println!("\n2=======getting types for func `{}`=======", symbol);
let ret_type = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
None
} else {
@ -715,6 +718,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
Some(ret_type) if !has_sret => ret_type.fn_type(&params, false),
_ => ctx.ctx.void_type().fn_type(&params, false)
};
// println!("2=======got types for func `{}`: {}=======\n", symbol, fun_ty.print_to_string().to_string());
let fun_val = ctx.module.add_function(&symbol, fun_ty, None);
let offset = if has_sret {
fun_val.add_attribute(AttributeLoc::Param(0),

View File

@ -203,9 +203,13 @@ impl WorkerRegistry {
}
fn worker_thread<G: CodeGenerator>(&self, generator: &mut G, f: Arc<WithCall>) {
// println!("thread start! 1");
let context = Context::create();
// println!("thread start! 2");
let mut builder = context.create_builder();
let module = context.create_module(generator.get_name());
// println!("thread start! 3");
let mut module = context.create_module(generator.get_name());
// println!("thread start! 4");
module.add_basic_value_flag(
"Debug Info Version",
@ -218,23 +222,46 @@ impl WorkerRegistry {
context.i32_type().const_int(4, false),
);
let pass_builder = PassManagerBuilder::create();
pass_builder.set_optimization_level(OptimizationLevel::Default);
let passes = PassManager::create(&module);
pass_builder.populate_function_pass_manager(&passes);
let mut errors = HashSet::new();
// while let Some(task) = self.receiver.recv().unwrap() {
// println!("creating tmp");
// let tmp_module = context.create_module("tmp");
// println!("creating tmp done {}", tmp_module.print_to_string().to_string());
// let n = task.symbol_name.clone();
// println!("{} start0:", n);
// let res = gen_func(&context, generator, self, builder, tmp_module, task);
// match res {
// Ok(result) => {
// builder = result.0;
// passes.run_on(&result.2);
// result.1.verify().unwrap();
// module.link_in_module(result.1).unwrap();
// }
// Err((old_builder, e)) => {
// builder = old_builder;
// errors.insert(e);
// }
// }
// println!("{} done0:", n);
// *self.task_count.lock() -= 1;
// self.wait_condvar.notify_all();
// }
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) {
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();
// passes.run_on(&result.2);
// module.link_in_module(result.1).unwrap();
module = result.1;
}
Err((old_builder, e)) => {
builder = old_builder;
// builder = old_builder;
// create a new module to continue to just collect other errors
// module = context.create_module(generator.get_name());
errors.insert(e);
panic!("Codegen error: {}", errors.into_iter().sorted().join("\n----------\n"));
}
}
*self.task_count.lock() -= 1;
@ -246,10 +273,20 @@ impl WorkerRegistry {
let result = module.verify();
if let Err(err) = result {
println!("{}", module.print_to_string().to_str().unwrap());
println!("{}", err);
println!("\n\n!!!!!!!!!!!!!!!!!!error!!!!!!!!!!!!!!!!!!!!!");
println!("{}", module.print_to_string().to_string());
println!("{}", err.to_string());
println!("!!!!!!!!!!!!!!!!!!error!!!!!!!!!!!!!!!!!!!!!\n\n");
panic!()
}
println!("aaaa");
let pass_builder = PassManagerBuilder::create();
pass_builder.set_optimization_level(OptimizationLevel::Default);
let passes = PassManager::create(&module);
pass_builder.populate_function_pass_manager(&passes);
println!("ddddd");
f.run(&module);
let mut lock = self.task_count.lock();
*lock += 1;
@ -271,6 +308,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,
@ -282,6 +320,7 @@ fn get_llvm_type<'ctx>(
// we assume the type cache should already contain primitive types,
// and they should be passed by value instead of passing as pointer.
type_cache.get(&unifier.get_representative(ty)).cloned().unwrap_or_else(|| {
// println!("getting new: {}", unifier.stringify(ty));
let ty_enum = unifier.get_ty(ty);
let result = match &*ty_enum {
TObj { obj_id, fields, .. } => {
@ -295,6 +334,7 @@ fn get_llvm_type<'ctx>(
) if *obj_id == *opt_id => {
return get_llvm_type(
ctx,
module,
generator,
unifier,
top_level,
@ -314,6 +354,28 @@ fn get_llvm_type<'ctx>(
let ty = if let TopLevelDef::Class { name, fields: fields_list, .. } =
&*definition.read()
{
// let struct_type = {
// 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,
// module,
// generator,
// unifier,
// top_level,
// type_cache,
// primitives,
// fields[&f.0].0,
// )
// })
// .collect_vec();
// struct_type.set_body(&fields, false);
// struct_type
// };
let struct_type = module.get_struct_type(&name.to_string()).unwrap_or_else(|| {
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
@ -321,6 +383,7 @@ fn get_llvm_type<'ctx>(
.map(|f| {
get_llvm_type(
ctx,
module,
generator,
unifier,
top_level,
@ -331,7 +394,11 @@ fn get_llvm_type<'ctx>(
})
.collect_vec();
struct_type.set_body(&fields, false);
struct_type.ptr_type(AddressSpace::Generic).into()
struct_type
});
let res = struct_type.ptr_type(AddressSpace::Generic).into();
// println!("got: {:?}", res);
res
} else {
unreachable!()
};
@ -341,14 +408,14 @@ 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);
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(),
@ -475,10 +542,11 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
} else {
unreachable!()
};
// println!("\n=======getting types for func `{}`=======", task.symbol_name);
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 +555,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(),
@ -497,7 +566,6 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
.into()
})
.collect_vec();
if has_sret {
params.insert(0, ret_type.unwrap().ptr_type(AddressSpace::Generic).into());
}
@ -506,7 +574,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
Some(ret_type) if !has_sret => ret_type.fn_type(&params, false),
_ => context.void_type().fn_type(&params, false)
};
// println!("=======got types for func `{}`: {:?}=======\n", task.symbol_name, fn_type);
let symbol = &task.symbol_name;
let fn_val =
module.get_function(symbol).unwrap_or_else(|| module.add_function(symbol, fn_type, None));
@ -535,6 +603,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(),
@ -678,11 +747,15 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
module: Module<'ctx>,
task: CodeGenTask,
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
let n = task.symbol_name.clone();
println!("{} start:", n);
let body = task.body.clone();
gen_func_impl(context, generator, registry, builder, module, task, |generator, ctx| {
let res = gen_func_impl(context, generator, registry, builder, module, task, |generator, ctx| {
for stmt in body.iter() {
generator.gen_stmt(ctx, stmt)?;
}
Ok(())
})
});
println!("{} end:", n);
res
}

View File

@ -7,8 +7,8 @@ if [ -z "$1" ]; then
exit 1
fi
if [ -e ../../target/release/nac3standalone ]; then
nac3standalone=../../target/release/nac3standalone
if [ -e ../../target/debug/nac3standalone ]; then
nac3standalone=../../target/debug/nac3standalone
else
# used by Nix builds
nac3standalone=../../target/x86_64-unknown-linux-gnu/release/nac3standalone

View File

@ -2,7 +2,7 @@ use inkwell::{
memory_buffer::MemoryBuffer,
passes::{PassManager, PassManagerBuilder},
targets::*,
OptimizationLevel,
OptimizationLevel, module::Module, context::Context, AddressSpace,
};
use parking_lot::{Mutex, RwLock};
use std::{borrow::Borrow, collections::HashMap, env, fs, path::Path, sync::Arc};
@ -156,7 +156,7 @@ fn handle_assignment_pattern(
fn main() {
let file_name = env::args().nth(1).unwrap();
let threads: u32 = env::args().nth(2).map(|s| str::parse(&s).unwrap()).unwrap_or(1);
let threads: u32 = env::args().nth(2).map(|s| str::parse(&s).unwrap()).unwrap_or(2);
Target::initialize_all(&InitializationConfig::default());
@ -313,4 +313,210 @@ fn main() {
target_machine
.write_to_file(&main, FileType::Object, Path::new("module.o"))
.expect("couldn't write module to file");
// ===================================
// let ctxx = inkwell::context::Context::create();
// let ctxx2 = inkwell::context::Context::create();
// let ctxx3 = inkwell::context::Context::create();
// // let builder = PassManagerBuilder::create();
// // builder.set_optimization_level(OptimizationLevel::Aggressive);
// // let passes = PassManager::create(());
// // builder.set_inliner_with_threshold(255);
// // builder.populate_module_pass_manager(&passes);
// let mmm = test2(&ctxx, &ctxx, &ctxx3);
// // passes.run_on(&mmm);
// Target::initialize_all(&InitializationConfig::default());
// let triple = TargetMachine::get_default_triple();
// let target = Target::from_triple(&triple).expect("couldn't create target from target triple");
// let target_machine = target
// .create_target_machine(
// &triple,
// "",
// "",
// OptimizationLevel::Default,
// RelocMode::Default,
// CodeModel::Default,
// )
// .expect("couldn't create target machine");
// target_machine
// .write_to_file(&mmm, FileType::Object, Path::new("module.o"))
// .expect("couldn't write module to file");
}
fn test<'ctx>(ctx: &'ctx Context, ctx2: &'ctx Context, ctx3: &'ctx Context) -> Module<'ctx> {
let module = ctx.create_module("test");
let module2 = ctx2.create_module("test2");
let builder = ctx.create_builder();
let builder2 = ctx2.create_builder();
let int32 = ctx.i32_type();
let int8 = ctx.i8_type();
let int322 = ctx2.i32_type();
let int82 = ctx2.i8_type();
let opaque = ctx.opaque_struct_type("TestType");
let opaque = ctx.opaque_struct_type("TestType");
opaque.set_body(&[int32.into(), opaque.ptr_type(AddressSpace::Generic).into()], false);
let opaque = opaque.ptr_type(AddressSpace::Generic);
// let opaque2 = module.get_struct_type("TestType").unwrap();
let opaque2 = ctx2.opaque_struct_type("TestType");
// let opaque2 = ctx2.opaque_struct_type("TestType");
opaque2.set_body(&[int322.into(), opaque2.ptr_type(AddressSpace::Generic).into()], false);
let opaque2 = opaque2.ptr_type(AddressSpace::Generic);
let func2 = module2.add_function("f", ctx2.void_type().fn_type(&[opaque2.into()], false), None);
let func2_bb = ctx2.append_basic_block(func2, "init");
builder2.position_at_end(func2_bb);
builder2.build_return(None);
let func = module.add_function("run", ctx.void_type().fn_type(&[], false), None);
let fun2_mod1 = module.add_function("f", ctx.void_type().fn_type(&[opaque.into()], false), None);
let func1_bb = ctx.append_basic_block(func, "init");
builder.position_at_end(func1_bb);
let opaque1_ptr = builder.build_alloca(opaque.get_element_type().into_struct_type(), "alloc1");
let opaque2_ptr = builder.build_alloca(opaque.get_element_type().into_struct_type(), "alloc2");
builder.build_store(
unsafe { builder.build_gep(opaque1_ptr, &[int32.const_zero(), int32.const_zero()], "gep") },
int32.const_int(123, false)
);
builder.build_store(
unsafe { builder.build_gep(opaque2_ptr, &[int32.const_zero(), int32.const_zero()], "gep") },
int32.const_int(23, false)
);
builder.build_store(
unsafe { builder.build_gep(opaque1_ptr, &[int32.const_zero(), int32.const_int(1, false)], "gep") },
opaque2_ptr
);
builder.build_store(
unsafe { builder.build_gep(opaque2_ptr, &[int32.const_zero(), int32.const_int(1, false)], "gep") },
opaque1_ptr
);
// let arr = builder.build_array_alloca(opaque, int32.const_int(2, false), "arr");
// builder.build_store(
// unsafe { builder.build_gep(arr, &[int32.const_zero()], "zero")},
// opaque1_ptr
// );
let arr = module.add_global(
opaque.array_type(2),
None,
"arr_const",
);
arr.set_initializer(&opaque.const_array(&[opaque1_ptr, opaque2_ptr]));
let arr = arr.as_pointer_value();
let arg = builder.build_load(
unsafe { builder.build_gep(arr, &[int32.const_zero(), int32.const_zero()], "zero")},
"load"
);
builder.build_call(fun2_mod1, &[arg.into()], "call");
builder.build_return(None);
// builder.build_call(func2, args, name)
println!("before: \n========= module1: \n{}\n=========module2: \n{}=======\n\n", module.print_to_string().to_string(), module2.print_to_string().to_string());
module.verify().unwrap();
module2.verify().unwrap();
// module.link_in_module(module2).unwrap();
let mut mem: Vec<Vec<u8>> = Default::default();
let bitcode1 = module.write_bitcode_to_memory();
let bitcode1 = bitcode1.as_slice();
mem.push(bitcode1.into());
let bitcode2 = module2.write_bitcode_to_memory();
let bitcode2 = bitcode2.as_slice();
mem.push(bitcode2.into());
let mod1 = ctx3.create_module_from_ir(MemoryBuffer::create_from_memory_range(&mem[0], "mod1")).unwrap();
let mod2 = ctx3.create_module_from_ir(MemoryBuffer::create_from_memory_range(&mem[1], "mod2")).unwrap();
mod1.verify().unwrap();
mod2.verify().unwrap();
mod1.link_in_module(mod2).unwrap();
let module = mod1;
println!("after");
println!("\n\n====finish===\n{}\n=====finish=====\n\n\n", module.print_to_string().to_string());
println!("before2");
match module.verify() {
Ok(_) => (),
Err(s) => {
println!("after2");
println!("\n\n=======\n{}\n==========\n{}\n\n", module.print_to_string().to_string(), s.to_string());
println!("after3");
panic!();
}
};
println!("\n=====done===========");
module
}
fn test2<'ctx>(ctx: &'ctx Context, ctx2: &'ctx Context, ctx3: &'ctx Context) -> Module<'ctx> {
let module = ctx.create_module("test");
let module2 = ctx2.create_module("test2");
let builder = ctx.create_builder();
let builder2 = ctx2.create_builder();
let int32 = ctx.i32_type();
let int8 = ctx.i8_type();
let int322 = ctx2.i32_type();
let int82 = ctx2.i8_type();
let opaque = ctx.opaque_struct_type("TestType");
opaque.set_body(&[int32.into(), int8.into()], false);
let opaque = opaque.ptr_type(AddressSpace::Generic);
let opaque2 = module2.get_struct_type("TestType").unwrap();
// let opaque2 = ctx2.opaque_struct_type("TestType");
// let opaque2 = ctx2.opaque_struct_type("TestType");
opaque2.set_body(&[int322.into(), int82.into()], false);
let opaque2 = opaque2.ptr_type(AddressSpace::Generic);
let func2 = module2.add_function("f", ctx2.void_type().fn_type(&[opaque2.into()], false), None);
let func2_bb = ctx2.append_basic_block(func2, "init");
builder2.position_at_end(func2_bb);
builder2.build_return(None);
let func = module.add_function("run", ctx.void_type().fn_type(&[], false), None);
// let fun2_mod1 = module.add_function("f", ctx.void_type().fn_type(&[opaque2.into()], false), None);
let func1_bb = ctx.append_basic_block(func, "init");
builder.position_at_end(func1_bb);
let opaque1_ptr = builder.build_alloca(opaque.get_element_type().into_struct_type(), "alloc1");
builder.build_store(
unsafe { builder.build_gep(opaque1_ptr, &[int32.const_zero(), int32.const_zero()], "gep") },
int32.const_int(123, false)
);
builder.build_store(
unsafe { builder.build_gep(opaque1_ptr, &[int32.const_zero(), int32.const_int(1, false)], "gep") },
int8.const_int(12, false),
);
builder.build_call(func2, &[opaque1_ptr.into()], "call");
builder.build_return(None);
println!("before: \n========= module1: \n{}\n=========module2: \n{}=======\n\n", module.print_to_string().to_string(), module2.print_to_string().to_string());
module.verify().unwrap();
module2.verify().unwrap();
module.link_in_module(module2).unwrap();
println!("after");
// println!("\n\n====finish===\n{}\n=====finish=====\n\n\n", module.print_to_string().to_string());
println!("before2");
match module.verify() {
Ok(_) => (),
Err(s) => {
println!("after2");
println!("\n\n=======\n{}\n==========\n{}\n\n", module.print_to_string().to_string(), s.to_string());
println!("after3");
panic!();
}
};
println!("\n=====done===========");
module
}