Open neon64 opened 2 years ago
This is also an issue for compile time garbage collection.
Mutate instructions contain the size of the structure, and offset, and the size of the field being overwritten, so it is quite possible to see that the mutations do not overlap.
I found an annoying limitation of current analysis, when we start defining recursive data structures the "unexpected way".
For example: suppose we define our list type in the reverse order, i.e.: the element comes after the tail of the list.
type revlist(T) { pub empty | some(tail: revlist(T), elem: T) }
Then the following
append
proc isn't eligible for TCMC optimization under the current implementation.Here's why:
reverse_append.append<0>
down as far as possible, until we reach a prim which uses one of the outputs from the recursive callalloc()
, but not below the first of twomutate()
s, since the first mutate uses thetail
from the recursive call (rather than setting the headh
)mutate(..., ..., ..., h)
would be the first mutate (since fields are initialized in order of declaration), and the recursive call would be moved below it without a problem.Fortunately this isn't so bad in practice, since all the major data structures (lists, trees, etc...) tend to have the convention that the "value" is the first field. However in principle this is an arbitrary limitation to the optimization.
Ideally we want to realise that since the two mutates are writing to non-overlapping fields, it doesn't matter which order we do them. From analyzing the assignments/uses of variables, this is not obvious, since mutate effectively consumes a value and then emits a new one, there is an explicit ordering of variables. i.e.:
mutate(tmp#6, ?tmp#7,...)
must come beforemutate(~tmp#7, ?result,...)
sincetmp#7
was created by the first mutate. However it should be possible to keep the first two args of the mutates the same, and just swap around which values are being written to which fieldbecomes
The concept of "mutate chains" (which is used internally in the implementation) already captures this idea, we just need to make tryMovePrimAfterPrims smart enough to realise that mutates within a single "chain" can be reordered.