forked from M-Labs/nac3
nac3core/codegen: refactor according to #23
This commit is contained in:
parent
c4259d14d1
commit
1f5bea2448
|
@ -19,7 +19,7 @@ use rustpython_parser::{
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{CodeGenTask, WithCall, WorkerRegistry},
|
codegen::{CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{composer::TopLevelComposer, DefinitionId, GenCall, TopLevelContext, TopLevelDef},
|
toplevel::{composer::TopLevelComposer, DefinitionId, GenCall, TopLevelContext, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, FuncArg},
|
typecheck::typedef::{FunSignature, FuncArg},
|
||||||
|
@ -423,11 +423,13 @@ impl Nac3 {
|
||||||
.expect("couldn't write module to file");
|
.expect("couldn't write module to file");
|
||||||
})));
|
})));
|
||||||
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| Box::new(DefaultCodeGenerator::new(s.to_string())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
py.allow_threads(|| {
|
py.allow_threads(|| {
|
||||||
let (registry, handles) =
|
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level.clone(), f);
|
||||||
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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,8 @@ use inkwell::{
|
||||||
use itertools::{chain, izip, zip, Itertools};
|
use itertools::{chain, izip, zip, Itertools};
|
||||||
use rustpython_parser::ast::{self, Boolop, Constant, Expr, ExprKind, Operator, StrRef};
|
use rustpython_parser::ast::{self, Boolop, Constant, Expr, ExprKind, Operator, StrRef};
|
||||||
|
|
||||||
|
use super::CodeGenerator;
|
||||||
|
|
||||||
pub fn assert_int_val(val: BasicValueEnum<'_>) -> IntValue<'_> {
|
pub fn assert_int_val(val: BasicValueEnum<'_>) -> IntValue<'_> {
|
||||||
if let BasicValueEnum::IntValue(v) = val {
|
if let BasicValueEnum::IntValue(v) = val {
|
||||||
v
|
v
|
||||||
|
@ -102,172 +104,6 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
get_llvm_type(self.ctx, &mut self.unifier, self.top_level, &mut self.type_cache, ty)
|
get_llvm_type(self.ctx, &mut self.unifier, self.top_level, &mut self.type_cache, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_call(
|
|
||||||
&mut self,
|
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
|
||||||
fun: (&FunSignature, DefinitionId),
|
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
|
||||||
let definition = self.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
|
||||||
let mut task = None;
|
|
||||||
let key = self.get_subst_key(obj.map(|a| a.0), fun.0, None);
|
|
||||||
let symbol = {
|
|
||||||
// make sure this lock guard is dropped at the end of this scope...
|
|
||||||
let def = definition.read();
|
|
||||||
match &*def {
|
|
||||||
TopLevelDef::Function { instance_to_symbol, codegen_callback, .. } => {
|
|
||||||
if let Some(callback) = codegen_callback {
|
|
||||||
return callback.run(self, obj, fun, params);
|
|
||||||
}
|
|
||||||
instance_to_symbol.get(&key).cloned()
|
|
||||||
}
|
|
||||||
TopLevelDef::Class { methods, .. } => {
|
|
||||||
// TODO: what about other fields that require alloca?
|
|
||||||
let mut fun_id = None;
|
|
||||||
for (name, _, id) in methods.iter() {
|
|
||||||
if name == &"__init__".into() {
|
|
||||||
fun_id = Some(*id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let ty = self.get_llvm_type(fun.0.ret).into_pointer_type();
|
|
||||||
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
|
||||||
let zelf = self.builder.build_alloca(zelf_ty, "alloca").into();
|
|
||||||
// call `__init__` if there is one
|
|
||||||
if let Some(fun_id) = fun_id {
|
|
||||||
let mut sign = fun.0.clone();
|
|
||||||
sign.ret = self.primitives.none;
|
|
||||||
self.gen_call(Some((fun.0.ret, zelf)), (&sign, fun_id), params);
|
|
||||||
}
|
|
||||||
return Some(zelf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
if let TopLevelDef::Function {
|
|
||||||
name,
|
|
||||||
instance_to_symbol,
|
|
||||||
instance_to_stmt,
|
|
||||||
var_id,
|
|
||||||
resolver,
|
|
||||||
..
|
|
||||||
} = &mut *definition.write()
|
|
||||||
{
|
|
||||||
instance_to_symbol.get(&key).cloned().unwrap_or_else(|| {
|
|
||||||
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
|
||||||
instance_to_symbol.insert(key, symbol.clone());
|
|
||||||
let key = self.get_subst_key(obj.map(|a| a.0), fun.0, Some(var_id));
|
|
||||||
let instance = instance_to_stmt.get(&key).unwrap();
|
|
||||||
let unifiers = self.top_level.unifiers.read();
|
|
||||||
let (unifier, primitives) = &unifiers[instance.unifier_id];
|
|
||||||
let mut unifier = Unifier::from_shared_unifier(unifier);
|
|
||||||
|
|
||||||
let mut type_cache = [
|
|
||||||
(self.primitives.int32, primitives.int32),
|
|
||||||
(self.primitives.int64, primitives.int64),
|
|
||||||
(self.primitives.float, primitives.float),
|
|
||||||
(self.primitives.bool, primitives.bool),
|
|
||||||
(self.primitives.none, primitives.none),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.map(|(a, b)| {
|
|
||||||
(self.unifier.get_representative(*a), unifier.get_representative(*b))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let subst = fun
|
|
||||||
.0
|
|
||||||
.vars
|
|
||||||
.iter()
|
|
||||||
.map(|(id, ty)| {
|
|
||||||
(
|
|
||||||
*instance.subst.get(id).unwrap(),
|
|
||||||
unifier.copy_from(&mut self.unifier, *ty, &mut type_cache),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut signature = FunSignature {
|
|
||||||
args: fun
|
|
||||||
.0
|
|
||||||
.args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| FuncArg {
|
|
||||||
name: arg.name,
|
|
||||||
ty: unifier.copy_from(&mut self.unifier, arg.ty, &mut type_cache),
|
|
||||||
default_value: arg.default_value.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
ret: unifier.copy_from(&mut self.unifier, fun.0.ret, &mut type_cache),
|
|
||||||
vars: fun
|
|
||||||
.0
|
|
||||||
.vars
|
|
||||||
.iter()
|
|
||||||
.map(|(id, ty)| {
|
|
||||||
(*id, unifier.copy_from(&mut self.unifier, *ty, &mut type_cache))
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(obj) = &obj {
|
|
||||||
signature.args.insert(
|
|
||||||
0,
|
|
||||||
FuncArg { name: "self".into(), ty: obj.0, default_value: None },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let unifier = (unifier.get_shared_unifier(), *primitives);
|
|
||||||
|
|
||||||
task = Some(CodeGenTask {
|
|
||||||
symbol_name: symbol.clone(),
|
|
||||||
body: instance.body.clone(),
|
|
||||||
resolver: resolver.as_ref().unwrap().clone(),
|
|
||||||
calls: instance.calls.clone(),
|
|
||||||
subst,
|
|
||||||
signature,
|
|
||||||
unifier,
|
|
||||||
});
|
|
||||||
symbol
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(task) = task {
|
|
||||||
self.registry.add_task(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
let fun_val = self.module.get_function(&symbol).unwrap_or_else(|| {
|
|
||||||
let mut args = fun.0.args.clone();
|
|
||||||
if let Some(obj) = &obj {
|
|
||||||
args.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
|
|
||||||
}
|
|
||||||
let params = args.iter().map(|arg| self.get_llvm_type(arg.ty)).collect_vec();
|
|
||||||
let fun_ty = if self.unifier.unioned(fun.0.ret, self.primitives.none) {
|
|
||||||
self.ctx.void_type().fn_type(¶ms, false)
|
|
||||||
} else {
|
|
||||||
self.get_llvm_type(fun.0.ret).fn_type(¶ms, false)
|
|
||||||
};
|
|
||||||
self.module.add_function(&symbol, fun_ty, None)
|
|
||||||
});
|
|
||||||
let mut keys = fun.0.args.clone();
|
|
||||||
let mut mapping = HashMap::new();
|
|
||||||
for (key, value) in params.into_iter() {
|
|
||||||
mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value);
|
|
||||||
}
|
|
||||||
// default value handling
|
|
||||||
for k in keys.into_iter() {
|
|
||||||
mapping.insert(k.name, self.gen_symbol_val(&k.default_value.unwrap()));
|
|
||||||
}
|
|
||||||
// reorder the parameters
|
|
||||||
let mut params =
|
|
||||||
fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
|
|
||||||
if let Some(obj) = obj {
|
|
||||||
params.insert(0, obj.1);
|
|
||||||
}
|
|
||||||
self.builder.build_call(fun_val, ¶ms, "call").try_as_basic_value().left()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_const(&mut self, value: &Constant, ty: Type) -> BasicValueEnum<'ctx> {
|
fn gen_const(&mut self, value: &Constant, ty: Type) -> BasicValueEnum<'ctx> {
|
||||||
match value {
|
match value {
|
||||||
Constant::Bool(v) => {
|
Constant::Bool(v) => {
|
||||||
|
@ -378,165 +214,347 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gen_expr(&mut self, expr: &Expr<Option<Type>>) -> Option<BasicValueEnum<'ctx>> {
|
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let zero = self.ctx.i32_type().const_int(0, false);
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
signature: &FunSignature,
|
||||||
|
def: &TopLevelDef,
|
||||||
|
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
match def {
|
||||||
|
TopLevelDef::Class { methods, .. } => {
|
||||||
|
// TODO: what about other fields that require alloca?
|
||||||
|
let mut fun_id = None;
|
||||||
|
for (name, _, id) in methods.iter() {
|
||||||
|
if name == &"__init__".into() {
|
||||||
|
fun_id = Some(*id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let ty = ctx.get_llvm_type(signature.ret).into_pointer_type();
|
||||||
|
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
||||||
|
let zelf = ctx.builder.build_alloca(zelf_ty, "alloca").into();
|
||||||
|
// call `__init__` if there is one
|
||||||
|
if let Some(fun_id) = fun_id {
|
||||||
|
let mut sign = signature.clone();
|
||||||
|
sign.ret = ctx.primitives.none;
|
||||||
|
generator.gen_call(ctx, Some((signature.ret, zelf)), (&sign, fun_id), params);
|
||||||
|
}
|
||||||
|
zelf
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_func_instance<'ctx, 'a>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, &mut TopLevelDef, String),
|
||||||
|
) -> String {
|
||||||
|
if let (
|
||||||
|
sign,
|
||||||
|
TopLevelDef::Function {
|
||||||
|
name, instance_to_symbol, instance_to_stmt, var_id, resolver, ..
|
||||||
|
},
|
||||||
|
key,
|
||||||
|
) = fun
|
||||||
|
{
|
||||||
|
instance_to_symbol.get(&key).cloned().unwrap_or_else(|| {
|
||||||
|
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
||||||
|
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 subst = sign
|
||||||
|
.vars
|
||||||
|
.iter()
|
||||||
|
.map(|(id, ty)| {
|
||||||
|
(
|
||||||
|
*instance.subst.get(id).unwrap(),
|
||||||
|
unifier.copy_from(&mut ctx.unifier, *ty, &mut type_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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(obj) = &obj {
|
||||||
|
signature
|
||||||
|
.args
|
||||||
|
.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
|
||||||
|
}
|
||||||
|
|
||||||
|
let unifier = (unifier.get_shared_unifier(), *primitives);
|
||||||
|
|
||||||
|
ctx.registry.add_task(CodeGenTask {
|
||||||
|
symbol_name: symbol.clone(),
|
||||||
|
body: instance.body.clone(),
|
||||||
|
resolver: resolver.as_ref().unwrap().clone(),
|
||||||
|
calls: instance.calls.clone(),
|
||||||
|
subst,
|
||||||
|
signature,
|
||||||
|
unifier,
|
||||||
|
});
|
||||||
|
symbol
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, DefinitionId),
|
||||||
|
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
||||||
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
|
let definition = ctx.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
||||||
|
let key = ctx.get_subst_key(obj.map(|a| a.0), fun.0, None);
|
||||||
|
let symbol = {
|
||||||
|
// make sure this lock guard is dropped at the end of this scope...
|
||||||
|
let def = definition.read();
|
||||||
|
match &*def {
|
||||||
|
TopLevelDef::Function { instance_to_symbol, codegen_callback, .. } => {
|
||||||
|
if let Some(callback) = codegen_callback {
|
||||||
|
return callback.run(ctx, obj, fun, params);
|
||||||
|
}
|
||||||
|
instance_to_symbol.get(&key).cloned()
|
||||||
|
}
|
||||||
|
TopLevelDef::Class { .. } => {
|
||||||
|
return Some(generator.gen_constructor(ctx, fun.0, &*def, params))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
generator.gen_func_instance(ctx, obj, (fun.0, &mut *definition.write(), key))
|
||||||
|
});
|
||||||
|
let fun_val = ctx.module.get_function(&symbol).unwrap_or_else(|| {
|
||||||
|
let mut args = fun.0.args.clone();
|
||||||
|
if let Some(obj) = &obj {
|
||||||
|
args.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
|
||||||
|
}
|
||||||
|
let params = args.iter().map(|arg| ctx.get_llvm_type(arg.ty)).collect_vec();
|
||||||
|
let fun_ty = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
||||||
|
ctx.ctx.void_type().fn_type(¶ms, false)
|
||||||
|
} else {
|
||||||
|
ctx.get_llvm_type(fun.0.ret).fn_type(¶ms, false)
|
||||||
|
};
|
||||||
|
ctx.module.add_function(&symbol, fun_ty, None)
|
||||||
|
});
|
||||||
|
let mut keys = fun.0.args.clone();
|
||||||
|
let mut mapping = HashMap::new();
|
||||||
|
for (key, value) in params.into_iter() {
|
||||||
|
mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value);
|
||||||
|
}
|
||||||
|
// default value handling
|
||||||
|
for k in keys.into_iter() {
|
||||||
|
mapping.insert(k.name, ctx.gen_symbol_val(&k.default_value.unwrap()));
|
||||||
|
}
|
||||||
|
// reorder the parameters
|
||||||
|
let mut params = fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
|
||||||
|
if let Some(obj) = obj {
|
||||||
|
params.insert(0, obj.1);
|
||||||
|
}
|
||||||
|
ctx.builder.build_call(fun_val, ¶ms, "call").try_as_basic_value().left()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
expr: &Expr<Option<Type>>,
|
||||||
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
|
let zero = ctx.ctx.i32_type().const_int(0, false);
|
||||||
Some(match &expr.node {
|
Some(match &expr.node {
|
||||||
ExprKind::Constant { value, .. } => {
|
ExprKind::Constant { value, .. } => {
|
||||||
let ty = expr.custom.unwrap();
|
let ty = expr.custom.unwrap();
|
||||||
self.gen_const(value, ty)
|
ctx.gen_const(value, ty)
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
let ptr = self.var_assignment.get(id);
|
let ptr = ctx.var_assignment.get(id);
|
||||||
if let Some(ptr) = ptr {
|
if let Some(ptr) = ptr {
|
||||||
self.builder.build_load(*ptr, "load")
|
ctx.builder.build_load(*ptr, "load")
|
||||||
} else {
|
} else {
|
||||||
let resolver = self.resolver.clone();
|
let resolver = ctx.resolver.clone();
|
||||||
resolver.get_symbol_value(*id, self).unwrap()
|
resolver.get_symbol_value(*id, ctx).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...
|
||||||
// we should use memcpy for that instead of generating thousands of stores
|
// we should use memcpy for that instead of generating thousands of stores
|
||||||
let elements = elts.iter().map(|x| self.gen_expr(x).unwrap()).collect_vec();
|
let elements = elts.iter().map(|x| generator.gen_expr(ctx, x).unwrap()).collect_vec();
|
||||||
let ty = if elements.is_empty() {
|
let ty = if elements.is_empty() {
|
||||||
self.ctx.i32_type().into()
|
ctx.ctx.i32_type().into()
|
||||||
} else {
|
} else {
|
||||||
elements[0].get_type()
|
elements[0].get_type()
|
||||||
};
|
};
|
||||||
let arr_ptr = self.builder.build_array_alloca(
|
let arr_ptr = ctx.builder.build_array_alloca(
|
||||||
ty,
|
ty,
|
||||||
self.ctx.i32_type().const_int(elements.len() as u64, false),
|
ctx.ctx.i32_type().const_int(elements.len() as u64, false),
|
||||||
"tmparr",
|
"tmparr",
|
||||||
);
|
);
|
||||||
let arr_ty = self.ctx.struct_type(
|
let arr_ty = ctx.ctx.struct_type(
|
||||||
&[self.ctx.i32_type().into(), ty.ptr_type(AddressSpace::Generic).into()],
|
&[ctx.ctx.i32_type().into(), ty.ptr_type(AddressSpace::Generic).into()],
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
let arr_str_ptr = self.builder.build_alloca(arr_ty, "tmparrstr");
|
let arr_str_ptr = ctx.builder.build_alloca(arr_ty, "tmparrstr");
|
||||||
unsafe {
|
unsafe {
|
||||||
let len_ptr =
|
let len_ptr =
|
||||||
self.builder.build_in_bounds_gep(arr_str_ptr, &[zero, zero], "len_ptr");
|
ctx.builder.build_in_bounds_gep(arr_str_ptr, &[zero, zero], "len_ptr");
|
||||||
self.builder.build_store(
|
ctx.builder.build_store(
|
||||||
len_ptr,
|
len_ptr,
|
||||||
self.ctx.i32_type().const_int(elements.len() as u64, false),
|
ctx.ctx.i32_type().const_int(elements.len() as u64, false),
|
||||||
);
|
);
|
||||||
let ptr_to_arr = self.builder.build_in_bounds_gep(
|
let ptr_to_arr = ctx.builder.build_in_bounds_gep(
|
||||||
arr_str_ptr,
|
arr_str_ptr,
|
||||||
&[zero, self.ctx.i32_type().const_int(1, false)],
|
&[zero, ctx.ctx.i32_type().const_int(1, false)],
|
||||||
"ptr_to_arr",
|
"ptr_to_arr",
|
||||||
);
|
);
|
||||||
self.builder.build_store(ptr_to_arr, arr_ptr);
|
ctx.builder.build_store(ptr_to_arr, arr_ptr);
|
||||||
let i32_type = self.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
for (i, v) in elements.iter().enumerate() {
|
for (i, v) in elements.iter().enumerate() {
|
||||||
let elem_ptr = self.builder.build_in_bounds_gep(
|
let elem_ptr = ctx.builder.build_in_bounds_gep(
|
||||||
arr_ptr,
|
arr_ptr,
|
||||||
&[i32_type.const_int(i as u64, false)],
|
&[i32_type.const_int(i as u64, false)],
|
||||||
"elem_ptr",
|
"elem_ptr",
|
||||||
);
|
);
|
||||||
self.builder.build_store(elem_ptr, *v);
|
ctx.builder.build_store(elem_ptr, *v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arr_str_ptr.into()
|
arr_str_ptr.into()
|
||||||
}
|
}
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
let element_val = elts.iter().map(|x| self.gen_expr(x).unwrap()).collect_vec();
|
let element_val =
|
||||||
|
elts.iter().map(|x| generator.gen_expr(ctx, x).unwrap()).collect_vec();
|
||||||
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
let tuple_ty = self.ctx.struct_type(&element_ty, false);
|
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
||||||
let tuple_ptr = self.builder.build_alloca(tuple_ty, "tuple");
|
let tuple_ptr = ctx.builder.build_alloca(tuple_ty, "tuple");
|
||||||
for (i, v) in element_val.into_iter().enumerate() {
|
for (i, v) in element_val.into_iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.builder.build_in_bounds_gep(
|
let ptr = ctx.builder.build_in_bounds_gep(
|
||||||
tuple_ptr,
|
tuple_ptr,
|
||||||
&[zero, self.ctx.i32_type().const_int(i as u64, false)],
|
&[zero, ctx.ctx.i32_type().const_int(i as u64, false)],
|
||||||
"ptr",
|
"ptr",
|
||||||
);
|
);
|
||||||
self.builder.build_store(ptr, v);
|
ctx.builder.build_store(ptr, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tuple_ptr.into()
|
tuple_ptr.into()
|
||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
// note that we would handle class methods directly in calls
|
// note that we would handle class methods directly in calls
|
||||||
let index = self.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = self.gen_expr(value).unwrap();
|
let val = generator.gen_expr(ctx, value).unwrap();
|
||||||
let ptr = assert_pointer_val(val);
|
let ptr = assert_pointer_val(val);
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.builder.build_in_bounds_gep(
|
let ptr = ctx.builder.build_in_bounds_gep(
|
||||||
ptr,
|
ptr,
|
||||||
&[zero, self.ctx.i32_type().const_int(index as u64, false)],
|
&[zero, ctx.ctx.i32_type().const_int(index as u64, false)],
|
||||||
"attr",
|
"attr",
|
||||||
);
|
);
|
||||||
self.builder.build_load(ptr, "field")
|
ctx.builder.build_load(ptr, "field")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::BoolOp { op, values } => {
|
ExprKind::BoolOp { op, values } => {
|
||||||
// requires conditional branches for short-circuiting...
|
// requires conditional branches for short-circuiting...
|
||||||
let left = assert_int_val(self.gen_expr(&values[0]).unwrap());
|
let left = assert_int_val(generator.gen_expr(ctx, &values[0]).unwrap());
|
||||||
let current = self.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = self.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
let b_bb = self.ctx.append_basic_block(current, "b");
|
let b_bb = ctx.ctx.append_basic_block(current, "b");
|
||||||
let cont_bb = self.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
self.builder.build_conditional_branch(left, a_bb, b_bb);
|
ctx.builder.build_conditional_branch(left, a_bb, b_bb);
|
||||||
let (a, b) = match op {
|
let (a, b) = match op {
|
||||||
Boolop::Or => {
|
Boolop::Or => {
|
||||||
self.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = self.ctx.bool_type().const_int(1, false);
|
let a = ctx.ctx.bool_type().const_int(1, false);
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
self.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = assert_int_val(self.gen_expr(&values[1]).unwrap());
|
let b = assert_int_val(generator.gen_expr(ctx, &values[1]).unwrap());
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
Boolop::And => {
|
Boolop::And => {
|
||||||
self.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = assert_int_val(self.gen_expr(&values[1]).unwrap());
|
let a = assert_int_val(generator.gen_expr(ctx, &values[1]).unwrap());
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
self.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = self.ctx.bool_type().const_int(0, false);
|
let b = ctx.ctx.bool_type().const_int(0, false);
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = self.builder.build_phi(self.ctx.bool_type(), "phi");
|
let phi = ctx.builder.build_phi(ctx.ctx.bool_type(), "phi");
|
||||||
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
||||||
phi.as_basic_value()
|
phi.as_basic_value()
|
||||||
}
|
}
|
||||||
ExprKind::BinOp { op, left, right } => {
|
ExprKind::BinOp { op, left, right } => {
|
||||||
let ty1 = self.unifier.get_representative(left.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
||||||
let ty2 = self.unifier.get_representative(right.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
||||||
let left = self.gen_expr(left).unwrap();
|
let left = generator.gen_expr(ctx, left).unwrap();
|
||||||
let right = self.gen_expr(right).unwrap();
|
let right = generator.gen_expr(ctx, right).unwrap();
|
||||||
|
|
||||||
// we can directly compare the types, because we've got their representatives
|
// we can directly compare the types, because we've got their representatives
|
||||||
// which would be unchanged until further unification, which we would never do
|
// which would be unchanged until further unification, which we would never do
|
||||||
// when doing code generation for function instances
|
// when doing code generation for function instances
|
||||||
if ty1 == ty2 && [self.primitives.int32, self.primitives.int64].contains(&ty1) {
|
if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) {
|
||||||
self.gen_int_ops(op, left, right)
|
ctx.gen_int_ops(op, left, right)
|
||||||
} else if ty1 == ty2 && self.primitives.float == ty1 {
|
} else if ty1 == ty2 && ctx.primitives.float == ty1 {
|
||||||
self.gen_float_ops(op, left, right)
|
ctx.gen_float_ops(op, left, right)
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::UnaryOp { op, operand } => {
|
ExprKind::UnaryOp { op, operand } => {
|
||||||
let ty = self.unifier.get_representative(operand.custom.unwrap());
|
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
||||||
let val = self.gen_expr(operand).unwrap();
|
let val = generator.gen_expr(ctx, operand).unwrap();
|
||||||
if ty == self.primitives.bool {
|
if ty == ctx.primitives.bool {
|
||||||
let val = assert_int_val(val);
|
let val = assert_int_val(val);
|
||||||
match op {
|
match op {
|
||||||
ast::Unaryop::Invert | ast::Unaryop::Not => {
|
ast::Unaryop::Invert | ast::Unaryop::Not => {
|
||||||
self.builder.build_not(val, "not").into()
|
ctx.builder.build_not(val, "not").into()
|
||||||
}
|
}
|
||||||
_ => val.into(),
|
_ => val.into(),
|
||||||
}
|
}
|
||||||
} else if [self.primitives.int32, self.primitives.int64].contains(&ty) {
|
} else if [ctx.primitives.int32, ctx.primitives.int64].contains(&ty) {
|
||||||
let val = assert_int_val(val);
|
let val = assert_int_val(val);
|
||||||
match op {
|
match op {
|
||||||
ast::Unaryop::USub => self.builder.build_int_neg(val, "neg").into(),
|
ast::Unaryop::USub => ctx.builder.build_int_neg(val, "neg").into(),
|
||||||
ast::Unaryop::Invert => self.builder.build_not(val, "not").into(),
|
ast::Unaryop::Invert => ctx.builder.build_not(val, "not").into(),
|
||||||
ast::Unaryop::Not => self
|
ast::Unaryop::Not => ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_compare(
|
.build_int_compare(
|
||||||
inkwell::IntPredicate::EQ,
|
inkwell::IntPredicate::EQ,
|
||||||
|
@ -547,15 +565,12 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
.into(),
|
.into(),
|
||||||
_ => val.into(),
|
_ => val.into(),
|
||||||
}
|
}
|
||||||
} else if ty == self.primitives.float {
|
} else if ty == ctx.primitives.float {
|
||||||
let val = if let BasicValueEnum::FloatValue(val) = val {
|
let val =
|
||||||
val
|
if let BasicValueEnum::FloatValue(val) = val { val } else { unreachable!() };
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
match op {
|
match op {
|
||||||
ast::Unaryop::USub => self.builder.build_float_neg(val, "neg").into(),
|
ast::Unaryop::USub => ctx.builder.build_float_neg(val, "neg").into(),
|
||||||
ast::Unaryop::Not => self
|
ast::Unaryop::Not => ctx
|
||||||
.builder
|
.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OEQ,
|
inkwell::FloatPredicate::OEQ,
|
||||||
|
@ -571,23 +586,20 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Compare { left, ops, comparators } => {
|
ExprKind::Compare { left, ops, comparators } => {
|
||||||
izip!(
|
izip!(chain(once(left.as_ref()), comparators.iter()), comparators.iter(), ops.iter(),)
|
||||||
chain(once(left.as_ref()), comparators.iter()),
|
|
||||||
comparators.iter(),
|
|
||||||
ops.iter(),
|
|
||||||
)
|
|
||||||
.fold(None, |prev, (lhs, rhs, op)| {
|
.fold(None, |prev, (lhs, rhs, op)| {
|
||||||
let ty = self.unifier.get_representative(lhs.custom.unwrap());
|
let ty = ctx.unifier.get_representative(lhs.custom.unwrap());
|
||||||
let current =
|
let current =
|
||||||
if [self.primitives.int32, self.primitives.int64, self.primitives.bool]
|
if [ctx.primitives.int32, ctx.primitives.int64, ctx.primitives.bool]
|
||||||
.contains(&ty)
|
.contains(&ty)
|
||||||
{
|
{
|
||||||
let (lhs, rhs) = if let (
|
let (lhs, rhs) = if let (
|
||||||
BasicValueEnum::IntValue(lhs),
|
BasicValueEnum::IntValue(lhs),
|
||||||
BasicValueEnum::IntValue(rhs),
|
BasicValueEnum::IntValue(rhs),
|
||||||
) =
|
) = (
|
||||||
(self.gen_expr(lhs).unwrap(), self.gen_expr(rhs).unwrap())
|
generator.gen_expr(ctx, lhs).unwrap(),
|
||||||
{
|
generator.gen_expr(ctx, rhs).unwrap(),
|
||||||
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -601,14 +613,15 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
ast::Cmpop::GtE => inkwell::IntPredicate::SGE,
|
ast::Cmpop::GtE => inkwell::IntPredicate::SGE,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.builder.build_int_compare(op, lhs, rhs, "cmp")
|
ctx.builder.build_int_compare(op, lhs, rhs, "cmp")
|
||||||
} else if ty == self.primitives.float {
|
} else if ty == ctx.primitives.float {
|
||||||
let (lhs, rhs) = if let (
|
let (lhs, rhs) = if let (
|
||||||
BasicValueEnum::FloatValue(lhs),
|
BasicValueEnum::FloatValue(lhs),
|
||||||
BasicValueEnum::FloatValue(rhs),
|
BasicValueEnum::FloatValue(rhs),
|
||||||
) =
|
) = (
|
||||||
(self.gen_expr(lhs).unwrap(), self.gen_expr(rhs).unwrap())
|
generator.gen_expr(ctx, lhs).unwrap(),
|
||||||
{
|
generator.gen_expr(ctx, rhs).unwrap(),
|
||||||
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -622,46 +635,49 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
ast::Cmpop::GtE => inkwell::FloatPredicate::OGE,
|
ast::Cmpop::GtE => inkwell::FloatPredicate::OGE,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.builder.build_float_compare(op, lhs, rhs, "cmp")
|
ctx.builder.build_float_compare(op, lhs, rhs, "cmp")
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
};
|
};
|
||||||
prev.map(|v| self.builder.build_and(v, current, "cmp")).or(Some(current))
|
prev.map(|v| ctx.builder.build_and(v, current, "cmp")).or(Some(current))
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into() // as there should be at least 1 element, it should never be none
|
.into() // as there should be at least 1 element, it should never be none
|
||||||
}
|
}
|
||||||
ExprKind::IfExp { test, body, orelse } => {
|
ExprKind::IfExp { test, body, orelse } => {
|
||||||
let test = assert_int_val(self.gen_expr(test).unwrap());
|
let test = assert_int_val(generator.gen_expr(ctx, test).unwrap());
|
||||||
let current = self.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let then_bb = self.ctx.append_basic_block(current, "then");
|
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
||||||
let else_bb = self.ctx.append_basic_block(current, "else");
|
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
||||||
let cont_bb = self.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
self.builder.build_conditional_branch(test, then_bb, else_bb);
|
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
||||||
self.builder.position_at_end(then_bb);
|
ctx.builder.position_at_end(then_bb);
|
||||||
let a = self.gen_expr(body).unwrap();
|
let a = generator.gen_expr(ctx, body).unwrap();
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
self.builder.position_at_end(else_bb);
|
ctx.builder.position_at_end(else_bb);
|
||||||
let b = self.gen_expr(orelse).unwrap();
|
let b = generator.gen_expr(ctx, orelse).unwrap();
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
self.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = self.builder.build_phi(a.get_type(), "ifexpr");
|
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
||||||
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
|
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
|
||||||
phi.as_basic_value()
|
phi.as_basic_value()
|
||||||
}
|
}
|
||||||
ExprKind::Call { func, args, keywords } => {
|
ExprKind::Call { func, args, keywords } => {
|
||||||
let mut params =
|
let mut params =
|
||||||
args.iter().map(|arg| (None, self.gen_expr(arg).unwrap())).collect_vec();
|
args.iter().map(|arg| (None, generator.gen_expr(ctx, 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()),
|
||||||
|
generator.gen_expr(ctx, &kw.node.value).unwrap(),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
params.extend(kw_iter);
|
params.extend(kw_iter);
|
||||||
let call = self.calls.get(&expr.location.into());
|
let call = ctx.calls.get(&expr.location.into());
|
||||||
let signature = match call {
|
let signature = match call {
|
||||||
Some(call) => self.unifier.get_call_signature(*call).unwrap(),
|
Some(call) => ctx.unifier.get_call_signature(*call).unwrap(),
|
||||||
None => {
|
None => {
|
||||||
let ty = func.custom.unwrap();
|
let ty = func.custom.unwrap();
|
||||||
if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(ty) {
|
if let TypeEnum::TFunc(sign) = &*ctx.unifier.get_ty(ty) {
|
||||||
sign.borrow().clone()
|
sign.borrow().clone()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -671,21 +687,20 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
match &func.as_ref().node {
|
match &func.as_ref().node {
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
// TODO: handle primitive casts and function pointers
|
// TODO: handle primitive casts and function pointers
|
||||||
let fun =
|
let fun = ctx.resolver.get_identifier_def(*id).expect("Unknown identifier");
|
||||||
self.resolver.get_identifier_def(*id).expect("Unknown identifier");
|
return generator.gen_call(ctx, None, (&signature, fun), params);
|
||||||
return self.gen_call(None, (&signature, fun), params);
|
|
||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let val = self.gen_expr(value).unwrap();
|
let val = generator.gen_expr(ctx, value).unwrap();
|
||||||
let id = if let TypeEnum::TObj { obj_id, .. } =
|
let id = if let TypeEnum::TObj { obj_id, .. } =
|
||||||
&*self.unifier.get_ty(value.custom.unwrap())
|
&*ctx.unifier.get_ty(value.custom.unwrap())
|
||||||
{
|
{
|
||||||
*obj_id
|
*obj_id
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let fun_id = {
|
let fun_id = {
|
||||||
let defs = self.top_level.definitions.read();
|
let defs = ctx.top_level.definitions.read();
|
||||||
let obj_def = defs.get(id.0).unwrap().read();
|
let obj_def = defs.get(id.0).unwrap().read();
|
||||||
if let TopLevelDef::Class { methods, .. } = &*obj_def {
|
if let TopLevelDef::Class { methods, .. } = &*obj_def {
|
||||||
let mut fun_id = None;
|
let mut fun_id = None;
|
||||||
|
@ -699,7 +714,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return self.gen_call(
|
return generator.gen_call(
|
||||||
|
ctx,
|
||||||
Some((value.custom.unwrap(), val)),
|
Some((value.custom.unwrap(), val)),
|
||||||
(&signature, fun_id),
|
(&signature, fun_id),
|
||||||
params,
|
params,
|
||||||
|
@ -709,41 +725,40 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
if let TypeEnum::TList { .. } = &*self.unifier.get_ty(value.custom.unwrap()) {
|
if let TypeEnum::TList { .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||||
if let ExprKind::Slice { .. } = slice.node {
|
if let ExprKind::Slice { .. } = slice.node {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
} else {
|
} else {
|
||||||
// TODO: bound check
|
// TODO: bound check
|
||||||
let i32_type = self.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
let v = assert_pointer_val(self.gen_expr(value).unwrap());
|
let v = assert_pointer_val(generator.gen_expr(ctx, value).unwrap());
|
||||||
let index = assert_int_val(self.gen_expr(slice).unwrap());
|
let index = assert_int_val(generator.gen_expr(ctx, slice).unwrap());
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr_to_arr = self.builder.build_in_bounds_gep(
|
let ptr_to_arr = ctx.builder.build_in_bounds_gep(
|
||||||
v,
|
v,
|
||||||
&[i32_type.const_zero(), i32_type.const_int(1, false)],
|
&[i32_type.const_zero(), i32_type.const_int(1, false)],
|
||||||
"ptr_to_arr",
|
"ptr_to_arr",
|
||||||
);
|
);
|
||||||
let arr_ptr =
|
let arr_ptr =
|
||||||
assert_pointer_val(self.builder.build_load(ptr_to_arr, "loadptr"));
|
assert_pointer_val(ctx.builder.build_load(ptr_to_arr, "loadptr"));
|
||||||
let ptr = self.builder.build_gep(arr_ptr, &[index], "loadarrgep");
|
let ptr = ctx.builder.build_gep(arr_ptr, &[index], "loadarrgep");
|
||||||
self.builder.build_load(ptr, "loadarr")
|
ctx.builder.build_load(ptr, "loadarr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let i32_type = self.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
let v = assert_pointer_val(self.gen_expr(value).unwrap());
|
let v = assert_pointer_val(generator.gen_expr(ctx, value).unwrap());
|
||||||
let index = assert_int_val(self.gen_expr(slice).unwrap());
|
let index = assert_int_val(generator.gen_expr(ctx, slice).unwrap());
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr_to_elem = self.builder.build_in_bounds_gep(
|
let ptr_to_elem = ctx.builder.build_in_bounds_gep(
|
||||||
v,
|
v,
|
||||||
&[i32_type.const_zero(), index],
|
&[i32_type.const_zero(), index],
|
||||||
"ptr_to_elem",
|
"ptr_to_elem",
|
||||||
);
|
);
|
||||||
self.builder.build_load(ptr_to_elem, "loadelem")
|
ctx.builder.build_load(ptr_to_elem, "loadelem")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
use crate::{
|
||||||
|
codegen::{expr::*, stmt::*, CodeGenContext},
|
||||||
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
|
typecheck::typedef::{FunSignature, Type},
|
||||||
|
};
|
||||||
|
use inkwell::values::{BasicValueEnum, PointerValue};
|
||||||
|
use rustpython_parser::ast::{Expr, Stmt, StrRef};
|
||||||
|
|
||||||
|
pub trait CodeGenerator {
|
||||||
|
/// Return the module name for the code generator.
|
||||||
|
fn get_name(&self) -> &str;
|
||||||
|
|
||||||
|
/// Generate function call and returns the function return value.
|
||||||
|
/// - obj: Optional object for method call.
|
||||||
|
/// - fun: Function signature and definition ID.
|
||||||
|
/// - params: Function parameters. Note that this does not include the object even if the
|
||||||
|
/// function is a class method.
|
||||||
|
fn gen_call<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, DefinitionId),
|
||||||
|
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
||||||
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
|
gen_call(self, ctx, obj, fun, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate object constructor and returns the constructed object.
|
||||||
|
/// - signature: Function signature of the contructor.
|
||||||
|
/// - def: Class definition for the constructor class.
|
||||||
|
/// - params: Function parameters.
|
||||||
|
fn gen_constructor<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
signature: &FunSignature,
|
||||||
|
def: &TopLevelDef,
|
||||||
|
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
gen_constructor(self, ctx, signature, def, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a function instance.
|
||||||
|
/// - obj: Optional object for method call.
|
||||||
|
/// - fun: Function signature, definition ID and the substitution key.
|
||||||
|
/// - params: Function parameters. Note that this does not include the object even if the
|
||||||
|
/// function is a class method.
|
||||||
|
/// Note that this function should check if the function is generated in another thread (due to
|
||||||
|
/// possible race condition), see the default implementation for an example.
|
||||||
|
fn gen_func_instance<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
||||||
|
fun: (&FunSignature, &mut TopLevelDef, String),
|
||||||
|
) -> String {
|
||||||
|
gen_func_instance(ctx, obj, fun)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the code for an expression.
|
||||||
|
fn gen_expr<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
expr: &Expr<Option<Type>>,
|
||||||
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
|
gen_expr(self, ctx, expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for a variable and return a pointer pointing to it.
|
||||||
|
/// The default implementation places the allocations at the start of the function.
|
||||||
|
fn gen_var_alloc<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
ty: Type,
|
||||||
|
) -> PointerValue<'ctx> {
|
||||||
|
gen_var(ctx, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a pointer pointing to the target of the expression.
|
||||||
|
fn gen_store_target<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
pattern: &Expr<Option<Type>>,
|
||||||
|
) -> PointerValue<'ctx> {
|
||||||
|
gen_store_target(self, ctx, pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate code for an assignment expression.
|
||||||
|
fn gen_assign<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
target: &Expr<Option<Type>>,
|
||||||
|
value: BasicValueEnum<'ctx>,
|
||||||
|
) {
|
||||||
|
gen_assign(self, ctx, target, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate code for a while expression.
|
||||||
|
/// Return true if the while loop must early return
|
||||||
|
fn gen_while<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) -> bool {
|
||||||
|
gen_while(self, ctx, stmt);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate code for an if expression.
|
||||||
|
/// Return true if the statement must early return
|
||||||
|
fn gen_if<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) -> bool {
|
||||||
|
gen_if(self, ctx, stmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate code for a statement
|
||||||
|
/// Return true if the statement must early return
|
||||||
|
fn gen_stmt<'ctx, 'a>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) -> bool {
|
||||||
|
gen_stmt(self, ctx, stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultCodeGenerator {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultCodeGenerator {
|
||||||
|
pub fn new(name: String) -> DefaultCodeGenerator {
|
||||||
|
DefaultCodeGenerator { name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeGenerator for DefaultCodeGenerator {
|
||||||
|
fn get_name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,11 +27,14 @@ use std::sync::{
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
mod expr;
|
mod expr;
|
||||||
|
mod generator;
|
||||||
mod stmt;
|
mod stmt;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
|
pub use generator::{CodeGenerator, DefaultCodeGenerator};
|
||||||
|
|
||||||
pub struct CodeGenContext<'ctx, 'a> {
|
pub struct CodeGenContext<'ctx, 'a> {
|
||||||
pub ctx: &'ctx Context,
|
pub ctx: &'ctx Context,
|
||||||
pub builder: Builder<'ctx>,
|
pub builder: Builder<'ctx>,
|
||||||
|
@ -77,8 +80,8 @@ pub struct WorkerRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerRegistry {
|
impl WorkerRegistry {
|
||||||
pub fn create_workers(
|
pub fn create_workers<G: CodeGenerator + Send + 'static>(
|
||||||
names: &[&str],
|
generators: Vec<Box<G>>,
|
||||||
top_level_ctx: Arc<TopLevelContext>,
|
top_level_ctx: Arc<TopLevelContext>,
|
||||||
f: Arc<WithCall>,
|
f: Arc<WithCall>,
|
||||||
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
||||||
|
@ -89,21 +92,20 @@ impl WorkerRegistry {
|
||||||
let registry = Arc::new(WorkerRegistry {
|
let registry = Arc::new(WorkerRegistry {
|
||||||
sender: Arc::new(sender),
|
sender: Arc::new(sender),
|
||||||
receiver: Arc::new(receiver),
|
receiver: Arc::new(receiver),
|
||||||
thread_count: names.len(),
|
thread_count: generators.len(),
|
||||||
panicked: AtomicBool::new(false),
|
panicked: AtomicBool::new(false),
|
||||||
task_count,
|
task_count,
|
||||||
wait_condvar,
|
wait_condvar,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
for name in names.iter() {
|
for mut generator in generators.into_iter() {
|
||||||
let top_level_ctx = top_level_ctx.clone();
|
let top_level_ctx = top_level_ctx.clone();
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let registry2 = registry.clone();
|
let registry2 = registry.clone();
|
||||||
let name = name.to_string();
|
|
||||||
let f = f.clone();
|
let f = f.clone();
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
registry.worker_thread(name, top_level_ctx, f);
|
registry.worker_thread(generator.as_mut(), top_level_ctx, f);
|
||||||
});
|
});
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
if let Err(e) = handle.join() {
|
if let Err(e) = handle.join() {
|
||||||
|
@ -156,18 +158,19 @@ impl WorkerRegistry {
|
||||||
self.sender.send(Some(task)).unwrap();
|
self.sender.send(Some(task)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worker_thread(
|
fn worker_thread<G: CodeGenerator>(
|
||||||
&self,
|
&self,
|
||||||
module_name: String,
|
generator: &mut G,
|
||||||
top_level_ctx: Arc<TopLevelContext>,
|
top_level_ctx: Arc<TopLevelContext>,
|
||||||
f: Arc<WithCall>,
|
f: Arc<WithCall>,
|
||||||
) {
|
) {
|
||||||
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(generator.get_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, generator, self, builder, module, task, top_level_ctx.clone());
|
||||||
builder = result.0;
|
builder = result.0;
|
||||||
module = result.1;
|
module = result.1;
|
||||||
*self.task_count.lock() -= 1;
|
*self.task_count.lock() -= 1;
|
||||||
|
@ -243,8 +246,9 @@ fn get_llvm_type<'ctx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_func<'ctx>(
|
pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
|
generator: &mut G,
|
||||||
registry: &WorkerRegistry,
|
registry: &WorkerRegistry,
|
||||||
builder: Builder<'ctx>,
|
builder: Builder<'ctx>,
|
||||||
module: Module<'ctx>,
|
module: Module<'ctx>,
|
||||||
|
@ -351,7 +355,7 @@ pub fn gen_func<'ctx>(
|
||||||
|
|
||||||
let mut returned = false;
|
let mut returned = false;
|
||||||
for stmt in task.body.iter() {
|
for stmt in task.body.iter() {
|
||||||
returned = code_gen_context.gen_stmt(stmt);
|
returned = generator.gen_stmt(&mut code_gen_context, stmt);
|
||||||
if returned {
|
if returned {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,221 +1,250 @@
|
||||||
use super::{
|
use super::{
|
||||||
expr::{assert_int_val, assert_pointer_val},
|
expr::{assert_int_val, assert_pointer_val},
|
||||||
CodeGenContext,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::Type;
|
||||||
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
||||||
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||||
|
|
||||||
impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
pub fn gen_var<'ctx, 'a>(ctx: &mut CodeGenContext<'ctx, 'a>, ty: Type) -> PointerValue<'ctx> {
|
||||||
fn gen_var(&mut self, ty: Type) -> PointerValue<'ctx> {
|
|
||||||
// put the alloca in init block
|
// put the alloca in init block
|
||||||
let current = self.builder.get_insert_block().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap();
|
||||||
// position before the last branching instruction...
|
// position before the last branching instruction...
|
||||||
self.builder.position_before(&self.init_bb.get_last_instruction().unwrap());
|
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
||||||
let ty = self.get_llvm_type(ty);
|
let ty = ctx.get_llvm_type(ty);
|
||||||
let ptr = self.builder.build_alloca(ty, "tmp");
|
let ptr = ctx.builder.build_alloca(ty, "tmp");
|
||||||
self.builder.position_at_end(current);
|
ctx.builder.position_at_end(current);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pattern(&mut self, pattern: &Expr<Option<Type>>) -> PointerValue<'ctx> {
|
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
pattern: &Expr<Option<Type>>,
|
||||||
|
) -> PointerValue<'ctx> {
|
||||||
// very similar to gen_expr, but we don't do an extra load at the end
|
// very similar to gen_expr, but we don't do an extra load at the end
|
||||||
// and we flatten nested tuples
|
// and we flatten nested tuples
|
||||||
match &pattern.node {
|
match &pattern.node {
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).cloned().unwrap_or_else(|| {
|
||||||
self.var_assignment.get(id).cloned().unwrap_or_else(|| {
|
let ptr = generator.gen_var_alloc(ctx, pattern.custom.unwrap());
|
||||||
let ptr = self.gen_var(pattern.custom.unwrap());
|
ctx.var_assignment.insert(*id, ptr);
|
||||||
self.var_assignment.insert(*id, ptr);
|
|
||||||
ptr
|
ptr
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let index = self.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = self.gen_expr(value).unwrap();
|
let val = generator.gen_expr(ctx, value).unwrap();
|
||||||
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
self.builder.build_in_bounds_gep(
|
ctx.builder.build_in_bounds_gep(
|
||||||
ptr,
|
ptr,
|
||||||
&[
|
&[
|
||||||
self.ctx.i32_type().const_zero(),
|
ctx.ctx.i32_type().const_zero(),
|
||||||
self.ctx.i32_type().const_int(index as u64, false),
|
ctx.ctx.i32_type().const_int(index as u64, false),
|
||||||
],
|
],
|
||||||
"attr",
|
"attr",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
let i32_type = self.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
let v = assert_pointer_val(self.gen_expr(value).unwrap());
|
let v = assert_pointer_val(generator.gen_expr(ctx, value).unwrap());
|
||||||
let index = assert_int_val(self.gen_expr(slice).unwrap());
|
let index = assert_int_val(generator.gen_expr(ctx, slice).unwrap());
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr_to_arr = self.builder.build_in_bounds_gep(
|
let ptr_to_arr = ctx.builder.build_in_bounds_gep(
|
||||||
v,
|
v,
|
||||||
&[i32_type.const_zero(), i32_type.const_int(1, false)],
|
&[i32_type.const_zero(), i32_type.const_int(1, false)],
|
||||||
"ptr_to_arr",
|
"ptr_to_arr",
|
||||||
);
|
);
|
||||||
let arr_ptr =
|
let arr_ptr = assert_pointer_val(ctx.builder.build_load(ptr_to_arr, "loadptr"));
|
||||||
assert_pointer_val(self.builder.build_load(ptr_to_arr, "loadptr"));
|
ctx.builder.build_gep(arr_ptr, &[index], "loadarrgep")
|
||||||
self.builder.build_gep(arr_ptr, &[index], "loadarrgep")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_assignment(&mut self, target: &Expr<Option<Type>>, value: BasicValueEnum<'ctx>) {
|
pub fn gen_assign<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let i32_type = self.ctx.i32_type();
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
target: &Expr<Option<Type>>,
|
||||||
|
value: BasicValueEnum<'ctx>,
|
||||||
|
) {
|
||||||
|
let i32_type = ctx.ctx.i32_type();
|
||||||
if let ExprKind::Tuple { elts, .. } = &target.node {
|
if let ExprKind::Tuple { elts, .. } = &target.node {
|
||||||
if let BasicValueEnum::PointerValue(ptr) = value {
|
if let BasicValueEnum::PointerValue(ptr) = value {
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = self.builder.build_in_bounds_gep(
|
let t = ctx.builder.build_in_bounds_gep(
|
||||||
ptr,
|
ptr,
|
||||||
&[i32_type.const_zero(), i32_type.const_int(i as u64, false)],
|
&[i32_type.const_zero(), i32_type.const_int(i as u64, false)],
|
||||||
"elem",
|
"elem",
|
||||||
);
|
);
|
||||||
let v = self.builder.build_load(t, "tmpload");
|
let v = ctx.builder.build_load(t, "tmpload");
|
||||||
self.gen_assignment(elt, v);
|
generator.gen_assign(ctx, elt, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let ptr = self.parse_pattern(target);
|
let ptr = generator.gen_store_target(ctx, target);
|
||||||
self.builder.build_store(ptr, value);
|
ctx.builder.build_store(ptr, value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// return true if it contains terminator
|
pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
pub fn gen_stmt(&mut self, stmt: &Stmt<Option<Type>>) -> bool {
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) {
|
||||||
|
if let StmtKind::While { test, body, orelse } = &stmt.node {
|
||||||
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
||||||
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
||||||
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
|
// if there is no orelse, we just go to cont_bb
|
||||||
|
let orelse_bb =
|
||||||
|
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "orelse") };
|
||||||
|
// store loop bb information and restore it later
|
||||||
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
||||||
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
ctx.builder.position_at_end(test_bb);
|
||||||
|
let test = generator.gen_expr(ctx, test).unwrap();
|
||||||
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
ctx.builder.position_at_end(body_bb);
|
||||||
|
for stmt in body.iter() {
|
||||||
|
generator.gen_stmt(ctx, stmt);
|
||||||
|
}
|
||||||
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
if !orelse.is_empty() {
|
||||||
|
ctx.builder.position_at_end(orelse_bb);
|
||||||
|
for stmt in orelse.iter() {
|
||||||
|
generator.gen_stmt(ctx, stmt);
|
||||||
|
}
|
||||||
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
|
}
|
||||||
|
ctx.builder.position_at_end(cont_bb);
|
||||||
|
ctx.loop_bb = loop_bb;
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) -> bool {
|
||||||
|
if let StmtKind::If { test, body, orelse } = &stmt.node {
|
||||||
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
||||||
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
||||||
|
let mut cont_bb = None;
|
||||||
|
// if there is no orelse, we just go to cont_bb
|
||||||
|
let orelse_bb = if orelse.is_empty() {
|
||||||
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
||||||
|
cont_bb.unwrap()
|
||||||
|
} else {
|
||||||
|
ctx.ctx.append_basic_block(current, "orelse")
|
||||||
|
};
|
||||||
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
ctx.builder.position_at_end(test_bb);
|
||||||
|
let test = generator.gen_expr(ctx, test).unwrap();
|
||||||
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
ctx.builder.position_at_end(body_bb);
|
||||||
|
let mut exited = false;
|
||||||
|
for stmt in body.iter() {
|
||||||
|
exited = generator.gen_stmt(ctx, stmt);
|
||||||
|
if exited {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exited {
|
||||||
|
if cont_bb.is_none() {
|
||||||
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
||||||
|
}
|
||||||
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap());
|
||||||
|
}
|
||||||
|
let then_exited = exited;
|
||||||
|
let else_exited = if !orelse.is_empty() {
|
||||||
|
exited = false;
|
||||||
|
ctx.builder.position_at_end(orelse_bb);
|
||||||
|
for stmt in orelse.iter() {
|
||||||
|
exited = generator.gen_stmt(ctx, stmt);
|
||||||
|
if exited {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exited {
|
||||||
|
if cont_bb.is_none() {
|
||||||
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
||||||
|
}
|
||||||
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap());
|
||||||
|
}
|
||||||
|
exited
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if let Some(cont_bb) = cont_bb {
|
||||||
|
ctx.builder.position_at_end(cont_bb);
|
||||||
|
}
|
||||||
|
then_exited && else_exited
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
) -> bool {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StmtKind::Pass => {},
|
StmtKind::Pass => {}
|
||||||
StmtKind::Expr { value } => {
|
StmtKind::Expr { value } => {
|
||||||
self.gen_expr(value);
|
generator.gen_expr(ctx, value);
|
||||||
}
|
}
|
||||||
StmtKind::Return { value } => {
|
StmtKind::Return { value } => {
|
||||||
let value = value.as_ref().map(|v| self.gen_expr(v).unwrap());
|
let value = value.as_ref().map(|v| generator.gen_expr(ctx, v).unwrap());
|
||||||
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
||||||
self.builder.build_return(value);
|
ctx.builder.build_return(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
StmtKind::AnnAssign { target, value, .. } => {
|
StmtKind::AnnAssign { target, value, .. } => {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
let value = self.gen_expr(value).unwrap();
|
let value = generator.gen_expr(ctx, value).unwrap();
|
||||||
self.gen_assignment(target, value);
|
generator.gen_assign(ctx, target, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Assign { targets, value, .. } => {
|
StmtKind::Assign { targets, value, .. } => {
|
||||||
let value = self.gen_expr(value).unwrap();
|
let value = generator.gen_expr(ctx, value).unwrap();
|
||||||
for target in targets.iter() {
|
for target in targets.iter() {
|
||||||
self.gen_assignment(target, value);
|
generator.gen_assign(ctx, target, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Continue => {
|
StmtKind::Continue => {
|
||||||
self.builder.build_unconditional_branch(self.loop_bb.unwrap().0);
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
StmtKind::Break => {
|
StmtKind::Break => {
|
||||||
self.builder.build_unconditional_branch(self.loop_bb.unwrap().1);
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
StmtKind::If { test, body, orelse } => {
|
StmtKind::If { .. } => return generator.gen_if(ctx, stmt),
|
||||||
let current = self.builder.get_insert_block().unwrap().get_parent().unwrap();
|
StmtKind::While { .. } => return generator.gen_while(ctx, stmt),
|
||||||
let test_bb = self.ctx.append_basic_block(current, "test");
|
_ => unimplemented!()
|
||||||
let body_bb = self.ctx.append_basic_block(current, "body");
|
|
||||||
let mut cont_bb = None; // self.ctx.append_basic_block(current, "cont");
|
|
||||||
// if there is no orelse, we just go to cont_bb
|
|
||||||
let orelse_bb = if orelse.is_empty() {
|
|
||||||
cont_bb = Some(self.ctx.append_basic_block(current, "cont"));
|
|
||||||
cont_bb.unwrap()
|
|
||||||
} else {
|
|
||||||
self.ctx.append_basic_block(current, "orelse")
|
|
||||||
};
|
|
||||||
self.builder.build_unconditional_branch(test_bb);
|
|
||||||
self.builder.position_at_end(test_bb);
|
|
||||||
let test = self.gen_expr(test).unwrap();
|
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
|
||||||
self.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
self.builder.position_at_end(body_bb);
|
|
||||||
let mut exited = false;
|
|
||||||
for stmt in body.iter() {
|
|
||||||
exited = self.gen_stmt(stmt);
|
|
||||||
if exited {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !exited {
|
|
||||||
if cont_bb.is_none() {
|
|
||||||
cont_bb = Some(self.ctx.append_basic_block(current, "cont"));
|
|
||||||
}
|
|
||||||
self.builder.build_unconditional_branch(cont_bb.unwrap());
|
|
||||||
}
|
|
||||||
if !orelse.is_empty() {
|
|
||||||
exited = false;
|
|
||||||
self.builder.position_at_end(orelse_bb);
|
|
||||||
for stmt in orelse.iter() {
|
|
||||||
exited = self.gen_stmt(stmt);
|
|
||||||
if exited {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !exited {
|
|
||||||
if cont_bb.is_none() {
|
|
||||||
cont_bb = Some(self.ctx.append_basic_block(current, "cont"));
|
|
||||||
}
|
|
||||||
self.builder.build_unconditional_branch(cont_bb.unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(cont_bb) = cont_bb {
|
|
||||||
self.builder.position_at_end(cont_bb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StmtKind::While { test, body, orelse } => {
|
|
||||||
let current = self.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
||||||
let test_bb = self.ctx.append_basic_block(current, "test");
|
|
||||||
let body_bb = self.ctx.append_basic_block(current, "body");
|
|
||||||
let cont_bb = self.ctx.append_basic_block(current, "cont");
|
|
||||||
// if there is no orelse, we just go to cont_bb
|
|
||||||
let orelse_bb = if orelse.is_empty() {
|
|
||||||
cont_bb
|
|
||||||
} else {
|
|
||||||
self.ctx.append_basic_block(current, "orelse")
|
|
||||||
};
|
|
||||||
// store loop bb information and restore it later
|
|
||||||
let loop_bb = self.loop_bb.replace((test_bb, cont_bb));
|
|
||||||
self.builder.build_unconditional_branch(test_bb);
|
|
||||||
self.builder.position_at_end(test_bb);
|
|
||||||
let test = self.gen_expr(test).unwrap();
|
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
|
||||||
self.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
self.builder.position_at_end(body_bb);
|
|
||||||
for stmt in body.iter() {
|
|
||||||
self.gen_stmt(stmt);
|
|
||||||
}
|
|
||||||
self.builder.build_unconditional_branch(test_bb);
|
|
||||||
if !orelse.is_empty() {
|
|
||||||
self.builder.position_at_end(orelse_bb);
|
|
||||||
for stmt in orelse.iter() {
|
|
||||||
self.gen_stmt(stmt);
|
|
||||||
}
|
|
||||||
self.builder.build_unconditional_branch(cont_bb);
|
|
||||||
}
|
|
||||||
self.builder.position_at_end(cont_bb);
|
|
||||||
self.loop_bb = loop_bb;
|
|
||||||
}
|
|
||||||
_ => unimplemented!("{:?}", stmt),
|
|
||||||
};
|
};
|
||||||
false
|
false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{CodeGenTask, WithCall, WorkerRegistry, CodeGenContext},
|
codegen::{CodeGenTask, WithCall, WorkerRegistry, CodeGenContext, DefaultCodeGenerator},
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{
|
toplevel::{
|
||||||
|
@ -72,7 +72,7 @@ fn test_primitives() {
|
||||||
class_names: Default::default(),
|
class_names: Default::default(),
|
||||||
}) as Arc<dyn SymbolResolver + Send + Sync>;
|
}) as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
|
|
||||||
let threads = ["test"];
|
let threads = vec![DefaultCodeGenerator::new("test".into()).into()];
|
||||||
let signature = FunSignature {
|
let signature = FunSignature {
|
||||||
args: vec![
|
args: vec![
|
||||||
FuncArg { name: "a".into(), ty: primitives.int32, default_value: None },
|
FuncArg { name: "a".into(), ty: primitives.int32, default_value: None },
|
||||||
|
@ -186,7 +186,7 @@ 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 (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ fn test_simple_call() {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
let threads = ["test"];
|
let threads = vec![DefaultCodeGenerator::new("test".into()).into()];
|
||||||
let mut function_data = FunctionData {
|
let mut function_data = FunctionData {
|
||||||
resolver: resolver.clone(),
|
resolver: resolver.clone(),
|
||||||
bound_variables: Vec::new(),
|
bound_variables: Vec::new(),
|
||||||
|
@ -351,7 +351,7 @@ 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 (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
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::env;
|
||||||
|
use std::fs;
|
||||||
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, DefaultCodeGenerator, WithCall, WorkerRegistry},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{composer::TopLevelComposer, TopLevelDef},
|
toplevel::{composer::TopLevelComposer, TopLevelDef},
|
||||||
typecheck::typedef::FunSignature,
|
typecheck::typedef::FunSignature,
|
||||||
|
@ -17,7 +21,10 @@ use basic_symbol_resolver::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let demo_name = env::args().nth(1).unwrap();
|
let demo_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(1);
|
||||||
|
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
|
|
||||||
|
@ -38,23 +45,27 @@ fn main() {
|
||||||
id_to_type: builtins_ty.into(),
|
id_to_type: builtins_ty.into(),
|
||||||
id_to_def: builtins_def.into(),
|
id_to_def: builtins_def.into(),
|
||||||
class_names: Default::default(),
|
class_names: Default::default(),
|
||||||
}.into();
|
}
|
||||||
let resolver = Arc::new(
|
.into();
|
||||||
Resolver(internal_resolver.clone())
|
let resolver =
|
||||||
) as Arc<dyn SymbolResolver + Send + Sync>;
|
Arc::new(Resolver(internal_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
let setup_time = SystemTime::now();
|
let setup_time = SystemTime::now();
|
||||||
println!("setup time: {}ms", setup_time.duration_since(start).unwrap().as_millis());
|
println!(
|
||||||
|
"setup time: {}ms",
|
||||||
|
setup_time.duration_since(start).unwrap().as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
let parser_result = parser::parse_program(&program).unwrap();
|
let parser_result = parser::parse_program(&program).unwrap();
|
||||||
let parse_time = SystemTime::now();
|
let parse_time = SystemTime::now();
|
||||||
println!("parse time: {}ms", parse_time.duration_since(setup_time).unwrap().as_millis());
|
println!(
|
||||||
|
"parse time: {}ms",
|
||||||
|
parse_time.duration_since(setup_time).unwrap().as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
for stmt in parser_result.into_iter() {
|
for stmt in parser_result.into_iter() {
|
||||||
let (name, def_id, ty) = composer.register_top_level(
|
let (name, def_id, ty) = composer
|
||||||
stmt,
|
.register_top_level(stmt, Some(resolver.clone()), "__main__".into())
|
||||||
Some(resolver.clone()),
|
.unwrap();
|
||||||
"__main__".into(),
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
internal_resolver.add_id_def(name, def_id);
|
internal_resolver.add_id_def(name, def_id);
|
||||||
if let Some(ty) = ty {
|
if let Some(ty) = ty {
|
||||||
|
@ -64,7 +75,13 @@ fn main() {
|
||||||
|
|
||||||
composer.start_analysis(true).unwrap();
|
composer.start_analysis(true).unwrap();
|
||||||
let analysis_time = SystemTime::now();
|
let analysis_time = SystemTime::now();
|
||||||
println!("analysis time: {}ms", analysis_time.duration_since(parse_time).unwrap().as_millis());
|
println!(
|
||||||
|
"analysis time: {}ms",
|
||||||
|
analysis_time
|
||||||
|
.duration_since(parse_time)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
let top_level = Arc::new(composer.make_top_level_context());
|
let top_level = Arc::new(composer.make_top_level_context());
|
||||||
|
|
||||||
|
@ -119,19 +136,32 @@ fn main() {
|
||||||
)
|
)
|
||||||
.expect("couldn't create target machine");
|
.expect("couldn't create target machine");
|
||||||
target_machine
|
target_machine
|
||||||
.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");
|
||||||
|
|
||||||
// println!("IR:\n{}", module.print_to_string().to_str().unwrap());
|
// println!("IR:\n{}", module.print_to_string().to_str().unwrap());
|
||||||
|
|
||||||
})));
|
})));
|
||||||
let threads: Vec<String> = (0..threads).map(|i| format!("module{}", i)).collect();
|
let threads = (0..threads)
|
||||||
let threads: Vec<_> = threads.iter().map(|s| s.as_str()).collect();
|
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i))))
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f);
|
.collect();
|
||||||
|
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
|
|
||||||
let final_time = SystemTime::now();
|
let final_time = SystemTime::now();
|
||||||
println!("codegen time (including LLVM): {}ms", final_time.duration_since(analysis_time).unwrap().as_millis());
|
println!(
|
||||||
println!("total time: {}ms", final_time.duration_since(start).unwrap().as_millis());
|
"codegen time (including LLVM): {}ms",
|
||||||
|
final_time
|
||||||
|
.duration_since(analysis_time)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"total time: {}ms",
|
||||||
|
final_time.duration_since(start).unwrap().as_millis()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue