nac3artiq: added simple host value support

This commit is contained in:
pca006132 2021-10-06 16:07:42 +08:00
parent 4fcb54e463
commit 11144301ca
11 changed files with 537 additions and 191 deletions

View File

@ -1,12 +1,10 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use inkwell::{ use inkwell::{
AddressSpace, AtomicOrdering,
values::BasicValueEnum,
passes::{PassManager, PassManagerBuilder}, passes::{PassManager, PassManagerBuilder},
targets::*, targets::*,
OptimizationLevel, OptimizationLevel,
@ -18,13 +16,13 @@ use rustpython_parser::{
parser, parser,
}; };
use parking_lot::RwLock; use parking_lot::{RwLock, Mutex};
use nac3core::{ use nac3core::{
codegen::{CodeGenTask, WithCall, WorkerRegistry}, codegen::{CodeGenTask, WithCall, WorkerRegistry},
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
toplevel::{composer::TopLevelComposer, TopLevelContext, TopLevelDef, GenCall}, toplevel::{composer::TopLevelComposer, TopLevelContext, TopLevelDef},
typecheck::typedef::{FunSignature, FuncArg}, typecheck::typedef::FunSignature,
}; };
use nac3core::{ use nac3core::{
toplevel::DefinitionId, toplevel::DefinitionId,
@ -33,6 +31,7 @@ use nac3core::{
use crate::symbol_resolver::Resolver; use crate::symbol_resolver::Resolver;
mod builtins;
mod symbol_resolver; mod symbol_resolver;
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
@ -41,6 +40,17 @@ enum Isa {
CortexA9, CortexA9,
} }
#[derive(Clone)]
pub struct PrimitivePythonId {
int: u64,
int32: u64,
int64: u64,
float: u64,
bool: u64,
list: u64,
tuple: u64,
}
// TopLevelComposer is unsendable as it holds the unification table, which is // TopLevelComposer is unsendable as it holds the unification table, which is
// unsendable due to Rc. Arc would cause a performance hit. // unsendable due to Rc. Arc would cause a performance hit.
#[pyclass(unsendable, name = "NAC3")] #[pyclass(unsendable, name = "NAC3")]
@ -54,6 +64,8 @@ struct Nac3 {
composer: TopLevelComposer, composer: TopLevelComposer,
top_level: Option<Arc<TopLevelContext>>, top_level: Option<Arc<TopLevelContext>>,
to_be_registered: Vec<PyObject>, to_be_registered: Vec<PyObject>,
primitive_ids: PrimitivePythonId,
global_value_ids: Arc<Mutex<HashSet<u64>>>,
} }
impl Nac3 { impl Nac3 {
@ -81,16 +93,18 @@ impl Nac3 {
let source = fs::read_to_string(source_file).map_err(|e| { let source = fs::read_to_string(source_file).map_err(|e| {
exceptions::PyIOError::new_err(format!("failed to read input file: {}", e)) exceptions::PyIOError::new_err(format!("failed to read input file: {}", e))
})?; })?;
let parser_result = parser::parse_program(&source).map_err(|e| { let parser_result = parser::parse_program(&source)
exceptions::PySyntaxError::new_err(format!("parse error: {}", e)) .map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {}", e)))?;
})?;
let resolver = Arc::new(Box::new(Resolver { let resolver = Arc::new(Box::new(Resolver {
id_to_type: self.builtins_ty.clone().into(), id_to_type: self.builtins_ty.clone().into(),
id_to_def: self.builtins_def.clone().into(), id_to_def: self.builtins_def.clone().into(),
pyid_to_def: self.pyid_to_def.clone(), pyid_to_def: self.pyid_to_def.clone(),
pyid_to_type: self.pyid_to_type.clone(), pyid_to_type: self.pyid_to_type.clone(),
primitive_ids: self.primitive_ids.clone(),
global_value_ids: self.global_value_ids.clone(),
class_names: Default::default(), class_names: Default::default(),
name_to_pyid: name_to_pyid.clone(), name_to_pyid: name_to_pyid.clone(),
module: obj,
}) as Box<dyn SymbolResolver + Send + Sync>); }) as Box<dyn SymbolResolver + Send + Sync>);
let mut name_to_def = HashMap::new(); let mut name_to_def = HashMap::new();
let mut name_to_type = HashMap::new(); let mut name_to_type = HashMap::new();
@ -163,128 +177,76 @@ impl Nac3 {
} }
} }
// ARTIQ timeline control with now-pinning optimization.
fn timeline_builtins(primitive: &PrimitiveStore) -> Vec<(StrRef, FunSignature, Arc<GenCall>)> {
vec![(
"now_mu".into(),
FunSignature {
args: vec![],
ret: primitive.int64,
vars: HashMap::new(),
},
Arc::new(GenCall::new(Box::new(
|ctx, _, _, _| {
let i64_type = ctx.ctx.i64_type();
let now = ctx.module.get_global("now").unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now");
if let BasicValueEnum::IntValue(now_raw) = now_raw {
let i64_32 = i64_type.const_int(32, false).into();
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl");
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now_lshr").into();
Some(ctx.builder.build_or(now_lo, now_hi, "now_or").into())
} else {
unreachable!()
}
}
)))
),(
"at_mu".into(),
FunSignature {
args: vec![FuncArg {
name: "t".into(),
ty: primitive.int64,
default_value: None,
}],
ret: primitive.none,
vars: HashMap::new(),
},
Arc::new(GenCall::new(Box::new(
|ctx, _, _, args| {
let i32_type = ctx.ctx.i32_type();
let i64_type = ctx.ctx.i64_type();
let i64_32 = i64_type.const_int(32, false).into();
if let BasicValueEnum::IntValue(time) = args[0].1 {
let time_hi = ctx.builder.build_int_truncate(ctx.builder.build_right_shift(time, i64_32, false, "now_lshr"), i32_type, "now_trunc");
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
let now = ctx.module.get_global("now").unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
let now_hiptr = ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::Generic), "now_bitcast");
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
let now_loptr = unsafe { ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false).into()], "now_gep") };
ctx.builder.build_store(now_hiptr, time_hi).set_atomic_ordering(AtomicOrdering::SequentiallyConsistent).unwrap();
ctx.builder.build_store(now_loptr, time_lo).set_atomic_ordering(AtomicOrdering::SequentiallyConsistent).unwrap();
None
} else {
unreachable!();
}
} else {
unreachable!();
}
}
)))
),(
"delay_mu".into(),
FunSignature {
args: vec![FuncArg {
name: "dt".into(),
ty: primitive.int64,
default_value: None,
}],
ret: primitive.none,
vars: HashMap::new(),
},
Arc::new(GenCall::new(Box::new(
|ctx, _, _, args| {
let i32_type = ctx.ctx.i32_type();
let i64_type = ctx.ctx.i64_type();
let i64_32 = i64_type.const_int(32, false).into();
let now = ctx.module.get_global("now").unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now");
if let (BasicValueEnum::IntValue(now_raw), BasicValueEnum::IntValue(dt)) = (now_raw, args[0].1) {
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl");
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now_lshr").into();
let now_val = ctx.builder.build_or(now_lo, now_hi, "now_or");
let time = ctx.builder.build_int_add(now_val, dt, "now_add");
let time_hi = ctx.builder.build_int_truncate(ctx.builder.build_right_shift(time, i64_32, false, "now_lshr"), i32_type, "now_trunc");
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
let now_hiptr = ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::Generic), "now_bitcast");
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
let now_loptr = unsafe { ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false).into()], "now_gep") };
ctx.builder.build_store(now_hiptr, time_hi).set_atomic_ordering(AtomicOrdering::SequentiallyConsistent).unwrap();
ctx.builder.build_store(now_loptr, time_lo).set_atomic_ordering(AtomicOrdering::SequentiallyConsistent).unwrap();
None
} else {
unreachable!();
}
} else {
unreachable!();
}
}
)))
)]
}
#[pymethods] #[pymethods]
impl Nac3 { impl Nac3 {
#[new] #[new]
fn new(isa: &str) -> PyResult<Self> { fn new(isa: &str, py: Python) -> PyResult<Self> {
let isa = match isa { let isa = match isa {
"riscv" => Isa::RiscV, "riscv" => Isa::RiscV,
"cortexa9" => Isa::CortexA9, "cortexa9" => Isa::CortexA9,
_ => return Err(exceptions::PyValueError::new_err("invalid ISA")), _ => return Err(exceptions::PyValueError::new_err("invalid ISA")),
}; };
let primitive: PrimitiveStore = TopLevelComposer::make_primitives().0; let primitive: PrimitiveStore = TopLevelComposer::make_primitives().0;
let builtins = if isa == Isa::RiscV { timeline_builtins(&primitive) } else { vec![] }; let builtins = if isa == Isa::RiscV {
builtins::timeline_builtins(&primitive)
} else {
vec![]
};
let (composer, builtins_def, builtins_ty) = TopLevelComposer::new(builtins); let (composer, builtins_def, builtins_ty) = TopLevelComposer::new(builtins);
let builtins_mod = PyModule::import(py, "builtins").unwrap();
let id_fn = builtins_mod.getattr("id").unwrap();
let numpy_mod = PyModule::import(py, "numpy").unwrap();
let primitive_ids = PrimitivePythonId {
int: id_fn
.call1((builtins_mod.getattr("int").unwrap(),))
.unwrap()
.extract()
.unwrap(),
int32: id_fn
.call1((numpy_mod.getattr("int32").unwrap(),))
.unwrap()
.extract()
.unwrap(),
int64: id_fn
.call1((numpy_mod.getattr("int64").unwrap(),))
.unwrap()
.extract()
.unwrap(),
bool: id_fn
.call1((builtins_mod.getattr("bool").unwrap(),))
.unwrap()
.extract()
.unwrap(),
float: id_fn
.call1((builtins_mod.getattr("float").unwrap(),))
.unwrap()
.extract()
.unwrap(),
list: id_fn
.call1((builtins_mod.getattr("list").unwrap(),))
.unwrap()
.extract()
.unwrap(),
tuple: id_fn
.call1((builtins_mod.getattr("tuple").unwrap(),))
.unwrap()
.extract()
.unwrap(),
};
Ok(Nac3 { Ok(Nac3 {
isa, isa,
primitive, primitive,
builtins_ty, builtins_ty,
builtins_def, builtins_def,
composer, composer,
primitive_ids,
top_level: None, top_level: None,
pyid_to_def: Default::default(), pyid_to_def: Default::default(),
pyid_to_type: Default::default(), pyid_to_type: Default::default(),
to_be_registered: Default::default(), to_be_registered: Default::default(),
global_value_ids: Default::default(),
}) })
} }
@ -301,7 +263,7 @@ impl Nac3 {
Ok(()) Ok(())
} }
fn compile_method(&mut self, class: u64, method_name: String) -> PyResult<()> { fn compile_method(&mut self, class: u64, method_name: String, py: Python) -> PyResult<()> {
let top_level = self.top_level.as_ref().unwrap(); let top_level = self.top_level.as_ref().unwrap();
let module_resolver; let module_resolver;
let instance = { let instance = {
@ -356,7 +318,7 @@ impl Nac3 {
let isa = self.isa; let isa = self.isa;
let f = Arc::new(WithCall::new(Box::new(move |module| { let f = Arc::new(WithCall::new(Box::new(move |module| {
let builder = PassManagerBuilder::create(); let builder = PassManagerBuilder::create();
builder.set_optimization_level(OptimizationLevel::Aggressive); builder.set_optimization_level(OptimizationLevel::Default);
let passes = PassManager::create(()); let passes = PassManager::create(());
builder.populate_module_pass_manager(&passes); builder.populate_module_pass_manager(&passes);
passes.run_on(module); passes.run_on(module);
@ -390,9 +352,13 @@ impl Nac3 {
}))); })));
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);
py.allow_threads(|| {
let (registry, handles) =
WorkerRegistry::create_workers(&threads, top_level.clone(), f);
registry.add_task(task); registry.add_task(task);
registry.wait_tasks_complete(handles); registry.wait_tasks_complete(handles);
});
let mut linker_args = vec![ let mut linker_args = vec![
"-shared".to_string(), "-shared".to_string(),

View File

@ -1,32 +1,348 @@
use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
use nac3core::{ use nac3core::{
codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::{SymbolResolver, SymbolValue}, symbol_resolver::SymbolResolver,
toplevel::DefinitionId, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
typedef::{Type, Unifier}, typedef::{Type, TypeEnum, Unifier},
}, },
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use pyo3::{
types::{PyList, PyModule, PyTuple},
PyAny, PyObject, PyResult, Python,
};
use rustpython_parser::ast::StrRef; use rustpython_parser::ast::StrRef;
use std::{collections::HashMap, sync::Arc}; use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use crate::PrimitivePythonId;
pub struct Resolver { pub struct Resolver {
pub id_to_type: Mutex<HashMap<StrRef, Type>>, pub id_to_type: Mutex<HashMap<StrRef, Type>>,
pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>, pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
pub global_value_ids: Arc<Mutex<HashSet<u64>>>,
pub class_names: Mutex<HashMap<StrRef, Type>>, pub class_names: Mutex<HashMap<StrRef, Type>>,
pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>, pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>, pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>,
pub primitive_ids: PrimitivePythonId,
// module specific // module specific
pub name_to_pyid: HashMap<StrRef, u64>, pub name_to_pyid: HashMap<StrRef, u64>,
pub module: PyObject,
}
struct PythonHelper<'a> {
type_fn: &'a PyAny,
len_fn: &'a PyAny,
id_fn: &'a PyAny,
}
impl Resolver {
fn get_list_elem_type(
&self,
list: &PyAny,
len: usize,
helper: &PythonHelper,
unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> {
let first = self.get_obj_type(list.get_item(0)?, helper, unifier, defs, primitives)?;
Ok((1..len).fold(first, |a, i| {
let b = list
.get_item(i)
.map(|elem| self.get_obj_type(elem, helper, unifier, defs, primitives));
a.and_then(|a| {
if let Ok(Ok(Some(ty))) = b {
if unifier.unify(a, ty).is_ok() {
Some(a)
} else {
None
}
} else {
None
}
})
}))
}
fn get_obj_type(
&self,
obj: &PyAny,
helper: &PythonHelper,
unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> {
let ty_id: u64 = helper
.id_fn
.call1((helper.type_fn.call1((obj,))?,))?
.extract()?;
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
Ok(Some(primitives.int32))
} else if ty_id == self.primitive_ids.int64 {
Ok(Some(primitives.int64))
} else if ty_id == self.primitive_ids.bool {
Ok(Some(primitives.bool))
} else if ty_id == self.primitive_ids.float {
Ok(Some(primitives.float))
} else if ty_id == self.primitive_ids.list {
let len: usize = helper.len_fn.call1((obj,))?.extract()?;
if len == 0 {
let var = unifier.get_fresh_var().0;
let list = unifier.add_ty(TypeEnum::TList { ty: var });
Ok(Some(list))
} else {
let ty = self.get_list_elem_type(obj, len, helper, unifier, defs, primitives)?;
Ok(ty.map(|ty| unifier.add_ty(TypeEnum::TList { ty })))
}
} else if ty_id == self.primitive_ids.tuple {
let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements
.iter()
.map(|elem| self.get_obj_type(elem, helper, unifier, defs, primitives))
.collect();
let types = types?;
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
} else {
Ok(None)
}
}
fn get_obj_value<'ctx, 'a>(
&self,
obj: &PyAny,
helper: &PythonHelper,
ctx: &mut CodeGenContext<'ctx, 'a>,
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
let ty_id: u64 = helper
.id_fn
.call1((helper.type_fn.call1((obj,))?,))?
.extract()?;
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
let val: i32 = obj.extract()?;
Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.int64 {
let val: i64 = obj.extract()?;
Ok(Some(ctx.ctx.i64_type().const_int(val as u64, false).into()))
} else if ty_id == self.primitive_ids.bool {
let val: bool = obj.extract()?;
Ok(Some(
ctx.ctx.bool_type().const_int(val as u64, false).into(),
))
} else if ty_id == self.primitive_ids.float {
let val: f64 = obj.extract()?;
Ok(Some(ctx.ctx.f64_type().const_float(val).into()))
} else if ty_id == self.primitive_ids.list {
let id: u64 = helper.id_fn.call1((obj,))?.extract()?;
let id_str = id.to_string();
let len: usize = helper.len_fn.call1((obj,))?.extract()?;
if len == 0 {
let int32 = ctx.ctx.i32_type();
return Ok(Some(
ctx.ctx
.struct_type(
&[int32.into(), int32.ptr_type(AddressSpace::Generic).into()],
false,
)
.const_zero()
.into(),
));
}
let ty = self
.get_list_elem_type(
obj,
len,
helper,
&mut ctx.unifier,
&ctx.top_level.definitions.read(),
&ctx.primitives,
)?
.unwrap();
let ty = ctx.get_llvm_type(ty);
let arr_ty = ctx.ctx.struct_type(
&[
ctx.ctx.i32_type().into(),
ty.ptr_type(AddressSpace::Generic).into(),
],
false,
);
{
let mut global_value_ids = self.global_value_ids.lock();
if global_value_ids.contains(&id) {
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module
.add_global(arr_ty, Some(AddressSpace::Generic), &id_str)
});
return Ok(Some(global.as_pointer_value().into()));
} else {
global_value_ids.insert(id);
}
}
let arr: Result<Option<Vec<_>>, _> = (0..len)
.map(|i| {
obj.get_item(i)
.and_then(|elem| self.get_obj_value(elem, helper, ctx))
})
.collect();
let arr = arr?.unwrap();
let arr_global = ctx.module.add_global(
ty.array_type(len as u32),
Some(AddressSpace::Generic),
&(id_str.clone() + "_"),
);
let arr: BasicValueEnum = if ty.is_int_type() {
let arr: Vec<_> = arr
.into_iter()
.map(BasicValueEnum::into_int_value)
.collect();
ty.into_int_type().const_array(&arr)
} else if ty.is_float_type() {
let arr: Vec<_> = arr
.into_iter()
.map(BasicValueEnum::into_float_value)
.collect();
ty.into_float_type().const_array(&arr)
} else if ty.is_array_type() {
let arr: Vec<_> = arr
.into_iter()
.map(BasicValueEnum::into_array_value)
.collect();
ty.into_array_type().const_array(&arr)
} else if ty.is_struct_type() {
let arr: Vec<_> = arr
.into_iter()
.map(BasicValueEnum::into_struct_value)
.collect();
ty.into_struct_type().const_array(&arr)
} else if ty.is_pointer_type() {
let arr: Vec<_> = arr
.into_iter()
.map(BasicValueEnum::into_pointer_value)
.collect();
ty.into_pointer_type().const_array(&arr)
} else {
unreachable!()
}
.into();
arr_global.set_initializer(&arr);
let val = arr_ty.const_named_struct(&[
ctx.ctx.i32_type().const_int(len as u64, false).into(),
arr_global
.as_pointer_value()
.const_cast(ty.ptr_type(AddressSpace::Generic))
.into(),
]);
let global = ctx
.module
.add_global(arr_ty, Some(AddressSpace::Generic), &id_str);
global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into()))
} else if ty_id == self.primitive_ids.tuple {
let id: u64 = helper.id_fn.call1((obj,))?.extract()?;
let id_str = id.to_string();
let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements
.iter()
.map(|elem| {
self.get_obj_type(
elem,
helper,
&mut ctx.unifier,
&ctx.top_level.definitions.read(),
&ctx.primitives,
)
.map(|ty| ty.map(|ty| ctx.get_llvm_type(ty)))
})
.collect();
let types = types?.unwrap();
let ty = ctx.ctx.struct_type(&types, false);
{
let mut global_value_ids = self.global_value_ids.lock();
if global_value_ids.contains(&id) {
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
ctx.module
.add_global(ty, Some(AddressSpace::Generic), &id_str)
});
return Ok(Some(global.as_pointer_value().into()));
} else {
global_value_ids.insert(id);
}
}
let val: Result<Option<Vec<_>>, _> = elements
.iter()
.map(|elem| self.get_obj_value(elem, helper, ctx))
.collect();
let val = val?.unwrap();
let val = ctx.ctx.const_struct(&val, false);
let global = ctx
.module
.add_global(ty, Some(AddressSpace::Generic), &id_str);
global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into()))
} else {
Ok(None)
}
}
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: StrRef) -> Option<Type> { fn get_symbol_type(
&self,
unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore,
str: StrRef,
) -> Option<Type> {
let mut id_to_type = self.id_to_type.lock(); let mut id_to_type = self.id_to_type.lock();
id_to_type.get(&str).cloned().or_else(|| { id_to_type.get(&str).cloned().or_else(|| {
let py_id = self.name_to_pyid.get(&str); let py_id = self.name_to_pyid.get(&str);
let result = py_id.and_then(|id| self.pyid_to_type.read().get(&id).copied()); let result = py_id.and_then(|id| {
self.pyid_to_type.read().get(&id).copied().or_else(|| {
Python::with_gil(|py| -> PyResult<Option<Type>> {
let obj: &PyAny = self.module.extract(py)?;
let members: &PyList = PyModule::import(py, "inspect")?
.getattr("getmembers")?
.call1((obj,))?
.cast_as()?;
let mut sym_ty = None;
for member in members.iter() {
let key: &str = member.get_item(0)?.extract()?;
if key == str.to_string() {
let builtins = PyModule::import(py, "builtins")?;
let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap(),
len_fn: builtins.getattr("len").unwrap(),
type_fn: builtins.getattr("type").unwrap(),
};
sym_ty = self.get_obj_type(
member.get_item(1)?,
&helper,
unifier,
defs,
primitives,
)?;
break;
}
}
Ok(sym_ty)
})
.unwrap()
})
});
if let Some(result) = &result { if let Some(result) = &result {
id_to_type.insert(str, *result); id_to_type.insert(str, *result);
} }
@ -34,8 +350,35 @@ impl SymbolResolver for Resolver {
}) })
} }
fn get_symbol_value(&self, _: StrRef) -> Option<SymbolValue> { fn get_symbol_value<'ctx, 'a>(
unimplemented!() &self,
id: StrRef,
ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<BasicValueEnum<'ctx>> {
Python::with_gil(|py| -> PyResult<Option<BasicValueEnum<'ctx>>> {
let obj: &PyAny = self.module.extract(py)?;
let members: &PyList = PyModule::import(py, "inspect")?
.getattr("getmembers")?
.call1((obj,))?
.cast_as()?;
let mut sym_value = None;
for member in members.iter() {
let key: &str = member.get_item(0)?.extract()?;
let val = member.get_item(1)?;
if key == id.to_string() {
let builtins = PyModule::import(py, "builtins")?;
let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap(),
len_fn: builtins.getattr("len").unwrap(),
type_fn: builtins.getattr("type").unwrap(),
};
sym_value = self.get_obj_value(val, &helper, ctx)?;
break;
}
}
Ok(sym_value)
})
.unwrap()
} }
fn get_symbol_location(&self, _: StrRef) -> Option<Location> { fn get_symbol_location(&self, _: StrRef) -> Option<Location> {

View File

@ -108,7 +108,7 @@ 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>> {
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;
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 symbol = { let symbol = {
@ -283,7 +283,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
} else { } else {
unreachable!(); unreachable!();
}; };
ty.const_int(v.try_into().unwrap(), false).into() let val: i64 = v.try_into().unwrap();
ty.const_int(val as u64, false).into()
} }
Constant::Float(v) => { Constant::Float(v) => {
assert!(self.unifier.unioned(ty, self.primitives.float)); assert!(self.unifier.unioned(ty, self.primitives.float));
@ -386,8 +387,13 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
self.gen_const(value, ty) self.gen_const(value, ty)
} }
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
let ptr = self.var_assignment.get(id).unwrap(); let ptr = self.var_assignment.get(id);
if let Some(ptr) = ptr {
self.builder.build_load(*ptr, "load") self.builder.build_load(*ptr, "load")
} else {
let resolver = self.resolver.clone();
resolver.get_symbol_value(*id, self).unwrap()
}
} }
ExprKind::List { elts, .. } => { ExprKind::List { elts, .. } => {
// this shall be optimized later for constant primitive lists... // this shall be optimized later for constant primitive lists...
@ -647,10 +653,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
let mut params = let mut params =
args.iter().map(|arg| (None, self.gen_expr(arg).unwrap())).collect_vec(); args.iter().map(|arg| (None, self.gen_expr(arg).unwrap())).collect_vec();
let kw_iter = keywords.iter().map(|kw| { let kw_iter = keywords.iter().map(|kw| {
( (Some(*kw.node.arg.as_ref().unwrap()), self.gen_expr(&kw.node.value).unwrap())
Some(*kw.node.arg.as_ref().unwrap()),
self.gen_expr(&kw.node.value).unwrap(),
)
}); });
params.extend(kw_iter); params.extend(kw_iter);
let call = self.calls.get(&expr.location.into()); let call = self.calls.get(&expr.location.into());

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
codegen::{CodeGenTask, WithCall, WorkerRegistry}, codegen::{CodeGenTask, WithCall, WorkerRegistry, CodeGenContext},
location::Location, location::Location,
symbol_resolver::{SymbolResolver, SymbolValue}, symbol_resolver::SymbolResolver,
toplevel::{ toplevel::{
composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef, composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
}, },
@ -11,6 +11,7 @@ use crate::{
}, },
}; };
use indoc::indoc; use indoc::indoc;
use inkwell::values::BasicValueEnum;
use parking_lot::RwLock; use parking_lot::RwLock;
use rustpython_parser::{ use rustpython_parser::{
ast::{fold::Fold, StrRef}, ast::{fold::Fold, StrRef},
@ -33,11 +34,11 @@ impl Resolver {
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: StrRef) -> Option<Type> { fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc<RwLock<TopLevelDef>>], _: &PrimitiveStore, str: StrRef) -> Option<Type> {
self.id_to_type.get(&str).cloned() self.id_to_type.get(&str).cloned()
} }
fn get_symbol_value(&self, _: StrRef) -> Option<SymbolValue> { fn get_symbol_value<'ctx, 'a>(&self, _: StrRef, _: &mut CodeGenContext<'ctx, 'a>) -> Option<BasicValueEnum<'ctx>> {
unimplemented!() unimplemented!()
} }

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::{cell::RefCell, sync::Arc}; use std::{cell::RefCell, sync::Arc};
use crate::toplevel::{DefinitionId, TopLevelDef}; use crate::{codegen::CodeGenContext, toplevel::{DefinitionId, TopLevelDef}};
use crate::typecheck::{ use crate::typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
typedef::{Type, Unifier}, typedef::{Type, Unifier},
@ -11,6 +11,7 @@ use crate::{location::Location, typecheck::typedef::TypeEnum};
use itertools::{chain, izip}; use itertools::{chain, izip};
use parking_lot::RwLock; use parking_lot::RwLock;
use rustpython_parser::ast::{Expr, StrRef}; use rustpython_parser::ast::{Expr, StrRef};
use inkwell::values::BasicValueEnum;
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum SymbolValue { pub enum SymbolValue {
@ -28,12 +29,13 @@ pub trait SymbolResolver {
fn get_symbol_type( fn get_symbol_type(
&self, &self,
unifier: &mut Unifier, unifier: &mut Unifier,
top_level_defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Option<Type>; ) -> Option<Type>;
// get the top-level definition of identifiers // get the top-level definition of identifiers
fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>; fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>;
fn get_symbol_value(&self, str: StrRef) -> Option<SymbolValue>; fn get_symbol_value<'ctx, 'a>(&self, str: StrRef, ctx: &mut CodeGenContext<'ctx, 'a>) -> Option<BasicValueEnum<'ctx>>;
fn get_symbol_location(&self, str: StrRef) -> Option<Location>; fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
// handle function call etc. // handle function call etc.
} }
@ -113,7 +115,7 @@ pub fn parse_type_annotation<T>(
} else { } else {
// it could be a type variable // it could be a type variable
let ty = resolver let ty = resolver
.get_symbol_type(unifier, primitives, *id) .get_symbol_type(unifier, top_level_defs, primitives, *id)
.ok_or_else(|| "unknown type variable name".to_owned())?; .ok_or_else(|| "unknown type variable name".to_owned())?;
if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) {
Ok(ty) Ok(ty)

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::{SymbolResolver, SymbolValue}, symbol_resolver::SymbolResolver,
toplevel::DefinitionId, toplevel::DefinitionId,
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
@ -34,7 +35,7 @@ impl ResolverInternal {
struct Resolver(Arc<ResolverInternal>); struct Resolver(Arc<ResolverInternal>);
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: StrRef) -> Option<Type> { fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc<RwLock<TopLevelDef>>], _: &PrimitiveStore, str: StrRef) -> Option<Type> {
let ret = self.0.id_to_type.lock().get(&str).cloned(); let ret = self.0.id_to_type.lock().get(&str).cloned();
if ret.is_none() { if ret.is_none() {
// println!("unknown here resolver {}", str); // println!("unknown here resolver {}", str);
@ -42,7 +43,11 @@ impl SymbolResolver for Resolver {
ret ret
} }
fn get_symbol_value(&self, _: StrRef) -> Option<SymbolValue> { fn get_symbol_value<'ctx, 'a>(
&self,
_: StrRef,
_: &mut CodeGenContext<'ctx, 'a>,
) -> Option<BasicValueEnum<'ctx>> {
unimplemented!() unimplemented!()
} }

View File

@ -62,7 +62,7 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
)); ));
} }
Ok(TypeAnnotation::CustomClassKind { id: obj_id, params: vec![] }) Ok(TypeAnnotation::CustomClassKind { id: obj_id, params: vec![] })
} else if let Some(ty) = resolver.get_symbol_type(unifier, primitives, *id) { } else if let Some(ty) = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id) {
if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() { if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
Ok(TypeAnnotation::TypeVarKind(ty)) Ok(TypeAnnotation::TypeVarKind(ty))
} else { } else {

View File

@ -57,7 +57,17 @@ impl<'a> Inferencer<'a> {
match &expr.node { match &expr.node {
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
if !defined_identifiers.contains(id) { if !defined_identifiers.contains(id) {
if self.function_data.resolver.get_identifier_def(*id).is_some() { if self
.function_data
.resolver
.get_symbol_type(
self.unifier,
&self.top_level.definitions.read(),
self.primitives,
*id,
)
.is_some()
{
defined_identifiers.insert(*id); defined_identifiers.insert(*id);
} else { } else {
return Err(format!( return Err(format!(

View File

@ -111,17 +111,24 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
if let ast::StmtKind::Assign { targets, value, .. } = node.node { if let ast::StmtKind::Assign { targets, value, .. } = node.node {
let value = self.fold_expr(*value)?; let value = self.fold_expr(*value)?;
let value_ty = value.custom.unwrap(); let value_ty = value.custom.unwrap();
let targets: Result<Vec<_>, _> = targets.into_iter().map(|target| { let targets: Result<Vec<_>, _> = targets
.into_iter()
.map(|target| {
if let ast::ExprKind::Name { id, ctx } = target.node { if let ast::ExprKind::Name { id, ctx } = target.node {
self.defined_identifiers.insert(id); self.defined_identifiers.insert(id);
let target_ty = if let Some(ty) = self.variable_mapping.get(&id) { let target_ty = if let Some(ty) = self.variable_mapping.get(&id)
{
*ty *ty
} else { } else {
let unifier = &mut self.unifier; let unifier = &mut self.unifier;
self self.function_data
.function_data
.resolver .resolver
.get_symbol_type(unifier, self.primitives, id) .get_symbol_type(
unifier,
&self.top_level.definitions.read(),
self.primitives,
id,
)
.unwrap_or_else(|| { .unwrap_or_else(|| {
self.variable_mapping.insert(id, value_ty); self.variable_mapping.insert(id, value_ty);
value_ty value_ty
@ -131,12 +138,13 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
self.unifier.unify(value_ty, target_ty).map(|_| Located { self.unifier.unify(value_ty, target_ty).map(|_| Located {
location, location,
node: ast::ExprKind::Name { id, ctx }, node: ast::ExprKind::Name { id, ctx },
custom: Some(target_ty) custom: Some(target_ty),
}) })
} else { } else {
unreachable!() unreachable!()
} }
}).collect(); })
.collect();
let targets = targets?; let targets = targets?;
return Ok(Located { return Ok(Located {
location: node.location, location: node.location,
@ -145,7 +153,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
value: Box::new(value), value: Box::new(value),
type_comment: None, type_comment: None,
}, },
custom: None custom: None,
}); });
} else { } else {
unreachable!() unreachable!()
@ -207,7 +215,17 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
ast::ExprKind::Constant { value, .. } => Some(self.infer_constant(value)?), ast::ExprKind::Constant { value, .. } => Some(self.infer_constant(value)?),
ast::ExprKind::Name { id, .. } => { ast::ExprKind::Name { id, .. } => {
if !self.defined_identifiers.contains(id) { if !self.defined_identifiers.contains(id) {
if self.function_data.resolver.get_identifier_def(*id).is_some() { if self
.function_data
.resolver
.get_symbol_type(
self.unifier,
&self.top_level.definitions.read(),
self.primitives,
*id,
)
.is_some()
{
self.defined_identifiers.insert(*id); self.defined_identifiers.insert(*id);
} else { } else {
return Err(format!( return Err(format!(
@ -359,11 +377,8 @@ impl<'a> Inferencer<'a> {
defined_identifiers.insert(*name); defined_identifiers.insert(*name);
} }
} }
let fn_args: Vec<_> = args let fn_args: Vec<_> =
.args args.args.iter().map(|v| (v.node.arg, self.unifier.get_fresh_var().0)).collect();
.iter()
.map(|v| (v.node.arg, self.unifier.get_fresh_var().0))
.collect();
let mut variable_mapping = self.variable_mapping.clone(); let mut variable_mapping = self.variable_mapping.clone();
variable_mapping.extend(fn_args.iter().cloned()); variable_mapping.extend(fn_args.iter().cloned());
let ret = self.unifier.get_fresh_var().0; let ret = self.unifier.get_fresh_var().0;
@ -596,7 +611,7 @@ impl<'a> Inferencer<'a> {
Ok(self Ok(self
.function_data .function_data
.resolver .resolver
.get_symbol_type(unifier, self.primitives, id) .get_symbol_type(unifier, &self.top_level.definitions.read(), self.primitives, id)
.unwrap_or_else(|| { .unwrap_or_else(|| {
let ty = unifier.get_fresh_var().0; let ty = unifier.get_fresh_var().0;
variable_mapping.insert(id, ty); variable_mapping.insert(id, ty);

View File

@ -1,11 +1,12 @@
use super::super::typedef::*; use super::super::typedef::*;
use super::*; use super::*;
use crate::symbol_resolver::*;
use crate::{ use crate::{
codegen::CodeGenContext,
location::Location, location::Location,
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
}; };
use indoc::indoc; use indoc::indoc;
use inkwell::values::BasicValueEnum;
use itertools::zip; use itertools::zip;
use parking_lot::RwLock; use parking_lot::RwLock;
use rustpython_parser::parser::parse_program; use rustpython_parser::parser::parse_program;
@ -18,11 +19,15 @@ struct Resolver {
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: StrRef) -> Option<Type> { fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc<RwLock<TopLevelDef>>], _: &PrimitiveStore, str: StrRef) -> Option<Type> {
self.id_to_type.get(&str).cloned() self.id_to_type.get(&str).cloned()
} }
fn get_symbol_value(&self, _: StrRef) -> Option<SymbolValue> { fn get_symbol_value<'ctx, 'a>(
&self,
_: StrRef,
_: &mut CodeGenContext<'ctx, 'a>,
) -> Option<BasicValueEnum<'ctx>> {
unimplemented!() unimplemented!()
} }
@ -278,7 +283,7 @@ impl TestEnvironment {
let top_level = TopLevelContext { let top_level = TopLevelContext {
definitions: Arc::new(top_level_defs.into()), definitions: Arc::new(top_level_defs.into()),
unifiers: Default::default(), unifiers: Default::default(),
personality_symbol: None personality_symbol: None,
}; };
let resolver = Arc::new(Box::new(Resolver { let resolver = Arc::new(Box::new(Resolver {

View File

@ -1,13 +1,9 @@
use nac3core::{ use inkwell::values::BasicValueEnum;
location::Location, use nac3core::{codegen::CodeGenContext, location::Location, symbol_resolver::{SymbolResolver, SymbolValue}, toplevel::{DefinitionId, TopLevelDef}, typecheck::{
symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::DefinitionId,
typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
typedef::{Type, Unifier}, typedef::{Type, Unifier},
}, }};
}; use parking_lot::{Mutex, RwLock};
use parking_lot::Mutex;
use rustpython_parser::ast::StrRef; use rustpython_parser::ast::StrRef;
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
@ -30,7 +26,7 @@ impl ResolverInternal {
pub struct Resolver(pub Arc<ResolverInternal>); pub struct Resolver(pub Arc<ResolverInternal>);
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: StrRef) -> Option<Type> { fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc<RwLock<TopLevelDef>>], _: &PrimitiveStore, str: StrRef) -> Option<Type> {
let ret = self.0.id_to_type.lock().get(&str).cloned(); let ret = self.0.id_to_type.lock().get(&str).cloned();
if ret.is_none() { if ret.is_none() {
// println!("unknown here resolver {}", str); // println!("unknown here resolver {}", str);
@ -38,7 +34,7 @@ impl SymbolResolver for Resolver {
ret ret
} }
fn get_symbol_value(&self, _: StrRef) -> Option<SymbolValue> { fn get_symbol_value<'ctx, 'a>(&self, _: StrRef, _: &mut CodeGenContext<'ctx, 'a>) -> Option<BasicValueEnum<'ctx>> {
unimplemented!() unimplemented!()
} }