This generates rather more code than necessary, but has
the advantage of automatically handling incomplete
multi-dimensional subscripts which still leave arrays
behind.
Lists and arrays no longer have the same representation all
the way through codegen, as used to be the case.
This could/should be made more efficient later, eliding the
temporary copies.
Left generic transpose (shape order inversion) for now, as that
would be less ugly if we implement forwarding to Python function
bodies for array function implementations.
Needs a runtime test case.
LLVM will take care of optimising the loops. This was still
unnecessarily painful; implementing generics and implementing
this in ARTIQ Python looks very attractive right now.
Relies on the runtime to provide the necessary
(libm-compatible) functions.
The test is nifty, but a bit brittle; if this breaks in the
future because of optimizer changes, do not hesitate to convert
this into a more pedestrian test case.
So far, this is not exposed to the user beyond implicit conversions.
Note that all the implicit conversions, such as triggered by adding
arrays of mismatching types, or dividing integer arrays, are currently
emitted in a maximally inefficient way, where a temporary copy is first
made for the type conversion. The conversions would more sensibly be
implemented during the per-element operations to save on the extra
copies, but the current behaviour fell out of the rest of the IR
generator structure without extra changes.
Matches NumPy. Slicing a TList reallocates, this doesn't; offsetting
couldn't be handled in the IR without introducing new semantics
(the Alloc kludge; could/should be made its own IR type).
Still needs support through all the rest of the compiler, and
support for higher-dimensional arrays.
Alternatively, we could always assume ndarrays of ndarrays
are rectangular (i.e. ban array/list element types), and
detect mismatch at runtime. This might turn out to be
preferrable to be able to construct matrices from rows/columns.
`array()` is disallowed for no particularly good reason but
numpy API compatibility.
This reverts commits f8d1506922
and cf19c9512d.
While the commit just fixes a clear typo in the implementation,
it turns out the original algorithm isn't flexible enough to
capture functions that transitively return references to
long-lived data. For instance, while cache_get() is special-cased
in the compiler to be recognised as returning a value of Global()
lifetime, a function just forwarding to it (as seen in the
embedding tests) isn't anymore.
A separate issue is also that this makes implementing functions
that take lists and return references to global data in user code
impossible, which central parts of the Oxford codebase rely on.
Just reverting for now to unblock master; a fix is easily designed,
but needs testing.
Interestingly enough, these actually seem to give a measurable
speedup (if small – about 1% improvement out of 6s whole-program
compile-time in one particular test case).
The previous implementation of is_mono() had also interesting
behaviour if `name` wasn't given; it would test only for the
presence of any keys specified via keyword arguments,
disregarding their values. Looking at uses across the current
ARTIQ codebase, I could neither find a case where this would
have actually been triggered, nor any rationale for it.
With the short-circuited implementation from this commit,
is_mono() now checks name/all of params against any specified
conditions.
This was mistakenly included in fb2b634c4a, and broke the test
case verifying that using None as an ARTIQ type annotation in fact
generates an error message.
With support for polymorphism (or type erasure on pointers to
member functions) being absent in the ARTIQ compiler, code
generation is vital to be able to implement abstractions that
work with user-provided lists/trees of objects with uniform
interfaces (e.g. a common base class, or duck typing), but
different concrete types.
@kernel_from_string has been in production use for exactly
this use case in Oxford for the better part of a year now
(various places in ndscan).
GitHub: Fixes#1089.
`var_type` was presumably intended to convert to a target type,
but wasn't actually acted on in the function body (nor was it
used anywhere in the codebase).
This reverts 425cd7851, which broke the use of casts to define
integer width.
Instead of it, two steps are taken:
* First, literals are monomorphized, leading to predictable result.
* Second, casts are monomorphized, in a top-bottom way. I.e.
consider the expression `int64(round(x))`. If round() was visited
first, the intermediate precision would be 32-bit, which is
clearly undesirable. Therefore, contextual rules should take
priority over non-contextual ones.
Fixes#1252.
async is now a full (non-contextual) keyword.
There are two more instances:
- artiq/frontend/artiq_client.py
- artiq/devices/thorlabs_tcube/driver.py
It is not immediately clear how to fix those, so they are left for
later work.
For instance, TTuple(TList(TInt32())) has indirections, while
TTuple(TInt32()) does not.
This fixes memory corruption with RPCs that return tuples of lists.
Signed-off-by: David Nadlinger <code@klickverbot.at>
This fixes access violations on Windows that are present both with
input and output files. For some reason, Cygwin-compiled binutils
did not exhibit this problem, but MSYS-compiled binutils do.
Fixes#961.
Otherwise, declarations such as:
@syscall(flags={"nounwind", "nowrite"})
def foo(...):
trip an LLVM assert because the invoke instruction and the !tbaa
metadata are no longer compatible since LLVM 4.0.
Consider delay(8*us). It results in the following computation...
>>> 8*1e-06/1e-09
7999.999999999999
with the result promptly getting truncated to 7999.
Fixes#706.
Before this commit, we had a hack where inferencing would run
one more time, in case we can still infer more attributes even
after all the type information is there. This doesn't work
if *that* round of inferencing brings even more code, e.g.
this is easy to trigger with context managers.
Before this commit, the following code would fail to compile...
obj.foo.bar = True
... if foo is marked kernel_invariant in obj, even if bar is not
marked as such in obj.foo.