forked from M-Labs/nac3
nac3core/codegen: avoid sending unifiers
Previously, we have to copy types from one unification table to another, and make the table sendable. This requires cloning (processing) the whole table 3 times per function call which is not efficient and uses more memory than required when the unification table is large. We now use a concrete type table to only copy the type we need. This reduces the overhead as we only need to process the unification table for once (when we do the function codegen), and reduces memory usage by a bit (but not noticeable when the unification table is small, i.e. the types are simple).
This commit is contained in:
parent
9850cbe313
commit
279f47f633
@ -19,7 +19,10 @@ use rustpython_parser::{
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
use nac3core::{
|
||||
codegen::{CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry},
|
||||
codegen::{
|
||||
concrete_type::ConcreteTypeStore, CodeGenTask, DefaultCodeGenerator, WithCall,
|
||||
WorkerRegistry,
|
||||
},
|
||||
symbol_resolver::SymbolResolver,
|
||||
toplevel::{composer::TopLevelComposer, DefinitionId, GenCall, TopLevelContext, TopLevelDef},
|
||||
typecheck::typedef::{FunSignature, FuncArg},
|
||||
@ -354,6 +357,21 @@ impl Nac3 {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signature = FunSignature {
|
||||
args: vec![],
|
||||
ret: self.primitive.none,
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
let mut store = ConcreteTypeStore::new();
|
||||
let mut cache = HashMap::new();
|
||||
let signature = store.from_signature(
|
||||
&mut self.composer.unifier,
|
||||
&self.primitive,
|
||||
&signature,
|
||||
&mut cache,
|
||||
);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
self.composer.start_analysis(true).unwrap();
|
||||
self.top_level = Some(Arc::new(self.composer.make_top_level_context()));
|
||||
let top_level = self.top_level.as_ref().unwrap();
|
||||
@ -373,18 +391,14 @@ impl Nac3 {
|
||||
}
|
||||
};
|
||||
|
||||
let signature = FunSignature {
|
||||
args: vec![],
|
||||
ret: self.primitive.none,
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
let task = CodeGenTask {
|
||||
subst: Default::default(),
|
||||
symbol_name: "__modinit__".to_string(),
|
||||
body: instance.body,
|
||||
signature,
|
||||
resolver,
|
||||
unifier: top_level.unifiers.read()[instance.unifier_id].clone(),
|
||||
store,
|
||||
unifier_index: instance.unifier_id,
|
||||
calls: instance.calls,
|
||||
};
|
||||
let isa = self.isa;
|
||||
|
277
nac3core/src/codegen/concrete_type.rs
Normal file
277
nac3core/src/codegen/concrete_type.rs
Normal file
@ -0,0 +1,277 @@
|
||||
use crate::{
|
||||
symbol_resolver::SymbolValue,
|
||||
toplevel::DefinitionId,
|
||||
typecheck::{
|
||||
type_inferencer::PrimitiveStore,
|
||||
typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
||||
},
|
||||
};
|
||||
|
||||
use rustpython_parser::ast::StrRef;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct ConcreteTypeStore {
|
||||
store: Vec<ConcreteTypeEnum>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct ConcreteType(usize);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConcreteFuncArg {
|
||||
pub name: StrRef,
|
||||
pub ty: ConcreteType,
|
||||
pub default_value: Option<SymbolValue>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Primitive {
|
||||
Int32,
|
||||
Int64,
|
||||
Float,
|
||||
Bool,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConcreteTypeEnum {
|
||||
TPrimitive(Primitive),
|
||||
TTuple {
|
||||
ty: Vec<ConcreteType>,
|
||||
},
|
||||
TList {
|
||||
ty: ConcreteType,
|
||||
},
|
||||
TObj {
|
||||
obj_id: DefinitionId,
|
||||
fields: HashMap<StrRef, ConcreteType>,
|
||||
params: HashMap<u32, ConcreteType>,
|
||||
},
|
||||
TVirtual {
|
||||
ty: ConcreteType,
|
||||
},
|
||||
TFunc {
|
||||
args: Vec<ConcreteFuncArg>,
|
||||
ret: ConcreteType,
|
||||
vars: HashMap<u32, ConcreteType>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ConcreteTypeStore {
|
||||
pub fn new() -> ConcreteTypeStore {
|
||||
ConcreteTypeStore {
|
||||
store: vec![
|
||||
ConcreteTypeEnum::TPrimitive(Primitive::Int32),
|
||||
ConcreteTypeEnum::TPrimitive(Primitive::Int64),
|
||||
ConcreteTypeEnum::TPrimitive(Primitive::Float),
|
||||
ConcreteTypeEnum::TPrimitive(Primitive::Bool),
|
||||
ConcreteTypeEnum::TPrimitive(Primitive::None),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, cty: ConcreteType) -> &ConcreteTypeEnum {
|
||||
&self.store[cty.0]
|
||||
}
|
||||
|
||||
pub fn from_signature(
|
||||
&mut self,
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
signature: &FunSignature,
|
||||
cache: &mut HashMap<Type, Option<ConcreteType>>,
|
||||
) -> ConcreteTypeEnum {
|
||||
ConcreteTypeEnum::TFunc {
|
||||
args: signature
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| ConcreteFuncArg {
|
||||
name: arg.name,
|
||||
ty: self.from_unifier_type(unifier, primitives, arg.ty, cache),
|
||||
default_value: arg.default_value.clone(),
|
||||
})
|
||||
.collect(),
|
||||
ret: self.from_unifier_type(unifier, primitives, signature.ret, cache),
|
||||
vars: signature
|
||||
.vars
|
||||
.iter()
|
||||
.map(|(id, ty)| (*id, self.from_unifier_type(unifier, primitives, *ty, cache)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_unifier_type(
|
||||
&mut self,
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
ty: Type,
|
||||
cache: &mut HashMap<Type, Option<ConcreteType>>,
|
||||
) -> ConcreteType {
|
||||
let ty = unifier.get_representative(ty);
|
||||
if unifier.unioned(ty, primitives.int32) {
|
||||
ConcreteType(0)
|
||||
} else if unifier.unioned(ty, primitives.int64) {
|
||||
ConcreteType(1)
|
||||
} else if unifier.unioned(ty, primitives.float) {
|
||||
ConcreteType(2)
|
||||
} else if unifier.unioned(ty, primitives.bool) {
|
||||
ConcreteType(3)
|
||||
} else if unifier.unioned(ty, primitives.none) {
|
||||
ConcreteType(4)
|
||||
} else if let Some(cty) = cache.get(&ty) {
|
||||
if let Some(cty) = cty {
|
||||
*cty
|
||||
} else {
|
||||
let index = self.store.len();
|
||||
// placeholder
|
||||
self.store.push(ConcreteTypeEnum::TPrimitive(Primitive::Int32));
|
||||
let result = ConcreteType(index);
|
||||
cache.insert(ty, Some(result));
|
||||
result
|
||||
}
|
||||
} else {
|
||||
cache.insert(ty, None);
|
||||
let ty_enum = unifier.get_ty(ty);
|
||||
let result = match &*ty_enum {
|
||||
TypeEnum::TTuple { ty } => ConcreteTypeEnum::TTuple {
|
||||
ty: ty
|
||||
.iter()
|
||||
.map(|t| self.from_unifier_type(unifier, primitives, *t, cache))
|
||||
.collect(),
|
||||
},
|
||||
TypeEnum::TList { ty } => ConcreteTypeEnum::TList {
|
||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
||||
},
|
||||
TypeEnum::TObj { obj_id, fields, params } => ConcreteTypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: fields
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(name, ty)| {
|
||||
(*name, self.from_unifier_type(unifier, primitives, *ty, cache))
|
||||
})
|
||||
.collect(),
|
||||
params: params
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(id, ty)| {
|
||||
(*id, self.from_unifier_type(unifier, primitives, *ty, cache))
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
||||
},
|
||||
TypeEnum::TFunc(signature) => {
|
||||
let signature = signature.borrow();
|
||||
self.from_signature(unifier, primitives, &*signature, cache)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let index = if let Some(ConcreteType(index)) = cache.get(&ty).unwrap() {
|
||||
self.store[*index] = result;
|
||||
*index
|
||||
} else {
|
||||
self.store.push(result);
|
||||
self.store.len() - 1
|
||||
};
|
||||
cache.insert(ty, Some(ConcreteType(index)));
|
||||
ConcreteType(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_unifier_type(
|
||||
&self,
|
||||
unifier: &mut Unifier,
|
||||
primitives: &PrimitiveStore,
|
||||
cty: ConcreteType,
|
||||
cache: &mut HashMap<ConcreteType, Option<Type>>,
|
||||
) -> Type {
|
||||
if let Some(ty) = cache.get_mut(&cty) {
|
||||
return if let Some(ty) = ty {
|
||||
*ty
|
||||
} else {
|
||||
*ty = Some(unifier.get_fresh_var().0);
|
||||
ty.unwrap()
|
||||
};
|
||||
}
|
||||
cache.insert(cty, None);
|
||||
let result = match &self.store[cty.0] {
|
||||
ConcreteTypeEnum::TPrimitive(primitive) => {
|
||||
let ty = match primitive {
|
||||
Primitive::Int32 => primitives.int32,
|
||||
Primitive::Int64 => primitives.int64,
|
||||
Primitive::Float => primitives.float,
|
||||
Primitive::Bool => primitives.bool,
|
||||
Primitive::None => primitives.none,
|
||||
};
|
||||
*cache.get_mut(&cty).unwrap() = Some(ty);
|
||||
return ty;
|
||||
}
|
||||
ConcreteTypeEnum::TTuple { ty } => TypeEnum::TTuple {
|
||||
ty: ty
|
||||
.iter()
|
||||
.map(|cty| self.to_unifier_type(unifier, primitives, *cty, cache))
|
||||
.collect(),
|
||||
},
|
||||
ConcreteTypeEnum::TList { ty } => {
|
||||
TypeEnum::TList { ty: self.to_unifier_type(unifier, primitives, *ty, cache) }
|
||||
}
|
||||
ConcreteTypeEnum::TVirtual { ty } => {
|
||||
TypeEnum::TVirtual { ty: self.to_unifier_type(unifier, primitives, *ty, cache) }
|
||||
}
|
||||
ConcreteTypeEnum::TObj { obj_id, fields, params } => TypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: fields
|
||||
.iter()
|
||||
.map(|(name, cty)| {
|
||||
(*name, self.to_unifier_type(unifier, primitives, *cty, cache))
|
||||
})
|
||||
.collect::<HashMap<_, _>>()
|
||||
.into(),
|
||||
params: params
|
||||
.iter()
|
||||
.map(|(id, cty)| (*id, self.to_unifier_type(unifier, primitives, *cty, cache)))
|
||||
.collect::<HashMap<_, _>>()
|
||||
.into(),
|
||||
},
|
||||
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(
|
||||
FunSignature {
|
||||
args: args
|
||||
.iter()
|
||||
.map(|arg| FuncArg {
|
||||
name: arg.name,
|
||||
ty: self.to_unifier_type(unifier, primitives, arg.ty, cache),
|
||||
default_value: arg.default_value.clone(),
|
||||
})
|
||||
.collect(),
|
||||
ret: self.to_unifier_type(unifier, primitives, *ret, cache),
|
||||
vars: vars
|
||||
.iter()
|
||||
.map(|(id, cty)| {
|
||||
(*id, self.to_unifier_type(unifier, primitives, *cty, cache))
|
||||
})
|
||||
.collect::<HashMap<_, _>>(),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
};
|
||||
let result = unifier.add_ty(result);
|
||||
if let Some(ty) = cache.get(&cty).unwrap() {
|
||||
unifier.unify(*ty, result).unwrap();
|
||||
}
|
||||
cache.insert(cty, Some(result));
|
||||
result
|
||||
}
|
||||
|
||||
pub fn add_cty(&mut self, cty: ConcreteTypeEnum) -> ConcreteType {
|
||||
self.store.push(cty);
|
||||
ConcreteType(self.store.len() - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConcreteTypeStore {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
use std::{collections::HashMap, convert::TryInto, iter::once};
|
||||
|
||||
use crate::{
|
||||
codegen::{get_llvm_type, CodeGenContext, CodeGenTask},
|
||||
codegen::{
|
||||
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
||||
get_llvm_type, CodeGenContext, CodeGenTask,
|
||||
},
|
||||
symbol_resolver::SymbolValue,
|
||||
toplevel::{DefinitionId, TopLevelDef},
|
||||
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
||||
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum},
|
||||
};
|
||||
use inkwell::{
|
||||
types::{BasicType, BasicTypeEnum},
|
||||
@ -265,20 +268,9 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||
instance_to_symbol.insert(key, symbol.clone());
|
||||
let key = ctx.get_subst_key(obj.map(|a| a.0), sign, Some(var_id));
|
||||
let instance = instance_to_stmt.get(&key).unwrap();
|
||||
let unifiers = ctx.top_level.unifiers.read();
|
||||
let (unifier, primitives) = &unifiers[instance.unifier_id];
|
||||
let mut unifier = Unifier::from_shared_unifier(unifier);
|
||||
|
||||
let mut type_cache = [
|
||||
(ctx.primitives.int32, primitives.int32),
|
||||
(ctx.primitives.int64, primitives.int64),
|
||||
(ctx.primitives.float, primitives.float),
|
||||
(ctx.primitives.bool, primitives.bool),
|
||||
(ctx.primitives.none, primitives.none),
|
||||
]
|
||||
.iter()
|
||||
.map(|(a, b)| (ctx.unifier.get_representative(*a), unifier.get_representative(*b)))
|
||||
.collect();
|
||||
let mut store = ConcreteTypeStore::new();
|
||||
let mut cache = HashMap::new();
|
||||
|
||||
let subst = sign
|
||||
.vars
|
||||
@ -286,38 +278,27 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||
.map(|(id, ty)| {
|
||||
(
|
||||
*instance.subst.get(id).unwrap(),
|
||||
unifier.copy_from(&mut ctx.unifier, *ty, &mut type_cache),
|
||||
store.from_unifier_type(&mut ctx.unifier, &ctx.primitives, *ty, &mut cache),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut signature = FunSignature {
|
||||
args: sign
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| FuncArg {
|
||||
name: arg.name,
|
||||
ty: unifier.copy_from(&mut ctx.unifier, arg.ty, &mut type_cache),
|
||||
default_value: arg.default_value.clone(),
|
||||
})
|
||||
.collect(),
|
||||
ret: unifier.copy_from(&mut ctx.unifier, sign.ret, &mut type_cache),
|
||||
vars: sign
|
||||
.vars
|
||||
.iter()
|
||||
.map(|(id, ty)| {
|
||||
(*id, unifier.copy_from(&mut ctx.unifier, *ty, &mut type_cache))
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
let mut signature =
|
||||
store.from_signature(&mut ctx.unifier, &ctx.primitives, sign, &mut cache);
|
||||
|
||||
if let Some(obj) = &obj {
|
||||
signature
|
||||
.args
|
||||
.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
|
||||
let zelf =
|
||||
store.from_unifier_type(&mut ctx.unifier, &ctx.primitives, obj.0, &mut cache);
|
||||
if let ConcreteTypeEnum::TFunc { args, .. } = &mut signature {
|
||||
args.insert(
|
||||
0,
|
||||
ConcreteFuncArg { name: "self".into(), ty: zelf, default_value: None },
|
||||
)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
let unifier = (unifier.get_shared_unifier(), *primitives);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
ctx.registry.add_task(CodeGenTask {
|
||||
symbol_name: symbol.clone(),
|
||||
@ -326,7 +307,8 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||
calls: instance.calls.clone(),
|
||||
subst,
|
||||
signature,
|
||||
unifier,
|
||||
store,
|
||||
unifier_index: instance.unifier_id,
|
||||
});
|
||||
symbol
|
||||
})
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
toplevel::{TopLevelContext, TopLevelDef},
|
||||
typecheck::{
|
||||
type_inferencer::{CodeLocation, PrimitiveStore},
|
||||
typedef::{CallId, FunSignature, SharedUnifier, Type, TypeEnum, Unifier},
|
||||
typedef::{CallId, FuncArg, Type, TypeEnum, Unifier},
|
||||
},
|
||||
};
|
||||
use crossbeam::channel::{unbounded, Receiver, Sender};
|
||||
@ -27,6 +27,7 @@ use std::sync::{
|
||||
};
|
||||
use std::thread;
|
||||
|
||||
pub mod concrete_type;
|
||||
mod expr;
|
||||
mod generator;
|
||||
mod stmt;
|
||||
@ -34,6 +35,7 @@ mod stmt;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore};
|
||||
pub use generator::{CodeGenerator, DefaultCodeGenerator};
|
||||
|
||||
pub struct CodeGenContext<'ctx, 'a> {
|
||||
@ -198,12 +200,13 @@ impl WorkerRegistry {
|
||||
}
|
||||
|
||||
pub struct CodeGenTask {
|
||||
pub subst: Vec<(Type, Type)>,
|
||||
pub subst: Vec<(Type, ConcreteType)>,
|
||||
pub store: ConcreteTypeStore,
|
||||
pub symbol_name: String,
|
||||
pub signature: FunSignature,
|
||||
pub signature: ConcreteType,
|
||||
pub body: Arc<Vec<Stmt<Option<Type>>>>,
|
||||
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
||||
pub unifier: (SharedUnifier, PrimitiveStore),
|
||||
pub unifier_index: usize,
|
||||
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||
}
|
||||
|
||||
@ -218,7 +221,8 @@ 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(|| {
|
||||
match &*unifier.get_ty(ty) {
|
||||
let ty = unifier.get_ty(ty);
|
||||
match &*ty {
|
||||
TObj { obj_id, fields, .. } => {
|
||||
// a struct with fields in the order of declaration
|
||||
let top_level_defs = top_level.definitions.read();
|
||||
@ -252,7 +256,7 @@ fn get_llvm_type<'ctx>(
|
||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
TVirtual { .. } => unimplemented!(),
|
||||
_ => unreachable!(),
|
||||
_ => unreachable!("{}", ty.get_type_name()),
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -267,14 +271,16 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||
top_level_ctx: Arc<TopLevelContext>,
|
||||
) -> (Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>) {
|
||||
let (mut unifier, primitives) = {
|
||||
let (unifier, primitives) = task.unifier;
|
||||
(Unifier::from_shared_unifier(&unifier), primitives)
|
||||
let (unifier, primitives) = &top_level_ctx.unifiers.read()[task.unifier_index];
|
||||
(Unifier::from_shared_unifier(unifier), *primitives)
|
||||
};
|
||||
|
||||
let mut cache = HashMap::new();
|
||||
for (a, b) in task.subst.iter() {
|
||||
// this should be unification between variables and concrete types
|
||||
// and should not cause any problem...
|
||||
unifier.unify(*a, *b).unwrap();
|
||||
let b = task.store.to_unifier_type(&mut unifier, &primitives, *b, &mut cache);
|
||||
unifier.unify(*a, b).unwrap();
|
||||
}
|
||||
|
||||
// rebuild primitive store with unique representatives
|
||||
@ -296,26 +302,34 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let params = task
|
||||
.signature
|
||||
.args
|
||||
let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } =
|
||||
task.store.get(task.signature)
|
||||
{
|
||||
(
|
||||
args.iter()
|
||||
.map(|arg| FuncArg {
|
||||
name: arg.name,
|
||||
ty: task.store.to_unifier_type(&mut unifier, &primitives, arg.ty, &mut cache),
|
||||
default_value: arg.default_value.clone(),
|
||||
})
|
||||
.collect_vec(),
|
||||
task.store.to_unifier_type(&mut unifier, &primitives, *ret, &mut cache),
|
||||
)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let params = args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let fn_type = if unifier.unioned(task.signature.ret, primitives.none) {
|
||||
let fn_type = if unifier.unioned(ret, primitives.none) {
|
||||
context.void_type().fn_type(¶ms, false)
|
||||
} else {
|
||||
get_llvm_type(
|
||||
context,
|
||||
&mut unifier,
|
||||
top_level_ctx.as_ref(),
|
||||
&mut type_cache,
|
||||
task.signature.ret,
|
||||
)
|
||||
.fn_type(¶ms, false)
|
||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, ret)
|
||||
.fn_type(¶ms, false)
|
||||
};
|
||||
|
||||
let symbol = &task.symbol_name;
|
||||
@ -335,7 +349,7 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||
let body_bb = context.append_basic_block(fn_val, "body");
|
||||
|
||||
let mut var_assignment = HashMap::new();
|
||||
for (n, arg) in task.signature.args.iter().enumerate() {
|
||||
for (n, arg) in args.iter().enumerate() {
|
||||
let param = fn_val.get_nth_param(n as u32).unwrap();
|
||||
let alloca = builder.build_alloca(
|
||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty),
|
||||
|
@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
codegen::{CodeGenTask, WithCall, WorkerRegistry, CodeGenContext, DefaultCodeGenerator},
|
||||
codegen::{
|
||||
concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenTask, DefaultCodeGenerator,
|
||||
WithCall, WorkerRegistry,
|
||||
},
|
||||
location::Location,
|
||||
symbol_resolver::SymbolResolver,
|
||||
toplevel::{
|
||||
@ -34,11 +37,21 @@ impl Resolver {
|
||||
}
|
||||
|
||||
impl SymbolResolver for Resolver {
|
||||
fn get_symbol_type(&self, _: &mut Unifier, _: &[Arc<RwLock<TopLevelDef>>], _: &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()
|
||||
}
|
||||
|
||||
fn get_symbol_value<'ctx, 'a>(&self, _: StrRef, _: &mut CodeGenContext<'ctx, 'a>) -> Option<BasicValueEnum<'ctx>> {
|
||||
fn get_symbol_value<'ctx, 'a>(
|
||||
&self,
|
||||
_: StrRef,
|
||||
_: &mut CodeGenContext<'ctx, 'a>,
|
||||
) -> Option<BasicValueEnum<'ctx>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@ -82,6 +95,11 @@ fn test_primitives() {
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut store = ConcreteTypeStore::new();
|
||||
let mut cache = HashMap::new();
|
||||
let signature = store.from_signature(&mut unifier, &primitives, &signature, &mut cache);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
let mut function_data = FunctionData {
|
||||
resolver: resolver.clone(),
|
||||
bound_variables: Vec::new(),
|
||||
@ -116,15 +134,14 @@ fn test_primitives() {
|
||||
personality_symbol: None,
|
||||
});
|
||||
|
||||
let unifier = (unifier.get_shared_unifier(), primitives);
|
||||
|
||||
let task = CodeGenTask {
|
||||
subst: Default::default(),
|
||||
symbol_name: "testing".into(),
|
||||
body: Arc::new(statements),
|
||||
resolver,
|
||||
unifier,
|
||||
unifier_index: 0,
|
||||
calls: Arc::new(calls),
|
||||
resolver,
|
||||
store,
|
||||
signature,
|
||||
};
|
||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||
@ -216,6 +233,10 @@ fn test_simple_call() {
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
let fun_ty = unifier.add_ty(TypeEnum::TFunc(RefCell::new(signature.clone())));
|
||||
let mut store = ConcreteTypeStore::new();
|
||||
let mut cache = HashMap::new();
|
||||
let signature = store.from_signature(&mut unifier, &primitives, &signature, &mut cache);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
let foo_id = top_level.definitions.read().len();
|
||||
top_level.definitions.write().push(Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
@ -305,16 +326,15 @@ fn test_simple_call() {
|
||||
personality_symbol: None,
|
||||
});
|
||||
|
||||
let unifier = (unifier.get_shared_unifier(), primitives);
|
||||
|
||||
let task = CodeGenTask {
|
||||
subst: Default::default(),
|
||||
symbol_name: "testing".to_string(),
|
||||
body: Arc::new(statements_1),
|
||||
resolver,
|
||||
unifier,
|
||||
calls: Arc::new(calls1),
|
||||
unifier_index: 0,
|
||||
resolver,
|
||||
signature,
|
||||
store,
|
||||
};
|
||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||
let expected = indoc! {"
|
||||
|
@ -13,7 +13,7 @@ use parking_lot::RwLock;
|
||||
use rustpython_parser::ast::{Expr, StrRef};
|
||||
use inkwell::values::BasicValueEnum;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum SymbolValue {
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
|
@ -125,78 +125,6 @@ impl Unifier {
|
||||
}
|
||||
}
|
||||
|
||||
// copy concrete type from a type in another unifier
|
||||
// note that we are constructing a new type this way
|
||||
// this can handle recursive types
|
||||
pub fn copy_from(
|
||||
&mut self,
|
||||
unifier: &mut Unifier,
|
||||
ty: Type,
|
||||
type_cache: &mut HashMap<Type, Type>,
|
||||
) -> Type {
|
||||
let representative = unifier.get_representative(ty);
|
||||
type_cache.get(&representative).cloned().unwrap_or_else(|| {
|
||||
// put in a placeholder first to handle possible recursive type
|
||||
let placeholder = self.get_fresh_var().0;
|
||||
type_cache.insert(representative, placeholder);
|
||||
let ty = match &*self.get_ty(ty) {
|
||||
TypeEnum::TVar { .. } | TypeEnum::TRigidVar { .. } | TypeEnum::TCall(..) => {
|
||||
unreachable!()
|
||||
}
|
||||
TypeEnum::TObj { obj_id, fields, params } => TypeEnum::TObj {
|
||||
obj_id: *obj_id,
|
||||
fields: RefCell::new(
|
||||
fields
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(name, ty)| (*name, self.copy_from(unifier, *ty, type_cache)))
|
||||
.collect(),
|
||||
),
|
||||
params: RefCell::new(
|
||||
params
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(id, ty)| (*id, self.copy_from(unifier, *ty, type_cache)))
|
||||
.collect(),
|
||||
),
|
||||
},
|
||||
TypeEnum::TList { ty } => {
|
||||
TypeEnum::TList { ty: self.copy_from(unifier, *ty, type_cache) }
|
||||
}
|
||||
TypeEnum::TFunc(fun) => {
|
||||
let fun = fun.borrow();
|
||||
TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||
args: fun
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| FuncArg {
|
||||
name: arg.name,
|
||||
ty: self.copy_from(unifier, arg.ty, type_cache),
|
||||
default_value: arg.default_value.clone(),
|
||||
})
|
||||
.collect(),
|
||||
ret: self.copy_from(unifier, fun.ret, type_cache),
|
||||
vars: fun
|
||||
.vars
|
||||
.iter()
|
||||
.map(|(id, ty)| (*id, self.copy_from(unifier, *ty, type_cache)))
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
TypeEnum::TTuple { ty } => TypeEnum::TTuple {
|
||||
ty: ty.iter().map(|ty| self.copy_from(unifier, *ty, type_cache)).collect(),
|
||||
},
|
||||
TypeEnum::TVirtual { ty } => {
|
||||
TypeEnum::TVirtual { ty: self.copy_from(unifier, *ty, type_cache) }
|
||||
}
|
||||
};
|
||||
let ty = self.add_ty(ty);
|
||||
self.unify_impl(placeholder, ty, false).unwrap();
|
||||
type_cache.insert(representative, ty);
|
||||
ty
|
||||
})
|
||||
}
|
||||
|
||||
/// Determine if the two types are the same
|
||||
pub fn unioned(&mut self, a: Type, b: Type) -> bool {
|
||||
self.unification_table.unioned(a, b)
|
||||
|
@ -10,7 +10,10 @@ use std::fs;
|
||||
use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime};
|
||||
|
||||
use nac3core::{
|
||||
codegen::{CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry},
|
||||
codegen::{
|
||||
concrete_type::ConcreteTypeStore, CodeGenTask, DefaultCodeGenerator, WithCall,
|
||||
WorkerRegistry,
|
||||
},
|
||||
symbol_resolver::SymbolResolver,
|
||||
toplevel::{composer::TopLevelComposer, TopLevelDef},
|
||||
typecheck::typedef::FunSignature,
|
||||
@ -73,6 +76,16 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let signature = FunSignature {
|
||||
args: vec![],
|
||||
ret: primitive.int32,
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
let mut store = ConcreteTypeStore::new();
|
||||
let mut cache = HashMap::new();
|
||||
let signature = store.from_signature(&mut composer.unifier, &primitive, &signature, &mut cache);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
composer.start_analysis(true).unwrap();
|
||||
let analysis_time = SystemTime::now();
|
||||
println!(
|
||||
@ -100,11 +113,6 @@ fn main() {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
let signature = FunSignature {
|
||||
args: vec![],
|
||||
ret: primitive.int32,
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
|
||||
let task = CodeGenTask {
|
||||
subst: Default::default(),
|
||||
@ -112,7 +120,8 @@ fn main() {
|
||||
body: instance.body,
|
||||
signature,
|
||||
resolver,
|
||||
unifier: top_level.unifiers.read()[instance.unifier_id].clone(),
|
||||
store,
|
||||
unifier_index: instance.unifier_id,
|
||||
calls: instance.calls,
|
||||
};
|
||||
let f = Arc::new(WithCall::new(Box::new(move |module| {
|
||||
|
Loading…
Reference in New Issue
Block a user