Compare commits

..

6 Commits

Author SHA1 Message Date
David Mak 649874868a artiq: Implement handling for const generic variables 2023-12-08 13:02:35 +08:00
David Mak 638d9f8a30 core: Initial implementation for const generics 2023-12-08 13:02:31 +08:00
David Mak b9b725e78e core: Move some SymbolValue functions to symbol_resolver.rs 2023-12-08 13:01:12 +08:00
David Mak 7c41036c5c core: Codegen for ellipsis expression as NotImplemented
A lot of refactoring was performed, specifically with relaxing
expression codegen to return Option in case where ellipsis are used
within a subexpression.
2023-12-08 13:01:08 +08:00
David Mak aaaeccfc5a ast: Use `{filename}:{row}:{col}` for location output 2023-12-08 12:19:09 +08:00
David Mak 3b8309ae75 core: Infer builtins name list using builtin declaration list 2023-12-08 12:19:06 +08:00
7 changed files with 164 additions and 117 deletions

View File

@ -145,7 +145,8 @@ impl<'a> ArtiqCodeGenerator<'a> {
let end_store = self.gen_store_target(
ctx,
&end,
store_name.map(|name| format!("{name}.addr")).as_deref())?;
store_name.map(|name| format!("{name}.addr")).as_deref())?
.unwrap();
ctx.builder.build_store(end_store, max);
}
@ -261,7 +262,9 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
node: ExprKind::Name { id: start, ctx: name_ctx.clone() },
custom: Some(ctx.primitives.int64),
};
let start = self.gen_store_target(ctx, &start_expr, Some("start.addr"))?;
let start = self
.gen_store_target(ctx, &start_expr, Some("start.addr"))?
.unwrap();
ctx.builder.build_store(start, now);
Ok(Some(start_expr)) as Result<_, String>
},
@ -274,7 +277,9 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
node: ExprKind::Name { id: end, ctx: name_ctx.clone() },
custom: Some(ctx.primitives.int64),
};
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?;
let end = self
.gen_store_target(ctx, &end_expr, Some("end.addr"))?
.unwrap();
ctx.builder.build_store(end, now);
self.end = Some(end_expr);
self.name_counter += 1;

View File

