diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index c6ae59704..7d2395830 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -102,8 +102,20 @@ class RegionOf(algorithm.Visitor): if types.is_external_function(node.func.type, "cache_get"): # The cache is borrow checked dynamically return Global() - else: - self.visit_sometimes_allocating(node) + + if (types.is_builtin_function(node.func.type, "array") + or types.is_builtin_function(node.func.type, "make_array") + or types.is_builtin_function(node.func.type, "numpy.transpose")): + # While lifetime tracking across function calls in general is currently + # broken (see below), these special builtins that allocate an array on + # the stack of the caller _always_ allocate regardless of the parameters, + # and we can thus handle them without running into the precision issue + # mentioned in commit ae999db. + return self.visit_allocating(node) + + # FIXME: Return statement missing here, but see m-labs/artiq#1497 and + # commit ae999db. + self.visit_sometimes_allocating(node) # Value lives as long as the object/container, if it's mutable, # or else forever diff --git a/artiq/test/lit/escape/error_numpy_array.py b/artiq/test/lit/escape/error_numpy_array.py new file mode 100644 index 000000000..1ebdeda81 --- /dev/null +++ b/artiq/test/lit/escape/error_numpy_array.py @@ -0,0 +1,15 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.experiment import * +import numpy as np + +@kernel +def a(): + # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever + # CHECK-L: ${LINE:+1}: note: ... to this point + return np.array([0, 1]) + +@kernel +def entrypoint(): + a() diff --git a/artiq/test/lit/escape/error_numpy_full.py b/artiq/test/lit/escape/error_numpy_full.py new file mode 100644 index 000000000..66158d8ca --- /dev/null +++ b/artiq/test/lit/escape/error_numpy_full.py @@ -0,0 +1,16 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.experiment import * +import numpy as np + +@kernel +def a(): + # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever + # CHECK-L: ${LINE:+1}: note: ... to this point + return np.full(10, 42.0) + + +@kernel +def entrypoint(): + a() diff --git a/artiq/test/lit/escape/error_numpy_transpose.py b/artiq/test/lit/escape/error_numpy_transpose.py new file mode 100644 index 000000000..e1dc32d51 --- /dev/null +++ b/artiq/test/lit/escape/error_numpy_transpose.py @@ -0,0 +1,17 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.experiment import * +import numpy as np + +data = np.array([[0, 1], [2, 3]]) + +@kernel +def a(): + # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever + # CHECK-L: ${LINE:+1}: note: ... to this point + return np.transpose(data) + +@kernel +def entrypoint(): + a() diff --git a/doc/manual/compiler.rst b/doc/manual/compiler.rst index e4923dfa9..88b57d814 100644 --- a/doc/manual/compiler.rst +++ b/doc/manual/compiler.rst @@ -95,24 +95,6 @@ tracked across function calls (see `#1497