forked from M-Labs/artiq
1
0
Fork 0

compiler: fixed exception codegen issues

This commit is contained in:
pca006132 2022-01-10 15:21:39 +08:00 committed by Sébastien Bourdeauducq
parent 9f90088fa6
commit 6542b65db3
2 changed files with 34 additions and 4 deletions

View File

@ -1360,6 +1360,14 @@ class LandingPad(Terminator):
def cleanup(self): def cleanup(self):
return self.operands[0] 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): def clauses(self):
return zip(self.operands[1:], self.types) return zip(self.operands[1:], self.types)

View File

@ -626,6 +626,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.final_branch(raise_proxy, self.current_block) self.final_branch(raise_proxy, self.current_block)
self.current_block = raise_proxy 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: if exn is not None:
assert loc is not None assert loc is not None
loc_file = ir.Constant(loc.source_buffer.name, builtins.TStr()) loc_file = ir.Constant(loc.source_buffer.name, builtins.TStr())
@ -650,9 +655,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
def visit_Raise(self, node): def visit_Raise(self, node):
if node.exc is not None and types.is_exn_constructor(node.exc.type): 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: 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): def visit_Try(self, node):
dispatcher = self.add_block("try.dispatch") dispatcher = self.add_block("try.dispatch")
@ -671,6 +676,15 @@ class ARTIQIRGenerator(algorithm.Visitor):
final_targets.append(target) final_targets.append(target)
final_paths.append(block) 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: 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
@ -714,7 +728,7 @@ 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 old_final_branch, self.final_branch = self.final_branch, exception_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))
@ -745,6 +759,14 @@ class ARTIQIRGenerator(algorithm.Visitor):
# Finalize and continue after try statement. # Finalize and continue after try statement.
self.final_branch = old_final_branch 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") finalizer = self.add_block("finally")
self.current_block = finalizer self.current_block = finalizer
@ -997,7 +1019,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
old_final_branch, self.final_branch = self.final_branch, None old_final_branch, self.final_branch = self.final_branch, None
old_unwind, self.unwind_target = self.unwind_target, 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: finally:
self.current_function = old_func self.current_function = old_func
self.current_block = old_block self.current_block = old_block