1
0
forked from M-Labs/nac3

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 // return target bb, just emit ret if no such target
pub return_target: Option<BasicBlock<'ctx>>, pub return_target: Option<BasicBlock<'ctx>>,
pub return_buffer: Option<PointerValue<'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 // outer catch clauses
pub outer_catch_clauses: pub outer_catch_clauses:
Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>, Option<(Vec<Option<BasicValueEnum<'ctx>>>, BasicBlock<'ctx>, PhiValue<'ctx>)>,
@ -498,7 +496,6 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
return_target: None, return_target: None,
return_buffer, return_buffer,
unwind_target: None, unwind_target: None,
outer_final: None,
outer_catch_clauses: None, outer_catch_clauses: None,
const_strings: Default::default(), const_strings: Default::default(),
registry, registry,

View File

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