From 90be44c596d97c60853c6104f8d476be15e9fac4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 27 Jul 2015 10:13:22 +0300 Subject: [PATCH] Add tests for non-exceptional control flow across finally. --- artiq/compiler/ir.py | 5 +- .../transforms/dead_code_eliminator.py | 4 ++ lit-test/test/integration/finally.py | 64 +++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 lit-test/test/integration/finally.py diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index 94679fd18..3a00c7335 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -292,7 +292,7 @@ class BasicBlock(NamedValue): def erase(self): # self.instructions is updated while iterating - for insn in list(self.instructions): + for insn in reversed(self.instructions): insn.erase() self.remove_from_parent() # Check this after erasing instructions in case the block @@ -997,7 +997,8 @@ class Raise(Terminator): return self.operands[0] def exception_target(self): - return self.operands[1] + if len(self.operands) > 1: + return self.operands[1] class Invoke(Terminator): """ diff --git a/artiq/compiler/transforms/dead_code_eliminator.py b/artiq/compiler/transforms/dead_code_eliminator.py index 1d4e08f6f..003b8561c 100644 --- a/artiq/compiler/transforms/dead_code_eliminator.py +++ b/artiq/compiler/transforms/dead_code_eliminator.py @@ -25,6 +25,10 @@ class DeadCodeEliminator: use.remove_incoming_block(block) if not any(use.operands): self.remove_instruction(use) + elif isinstance(use, ir.SetLocal): + # Setting the target for `finally` resumption, e.g. + # setlocal(.k) %v.4, label %try.doreturn + use.erase() else: assert False diff --git a/lit-test/test/integration/finally.py b/lit-test/test/integration/finally.py new file mode 100644 index 000000000..376051e66 --- /dev/null +++ b/lit-test/test/integration/finally.py @@ -0,0 +1,64 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s +# RUN: %python %s +# REQUIRES: exceptions + +def f(): + while True: + try: + print("f-try") + break + finally: + print("f-finally") + print("f-out") + +# CHECK-L: f-try +# CHECK-L: f-finally +# CHECK-L: f-out +f() + +def g(): + x = True + while x: + try: + print("g-try") + x = False + continue + finally: + print("g-finally") + print("g-out") + +# CHECK-L: g-try +# CHECK-L: g-finally +# CHECK-L: g-out +g() + +def h(): + try: + print("h-try") + return 10 + finally: + print("h-finally") + print("h-out") + return 20 + +# CHECK-L: h-try +# CHECK-L: h-finally +# CHECK-NOT-L: h-out +# CHECK-L: h 10 +print("h", h()) + +def i(): + try: + print("i-try") + return 10 + finally: + print("i-finally") + return 30 + print("i-out") + return 20 + +# CHECK-L: i-try +# CHECK-L: i-finally +# CHECK-NOT-L: i-out +# CHECK-L: i 30 +print("i", i())