transforms.artiq_ir_generator: handle `raise` in `except:` with `finally:`.

This commit is contained in:
whitequark 2016-01-02 06:51:14 +08:00
parent 05bdd5c4a9
commit 5f68cc6a21
1 changed files with 27 additions and 13 deletions

View File

@ -66,6 +66,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
the basic block to which ``return`` will transfer control the basic block to which ``return`` will transfer control
:ivar unwind_target: (:class:`ir.BasicBlock` or None) :ivar unwind_target: (:class:`ir.BasicBlock` or None)
the basic block to which unwinding will transfer control the basic block to which unwinding will transfer control
:ivar final_branch: (function (target: :class:`ir.BasicBlock`, block: :class:`ir.BasicBlock)
or None)
the function that appends to ``block`` a jump through the ``finally`` statement
to ``target``
There is, additionally, some global state that is used to translate There is, additionally, some global state that is used to translate
the results of analyses on AST level to IR level: the results of analyses on AST level to IR level:
@ -102,6 +106,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.continue_target = None self.continue_target = None
self.return_target = None self.return_target = None
self.unwind_target = None self.unwind_target = None
self.final_branch = None
self.function_map = dict() self.function_map = dict()
self.variable_map = dict() self.variable_map = dict()
self.method_map = defaultdict(lambda: []) self.method_map = defaultdict(lambda: [])
@ -551,6 +556,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.append(ir.Branch(self.continue_target)) self.append(ir.Branch(self.continue_target))
def raise_exn(self, exn, loc=None): def raise_exn(self, exn, loc=None):
if self.final_branch is not None:
raise_proxy = self.add_block("try.raise")
self.final_branch(raise_proxy, self.current_block)
self.current_block = raise_proxy
if exn is not None: if exn is not None:
if loc is None: if loc is None:
loc = self.current_loc loc = self.current_loc
@ -588,29 +598,32 @@ class ARTIQIRGenerator(algorithm.Visitor):
vars={ "$k": ir.TBasicBlock() }) vars={ "$k": ir.TBasicBlock() })
final_state = self.append(ir.Alloc([], final_env_type)) final_state = self.append(ir.Alloc([], final_env_type))
final_targets = [] final_targets = []
final_paths = []
def final_branch(target, block):
block.append(ir.SetLocal(final_state, "$k", target))
final_targets.append(target)
final_paths.append(block)
if self.break_target is not None: if self.break_target is not None:
break_proxy = self.add_block("try.break") break_proxy = self.add_block("try.break")
old_break, self.break_target = self.break_target, break_proxy old_break, self.break_target = self.break_target, break_proxy
break_proxy.append(ir.SetLocal(final_state, "$k", old_break)) final_branch(old_break, break_proxy)
final_targets.append(old_break)
if self.continue_target is not None: if self.continue_target is not None:
continue_proxy = self.add_block("try.continue") continue_proxy = self.add_block("try.continue")
old_continue, self.continue_target = self.continue_target, continue_proxy old_continue, self.continue_target = self.continue_target, continue_proxy
continue_proxy.append(ir.SetLocal(final_state, "$k", old_continue)) final_branch(old_continue, continue_proxy)
final_targets.append(old_continue)
return_proxy = self.add_block("try.return") return_proxy = self.add_block("try.return")
old_return, self.return_target = self.return_target, return_proxy old_return, self.return_target = self.return_target, return_proxy
if old_return is not None: if old_return is not None:
return_proxy.append(ir.SetLocal(final_state, "$k", old_return)) final_branch(old_return, return_proxy)
final_targets.append(old_return)
else: else:
return_action = self.add_block("try.doreturn") return_action = self.add_block("try.doreturn")
value = return_action.append(ir.GetLocal(self.current_private_env, "$return")) value = return_action.append(ir.GetLocal(self.current_private_env, "$return"))
return_action.append(ir.Return(value)) return_action.append(ir.Return(value))
return_proxy.append(ir.SetLocal(final_state, "$k", return_action)) final_branch(return_action, return_proxy)
final_targets.append(return_action)
body = self.add_block("try.body") body = self.add_block("try.body")
self.append(ir.Branch(body)) self.append(ir.Branch(body))
@ -635,6 +648,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.continue_target = old_continue self.continue_target = old_continue
self.return_target = old_return self.return_target = old_return
old_final_branch, self.final_branch = self.final_branch, final_branch
cleanup = self.add_block('handler.cleanup') cleanup = self.add_block('handler.cleanup')
landingpad = dispatcher.append(ir.LandingPad(cleanup)) landingpad = dispatcher.append(ir.LandingPad(cleanup))
@ -659,6 +674,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
handlers.append((handler, post_handler)) handlers.append((handler, post_handler))
if any(node.finalbody): if any(node.finalbody):
self.final_branch = old_final_branch
finalizer = self.add_block("finally") finalizer = self.add_block("finally")
self.current_block = finalizer self.current_block = finalizer
@ -673,11 +690,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
final_targets.append(tail) final_targets.append(tail)
final_targets.append(reraise) final_targets.append(reraise)
if self.break_target: for block in final_paths:
break_proxy.append(ir.Branch(finalizer)) block.append(ir.Branch(finalizer))
if self.continue_target:
continue_proxy.append(ir.Branch(finalizer))
return_proxy.append(ir.Branch(finalizer))
if not body.is_terminated(): if not body.is_terminated():
body.append(ir.SetLocal(final_state, "$k", tail)) body.append(ir.SetLocal(final_state, "$k", tail))