nac3core: implementing #24

This commit is contained in:
pca006132 2021-09-26 22:17:09 +08:00
parent 3c121dfcda
commit d4ed76d76e
5 changed files with 88 additions and 31 deletions

View File

@ -108,6 +108,10 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
fun: (&FunSignature, DefinitionId), fun: (&FunSignature, DefinitionId),
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>, params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
) -> Option<BasicValueEnum<'ctx>> { ) -> Option<BasicValueEnum<'ctx>> {
if self.external_codegen.def_list.contains(&fun.1) {
let external_codegen = self.external_codegen.clone();
return external_codegen.run(self, obj, fun, params)
}
let key = self.get_subst_key(obj.map(|a| a.0), fun.0, None); let key = self.get_subst_key(obj.map(|a| a.0), fun.0, None);
let definition = self.top_level.definitions.read().get(fun.1.0).cloned().unwrap(); let definition = self.top_level.definitions.read().get(fun.1.0).cloned().unwrap();
let mut task = None; let mut task = None;

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
toplevel::{TopLevelContext, TopLevelDef}, toplevel::{DefinitionId, TopLevelContext, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::{CodeLocation, PrimitiveStore}, type_inferencer::{CodeLocation, PrimitiveStore},
typedef::{CallId, FunSignature, SharedUnifier, Type, TypeEnum, Unifier}, typedef::{CallId, FunSignature, SharedUnifier, Type, TypeEnum, Unifier},
@ -13,13 +13,13 @@ use inkwell::{
context::Context, context::Context,
module::Module, module::Module,
types::{BasicType, BasicTypeEnum}, types::{BasicType, BasicTypeEnum},
values::PointerValue, values::{BasicValueEnum, PointerValue},
AddressSpace, AddressSpace,
}; };
use itertools::Itertools; use itertools::Itertools;
use parking_lot::{Condvar, Mutex}; use parking_lot::{Condvar, Mutex};
use rustpython_parser::ast::{Stmt, StrRef}; use rustpython_parser::ast::{Stmt, StrRef};
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Arc,
@ -49,6 +49,7 @@ pub struct CodeGenContext<'ctx, 'a> {
// where continue and break should go to respectively // where continue and break should go to respectively
// the first one is the test_bb, and the second one is bb after the loop // the first one is the test_bb, and the second one is bb after the loop
pub loop_bb: Option<(BasicBlock<'ctx>, BasicBlock<'ctx>)>, pub loop_bb: Option<(BasicBlock<'ctx>, BasicBlock<'ctx>)>,
pub external_codegen: Arc<GenCall>,
} }
type Fp = Box<dyn Fn(&Module) + Send + Sync>; type Fp = Box<dyn Fn(&Module) + Send + Sync>;
@ -67,6 +68,42 @@ impl WithCall {
} }
} }
type GenCallCallback = Box<
dyn for<'ctx, 'a> Fn(
&mut CodeGenContext<'ctx, 'a>,
Option<(Type, BasicValueEnum)>,
(&FunSignature, DefinitionId),
Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
) -> Option<BasicValueEnum<'ctx>>
+ Send
+ Sync,
>;
pub struct GenCall {
def_list: HashSet<DefinitionId>,
fp: GenCallCallback,
}
impl GenCall {
pub fn new(fp: GenCallCallback, def_list: HashSet<DefinitionId>) -> GenCall {
GenCall { def_list, fp }
}
pub fn run<'ctx, 'a>(
&self,
ctx: &mut CodeGenContext<'ctx, 'a>,
obj: Option<(Type, BasicValueEnum<'ctx>)>,
fun: (&FunSignature, DefinitionId),
args: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
) -> Option<BasicValueEnum<'ctx>> {
(self.fp)(ctx, obj, fun, args)
}
pub fn need_external_codegen(&self, id: DefinitionId) -> bool {
self.def_list.contains(&id)
}
}
pub struct WorkerRegistry { pub struct WorkerRegistry {
sender: Arc<Sender<Option<CodeGenTask>>>, sender: Arc<Sender<Option<CodeGenTask>>>,
receiver: Arc<Receiver<Option<CodeGenTask>>>, receiver: Arc<Receiver<Option<CodeGenTask>>>,
@ -81,6 +118,7 @@ impl WorkerRegistry {
names: &[&str], names: &[&str],
top_level_ctx: Arc<TopLevelContext>, top_level_ctx: Arc<TopLevelContext>,
f: Arc<WithCall>, f: Arc<WithCall>,
external_codegen: Arc<GenCall>,
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) { ) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
let task_count = Mutex::new(0); let task_count = Mutex::new(0);
@ -102,8 +140,9 @@ impl WorkerRegistry {
let registry2 = registry.clone(); let registry2 = registry.clone();
let name = name.to_string(); let name = name.to_string();
let f = f.clone(); let f = f.clone();
let external_codegen = external_codegen.clone();
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
registry.worker_thread(name, top_level_ctx, f); registry.worker_thread(name, top_level_ctx, f, external_codegen);
}); });
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
if let Err(e) = handle.join() { if let Err(e) = handle.join() {
@ -161,13 +200,22 @@ impl WorkerRegistry {
module_name: String, module_name: String,
top_level_ctx: Arc<TopLevelContext>, top_level_ctx: Arc<TopLevelContext>,
f: Arc<WithCall>, f: Arc<WithCall>,
external_codegen: Arc<GenCall>,
) { ) {
let context = Context::create(); let context = Context::create();
let mut builder = context.create_builder(); let mut builder = context.create_builder();
let mut module = context.create_module(&module_name); let mut module = context.create_module(&module_name);
while let Some(task) = self.receiver.recv().unwrap() { while let Some(task) = self.receiver.recv().unwrap() {
let result = gen_func(&context, self, builder, module, task, top_level_ctx.clone()); let result = gen_func(
&context,
self,
builder,
module,
task,
top_level_ctx.clone(),
external_codegen.clone(),
);
builder = result.0; builder = result.0;
module = result.1; module = result.1;
*self.task_count.lock() -= 1; *self.task_count.lock() -= 1;
@ -250,6 +298,7 @@ pub fn gen_func<'ctx>(
module: Module<'ctx>, module: Module<'ctx>,
task: CodeGenTask, task: CodeGenTask,
top_level_ctx: Arc<TopLevelContext>, top_level_ctx: Arc<TopLevelContext>,
external_codegen: Arc<GenCall>,
) -> (Builder<'ctx>, Module<'ctx>) { ) -> (Builder<'ctx>, Module<'ctx>) {
// unwrap_or(0) is for unit tests without using rayon // unwrap_or(0) is for unit tests without using rayon
let (mut unifier, primitives) = { let (mut unifier, primitives) = {
@ -347,6 +396,7 @@ pub fn gen_func<'ctx>(
builder, builder,
module, module,
unifier, unifier,
external_codegen,
}; };
let mut returned = false; let mut returned = false;

View File

@ -1,15 +1,9 @@
use crate::{ use crate::{codegen::{CodeGenTask, GenCall, WithCall, WorkerRegistry}, location::Location, symbol_resolver::{SymbolResolver, SymbolValue}, toplevel::{
codegen::{CodeGenTask, WithCall, WorkerRegistry},
location::Location,
symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::{
composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef, composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
}, }, typecheck::{
typecheck::{
type_inferencer::{FunctionData, Inferencer, PrimitiveStore}, type_inferencer::{FunctionData, Inferencer, PrimitiveStore},
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier}, typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
}, }};
};
use indoc::indoc; use indoc::indoc;
use parking_lot::RwLock; use parking_lot::RwLock;
use rustpython_parser::{ast::{StrRef, fold::Fold}, parser::parse_program}; use rustpython_parser::{ast::{StrRef, fold::Fold}, parser::parse_program};
@ -188,7 +182,8 @@ fn test_primitives() {
.trim(); .trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim()); assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
}))); })));
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f); let external_codegen = Arc::new(GenCall::new(Box::new(|_, _, _, _| unimplemented!()), HashSet::new()));
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f, external_codegen);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
} }
@ -352,7 +347,8 @@ fn test_simple_call() {
.trim(); .trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim()); assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
}))); })));
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f); let external_codegen = Arc::new(GenCall::new(Box::new(|_, _, _, _| unimplemented!()), HashSet::new()));
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f, external_codegen);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
} }

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::sync::Arc; use std::sync::Arc;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
@ -14,7 +14,7 @@ use inkwell::{
use nac3core::typecheck::type_inferencer::PrimitiveStore; use nac3core::typecheck::type_inferencer::PrimitiveStore;
use nac3core::{ use nac3core::{
codegen::{CodeGenTask, WithCall, WorkerRegistry}, codegen::{CodeGenTask, WithCall, WorkerRegistry, GenCall},
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
toplevel::{composer::TopLevelComposer, TopLevelContext, TopLevelDef}, toplevel::{composer::TopLevelComposer, TopLevelContext, TopLevelDef},
typecheck::typedef::{FunSignature, FuncArg}, typecheck::typedef::{FunSignature, FuncArg},
@ -59,10 +59,10 @@ impl Nac3 {
Box::new(Resolver(internal_resolver.clone())) as Box<dyn SymbolResolver + Send + Sync> Box::new(Resolver(internal_resolver.clone())) as Box<dyn SymbolResolver + Send + Sync>
); );
Nac3 { Nac3 {
primitive: primitive, primitive,
internal_resolver: internal_resolver, internal_resolver,
resolver: resolver, resolver,
composer: composer, composer,
top_level: None top_level: None
} }
} }
@ -168,9 +168,10 @@ impl Nac3 {
.write_to_file(module, FileType::Object, Path::new(&format!("{}.o", module.get_name().to_str().unwrap()))) .write_to_file(module, FileType::Object, Path::new(&format!("{}.o", module.get_name().to_str().unwrap())))
.expect("couldn't write module to file"); .expect("couldn't write module to file");
}))); })));
let external_codegen = Arc::new(GenCall::new(Box::new(|_, _, _, _| unimplemented!()), HashSet::new()));
let thread_names: Vec<String> = (0..4).map(|i| format!("module{}", i)).collect(); let thread_names: Vec<String> = (0..4).map(|i| format!("module{}", i)).collect();
let threads: Vec<_> = thread_names.iter().map(|s| s.as_str()).collect(); let threads: Vec<_> = thread_names.iter().map(|s| s.as_str()).collect();
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level.clone(), f); let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level.clone(), f, external_codegen);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);

