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:
parent
cc769a7006
commit
e710b6c320
|
@ -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,
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in New Issue