Compare commits
11 Commits
18a3263af1
...
4481d48709
Author | SHA1 | Date |
---|---|---|
David Mak | 4481d48709 | |
David Mak | b4983526bd | |
David Mak | b4a9616648 | |
David Mak | e0de82993f | |
David Mak | 6805253515 | |
David Mak | 19915bac79 | |
David Mak | 17b4686260 | |
David Mak | 6de0884dc1 | |
David Mak | f1b0e05b3d | |
David Mak | ff23968544 | |
Sebastien Bourdeauducq | 049908044a |
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1688868408,
|
||||
"narHash": "sha256-RR9N5XTAxSBhK8MCvLq9uxfdkd7etC//seVXldy0k48=",
|
||||
"lastModified": 1693636127,
|
||||
"narHash": "sha256-ZlS/lFGzK7BJXX2YVGnP3yZi3T9OLOEtBCyMJsb91U8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "510d721ce097150ae3b80f84b04b13b039186571",
|
||||
"rev": "9075cba53e86dc318d159aee55dc9a7c9a4829c1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -84,7 +84,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
let end_store = self.gen_store_target(ctx, &end)?;
|
||||
let end_store = self.gen_store_target(ctx, &end, Some("end_store.addr"))?;
|
||||
ctx.builder.build_store(end_store, max);
|
||||
}
|
||||
if let Some(start) = self.start.clone() {
|
||||
|
@ -140,7 +140,7 @@ 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)?;
|
||||
let start = self.gen_store_target(ctx, &start_expr, Some("start.addr"))?;
|
||||
ctx.builder.build_store(start, now);
|
||||
Ok(Some(start_expr)) as Result<_, String>
|
||||
},
|
||||
|
@ -153,7 +153,7 @@ 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)?;
|
||||
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?;
|
||||
ctx.builder.build_store(end, now);
|
||||
self.end = Some(end_expr);
|
||||
self.name_counter += 1;
|
||||
|
@ -204,7 +204,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
let outer_end = self.gen_store_target(ctx, old_end)?;
|
||||
let outer_end = self.gen_store_target(ctx, old_end, Some("outer_end.addr"))?;
|
||||
ctx.builder.build_store(outer_end, max);
|
||||
}
|
||||
self.start = old_start;
|
||||
|
|
|
@ -810,7 +810,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||
let zero_size_t = size_t.const_zero();
|
||||
let zero_32 = int32.const_zero();
|
||||
|
||||
let index = generator.gen_var_alloc(ctx, size_t.into())?;
|
||||
let index = generator.gen_var_alloc(ctx, size_t.into(), Some("index.addr"))?;
|
||||
ctx.builder.build_store(index, zero_size_t);
|
||||
|
||||
let elem_ty = ctx.get_llvm_type(generator, elt.custom.unwrap());
|
||||
|
@ -853,7 +853,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||
list_content =
|
||||
ctx.build_gep_and_load(list, &[zero_size_t, zero_32]).into_pointer_value();
|
||||
|
||||
let i = generator.gen_store_target(ctx, target)?;
|
||||
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?;
|
||||
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
ctx.builder.position_at_end(test_bb);
|
||||
|
@ -888,7 +888,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||
list = allocate_list(generator, ctx, elem_ty, length);
|
||||
list_content =
|
||||
ctx.build_gep_and_load(list, &[zero_size_t, zero_32]).into_pointer_value();
|
||||
let counter = generator.gen_var_alloc(ctx, size_t.into())?;
|
||||
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
||||
// counter = -1
|
||||
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
|
|
|
@ -87,8 +87,9 @@ pub trait CodeGenerator {
|
|||
&mut self,
|
||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||
ty: BasicTypeEnum<'ctx>,
|
||||
name: Option<&str>,
|
||||
) -> Result<PointerValue<'ctx>, String> {
|
||||
gen_var(ctx, ty)
|
||||
gen_var(ctx, ty, name)
|
||||
}
|
||||
|
||||
/// Return a pointer pointing to the target of the expression.
|
||||
|
@ -96,11 +97,12 @@ pub trait CodeGenerator {
|
|||
&mut self,
|
||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||
pattern: &Expr<Option<Type>>,
|
||||
name: Option<&str>,
|
||||
) -> Result<PointerValue<'ctx>, String>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
gen_store_target(self, ctx, pattern)
|
||||
gen_store_target(self, ctx, pattern, name)
|
||||
}
|
||||
|
||||
/// Generate code for an assignment expression.
|
||||
|
|
|
@ -77,7 +77,8 @@ pub struct CodeGenContext<'ctx, 'a> {
|
|||
pub const_strings: HashMap<String, BasicValueEnum<'ctx>>,
|
||||
// stores the alloca for variables
|
||||
pub init_bb: BasicBlock<'ctx>,
|
||||
// the first one is the test_bb, and the second one is bb after the loop
|
||||
/// The header and exit basic blocks of a loop in this context. See
|
||||
/// https://llvm.org/docs/LoopTerminology.html for explanation of these terminology.
|
||||
pub loop_target: Option<(BasicBlock<'ctx>, BasicBlock<'ctx>)>,
|
||||
// unwind target bb
|
||||
pub unwind_target: Option<BasicBlock<'ctx>>,
|
||||
|
|
|
@ -13,8 +13,8 @@ use inkwell::{
|
|||
attributes::{Attribute, AttributeLoc},
|
||||
basic_block::BasicBlock,
|
||||
types::BasicTypeEnum,
|
||||
values::{BasicValue, BasicValueEnum, FunctionValue, PointerValue},
|
||||
IntPredicate::EQ,
|
||||
values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue},
|
||||
IntPredicate,
|
||||
};
|
||||
use nac3parser::ast::{
|
||||
Constant, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind, StrRef,
|
||||
|
@ -24,12 +24,13 @@ use std::convert::TryFrom;
|
|||
pub fn gen_var<'ctx, 'a>(
|
||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||
ty: BasicTypeEnum<'ctx>,
|
||||
name: Option<&str>,
|
||||
) -> Result<PointerValue<'ctx>, String> {
|
||||
// put the alloca in init block
|
||||
let current = ctx.builder.get_insert_block().unwrap();
|
||||
// position before the last branching instruction...
|
||||
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
||||
let ptr = ctx.builder.build_alloca(ty, "tmp");
|
||||
let ptr = ctx.builder.build_alloca(ty, name.unwrap_or(""));
|
||||
ctx.builder.position_at_end(current);
|
||||
Ok(ptr)
|
||||
}
|
||||
|
@ -38,6 +39,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||
pattern: &Expr<Option<Type>>,
|
||||
name: Option<&str>,
|
||||
) -> Result<PointerValue<'ctx>, String> {
|
||||
// very similar to gen_expr, but we don't do an extra load at the end
|
||||
// and we flatten nested tuples
|
||||
|
@ -45,7 +47,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
||||
None => {
|
||||
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
||||
let ptr = generator.gen_var_alloc(ctx, ptr_ty)?;
|
||||
let ptr = generator.gen_var_alloc(ctx, ptr_ty, name)?;
|
||||
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
||||
ptr
|
||||
}
|
||||
|
@ -74,7 +76,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
ctx.ctx.i32_type().const_zero(),
|
||||
ctx.ctx.i32_type().const_int(index as u64, false),
|
||||
],
|
||||
"attr",
|
||||
name.unwrap_or(""),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +107,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
);
|
||||
// handle negative index
|
||||
let is_negative = ctx.builder.build_int_compare(
|
||||
inkwell::IntPredicate::SLT,
|
||||
IntPredicate::SLT,
|
||||
raw_index,
|
||||
generator.get_size_type(ctx.ctx).const_zero(),
|
||||
"is_neg",
|
||||
|
@ -118,7 +120,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
// unsigned less than is enough, because negative index after adjustment is
|
||||
// bigger than the length (for unsigned cmp)
|
||||
let bound_check = ctx.builder.build_int_compare(
|
||||
inkwell::IntPredicate::ULT,
|
||||
IntPredicate::ULT,
|
||||
index,
|
||||
len,
|
||||
"inbound",
|
||||
|
@ -135,7 +137,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||
let arr_ptr = ctx
|
||||
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
|
||||
.into_pointer_value();
|
||||
ctx.builder.build_gep(arr_ptr, &[index], "loadarrgep")
|
||||
ctx.builder.build_gep(arr_ptr, &[index], name.unwrap_or(""))
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
@ -191,7 +193,13 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
let ptr = generator.gen_store_target(ctx, target)?;
|
||||
let name = if let ExprKind::Name { id, .. } = &target.node {
|
||||
format!("{}.addr", id.to_string())
|
||||
} else {
|
||||
String::from("target.addr")
|
||||
};
|
||||
let ptr = generator.gen_store_target(ctx, target, Some(name.as_str()))?;
|
||||
|
||||
if let ExprKind::Name { id, .. } = &target.node {
|
||||
let (_, static_value, counter) = ctx.var_assignment.get_mut(id).unwrap();
|
||||
*counter += 1;
|
||||
|
@ -206,6 +214,26 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a sequence of IR which checks whether [value] does not exceed the upper bound of the
|
||||
/// range as defined by [stop] and [step].
|
||||
///
|
||||
/// Note that the generated IR will **not** check whether value is part of the range or whether
|
||||
/// value exceeds the lower bound of the range (as evident by the missing `start` argument).
|
||||
///
|
||||
/// Returns an [IntValue] representing the result of whether the [value] is in the range.
|
||||
fn gen_in_range_check<'ctx, 'a>(
|
||||
ctx: &CodeGenContext<'ctx, 'a>,
|
||||
value: IntValue<'ctx>,
|
||||
stop: IntValue<'ctx>,
|
||||
step: IntValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let sign = ctx.builder.build_int_compare(IntPredicate::SGT, step, ctx.ctx.i32_type().const_zero(), "");
|
||||
let lo = ctx.builder.build_select(sign, value, stop, "").into_int_value();
|
||||
let hi = ctx.builder.build_select(sign, stop, value, "").into_int_value();
|
||||
|
||||
ctx.builder.build_int_compare(IntPredicate::SLT, lo, hi, "cmp")
|
||||
}
|
||||
|
||||
pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||
|
@ -219,60 +247,82 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
let int32 = ctx.ctx.i32_type();
|
||||
let size_t = generator.get_size_type(ctx.ctx);
|
||||
let zero = int32.const_zero();
|
||||
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");
|
||||
let current = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap();
|
||||
let body_bb = ctx.ctx.append_basic_block(current, "for.body");
|
||||
let cont_bb = ctx.ctx.append_basic_block(current, "for.end");
|
||||
// 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") };
|
||||
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "for.orelse") };
|
||||
|
||||
// Whether the iterable is a range() expression
|
||||
let is_iterable_range_expr = ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range);
|
||||
|
||||
// The target BB of the loop backedge
|
||||
let backedge_bb_target = if is_iterable_range_expr {
|
||||
body_bb
|
||||
} else {
|
||||
ctx.ctx.append_basic_block(current, "for.cond")
|
||||
};
|
||||
|
||||
// store loop bb information and restore it later
|
||||
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
||||
let loop_bb = ctx.loop_target.replace((backedge_bb_target, cont_bb));
|
||||
|
||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(
|
||||
ctx,
|
||||
generator,
|
||||
iter.custom.unwrap(),
|
||||
)?;
|
||||
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
||||
// setup
|
||||
if is_iterable_range_expr {
|
||||
let iter_val = iter_val.into_pointer_value();
|
||||
let i = generator.gen_var_alloc(ctx, int32.into())?;
|
||||
let user_i = generator.gen_store_target(ctx, target)?;
|
||||
let (start, end, step) = destructure_range(ctx, iter_val);
|
||||
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
ctx.builder.position_at_end(test_bb);
|
||||
let sign = ctx.builder.build_int_compare(
|
||||
inkwell::IntPredicate::SGT,
|
||||
step,
|
||||
int32.const_zero(),
|
||||
"sign",
|
||||
// Internal variable for loop; Cannot be assigned
|
||||
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
||||
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
||||
let target_i = generator.gen_store_target(ctx, target, Some("for.target.addr"))?;
|
||||
let (start, stop, step) = destructure_range(ctx, iter_val);
|
||||
|
||||
ctx.builder.build_store(i, start);
|
||||
|
||||
// Check "If step is zero, ValueError is raised."
|
||||
let rangenez = ctx.builder.build_int_compare(IntPredicate::NE, step, int32.const_zero(), "");
|
||||
ctx.make_assert(
|
||||
generator,
|
||||
rangenez,
|
||||
"ValueError",
|
||||
"range() arg 3 must not be zero",
|
||||
[None, None, None],
|
||||
ctx.current_loc
|
||||
);
|
||||
// add and test
|
||||
let tmp = ctx.builder.build_int_add(
|
||||
ctx.builder.build_load(i, "i").into_int_value(),
|
||||
step,
|
||||
"start_loop",
|
||||
);
|
||||
ctx.builder.build_store(i, tmp);
|
||||
ctx.builder.build_store(user_i, tmp);
|
||||
// // if step > 0, continue when i < end
|
||||
let cmp1 = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, end, "cmp1");
|
||||
// if step < 0, continue when i > end
|
||||
let cmp2 = ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, tmp, end, "cmp2");
|
||||
let pos = ctx.builder.build_and(sign, cmp1, "pos");
|
||||
let neg = ctx.builder.build_and(ctx.builder.build_not(sign, "inv"), cmp2, "neg");
|
||||
|
||||
ctx.builder.build_conditional_branch(
|
||||
ctx.builder.build_or(pos, neg, "or"),
|
||||
gen_in_range_check(ctx, start, stop, step),
|
||||
body_bb,
|
||||
orelse_bb,
|
||||
);
|
||||
|
||||
ctx.builder.position_at_end(body_bb);
|
||||
ctx.builder.build_store(target_i, ctx.builder.build_load(i, "").into_int_value());
|
||||
gen_block(generator, ctx, body.iter())?;
|
||||
|
||||
// Test if next element is still in range
|
||||
let next_i = ctx.builder.build_int_add(
|
||||
ctx.builder.build_load(i, "").into_int_value(),
|
||||
step,
|
||||
"next_i",
|
||||
);
|
||||
let cond_cont_bb = ctx.ctx.append_basic_block(current, "for.cond.cont");
|
||||
ctx.builder.build_conditional_branch(
|
||||
gen_in_range_check(ctx, next_i, stop, step),
|
||||
cond_cont_bb,
|
||||
orelse_bb,
|
||||
);
|
||||
|
||||
ctx.builder.position_at_end(cond_cont_bb);
|
||||
ctx.builder.build_store(i, next_i);
|
||||
} else {
|
||||
let counter = generator.gen_var_alloc(ctx, size_t.into())?;
|
||||
// counter = -1
|
||||
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
||||
let test_bb = backedge_bb_target;
|
||||
|
||||
let index_addr = generator.gen_var_alloc(ctx, size_t.into(), Some("for.index.addr"))?;
|
||||
ctx.builder.build_store(index_addr, size_t.const_zero());
|
||||
let len = ctx
|
||||
.build_gep_and_load(
|
||||
iter_val.into_pointer_value(),
|
||||
|
@ -280,30 +330,36 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
)
|
||||
.into_int_value();
|
||||
ctx.builder.build_unconditional_branch(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_int_add(tmp, size_t.const_int(1, false), "inc");
|
||||
ctx.builder.build_store(counter, tmp);
|
||||
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, len, "cmp");
|
||||
let index = ctx.builder.build_load(index_addr, "for.index").into_int_value();
|
||||
let cmp = ctx.builder.build_int_compare(IntPredicate::SLT, index, len, "cond");
|
||||
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb);
|
||||
|
||||
ctx.builder.position_at_end(body_bb);
|
||||
let arr_ptr = ctx
|
||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
||||
.into_pointer_value();
|
||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
||||
let val = ctx.build_gep_and_load(arr_ptr, &[index]);
|
||||
generator.gen_assign(ctx, target, val.into())?;
|
||||
gen_block(generator, ctx, body.iter())?;
|
||||
|
||||
let index = ctx.builder.build_load(index_addr, "for.index").into_int_value();
|
||||
let inc = ctx.builder.build_int_add(index, size_t.const_int(1, true), "");
|
||||
ctx.builder.build_store(index_addr, inc);
|
||||
}
|
||||
|
||||
gen_block(generator, ctx, body.iter())?;
|
||||
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||
if counter != counter2 {
|
||||
*static_val = None;
|
||||
}
|
||||
}
|
||||
|
||||
if !ctx.is_terminated() {
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
ctx.builder.build_unconditional_branch(backedge_bb_target);
|
||||
}
|
||||
|
||||
if !orelse.is_empty() {
|
||||
ctx.builder.position_at_end(orelse_bb);
|
||||
gen_block(generator, ctx, orelse.iter())?;
|
||||
|
@ -311,12 +367,14 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
ctx.builder.build_unconditional_branch(cont_bb);
|
||||
}
|
||||
}
|
||||
|
||||
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||
if counter != counter2 {
|
||||
*static_val = None;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.builder.position_at_end(cont_bb);
|
||||
ctx.loop_target = loop_bb;
|
||||
} else {
|
||||
|
@ -336,12 +394,12 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
|||
let var_assignment = ctx.var_assignment.clone();
|
||||
|
||||
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");
|
||||
let test_bb = ctx.ctx.append_basic_block(current, "while.test");
|
||||
let body_bb = ctx.ctx.append_basic_block(current, "while.body");
|
||||
let cont_bb = ctx.ctx.append_basic_block(current, "while.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") };
|
||||
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "while.orelse") };
|
||||
// store loop bb information and restore it later
|
||||
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
|
@ -399,15 +457,15 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
|||
let var_assignment = ctx.var_assignment.clone();
|
||||
|
||||
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 test_bb = ctx.ctx.append_basic_block(current, "if.test");
|
||||
let body_bb = ctx.ctx.append_basic_block(current, "if.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 = Some(ctx.ctx.append_basic_block(current, "if.cont"));
|
||||
cont_bb.unwrap()
|
||||
} else {
|
||||
ctx.ctx.append_basic_block(current, "orelse")
|
||||
ctx.ctx.append_basic_block(current, "if.orelse")
|
||||
};
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
ctx.builder.position_at_end(test_bb);
|
||||
|
@ -655,7 +713,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
|||
let mut final_data = None;
|
||||
let has_cleanup = !finalbody.is_empty();
|
||||
if has_cleanup {
|
||||
let final_state = generator.gen_var_alloc(ctx, ptr_type.into())?;
|
||||
let final_state = generator.gen_var_alloc(ctx, ptr_type.into(), Some("try.final_state.addr"))?;
|
||||
final_data = Some((final_state, Vec::new(), Vec::new()));
|
||||
if let Some((continue_target, break_target)) = ctx.loop_target {
|
||||
let break_proxy = ctx.ctx.append_basic_block(current_fun, "try.break");
|
||||
|
@ -821,7 +879,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
|||
ctx.builder.position_at_end(handler_bb);
|
||||
if let Some(name) = name {
|
||||
let exn_ty = ctx.get_llvm_type(generator, type_.as_ref().unwrap().custom.unwrap());
|
||||
let exn_store = generator.gen_var_alloc(ctx, exn_ty)?;
|
||||
let exn_store = generator.gen_var_alloc(ctx, exn_ty, Some("try.exn_store.addr"))?;
|
||||
ctx.var_assignment.insert(*name, (exn_store, None, 0));
|
||||
ctx.builder.build_store(exn_store, exn.as_basic_value());
|
||||
}
|
||||
|
@ -842,7 +900,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
|||
.builder
|
||||
.build_load(exn_type.into_pointer_value(), "expected_id")
|
||||
.into_int_value();
|
||||
let result = ctx.builder.build_int_compare(EQ, actual_id, expected_id, "exncheck");
|
||||
let result = ctx.builder.build_int_compare(IntPredicate::EQ, actual_id, expected_id, "exncheck");
|
||||
ctx.builder.build_conditional_branch(result, handler_bb, dispatcher_cont);
|
||||
dispatcher_end = dispatcher_cont;
|
||||
} else {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# For Loop using an increasing range() expression as its iterable
|
||||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
for _ in range(10):
|
||||
output_int32(_)
|
||||
_ = 0
|
||||
i = 0
|
||||
for i in range(10):
|
||||
output_int32(i)
|
||||
output_int32(i)
|
||||
return 0
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# For Loop using a decreasing range() expression as its iterable
|
||||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
i = 0
|
||||
for i in range(10, 0, -1):
|
||||
output_int32(i)
|
||||
output_int32(i)
|
||||
return 0
|
|
@ -0,0 +1,17 @@
|
|||
# For Loop using a list as its iterable
|
||||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
l = [0, 1, 2, 3, 4]
|
||||
|
||||
# i: int32 # declaration-without-initializer not yet supported
|
||||
i = 0 # i must be declared before the loop; this is not necessary in Python
|
||||
for i in l:
|
||||
output_int32(i)
|
||||
i = 0
|
||||
output_int32(i)
|
||||
output_int32(i)
|
||||
return 0
|
|
@ -0,0 +1,14 @@
|
|||
# For Loop using an range() expression as its iterable, additionally reassigning the target on each iteration
|
||||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
i = 0
|
||||
for i in range(10):
|
||||
output_int32(i)
|
||||
i = 0
|
||||
output_int32(i)
|
||||
output_int32(i)
|
||||
return 0
|
Loading…
Reference in New Issue