View File

@ -1,16 +1,12 @@
use std::fs;
use std::env; use std::env;
use inkwell::{ use std::fs;
passes::{PassManager, PassManagerBuilder}, use inkwell::{OptimizationLevel, passes::{PassManager, PassManagerBuilder}, targets::*};
targets::*,
OptimizationLevel,
};
use nac3core::typecheck::type_inferencer::PrimitiveStore; use nac3core::typecheck::type_inferencer::PrimitiveStore;
use rustpython_parser::parser; use rustpython_parser::parser;
use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime};
use nac3core::{ use nac3core::{
codegen::{CodeGenTask, WithCall, WorkerRegistry}, codegen::{CodeGenTask, WithCall, GenCall, WorkerRegistry},
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
toplevel::{composer::TopLevelComposer, TopLevelDef}, toplevel::{composer::TopLevelComposer, TopLevelDef},
typecheck::typedef::{FunSignature, FuncArg}, typecheck::typedef::{FunSignature, FuncArg},
@ -148,9 +144,19 @@ fn main() {
// println!("IR:\n{}", module.print_to_string().to_str().unwrap()); // println!("IR:\n{}", module.print_to_string().to_str().unwrap());
}))); })));
let external_codegen = Arc::new(GenCall::new(Box::new(
// example implementation that does sitofp:
// note that a proper implementation may want to check the definition ID
// |ctx, _, _, args| {
// let arg = args[0].1.into_int_value();
// let val = ctx.builder.build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp").into();
// Some(val)
// }
|_, _, _, _| unimplemented!()
), Default::default()));
let threads: Vec<String> = (0..threads).map(|i| format!("module{}", i)).collect(); let threads: Vec<String> = (0..threads).map(|i| format!("module{}", i)).collect();
let threads: Vec<_> = threads.iter().map(|s| s.as_str()).collect(); let threads: Vec<_> = threads.iter().map(|s| s.as_str()).collect();
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f); let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f, external_codegen);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);