forked from M-Labs/artiq
compiler: fixed exception codegen issues
This commit is contained in:
parent
9f90088fa6
commit
6542b65db3
@ -1360,6 +1360,14 @@ class LandingPad(Terminator):
|
||||
def cleanup(self):
|
||||
return self.operands[0]
|
||||
|
||||
def erase(self):
|
||||
self.remove_from_parent()
|
||||
# we should erase all clauses as well
|
||||
for block in set(self.operands):
|
||||
block.uses.remove(self)
|
||||
block.erase()
|
||||
assert not any(self.uses)
|
||||
|
||||
def clauses(self):
|
||||
return zip(self.operands[1:], self.types)
|
||||
|
||||
|
@ -626,6 +626,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
self.final_branch(raise_proxy, self.current_block)
|
||||
self.current_block = raise_proxy
|
||||
|
||||
if exn is not None:
|
||||
# if we need to raise the exception in a final body, we have to
|
||||
# lazy-evaluate the exception object to make sure that we generate
|
||||
# it in the raise_proxy block
|
||||
exn = exn()
|
||||
if exn is not None:
|
||||
assert loc is not None
|
||||
loc_file = ir.Constant(loc.source_buffer.name, builtins.TStr())
|
||||
@ -650,9 +655,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
def visit_Raise(self, node):
|
||||
if node.exc is not None and types.is_exn_constructor(node.exc.type):
|
||||
self.raise_exn(self.alloc_exn(node.exc.type.instance), loc=self.current_loc)
|
||||
self.raise_exn(lambda: self.alloc_exn(node.exc.type.instance), loc=self.current_loc)
|
||||
else:
|
||||
self.raise_exn(self.visit(node.exc), loc=self.current_loc)
|
||||
self.raise_exn(lambda: self.visit(node.exc), loc=self.current_loc)
|
||||
|
||||
def visit_Try(self, node):
|
||||
dispatcher = self.add_block("try.dispatch")
|
||||
@ -671,6 +676,15 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
final_targets.append(target)
|
||||
final_paths.append(block)
|
||||
|
||||
final_exn_targets = []
|
||||
final_exn_paths = []
|
||||
# raise has to be treated differently
|
||||
# we cannot follow indirectbr for local access validation, so we
|
||||
# have to construct the control flow explicitly
|
||||
def exception_final_branch(target, block):
|
||||
final_exn_targets.append(target)
|
||||
final_exn_paths.append(block)
|
||||
|
||||
if self.break_target is not None:
|
||||
break_proxy = self.add_block("try.break")
|
||||
old_break, self.break_target = self.break_target, break_proxy
|
||||
@ -714,7 +728,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
self.continue_target = old_continue
|
||||
self.return_target = old_return
|
||||
|
||||
old_final_branch, self.final_branch = self.final_branch, final_branch
|
||||
old_final_branch, self.final_branch = self.final_branch, exception_final_branch
|
||||
|
||||
cleanup = self.add_block('handler.cleanup')
|
||||
landingpad = dispatcher.append(ir.LandingPad(cleanup))
|
||||
@ -745,6 +759,14 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
# Finalize and continue after try statement.
|
||||
self.final_branch = old_final_branch
|
||||
|
||||
for (i, (target, block)) in enumerate(zip(final_exn_targets, final_exn_paths)):
|
||||
finalizer = self.add_block(f"finally{i}")
|
||||
self.current_block = block
|
||||
self.terminate(ir.Branch(finalizer))
|
||||
self.current_block = finalizer
|
||||
self.visit(node.finalbody)
|
||||
self.terminate(ir.Branch(target))
|
||||
|
||||
finalizer = self.add_block("finally")
|
||||
self.current_block = finalizer
|
||||
|
||||
@ -997,7 +1019,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
old_final_branch, self.final_branch = self.final_branch, None
|
||||
old_unwind, self.unwind_target = self.unwind_target, None
|
||||
self.raise_exn(exn_gen(*args[1:]), loc=loc)
|
||||
self.raise_exn(lambda: exn_gen(*args[1:]), loc=loc)
|
||||
finally:
|
||||
self.current_function = old_func
|
||||
self.current_block = old_block
|
||||
|
Loading…
Reference in New Issue
Block a user