@ -265,7 +265,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
}
}
Constant::Ellipsis => {
let msg = self.gen_string(generator, "");
let msg = self.gen_string(generator, "NotImplementedError");
self.raise_exn(
generator,
@ -967,9 +967,15 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
ctx.builder.position_at_end(init_bb);
let Comprehension { target, iter, ifs, .. } = &generators[0];
let iter_val = match generator.gen_expr(ctx, iter)? {
Some(v) => v.to_basic_value_enum(ctx, generator, iter.custom.unwrap())?,
None => return Ok(None),
let iter_val = if let Some(v) = generator.gen_expr(ctx, iter)? {
v.to_basic_value_enum(ctx, generator, iter.custom.unwrap())?
} else {
for bb in [test_bb, body_bb, cont_bb] {
ctx.builder.position_at_end(bb);
ctx.builder.build_unreachable();
}
return Ok(None)
};
let int32 = ctx.ctx.i32_type();
let size_t = generator.get_size_type(ctx.ctx);
@ -1013,9 +1019,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
list_content = ctx.build_gep_and_load(list, &[zero_size_t, zero_32], Some("listcomp.data.addr"))
.into_pointer_value();
let Some(i) = generator.gen_store_target(ctx, target, Some("i.addr"))? else {
unreachable!()
};
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?.unwrap();
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
ctx.builder.build_conditional_branch(
@ -1070,12 +1074,24 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
generator.gen_assign(ctx, target, val.into())?;
}
// Emits the content of `cont_bb`
let emit_cont_bb = |ctx: &CodeGenContext| {
ctx.builder.position_at_end(cont_bb);
let len_ptr = unsafe {
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
};
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
};
for cond in ifs.iter() {
let result = match generator.gen_expr(ctx, cond)? {
Some(v) => v
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?
.into_int_value(),
None => return Ok(None),
let result = if let Some(v) = generator.gen_expr(ctx, cond)? {
v.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?.into_int_value()
} else {
// Bail if the predicate is an ellipsis - Emit cont_bb contents in case the
// no element matches the predicate
emit_cont_bb(ctx);
return Ok(None)
};
let result = generator.bool_to_i1(ctx, result);
let succ = ctx.ctx.append_basic_block(current, "then");
@ -1084,9 +1100,11 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
ctx.builder.position_at_end(succ);
}
let elem = match generator.gen_expr(ctx, elt)? {
Some(v) => v,
None => return Ok(None),
let Some(elem) = generator.gen_expr(ctx, elt)? else {
// Similarly, bail if the generator expression is an ellipsis, but keep cont_bb contents
emit_cont_bb(ctx);
return Ok(None)
};
let i = ctx.builder.build_load(index, "i").into_int_value();
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
@ -1096,11 +1114,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
.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.position_at_end(cont_bb);
let len_ptr = unsafe {
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
};
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
emit_cont_bb(ctx);
Ok(Some(list.into()))
} else {
@ -1126,13 +1140,15 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
) -> Result<Option<ValueEnum<'ctx>>, String> {
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
let left_val = match generator.gen_expr(ctx, left)? {
Some(v) => v.to_basic_value_enum(ctx, generator, left.custom.unwrap())?,
None => return Ok(None),
let left_val = if let Some(v) = generator.gen_expr(ctx, left)? {
v.to_basic_value_enum(ctx, generator, left.custom.unwrap())?
} else {
return Ok(None)
};
let right_val = match generator.gen_expr(ctx, right)? {
Some(v) => v.to_basic_value_enum(ctx, generator, right.custom.unwrap())?,
None => return Ok(None),
let right_val = if let Some(v) = generator.gen_expr(ctx, right)? {
v.to_basic_value_enum(ctx, generator, right.custom.unwrap())?
} else {
return Ok(None)
};
// we can directly compare the types, because we've got their representatives
@ -1360,11 +1376,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
}
ExprKind::BoolOp { op, values } => {
// requires conditional branches for short-circuiting...
let left = match generator.gen_expr(ctx, &values[0])? {
Some(v) => v
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?
.into_int_value(),
None => return Ok(None),
let left = if let Some(v) = generator.gen_expr(ctx, &values[0])? {
v.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?.into_int_value()
} else {
return Ok(None)
};
let left = generator.bool_to_i1(ctx, left);
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
@ -1377,46 +1392,61 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
ctx.builder.position_at_end(a_bb);
let a = ctx.ctx.i8_type().const_int(1, false);
ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(b_bb);
let b = match generator.gen_expr(ctx, &values[1])? {
Some(v) =>
v.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
.into_int_value(),
None => return Ok(None),
let b = if let Some(v) = generator.gen_expr(ctx, &values[1])? {
let b = v.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?.into_int_value();
let b = generator.bool_to_i8(ctx, b);
ctx.builder.build_unconditional_branch(cont_bb);
Some(b)
} else {
None
};
let b = generator.bool_to_i8(ctx, b);
ctx.builder.build_unconditional_branch(cont_bb);
(a, b)
(Some(a), b)
}
Boolop::And => {
ctx.builder.position_at_end(a_bb);
let a = match generator.gen_expr(ctx, &values[1])? {
Some(v) => v
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
.into_int_value(),
None => return Ok(None),
let a = if let Some(v) = generator.gen_expr(ctx, &values[1])? {
let a = v.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?.into_int_value();
let a = generator.bool_to_i8(ctx, a);
ctx.builder.build_unconditional_branch(cont_bb);
Some(a)
} else {
None
};
let a = generator.bool_to_i8(ctx, a);
ctx.builder.build_unconditional_branch(cont_bb);
ctx.builder.position_at_end(b_bb);
let b = ctx.ctx.i8_type().const_zero();
ctx.builder.build_unconditional_branch(cont_bb);
(a, b)
(a, Some(b))
}
};
ctx.builder.position_at_end(cont_bb);
let phi = ctx.builder.build_phi(ctx.ctx.i8_type(), "");
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
phi.as_basic_value().into()
match (a, b) {
(Some(a), Some(b)) => {
let phi = ctx.builder.build_phi(ctx.ctx.i8_type(), "");
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
phi.as_basic_value().into()
}
(Some(a), None) => a.into(),
(None, Some(b)) => b.into(),
(None, None) => unreachable!(),
}
}
ExprKind::BinOp { op, left, right } => {
return gen_binop_expr(generator, ctx, left, op, right, expr.location, false);
}
ExprKind::UnaryOp { op, operand } => {
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
let val = match generator.gen_expr(ctx, operand)? {
Some(v) => v.to_basic_value_enum(ctx, generator, operand.custom.unwrap())?,
None => return Ok(None),
let val = if let Some(v) = generator.gen_expr(ctx, operand)? {
v.to_basic_value_enum(ctx, generator, operand.custom.unwrap())?
} else {
return Ok(None)
};
if ty == ctx.primitives.bool {
let val = val.into_int_value();
@ -1454,7 +1484,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
}
}
ExprKind::Compare { left, ops, comparators } => {
izip!(chain(once(left.as_ref()), comparators.iter()), comparators.iter(), ops.iter(),)
let cmp_val = izip!(chain(once(left.as_ref()), comparators.iter()), comparators.iter(), ops.iter(),)
.fold(Ok(None), |prev: Result<Option<_>, String>, (lhs, rhs, op)| {
let ty = ctx.unifier.get_representative(lhs.custom.unwrap());
let current =
@ -1529,9 +1559,12 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
unimplemented!()
};
Ok(prev?.map(|v| ctx.builder.build_and(v, current, "cmp")).or(Some(current)))
})?
.unwrap()
.into() // as there should be at least 1 element, it should never be none
})?;
match cmp_val {
Some(v) => v.into(),
None => return Ok(None),
}
}
ExprKind::IfExp { test, body, orelse } => {
let test = match generator.gen_expr(ctx, test)? {
@ -1580,9 +1613,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
}
ctx.builder.position_at_end(cont_bb);
match result {
None => return Ok(None),
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into()))
if let Some(v) = result {
ctx.builder.build_load(v, "if_exp_val_load").into()
} else {
return Ok(None)
}
}
ExprKind::Call { func, args, keywords } => {
@ -1732,11 +1766,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
}
ExprKind::Subscript { value, slice, .. } => {
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
let v = match generator.gen_expr(ctx, value)? {
Some(v) => v
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
.into_pointer_value(),
None => return Ok(None),
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?.into_pointer_value()
} else {
return Ok(None)
};
let ty = ctx.get_llvm_type(generator, *ty);
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero], Some("arr.addr"))
@ -1785,11 +1818,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
let len = ctx
.build_gep_and_load(v, &[zero, int32.const_int(1, false)], Some("len"))
.into_int_value();
let raw_index = match generator.gen_expr(ctx, slice)? {
Some(v) => v
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
.into_int_value(),
None => return Ok(None),
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
v.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value()
} else {
return Ok(None)
};
let raw_index = ctx.builder.build_int_s_extend(
raw_index,
@ -1855,10 +1887,13 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
unreachable!("should not be other subscriptable types after type check");
}
},
ExprKind::ListComp { .. } => match gen_comprehension(generator, ctx, expr)? {
Some(v) => v.into(),
None => return Ok(None),
},
ExprKind::ListComp { .. } => {
if let Some(v) = gen_comprehension(generator, ctx, expr)? {
v.into()
} else {
return Ok(None)
}
}
_ => unimplemented!(),
}))
}

