forked from M-Labs/nac3
nac3core: fix #84
This commit is contained in:
parent
66320679be
commit
0902d8adf4
|
@ -1,18 +1,19 @@
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{expr::gen_call, stmt::gen_with, CodeGenContext, CodeGenerator},
|
codegen::{expr::gen_call, stmt::gen_with, CodeGenContext, CodeGenerator},
|
||||||
|
symbol_resolver::ValueEnum,
|
||||||
toplevel::DefinitionId,
|
toplevel::DefinitionId,
|
||||||
typecheck::typedef::{FunSignature, Type},
|
typecheck::typedef::{FunSignature, Type},
|
||||||
symbol_resolver::ValueEnum,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
||||||
|
|
||||||
use inkwell::values::BasicValueEnum;
|
use inkwell::{context::Context, types::IntType, values::BasicValueEnum};
|
||||||
|
|
||||||
use crate::timeline::TimeFns;
|
use crate::timeline::TimeFns;
|
||||||
|
|
||||||
pub struct ArtiqCodeGenerator<'a> {
|
pub struct ArtiqCodeGenerator<'a> {
|
||||||
name: String,
|
name: String,
|
||||||
|
size_t: u32,
|
||||||
name_counter: u32,
|
name_counter: u32,
|
||||||
start: Option<Expr<Option<Type>>>,
|
start: Option<Expr<Option<Type>>>,
|
||||||
end: Option<Expr<Option<Type>>>,
|
end: Option<Expr<Option<Type>>>,
|
||||||
|
@ -20,9 +21,11 @@ pub struct ArtiqCodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ArtiqCodeGenerator<'a> {
|
impl<'a> ArtiqCodeGenerator<'a> {
|
||||||
pub fn new(name: String, timeline: &'a (dyn TimeFns + Sync)) -> ArtiqCodeGenerator<'a> {
|
pub fn new(name: String, size_t: u32, timeline: &'a (dyn TimeFns + Sync)) -> ArtiqCodeGenerator<'a> {
|
||||||
|
assert!(size_t == 32 || size_t == 64);
|
||||||
ArtiqCodeGenerator {
|
ArtiqCodeGenerator {
|
||||||
name,
|
name,
|
||||||
|
size_t,
|
||||||
name_counter: 0,
|
name_counter: 0,
|
||||||
start: None,
|
start: None,
|
||||||
end: None,
|
end: None,
|
||||||
|
@ -36,6 +39,14 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
|
if self.size_t == 32 {
|
||||||
|
ctx.i32_type()
|
||||||
|
} else {
|
||||||
|
ctx.i64_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn gen_call<'ctx, 'a>(
|
fn gen_call<'ctx, 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
@ -45,7 +56,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
let result = gen_call(self, ctx, obj, fun, params);
|
let result = gen_call(self, ctx, obj, fun, params);
|
||||||
if let Some(end) = self.end.clone() {
|
if let Some(end) = self.end.clone() {
|
||||||
let old_end = self.gen_expr(ctx, &end).unwrap().to_basic_value_enum(ctx);
|
let old_end = self.gen_expr(ctx, &end).unwrap().to_basic_value_enum(ctx, self);
|
||||||
let now = self.timeline.emit_now_mu(ctx);
|
let now = self.timeline.emit_now_mu(ctx);
|
||||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
let i64 = ctx.ctx.i64_type();
|
let i64 = ctx.ctx.i64_type();
|
||||||
|
@ -65,7 +76,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
ctx.builder.build_store(end_store, max);
|
ctx.builder.build_store(end_store, max);
|
||||||
}
|
}
|
||||||
if let Some(start) = self.start.clone() {
|
if let Some(start) = self.start.clone() {
|
||||||
let start_val = self.gen_expr(ctx, &start).unwrap().to_basic_value_enum(ctx);
|
let start_val = self.gen_expr(ctx, &start).unwrap().to_basic_value_enum(ctx, self);
|
||||||
self.timeline.emit_at_mu(ctx, start_val);
|
self.timeline.emit_at_mu(ctx, start_val);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
@ -97,7 +108,9 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
let old_start = self.start.take();
|
let old_start = self.start.take();
|
||||||
let old_end = self.end.take();
|
let old_end = self.end.take();
|
||||||
let now = if let Some(old_start) = &old_start {
|
let now = if let Some(old_start) = &old_start {
|
||||||
self.gen_expr(ctx, old_start).unwrap().to_basic_value_enum(ctx)
|
self.gen_expr(ctx, old_start)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, self)
|
||||||
} else {
|
} else {
|
||||||
self.timeline.emit_now_mu(ctx)
|
self.timeline.emit_now_mu(ctx)
|
||||||
};
|
};
|
||||||
|
@ -146,7 +159,10 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
}
|
}
|
||||||
// set duration
|
// set duration
|
||||||
let end_expr = self.end.take().unwrap();
|
let end_expr = self.end.take().unwrap();
|
||||||
let end_val = self.gen_expr(ctx, &end_expr).unwrap().to_basic_value_enum(ctx);
|
let end_val = self
|
||||||
|
.gen_expr(ctx, &end_expr)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, self);
|
||||||
|
|
||||||
// inside an sequential block
|
// inside an sequential block
|
||||||
if old_start.is_none() {
|
if old_start.is_none() {
|
||||||
|
@ -154,15 +170,19 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
}
|
}
|
||||||
// inside a parallel block, should update the outer max now_mu
|
// inside a parallel block, should update the outer max now_mu
|
||||||
if let Some(old_end) = &old_end {
|
if let Some(old_end) = &old_end {
|
||||||
let outer_end_val = self.gen_expr(ctx, old_end).unwrap().to_basic_value_enum(ctx);
|
let outer_end_val = self
|
||||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
.gen_expr(ctx, old_end)
|
||||||
let i64 = ctx.ctx.i64_type();
|
.unwrap()
|
||||||
ctx.module.add_function(
|
.to_basic_value_enum(ctx, self);
|
||||||
"llvm.smax.i64",
|
let smax =
|
||||||
i64.fn_type(&[i64.into(), i64.into()], false),
|
ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
None,
|
let i64 = ctx.ctx.i64_type();
|
||||||
)
|
ctx.module.add_function(
|
||||||
});
|
"llvm.smax.i64",
|
||||||
|
i64.fn_type(&[i64.into(), i64.into()], false),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
});
|
||||||
let max = ctx
|
let max = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_call(smax, &[end_val, outer_end_val], "smax")
|
.build_call(smax, &[end_val, outer_end_val], "smax")
|
||||||
|
|
|
@ -558,10 +558,15 @@ impl Nac3 {
|
||||||
let buffer = buffer.as_slice().into();
|
let buffer = buffer.as_slice().into();
|
||||||
membuffer.lock().push(buffer);
|
membuffer.lock().push(buffer);
|
||||||
})));
|
})));
|
||||||
|
let size_t = if self.isa == Isa::Host {
|
||||||
|
64
|
||||||
|
} else {
|
||||||
|
32
|
||||||
|
};
|
||||||
let thread_names: Vec<String> = (0..4).map(|_| "main".to_string()).collect();
|
let thread_names: Vec<String> = (0..4).map(|_| "main".to_string()).collect();
|
||||||
let threads: Vec<_> = thread_names
|
let threads: Vec<_> = thread_names
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), self.time_fns)))
|
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
py.allow_threads(|| {
|
py.allow_threads(|| {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
|
use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::CodeGenContext,
|
codegen::{CodeGenContext, CodeGenerator},
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::{StaticValue, SymbolResolver, SymbolValue, ValueEnum},
|
symbol_resolver::{StaticValue, SymbolResolver, SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
|
@ -72,6 +72,7 @@ impl StaticValue for PythonValue {
|
||||||
fn to_basic_value_enum<'ctx, 'a>(
|
fn to_basic_value_enum<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
|
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
|
||||||
return match val {
|
return match val {
|
||||||
|
@ -89,7 +90,7 @@ impl StaticValue for PythonValue {
|
||||||
|
|
||||||
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
||||||
self.resolver
|
self.resolver
|
||||||
.get_obj_value(py, self.value.as_ref(py), ctx)
|
.get_obj_value(py, self.value.as_ref(py), ctx, generator)
|
||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -540,6 +541,7 @@ impl InnerResolver {
|
||||||
py: Python,
|
py: Python,
|
||||||
obj: &PyAny,
|
obj: &PyAny,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
|
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
|
||||||
let ty_id: u64 = self
|
let ty_id: u64 = self
|
||||||
.helper
|
.helper
|
||||||
|
@ -595,11 +597,9 @@ impl InnerResolver {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
let ty = ctx.get_llvm_type(ty);
|
let ty = ctx.get_llvm_type(ty);
|
||||||
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
let arr_ty = ctx.ctx.struct_type(
|
let arr_ty = ctx.ctx.struct_type(
|
||||||
&[
|
&[ty.ptr_type(AddressSpace::Generic).into(), size_t.into()],
|
||||||
ctx.ctx.i32_type().into(),
|
|
||||||
ty.ptr_type(AddressSpace::Generic).into(),
|
|
||||||
],
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -618,7 +618,7 @@ impl InnerResolver {
|
||||||
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
obj.get_item(i)
|
obj.get_item(i)
|
||||||
.and_then(|elem| self.get_obj_value(py, elem, ctx))
|
.and_then(|elem| self.get_obj_value(py, elem, ctx, generator))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let arr = arr?.unwrap();
|
let arr = arr?.unwrap();
|
||||||
|
@ -665,11 +665,11 @@ impl InnerResolver {
|
||||||
arr_global.set_initializer(&arr);
|
arr_global.set_initializer(&arr);
|
||||||
|
|
||||||
let val = arr_ty.const_named_struct(&[
|
let val = arr_ty.const_named_struct(&[
|
||||||
ctx.ctx.i32_type().const_int(len as u64, false).into(),
|
|
||||||
arr_global
|
arr_global
|
||||||
.as_pointer_value()
|
.as_pointer_value()
|
||||||
.const_cast(ty.ptr_type(AddressSpace::Generic))
|
.const_cast(ty.ptr_type(AddressSpace::Generic))
|
||||||
.into(),
|
.into(),
|
||||||
|
size_t.const_int(len as u64, false).into(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let global = ctx
|
let global = ctx
|
||||||
|
@ -716,7 +716,7 @@ impl InnerResolver {
|
||||||
|
|
||||||
let val: Result<Option<Vec<_>>, _> = elements
|
let val: Result<Option<Vec<_>>, _> = elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|elem| self.get_obj_value(py, elem, ctx))
|
.map(|elem| self.get_obj_value(py, elem, ctx, generator))
|
||||||
.collect();
|
.collect();
|
||||||
let val = val?.unwrap();
|
let val = val?.unwrap();
|
||||||
let val = ctx.ctx.const_struct(&val, false);
|
let val = ctx.ctx.const_struct(&val, false);
|
||||||
|
@ -763,7 +763,7 @@ impl InnerResolver {
|
||||||
let values: Result<Option<Vec<_>>, _> = fields
|
let values: Result<Option<Vec<_>>, _> = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, _, _)| {
|
.map(|(name, _, _)| {
|
||||||
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx)
|
self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx, generator)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let values = values?;
|
let values = values?;
|
||||||
|
|
|
@ -35,12 +35,9 @@ pub fn get_subst_key(
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
vars.extend(fun_vars.iter());
|
vars.extend(fun_vars.iter());
|
||||||
let sorted =
|
let sorted = vars.keys().filter(|id| filter.map(|v| v.contains(id)).unwrap_or(true)).sorted();
|
||||||
vars.keys().filter(|id| filter.map(|v| v.contains(id)).unwrap_or(true)).sorted();
|
|
||||||
sorted
|
sorted
|
||||||
.map(|id| {
|
.map(|id| unifier.stringify(vars[id], &mut |id| id.to_string(), &mut |id| id.to_string()))
|
||||||
unifier.stringify(vars[id], &mut |id| id.to_string(), &mut |id| id.to_string())
|
|
||||||
})
|
|
||||||
.join(", ")
|
.join(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +101,19 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_llvm_type(&mut self, ty: Type) -> BasicTypeEnum<'ctx> {
|
pub fn get_llvm_type(
|
||||||
get_llvm_type(self.ctx, &mut self.unifier, self.top_level, &mut self.type_cache, ty)
|
&mut self,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
|
ty: Type,
|
||||||
|
) -> BasicTypeEnum<'ctx> {
|
||||||
|
get_llvm_type(
|
||||||
|
self.ctx,
|
||||||
|
generator,
|
||||||
|
&mut self.unifier,
|
||||||
|
self.top_level,
|
||||||
|
&mut self.type_cache,
|
||||||
|
ty,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_const(&mut self, value: &Constant, ty: Type) -> BasicValueEnum<'ctx> {
|
fn gen_const(&mut self, value: &Constant, ty: Type) -> BasicValueEnum<'ctx> {
|
||||||
|
@ -224,7 +232,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_constructor<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
signature: &FunSignature,
|
signature: &FunSignature,
|
||||||
|
@ -240,7 +248,7 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
fun_id = Some(*id);
|
fun_id = Some(*id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ty = ctx.get_llvm_type(signature.ret).into_pointer_type();
|
let ty = ctx.get_llvm_type(generator, signature.ret).into_pointer_type();
|
||||||
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
||||||
let zelf: BasicValueEnum<'ctx> = ctx.builder.build_alloca(zelf_ty, "alloca").into();
|
let zelf: BasicValueEnum<'ctx> = ctx.builder.build_alloca(zelf_ty, "alloca").into();
|
||||||
// call `__init__` if there is one
|
// call `__init__` if there is one
|
||||||
|
@ -329,7 +337,7 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_call<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, ValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
|
@ -353,10 +361,10 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
} => {
|
} => {
|
||||||
if let Some(callback) = codegen_callback {
|
if let Some(callback) = codegen_callback {
|
||||||
// TODO: Change signature
|
// TODO: Change signature
|
||||||
let obj = obj.map(|(t, v)| (t, v.to_basic_value_enum(ctx)));
|
let obj = obj.map(|(t, v)| (t, v.to_basic_value_enum(ctx, generator)));
|
||||||
let params = params
|
let params = params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, val)| (name, val.to_basic_value_enum(ctx)))
|
.map(|(name, val)| (name, val.to_basic_value_enum(ctx, generator)))
|
||||||
.collect();
|
.collect();
|
||||||
return callback.run(ctx, obj, fun, params);
|
return callback.run(ctx, obj, fun, params);
|
||||||
}
|
}
|
||||||
|
@ -410,8 +418,10 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
} else {
|
} else {
|
||||||
format!("{}:{}", id, old_key)
|
format!("{}:{}", id, old_key)
|
||||||
};
|
};
|
||||||
param_vals =
|
param_vals = real_params
|
||||||
real_params.into_iter().map(|p| p.to_basic_value_enum(ctx)).collect_vec();
|
.into_iter()
|
||||||
|
.map(|p| p.to_basic_value_enum(ctx, generator))
|
||||||
|
.collect_vec();
|
||||||
instance_to_symbol.get(&key).cloned()
|
instance_to_symbol.get(&key).cloned()
|
||||||
}
|
}
|
||||||
TopLevelDef::Class { .. } => {
|
TopLevelDef::Class { .. } => {
|
||||||
|
@ -427,11 +437,11 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
if let Some(obj) = &obj {
|
if let Some(obj) = &obj {
|
||||||
args.insert(0, FuncArg { name: "self".into(), ty: obj.0, default_value: None });
|
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 params = args.iter().map(|arg| ctx.get_llvm_type(generator, arg.ty)).collect_vec();
|
||||||
let fun_ty = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
let fun_ty = if ctx.unifier.unioned(fun.0.ret, ctx.primitives.none) {
|
||||||
ctx.ctx.void_type().fn_type(¶ms, false)
|
ctx.ctx.void_type().fn_type(¶ms, false)
|
||||||
} else {
|
} else {
|
||||||
ctx.get_llvm_type(fun.0.ret).fn_type(¶ms, false)
|
ctx.get_llvm_type(generator, fun.0.ret).fn_type(¶ms, false)
|
||||||
};
|
};
|
||||||
ctx.module.add_function(&symbol, fun_ty, None)
|
ctx.module.add_function(&symbol, fun_ty, None)
|
||||||
});
|
});
|
||||||
|
@ -455,32 +465,36 @@ pub fn destructure_range<'ctx, 'a>(
|
||||||
(start, end, step)
|
(start, end, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_list<'ctx, 'a>(
|
pub fn allocate_list<'ctx, 'a, G: CodeGenerator>(
|
||||||
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
ty: BasicTypeEnum<'ctx>,
|
ty: BasicTypeEnum<'ctx>,
|
||||||
length: IntValue<'ctx>,
|
length: IntValue<'ctx>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let arr_ptr = ctx.builder.build_array_alloca(ty, length, "tmparr");
|
let arr_ptr = ctx.builder.build_array_alloca(ty, length, "tmparr");
|
||||||
let arr_ty = ctx.ctx.struct_type(
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
&[ctx.ctx.i32_type().into(), ty.ptr_type(AddressSpace::Generic).into()],
|
let i32_t = ctx.ctx.i32_type();
|
||||||
false,
|
let arr_ty =
|
||||||
);
|
ctx.ctx.struct_type(&[ty.ptr_type(AddressSpace::Generic).into(), size_t.into()], false);
|
||||||
let zero = ctx.ctx.i32_type().const_zero();
|
let zero = ctx.ctx.i32_type().const_zero();
|
||||||
let arr_str_ptr = ctx.builder.build_alloca(arr_ty, "tmparrstr");
|
let arr_str_ptr = ctx.builder.build_alloca(arr_ty, "tmparrstr");
|
||||||
unsafe {
|
unsafe {
|
||||||
let len_ptr = ctx.builder.build_in_bounds_gep(arr_str_ptr, &[zero, zero], "len_ptr");
|
let len_ptr = ctx.builder.build_in_bounds_gep(
|
||||||
ctx.builder.build_store(len_ptr, length);
|
|
||||||
let ptr_to_arr = ctx.builder.build_in_bounds_gep(
|
|
||||||
arr_str_ptr,
|
arr_str_ptr,
|
||||||
&[zero, ctx.ctx.i32_type().const_int(1, false)],
|
&[zero, i32_t.const_int(1, false)],
|
||||||
"ptr_to_arr",
|
"len_ptr",
|
||||||
);
|
);
|
||||||
|
let length = ctx.builder.build_int_z_extend(length, size_t, "zext");
|
||||||
|
ctx.builder.build_store(len_ptr, length);
|
||||||
|
let ptr_to_arr =
|
||||||
|
ctx.builder.build_in_bounds_gep(arr_str_ptr, &[zero, i32_t.const_zero()], "ptr_to_arr");
|
||||||
ctx.builder.build_store(ptr_to_arr, arr_ptr);
|
ctx.builder.build_store(ptr_to_arr, arr_ptr);
|
||||||
|
println!("arr_str_ptr: {:?}", arr_str_ptr);
|
||||||
arr_str_ptr
|
arr_str_ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
|
@ -492,15 +506,16 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
|
|
||||||
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
||||||
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx);
|
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
|
let zero = size_t.const_zero();
|
||||||
|
|
||||||
let index = generator.gen_var_alloc(ctx, ctx.primitives.int32);
|
let index = generator.gen_var_alloc(ctx, size_t.into());
|
||||||
// counter = -1
|
// counter = -1
|
||||||
ctx.builder.build_store(index, ctx.ctx.i32_type().const_zero());
|
ctx.builder.build_store(index, size_t.const_zero());
|
||||||
|
|
||||||
let elem_ty = ctx.get_llvm_type(elt.custom.unwrap());
|
let elem_ty = ctx.get_llvm_type(generator, elt.custom.unwrap());
|
||||||
let is_range = ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range);
|
let is_range = ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range);
|
||||||
let list;
|
let list;
|
||||||
let list_content;
|
let list_content;
|
||||||
|
@ -523,18 +538,16 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ctx.builder.build_conditional_branch(is_valid, normal, empty);
|
ctx.builder.build_conditional_branch(is_valid, normal, empty);
|
||||||
// normal: allocate a list
|
// normal: allocate a list
|
||||||
ctx.builder.position_at_end(normal);
|
ctx.builder.position_at_end(normal);
|
||||||
let list_a = allocate_list(ctx, elem_ty, length);
|
let list_a = allocate_list(generator, ctx, elem_ty, length);
|
||||||
ctx.builder.build_unconditional_branch(list_init);
|
ctx.builder.build_unconditional_branch(list_init);
|
||||||
ctx.builder.position_at_end(empty);
|
ctx.builder.position_at_end(empty);
|
||||||
let list_b = allocate_list(ctx, elem_ty, zero);
|
let list_b = allocate_list(generator, ctx, elem_ty, zero);
|
||||||
ctx.builder.build_unconditional_branch(list_init);
|
ctx.builder.build_unconditional_branch(list_init);
|
||||||
ctx.builder.position_at_end(list_init);
|
ctx.builder.position_at_end(list_init);
|
||||||
let phi = ctx.builder.build_phi(list_a.get_type(), "phi");
|
let phi = ctx.builder.build_phi(list_a.get_type(), "phi");
|
||||||
phi.add_incoming(&[(&list_a, normal), (&list_b, empty)]);
|
phi.add_incoming(&[(&list_a, normal), (&list_b, empty)]);
|
||||||
list = phi.as_basic_value().into_pointer_value();
|
list = phi.as_basic_value().into_pointer_value();
|
||||||
list_content = ctx
|
list_content = ctx.build_gep_and_load(list, &[zero, zero]).into_pointer_value();
|
||||||
.build_gep_and_load(list, &[zero, int32.const_int(1, false)])
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let i = generator.gen_store_target(ctx, target);
|
let i = generator.gen_store_target(ctx, target);
|
||||||
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
||||||
|
@ -567,35 +580,36 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
} else {
|
} else {
|
||||||
let length = ctx
|
let length = ctx
|
||||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
.build_gep_and_load(
|
||||||
|
iter_val.into_pointer_value(),
|
||||||
|
&[zero, int32.const_int(1, false)],
|
||||||
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
list = allocate_list(ctx, elem_ty, length);
|
list = allocate_list(generator, ctx, elem_ty, length);
|
||||||
list_content = ctx
|
list_content = ctx.build_gep_and_load(list, &[zero, zero]).into_pointer_value();
|
||||||
.build_gep_and_load(list, &[zero, int32.const_int(1, false)])
|
let counter = generator.gen_var_alloc(ctx, size_t.into());
|
||||||
.into_pointer_value();
|
|
||||||
let counter = generator.gen_var_alloc(ctx, ctx.primitives.int32);
|
|
||||||
// counter = -1
|
// counter = -1
|
||||||
ctx.builder.build_store(counter, ctx.ctx.i32_type().const_int(u64::max_value(), true));
|
ctx.builder.build_store(counter, ctx.ctx.i32_type().const_int(u64::max_value(), true));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
||||||
let tmp = ctx.builder.build_int_add(tmp, int32.const_int(1, false), "inc");
|
let tmp = ctx.builder.build_int_add(tmp, size_t.const_int(1, false), "inc");
|
||||||
ctx.builder.build_store(counter, tmp);
|
ctx.builder.build_store(counter, tmp);
|
||||||
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, length, "cmp");
|
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, length, "cmp");
|
||||||
ctx.builder.build_conditional_branch(cmp, body_bb, cont_bb);
|
ctx.builder.build_conditional_branch(cmp, body_bb, cont_bb);
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
||||||
iter_val.into_pointer_value(),
|
|
||||||
&[zero, int32.const_int(1, false)],
|
|
||||||
)
|
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
||||||
generator.gen_assign(ctx, target, val.into());
|
generator.gen_assign(ctx, target, val.into());
|
||||||
}
|
}
|
||||||
for cond in ifs.iter() {
|
for cond in ifs.iter() {
|
||||||
let result =
|
let result = generator
|
||||||
generator.gen_expr(ctx, cond).unwrap().to_basic_value_enum(ctx).into_int_value();
|
.gen_expr(ctx, cond)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator)
|
||||||
|
.into_int_value();
|
||||||
let succ = ctx.ctx.append_basic_block(current, "then");
|
let succ = ctx.ctx.append_basic_block(current, "then");
|
||||||
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
||||||
ctx.builder.position_at_end(succ);
|
ctx.builder.position_at_end(succ);
|
||||||
|
@ -603,13 +617,14 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let elem = generator.gen_expr(ctx, elt).unwrap();
|
let elem = generator.gen_expr(ctx, elt).unwrap();
|
||||||
let i = ctx.builder.build_load(index, "i").into_int_value();
|
let i = ctx.builder.build_load(index, "i").into_int_value();
|
||||||
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
||||||
let val = elem.to_basic_value_enum(ctx);
|
let val = elem.to_basic_value_enum(ctx, generator);
|
||||||
ctx.builder.build_store(elem_ptr, val);
|
ctx.builder.build_store(elem_ptr, val);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_store(index, ctx.builder.build_int_add(i, int32.const_int(1, false), "inc"));
|
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let len_ptr = unsafe { ctx.builder.build_gep(list, &[zero, zero], "length") };
|
let len_ptr =
|
||||||
|
unsafe { ctx.builder.build_gep(list, &[zero, int32.const_int(1, false)], "length") };
|
||||||
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
||||||
list.into()
|
list.into()
|
||||||
} else {
|
} else {
|
||||||
|
@ -617,7 +632,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
|
@ -642,14 +657,12 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// 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
|
let elements = elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx))
|
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx, generator))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let ty = if elements.is_empty() { int32.into() } else { elements[0].get_type() };
|
let ty = if elements.is_empty() { int32.into() } else { elements[0].get_type() };
|
||||||
let length = int32.const_int(elements.len() as u64, false);
|
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
||||||
let arr_str_ptr = allocate_list(ctx, ty, length);
|
let arr_str_ptr = allocate_list(generator, ctx, ty, length);
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx.build_gep_and_load(arr_str_ptr, &[zero, zero]).into_pointer_value();
|
||||||
.build_gep_and_load(arr_str_ptr, &[zero, int32.const_int(1, false)])
|
|
||||||
.into_pointer_value();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
for (i, v) in elements.iter().enumerate() {
|
for (i, v) in elements.iter().enumerate() {
|
||||||
let elem_ptr = ctx.builder.build_gep(
|
let elem_ptr = ctx.builder.build_gep(
|
||||||
|
@ -665,7 +678,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
let element_val = elts
|
let element_val = elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx))
|
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx, generator))
|
||||||
.collect_vec();
|
.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 = ctx.ctx.struct_type(&element_ty, false);
|
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
||||||
|
@ -686,7 +699,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// note that we would handle class methods directly in calls
|
// note that we would handle class methods directly in calls
|
||||||
match generator.gen_expr(ctx, value).unwrap() {
|
match generator.gen_expr(ctx, value).unwrap() {
|
||||||
ValueEnum::Static(v) => v.get_field(*attr, ctx).unwrap_or_else(|| {
|
ValueEnum::Static(v) => v.get_field(*attr, ctx).unwrap_or_else(|| {
|
||||||
let v = v.to_basic_value_enum(ctx);
|
let v = v.to_basic_value_enum(ctx, generator);
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
v.into_pointer_value(),
|
v.into_pointer_value(),
|
||||||
|
@ -707,7 +720,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let left = generator
|
let left = generator
|
||||||
.gen_expr(ctx, &values[0])
|
.gen_expr(ctx, &values[0])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
|
@ -723,7 +736,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let b = generator
|
let b = generator
|
||||||
.gen_expr(ctx, &values[1])
|
.gen_expr(ctx, &values[1])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
|
@ -733,7 +746,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let a = generator
|
let a = generator
|
||||||
.gen_expr(ctx, &values[1])
|
.gen_expr(ctx, &values[1])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
|
@ -750,8 +763,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ExprKind::BinOp { op, left, right } => {
|
ExprKind::BinOp { op, left, right } => {
|
||||||
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
||||||
let left = generator.gen_expr(ctx, left).unwrap().to_basic_value_enum(ctx);
|
let left = generator.gen_expr(ctx, left).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
let right = generator.gen_expr(ctx, right).unwrap().to_basic_value_enum(ctx);
|
let right = generator.gen_expr(ctx, right).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -767,7 +780,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
ExprKind::UnaryOp { op, operand } => {
|
ExprKind::UnaryOp { op, operand } => {
|
||||||
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
||||||
let val = generator.gen_expr(ctx, operand).unwrap().to_basic_value_enum(ctx);
|
let val = generator.gen_expr(ctx, operand).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
if ty == ctx.primitives.bool {
|
if ty == ctx.primitives.bool {
|
||||||
let val = val.into_int_value();
|
let val = val.into_int_value();
|
||||||
match op {
|
match op {
|
||||||
|
@ -824,8 +837,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
BasicValueEnum::IntValue(lhs),
|
BasicValueEnum::IntValue(lhs),
|
||||||
BasicValueEnum::IntValue(rhs),
|
BasicValueEnum::IntValue(rhs),
|
||||||
) = (
|
) = (
|
||||||
generator.gen_expr(ctx, lhs).unwrap().to_basic_value_enum(ctx),
|
generator
|
||||||
generator.gen_expr(ctx, rhs).unwrap().to_basic_value_enum(ctx),
|
.gen_expr(ctx, lhs)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator),
|
||||||
|
generator
|
||||||
|
.gen_expr(ctx, rhs)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator),
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -846,8 +865,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
BasicValueEnum::FloatValue(lhs),
|
BasicValueEnum::FloatValue(lhs),
|
||||||
BasicValueEnum::FloatValue(rhs),
|
BasicValueEnum::FloatValue(rhs),
|
||||||
) = (
|
) = (
|
||||||
generator.gen_expr(ctx, lhs).unwrap().to_basic_value_enum(ctx),
|
generator
|
||||||
generator.gen_expr(ctx, rhs).unwrap().to_basic_value_enum(ctx),
|
.gen_expr(ctx, lhs)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator),
|
||||||
|
generator
|
||||||
|
.gen_expr(ctx, rhs)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator),
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -872,18 +897,21 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
.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 =
|
let test = generator
|
||||||
generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx).into_int_value();
|
.gen_expr(ctx, test)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator)
|
||||||
|
.into_int_value();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
||||||
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
||||||
ctx.builder.position_at_end(then_bb);
|
ctx.builder.position_at_end(then_bb);
|
||||||
let a = generator.gen_expr(ctx, body).unwrap().to_basic_value_enum(ctx);
|
let a = generator.gen_expr(ctx, body).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(else_bb);
|
ctx.builder.position_at_end(else_bb);
|
||||||
let b = generator.gen_expr(ctx, orelse).unwrap().to_basic_value_enum(ctx);
|
let b = generator.gen_expr(ctx, orelse).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
||||||
|
@ -965,27 +993,27 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)
|
.gen_expr(ctx, value)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let index = generator
|
let index = generator
|
||||||
.gen_expr(ctx, slice)
|
.gen_expr(ctx, slice)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let arr_ptr =
|
let zero = int32.const_zero();
|
||||||
ctx.build_gep_and_load(v, &[int32.const_zero(), int32.const_int(1, false)]);
|
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero]);
|
||||||
ctx.build_gep_and_load(arr_ptr.into_pointer_value(), &[index])
|
ctx.build_gep_and_load(arr_ptr.into_pointer_value(), &[index])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)
|
.gen_expr(ctx, value)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let index = generator
|
let index = generator
|
||||||
.gen_expr(ctx, slice)
|
.gen_expr(ctx, slice)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.build_gep_and_load(v, &[int32.const_zero(), index])
|
ctx.build_gep_and_load(v, &[int32.const_zero(), index])
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,19 @@ use crate::{
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, Type},
|
typecheck::typedef::{FunSignature, Type},
|
||||||
};
|
};
|
||||||
use inkwell::values::{BasicValueEnum, PointerValue};
|
use inkwell::{
|
||||||
|
context::Context,
|
||||||
|
types::{BasicTypeEnum, IntType},
|
||||||
|
values::{BasicValueEnum, PointerValue},
|
||||||
|
};
|
||||||
use nac3parser::ast::{Expr, Stmt, StrRef};
|
use nac3parser::ast::{Expr, Stmt, StrRef};
|
||||||
|
|
||||||
pub trait CodeGenerator {
|
pub trait CodeGenerator {
|
||||||
/// Return the module name for the code generator.
|
/// Return the module name for the code generator.
|
||||||
fn get_name(&self) -> &str;
|
fn get_name(&self) -> &str;
|
||||||
|
|
||||||
|
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx>;
|
||||||
|
|
||||||
/// Generate function call and returns the function return value.
|
/// Generate function call and returns the function return value.
|
||||||
/// - obj: Optional object for method call.
|
/// - obj: Optional object for method call.
|
||||||
/// - fun: Function signature and definition ID.
|
/// - fun: Function signature and definition ID.
|
||||||
|
@ -22,7 +28,10 @@ pub trait CodeGenerator {
|
||||||
obj: Option<(Type, ValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, DefinitionId),
|
fun: (&FunSignature, DefinitionId),
|
||||||
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_call(self, ctx, obj, fun, params)
|
gen_call(self, ctx, obj, fun, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +45,10 @@ pub trait CodeGenerator {
|
||||||
signature: &FunSignature,
|
signature: &FunSignature,
|
||||||
def: &TopLevelDef,
|
def: &TopLevelDef,
|
||||||
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_constructor(self, ctx, signature, def, params)
|
gen_constructor(self, ctx, signature, def, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +74,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
) -> Option<ValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_expr(self, ctx, expr)
|
gen_expr(self, ctx, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +86,7 @@ pub trait CodeGenerator {
|
||||||
fn gen_var_alloc<'ctx, 'a>(
|
fn gen_var_alloc<'ctx, 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
ty: Type,
|
ty: BasicTypeEnum<'ctx>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
gen_var(ctx, ty)
|
gen_var(ctx, ty)
|
||||||
}
|
}
|
||||||
|
@ -81,7 +96,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
pattern: &Expr<Option<Type>>,
|
pattern: &Expr<Option<Type>>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_store_target(self, ctx, pattern)
|
gen_store_target(self, ctx, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +109,9 @@ pub trait CodeGenerator {
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
target: &Expr<Option<Type>>,
|
target: &Expr<Option<Type>>,
|
||||||
value: ValueEnum<'ctx>,
|
value: ValueEnum<'ctx>,
|
||||||
) {
|
) where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_assign(self, ctx, target, value)
|
gen_assign(self, ctx, target, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +121,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_while(self, ctx, stmt);
|
gen_while(self, ctx, stmt);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -112,7 +135,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_for(self, ctx, stmt);
|
gen_for(self, ctx, stmt);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -123,7 +149,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_if(self, ctx, stmt)
|
gen_if(self, ctx, stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +160,10 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_with(self, ctx, stmt)
|
gen_with(self, ctx, stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,18 +173,23 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
gen_stmt(self, ctx, stmt)
|
gen_stmt(self, ctx, stmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultCodeGenerator {
|
pub struct DefaultCodeGenerator {
|
||||||
name: String,
|
name: String,
|
||||||
|
size_t: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultCodeGenerator {
|
impl DefaultCodeGenerator {
|
||||||
pub fn new(name: String) -> DefaultCodeGenerator {
|
pub fn new(name: String, size_t: u32) -> DefaultCodeGenerator {
|
||||||
DefaultCodeGenerator { name }
|
assert!(size_t == 32 || size_t == 64);
|
||||||
|
DefaultCodeGenerator { name, size_t }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,4 +197,14 @@ impl CodeGenerator for DefaultCodeGenerator {
|
||||||
fn get_name(&self) -> &str {
|
fn get_name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
|
// it should be unsigned, but we don't really need unsigned and this could save us from
|
||||||
|
// having to do a bit cast...
|
||||||
|
if self.size_t == 32 {
|
||||||
|
ctx.i32_type()
|
||||||
|
} else {
|
||||||
|
ctx.i64_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,7 @@ pub struct CodeGenTask {
|
||||||
|
|
||||||
fn get_llvm_type<'ctx>(
|
fn get_llvm_type<'ctx>(
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
top_level: &TopLevelContext,
|
top_level: &TopLevelContext,
|
||||||
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
type_cache: &mut HashMap<Type, BasicTypeEnum<'ctx>>,
|
||||||
|
@ -244,7 +245,7 @@ fn get_llvm_type<'ctx>(
|
||||||
let fields = fields.borrow();
|
let fields = fields.borrow();
|
||||||
let fields = fields_list
|
let fields = fields_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| get_llvm_type(ctx, unifier, top_level, type_cache, fields[&f.0].0))
|
.map(|f| get_llvm_type(ctx, generator, unifier, top_level, type_cache, fields[&f.0].0))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,15 +257,15 @@ fn get_llvm_type<'ctx>(
|
||||||
// a struct with fields in the order present in the tuple
|
// a struct with fields in the order present in the tuple
|
||||||
let fields = ty
|
let fields = ty
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| get_llvm_type(ctx, unifier, top_level, type_cache, *ty))
|
.map(|ty| get_llvm_type(ctx, generator, unifier, top_level, type_cache, *ty))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
||||||
}
|
}
|
||||||
TList { ty } => {
|
TList { ty } => {
|
||||||
// a struct with an integer and a pointer to an array
|
// a struct with an integer and a pointer to an array
|
||||||
let element_type = get_llvm_type(ctx, unifier, top_level, type_cache, *ty);
|
let element_type = get_llvm_type(ctx, generator, unifier, top_level, type_cache, *ty);
|
||||||
let fields =
|
let fields =
|
||||||
[ctx.i32_type().into(), element_type.ptr_type(AddressSpace::Generic).into()];
|
[element_type.ptr_type(AddressSpace::Generic).into(), generator.get_size_type(ctx).into()];
|
||||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
ctx.struct_type(&fields, false).ptr_type(AddressSpace::Generic).into()
|
||||||
}
|
}
|
||||||
TVirtual { .. } => unimplemented!(),
|
TVirtual { .. } => unimplemented!(),
|
||||||
|
@ -273,7 +274,7 @@ fn get_llvm_type<'ctx>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
registry: &WorkerRegistry,
|
registry: &WorkerRegistry,
|
||||||
|
@ -351,14 +352,14 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
let params = args
|
let params = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty)
|
get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty)
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
let fn_type = if unifier.unioned(ret, primitives.none) {
|
let fn_type = if unifier.unioned(ret, primitives.none) {
|
||||||
context.void_type().fn_type(¶ms, false)
|
context.void_type().fn_type(¶ms, false)
|
||||||
} else {
|
} else {
|
||||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, ret)
|
get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, ret)
|
||||||
.fn_type(¶ms, false)
|
.fn_type(¶ms, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -382,7 +383,7 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
for (n, arg) in args.iter().enumerate() {
|
for (n, arg) in args.iter().enumerate() {
|
||||||
let param = fn_val.get_nth_param(n as u32).unwrap();
|
let param = fn_val.get_nth_param(n as u32).unwrap();
|
||||||
let alloca = builder.build_alloca(
|
let alloca = builder.build_alloca(
|
||||||
get_llvm_type(context, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty),
|
get_llvm_type(context, generator, &mut unifier, top_level_ctx.as_ref(), &mut type_cache, arg.ty),
|
||||||
&arg.name.to_string(),
|
&arg.name.to_string(),
|
||||||
);
|
);
|
||||||
builder.build_store(alloca, param);
|
builder.build_store(alloca, param);
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
use super::{expr::destructure_range, CodeGenContext, CodeGenerator, super::symbol_resolver::ValueEnum};
|
use super::{
|
||||||
|
super::symbol_resolver::ValueEnum, expr::destructure_range, CodeGenContext, CodeGenerator,
|
||||||
|
};
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::Type;
|
||||||
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
use inkwell::{
|
||||||
|
types::BasicTypeEnum,
|
||||||
|
values::{BasicValue, BasicValueEnum, PointerValue},
|
||||||
|
};
|
||||||
use nac3parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
use nac3parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||||
|
|
||||||
pub fn gen_var<'ctx, 'a>(ctx: &mut CodeGenContext<'ctx, 'a>, ty: Type) -> PointerValue<'ctx> {
|
pub fn gen_var<'ctx, 'a>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
ty: BasicTypeEnum<'ctx>,
|
||||||
|
) -> PointerValue<'ctx> {
|
||||||
// put the alloca in init block
|
// put the alloca in init block
|
||||||
let current = ctx.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...
|
||||||
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
||||||
let ty = ctx.get_llvm_type(ty);
|
|
||||||
let ptr = ctx.builder.build_alloca(ty, "tmp");
|
let ptr = ctx.builder.build_alloca(ty, "tmp");
|
||||||
ctx.builder.position_at_end(current);
|
ctx.builder.position_at_end(current);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
pattern: &Expr<Option<Type>>,
|
pattern: &Expr<Option<Type>>,
|
||||||
|
@ -23,13 +30,14 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// and we flatten nested tuples
|
// and we flatten nested tuples
|
||||||
match &pattern.node {
|
match &pattern.node {
|
||||||
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).map(|v| v.0).unwrap_or_else(|| {
|
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).map(|v| v.0).unwrap_or_else(|| {
|
||||||
let ptr = generator.gen_var_alloc(ctx, pattern.custom.unwrap());
|
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
||||||
|
let ptr = generator.gen_var_alloc(ctx, ptr_ty);
|
||||||
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
||||||
ptr
|
ptr
|
||||||
}),
|
}),
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx);
|
let val = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,10 +59,13 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let v = generator
|
let v = generator
|
||||||
.gen_expr(ctx, value)
|
.gen_expr(ctx, value)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx)
|
.to_basic_value_enum(ctx, generator)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let index =
|
let index = generator
|
||||||
generator.gen_expr(ctx, slice).unwrap().to_basic_value_enum(ctx).into_int_value();
|
.gen_expr(ctx, slice)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx, generator)
|
||||||
|
.into_int_value();
|
||||||
unsafe {
|
unsafe {
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_int(1, false)])
|
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_int(1, false)])
|
||||||
|
@ -66,14 +77,14 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_assign<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
target: &Expr<Option<Type>>,
|
target: &Expr<Option<Type>>,
|
||||||
value: ValueEnum<'ctx>,
|
value: ValueEnum<'ctx>,
|
||||||
) {
|
) {
|
||||||
if let ExprKind::Tuple { elts, .. } = &target.node {
|
if let ExprKind::Tuple { elts, .. } = &target.node {
|
||||||
if let BasicValueEnum::PointerValue(ptr) = value.to_basic_value_enum(ctx) {
|
if let BasicValueEnum::PointerValue(ptr) = value.to_basic_value_enum(ctx, generator) {
|
||||||
let i32_type = ctx.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
let v = ctx.build_gep_and_load(
|
let v = ctx.build_gep_and_load(
|
||||||
|
@ -94,12 +105,12 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
*static_value = Some(s.clone());
|
*static_value = Some(s.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let val = value.to_basic_value_enum(ctx);
|
let val = value.to_basic_value_enum(ctx, generator);
|
||||||
ctx.builder.build_store(ptr, val);
|
ctx.builder.build_store(ptr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
@ -110,6 +121,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let var_assignment = ctx.var_assignment.clone();
|
let var_assignment = ctx.var_assignment.clone();
|
||||||
|
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
||||||
|
@ -121,7 +133,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// store loop bb information and restore it later
|
// store loop bb information and restore it later
|
||||||
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
||||||
|
|
||||||
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx);
|
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
||||||
// setup
|
// setup
|
||||||
let iter_val = iter_val.into_pointer_value();
|
let iter_val = iter_val.into_pointer_value();
|
||||||
|
@ -156,25 +168,26 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
);
|
);
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
} else {
|
} else {
|
||||||
let counter = generator.gen_var_alloc(ctx, ctx.primitives.int32);
|
println!("{:?}", iter_val);
|
||||||
|
let counter = generator.gen_var_alloc(ctx, size_t.into());
|
||||||
// counter = -1
|
// counter = -1
|
||||||
ctx.builder.build_store(counter, ctx.ctx.i32_type().const_int(u64::max_value(), true));
|
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
||||||
let len = ctx
|
let len = ctx
|
||||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
.build_gep_and_load(
|
||||||
|
iter_val.into_pointer_value(),
|
||||||
|
&[zero, int32.const_int(1, false)],
|
||||||
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
||||||
let tmp = ctx.builder.build_int_add(tmp, int32.const_int(1, false), "inc");
|
let tmp = ctx.builder.build_int_add(tmp, size_t.const_int(1, false), "inc");
|
||||||
ctx.builder.build_store(counter, tmp);
|
ctx.builder.build_store(counter, tmp);
|
||||||
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, len, "cmp");
|
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, len, "cmp");
|
||||||
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb);
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
||||||
iter_val.into_pointer_value(),
|
|
||||||
&[zero, int32.const_int(1, false)],
|
|
||||||
)
|
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
||||||
generator.gen_assign(ctx, target, val.into());
|
generator.gen_assign(ctx, target, val.into());
|
||||||
|
@ -210,7 +223,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
@ -231,7 +244,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx);
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -268,7 +281,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
@ -291,7 +304,7 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
};
|
};
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx);
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -353,7 +366,7 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_with<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
|
||||||
_: &mut G,
|
_: &mut G,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
_: &Stmt<Option<Type>>,
|
_: &Stmt<Option<Type>>,
|
||||||
|
@ -362,7 +375,7 @@ pub fn gen_with<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
|
@ -375,7 +388,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
StmtKind::Return { value, .. } => {
|
StmtKind::Return { value, .. } => {
|
||||||
let value = value
|
let value = value
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|v| generator.gen_expr(ctx, v).unwrap().to_basic_value_enum(ctx));
|
.map(|v| generator.gen_expr(ctx, v).unwrap().to_basic_value_enum(ctx, generator));
|
||||||
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
||||||
ctx.builder.build_return(value);
|
ctx.builder.build_return(value);
|
||||||
return true;
|
return true;
|
||||||
|
@ -408,8 +421,10 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let value = {
|
let value = {
|
||||||
let ty1 = ctx.unifier.get_representative(target.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(target.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(value.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(value.custom.unwrap());
|
||||||
let left = generator.gen_expr(ctx, target).unwrap().to_basic_value_enum(ctx);
|
let left =
|
||||||
let right = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx);
|
generator.gen_expr(ctx, target).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
|
let right =
|
||||||
|
generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx, generator);
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -88,7 +88,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 = vec![DefaultCodeGenerator::new("test".into()).into()];
|
let threads = vec![DefaultCodeGenerator::new("test".into(), 32).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 },
|
||||||
|
@ -245,7 +245,7 @@ fn test_simple_call() {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
let threads = vec![DefaultCodeGenerator::new("test".into()).into()];
|
let threads = vec![DefaultCodeGenerator::new("test".into(), 32).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(),
|
||||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc};
|
||||||
|
|
||||||
use crate::typecheck::{
|
use crate::{codegen::CodeGenerator, typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, Unifier},
|
typedef::{Type, Unifier},
|
||||||
};
|
}};
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
|
@ -31,6 +31,7 @@ pub trait StaticValue {
|
||||||
fn to_basic_value_enum<'ctx, 'a>(
|
fn to_basic_value_enum<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
generator: &mut dyn CodeGenerator
|
||||||
) -> BasicValueEnum<'ctx>;
|
) -> BasicValueEnum<'ctx>;
|
||||||
|
|
||||||
fn get_field<'ctx, 'a>(
|
fn get_field<'ctx, 'a>(
|
||||||
|
@ -74,9 +75,10 @@ impl<'ctx> ValueEnum<'ctx> {
|
||||||
pub fn to_basic_value_enum<'a>(
|
pub fn to_basic_value_enum<'a>(
|
||||||
self,
|
self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
match self {
|
match self {
|
||||||
ValueEnum::Static(v) => v.to_basic_value_enum(ctx),
|
ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator),
|
||||||
ValueEnum::Dynamic(v) => v,
|
ValueEnum::Dynamic(v) => v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,7 +295,7 @@ fn main() {
|
||||||
// println!("IR:\n{}", module.print_to_string().to_str().unwrap());
|
// println!("IR:\n{}", module.print_to_string().to_str().unwrap());
|
||||||
})));
|
})));
|
||||||
let threads = (0..threads)
|
let threads = (0..threads)
|
||||||
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i))))
|
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{}", i), 64)))
|
||||||
.collect();
|
.collect();
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue