From c1733eef49ba3c1a333992d780753ebdc3de34f4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 21 Mar 2021 01:31:26 +0000 Subject: [PATCH] compiler: Fix crash with try/finally and stack-return function calls The previous code could have never worked as-is, as the result slot went unused, and it tried to append the load instruction to the block just terminated with the invoke. GitHub: Fixes #1506, #1531. --- .../compiler/transforms/llvm_ir_generator.py | 9 ++-- artiq/test/lit/regression/issue_1506.py | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 artiq/test/lit/regression/issue_1506.py diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 4dfb37cc7..49bbebc57 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1474,19 +1474,22 @@ class LLVMIRGenerator: llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), []) llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee) - llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, - name=insn.name) + llcall = self.llbuilder.invoke(llfun, [llresultslot] + llargs, + llnormalblock, llunwindblock, name=insn.name) + + self.llbuilder.position_at_start(llnormalblock) llresult = self.llbuilder.load(llresultslot) self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) else: llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, name=insn.name) + llresult = llcall # The !tbaa metadata is not legal to use with the invoke instruction, # so unlike process_Call, we do not set it here. - return llcall + return llresult def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name): llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)]) diff --git a/artiq/test/lit/regression/issue_1506.py b/artiq/test/lit/regression/issue_1506.py new file mode 100644 index 000000000..88d8831bd --- /dev/null +++ b/artiq/test/lit/regression/issue_1506.py @@ -0,0 +1,44 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +# +# Check various sret-ized return types integrate properly with try/finally, which lowers +# to `invoke` on the LLVM level (code adapted from GitHub #1506). +# + +LIST = [1, 2] + + +def get_tuple(): + return (1, 2) + + +def get_list(): + return LIST + + +def get_range(): + return range(10) + + +def main(): + try: + a, b = get_tuple() + assert a == 1 + assert b == 2 + finally: + pass + + try: + for _ in get_list(): + pass + finally: + pass + + try: + for _ in get_range(): + pass + finally: + pass + + +main()