View File

@ -166,22 +166,22 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
let length = ctx.builder.build_int_truncate_or_bit_cast(length, int32, "leni32");
Ok(Some(match (start, end, step) {
(s, e, None) => (
match s.as_ref() {
Some(s) => {
if let Some(v) = handle_slice_index_bound(s, ctx, generator, length)? {
v
} else { return Ok(None) }
if let Some(s) = s.as_ref() {
match handle_slice_index_bound(s, ctx, generator, length)? {
Some(v) => v,
None => return Ok(None),
}
None => int32.const_zero(),
} else {
int32.const_zero()
},
{
let e = match e.as_ref() {
Some(s) => {
if let Some(v) = handle_slice_index_bound(s, ctx, generator, length)? {
v
} else { return Ok(None) }
let e = if let Some(s) = e.as_ref() {
match handle_slice_index_bound(s, ctx, generator, length)? {
Some(v) => v,
None => return Ok(None),
}
None => length,
} else {
length
};
ctx.builder.build_int_sub(e, one, "final_end")
},
@ -190,7 +190,9 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
(s, e, Some(step)) => {
let step = if let Some(v) = generator.gen_expr(ctx, step)? {
v.to_basic_value_enum(ctx, generator, ctx.primitives.int32)?.into_int_value()
} else { return Ok(None) };
} else {
return Ok(None)
};
// assert step != 0, throw exception if not
let not_zero = ctx.builder.build_int_compare(
IntPredicate::NE,
@ -273,7 +275,9 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
let i = if let Some(v) = generator.gen_expr(ctx, i)? {
v.to_basic_value_enum(ctx, generator, i.custom.unwrap())?
} else { return Ok(None) };
} else {
return Ok(None)
};
Ok(Some(ctx
.builder
.build_call(func, &[i.into(), length.into()], "bounded_ind")

View File

@ -109,13 +109,17 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
let zero = i32_type.const_zero();
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?.into_pointer_value()
} else { return Ok(None) };
} else {
return Ok(None)
};
let len = ctx
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)], Some("len"))
.into_int_value();
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
v.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value()
} else { return Ok(None) };
} else {
return Ok(None)
};
let raw_index = ctx.builder.build_int_s_extend(
raw_index,
generator.get_size_type(ctx.ctx),
@ -272,13 +276,14 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
// store loop bb information and restore it later
let loop_bb = ctx.loop_target.replace((incr_bb, cont_bb));
let iter_val = match generator.gen_expr(ctx, iter)? {
Some(v) => v.to_basic_value_enum(
let iter_val = if let Some(v) = generator.gen_expr(ctx, iter)? {
v.to_basic_value_enum(
ctx,
generator,
iter.custom.unwrap(),
)?,
None => return Ok(()),
)?
} else {
return Ok(())
};
if is_iterable_range_expr {
let iter_val = iter_val.into_pointer_value();
@ -421,7 +426,14 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
ctx.builder.position_at_end(test_bb);
let test = if let Some(v) = generator.gen_expr(ctx, test)? {
v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
} else { return Ok(()) };
} else {
for bb in [body_bb, cont_bb] {
ctx.builder.position_at_end(bb);
ctx.builder.build_unreachable();
}
return Ok(())
};
if let BasicValueEnum::IntValue(test) = test {
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
} else {
@ -483,14 +495,11 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
};
ctx.builder.build_unconditional_branch(test_bb);
ctx.builder.position_at_end(test_bb);
let test = match generator.gen_expr(ctx, test)? {
Some(v) => v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?,
None => return Ok(()),
};
if let BasicValueEnum::IntValue(test) = test {
let test = generator
.gen_expr(ctx, test)
.and_then(|v| v.map(|v| v.to_basic_value_enum(ctx, generator, test.custom.unwrap())).transpose())?;
if let Some(BasicValueEnum::IntValue(test)) = test {
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
} else {
unreachable!()
};
ctx.builder.position_at_end(body_bb);
generator.gen_block(ctx, body.iter())?;
@ -1043,11 +1052,12 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
) -> Result<(), String> {
let func = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap();
let value = if let Some(v_expr) = value.as_ref() {
match generator.gen_expr(ctx, v_expr).transpose() {
Some(v) => Some(
if let Some(v) = generator.gen_expr(ctx, v_expr).transpose() {
Some(
v.and_then(|v| v.to_basic_value_enum(ctx, generator, v_expr.custom.unwrap()))?
),
None => return Ok(())
)
} else {
return Ok(())
}
} else {
None

View File

@ -1,7 +0,0 @@
@extern
def output_str(x: str):
...
def run() -> int32:
[i for i in range(10) if ...]
return 0

View File

@ -76,7 +76,7 @@ fn handle_typevar_definition(
) -> Result<Type, String> {
let ExprKind::Call { func, args, .. } = &var.node else {
return Err(format!(
"expression {:?} cannot be handled as a TypeVar or ConstGeneric in global scope",
"expression {:?} cannot be handled as a generic parameter in global scope",
var
))
};