forked from M-Labs/artiq
transforms.artiq_ir_generator: handle `raise` in `except:` with `finally:`.
This commit is contained in:
parent
05bdd5c4a9
commit
5f68cc6a21
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue