forked from M-Labs/artiq
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.
This commit is contained in:
parent
1f40f3ce15
commit
be4669d7a5
|
@ -1474,19 +1474,22 @@ class LLVMIRGenerator:
|
||||||
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
||||||
|
|
||||||
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
||||||
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
llcall = self.llbuilder.invoke(llfun, [llresultslot] + llargs,
|
||||||
name=insn.name)
|
llnormalblock, llunwindblock, name=insn.name)
|
||||||
|
|
||||||
|
self.llbuilder.position_at_start(llnormalblock)
|
||||||
llresult = self.llbuilder.load(llresultslot)
|
llresult = self.llbuilder.load(llresultslot)
|
||||||
|
|
||||||
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
||||||
else:
|
else:
|
||||||
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
|
llresult = llcall
|
||||||
|
|
||||||
# The !tbaa metadata is not legal to use with the invoke instruction,
|
# The !tbaa metadata is not legal to use with the invoke instruction,
|
||||||
# so unlike process_Call, we do not set it here.
|
# 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):
|
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
|
||||||
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
||||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue