forked from M-Labs/nac3
1
0
Fork 0

nac3core: fix exception final branch handling

According to https://github.com/m-labs/artiq/pull/1855
Passed the test cases from 1855.
Fixes #196.
This commit is contained in:
pca006132 2022-02-25 13:59:53 +08:00
parent cc769a7006
commit e710b6c320
2 changed files with 14 additions and 21 deletions

View File

@ -71,8 +71,6 @@ pub struct CodeGenContext<'ctx, 'a> {
// return target bb, just emit ret if no such target
pub return_target: Option<BasicBlock<'ctx>>,
pub return_buffer: Option<PointerValue<'ctx>>,
// outer finally block function
pub outer_final: Option<(PointerValue<'ctx>, Vec<BasicBlock<'ctx>>, Vec<BasicBlock<'ctx>>)>,
// outer catch clauses
pub outer_catch_clauses:
Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>,
@ -498,7 +496,6 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
return_target: None,
return_buffer,
unwind_target: None,
outer_final: None,
outer_catch_clauses: None,
const_strings: Default::default(),
registry,

View File

@ -407,8 +407,9 @@ pub fn final_proxy<'ctx, 'a>(
ctx: &mut CodeGenContext<'ctx, 'a>,
target: BasicBlock<'ctx>,
block: BasicBlock<'ctx>,
final_data: &mut (PointerValue, Vec<BasicBlock<'ctx>>, Vec<BasicBlock<'ctx>>),
) {
let (final_state, final_targets, final_paths) = ctx.outer_final.as_mut().unwrap();
let (final_state, final_targets, final_paths) = final_data;
let prev = ctx.builder.get_insert_block().unwrap();
ctx.builder.position_at_end(block);
unsafe {
@ -593,34 +594,32 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
let mut cleanup = None;
let mut old_loop_target = None;
let mut old_return = None;
let mut old_outer_final = None;
let has_cleanup = if !finalbody.is_empty() {
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())?;
old_outer_final = ctx.outer_final.replace((final_state, Vec::new(), Vec::new()));
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");
let continue_proxy = ctx.ctx.append_basic_block(current_fun, "try.continue");
final_proxy(ctx, break_target, break_proxy);
final_proxy(ctx, continue_target, continue_proxy);
final_proxy(ctx, break_target, break_proxy, final_data.as_mut().unwrap());
final_proxy(ctx, continue_target, continue_proxy, final_data.as_mut().unwrap());
old_loop_target = ctx.loop_target.replace((continue_proxy, break_proxy));
}
let return_proxy = ctx.ctx.append_basic_block(current_fun, "try.return");
if let Some(return_target) = ctx.return_target {
final_proxy(ctx, return_target, return_proxy);
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
} else {
let return_target = ctx.ctx.append_basic_block(current_fun, "try.return_target");
ctx.builder.position_at_end(return_target);
let return_value = ctx.return_buffer.map(|v| ctx.builder.build_load(v, "$ret"));
ctx.builder.build_return(return_value.as_ref().map(|v| v as &dyn BasicValue));
ctx.builder.position_at_end(current_block);
final_proxy(ctx, return_target, return_proxy);
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
}
old_return = ctx.return_target.replace(return_proxy);
cleanup = Some(ctx.ctx.append_basic_block(current_fun, "try.cleanup"));
true
} else {
ctx.outer_final.is_some()
};
}
let mut clauses = Vec::new();
let mut found_catch_all = false;
@ -691,7 +690,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
let mut final_proxy_lambda =
|ctx: &mut CodeGenContext<'ctx, 'a>,
target: BasicBlock<'ctx>,
block: BasicBlock<'ctx>| final_proxy(ctx, target, block);
block: BasicBlock<'ctx>| final_proxy(ctx, target, block, final_data.as_mut().unwrap());
let mut redirect_lambda = |ctx: &mut CodeGenContext<'ctx, 'a>,
target: BasicBlock<'ctx>,
block: BasicBlock<'ctx>| {
@ -699,7 +698,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
ctx.builder.build_unconditional_branch(target);
ctx.builder.position_at_end(body);
};
let redirect = if ctx.outer_final.is_some() {
let redirect = if has_cleanup {
&mut final_proxy_lambda
as &mut dyn FnMut(&mut CodeGenContext<'ctx, 'a>, BasicBlock<'ctx>, BasicBlock<'ctx>)
} else {
@ -842,9 +841,6 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
}
ctx.builder.position_at_end(tail);
} else {
let final_branches = ctx.outer_final.take().unwrap();
ctx.outer_final = old_outer_final;
// exception path
let cleanup = cleanup.unwrap();
ctx.builder.position_at_end(cleanup);
@ -855,7 +851,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
}
// normal path
let (final_state, mut final_targets, final_paths) = final_branches;
let (final_state, mut final_targets, final_paths) = final_data.unwrap();
let tail = ctx.ctx.append_basic_block(current_fun, "try.tail");
final_targets.push(tail);
let finalizer = ctx.ctx.append_basic_block(current_fun, "try.finally");