Projection ABI #1718
Replies: 2 comments 2 replies
-
I'll also add a few notes here to keep as a memo. Those are not direct answers to nor a rebuttal of Dave's points. Inversion of control using higher-order functions is not as expressive as subscripts Consider this example:
Here the last use of It is probably not possible to predict the size of a stack frame in general Consider this example:
There has been discussions of lowering subscripts so that there's a symbol next to the corresponding function that tells about the size of its frame. But it is not possible to compute such a size AoT here because it is function of Also, perhaps even more simply, I think we can't compute frame sizes for recursive subscripts. It is only the memory acquired in the ramp and released in a slide that is problematic If subscripts are lowered as a pair of functions (one slide and one ramp), then it is only the memory that must persists until the second function is called that is problematic (insofar as it may require dynamic allocation). It is probably impossible to eliminate dynamic allocation completely If we're gonna support existential containers, or any similar form of data abstraction, then I think there is no way to completely eliminate dynamic allocation from the language. If that is the case, then I believe we should provide users with ways to predict exactly when dynamic allocation will occur and teach them refactoring techniques to avoid them. I am concerned about any compilation scheme relying heavily on higher-order-functions It is my understanding that higher-order functions tend to obscure the code for optimizers, which hinders very important optimizations, like scalar replacement of aggregates and memory to register promotion. To illustrate, consider this silly example:
The important bits are that:
Using what I understood to be Dave's suggestion, one issue I can see is that the local lambda that will be passed to the subscript will have to close over Note that the same issue arises around the ephemeral value Anyways, I believe this issue suggests that there is no free lunch when it comes to optimizing subscripts without arbitrary inlining. Specifically we'll have to sacrifice some optimizations to abstract over the two parts of a subscript (the slide and the ramp). Whether or not it is better to come up with a model that guarantee freedom from dynamic allocation in general at the cost of other optimizations is a very interesting research question, and I clearly do not have the answer. |
Beta Was this translation helpful? Give feedback.
-
It's worth noting that through discussion in our weekly meetings, this scheme is now the plan of record. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I wanted to write this all down in advance of our discussion Thursday so I wouldn't forget any of it, and so, hopefully, my concerns and idea will be clear before we start.
Here's what I'm after: I want the generalized projection model that supports ephemeral values to be a first class citizen. For example, I want to be able to satisfy standard library protocols like
Collection
with types that project ephemeral values. I note that slices are ephemeral. I want to be able to do generalized projection with a guarantee of no dynamic allocation, so that it is usable without a dynamically allocating runtime. I want Hylo to retain an efficient before-optimization compilation model.I'm happy to bake "addressor-ness" into the ABI/API of specific types like
Array
and I think we should. I have no objection to any plan that gets the language functioning in the short term—this post is about long-term direction.The current plan, which depends for basic efficiency on being able to know how much stack memory will be needed during any given projection, does not achieve what I'm after. Resilience boundaries, recursion, and existentials all create situations where the current plan cannot avoid dynamic allocation.
I am also concerned about the cases where we can potentially use addressors because it is my impression that:
Admittedly these bullets are all impressions, and certainly Swift does the latter thing all the time. But I do have the impression that it's hard—partly from my experience working with the people who had to implement those things fro Swift.
I think I see how to avoid these problems using a variation of the higher-order function technique that we've often said in talks, not-quite-accurately, is equivalent to our subscripts. It goes like this:
For the purposes of this discussion, I'm going to define the concept of a "local lambda:" it's just a non-escaping function pointer bundled with a referene that allows access to the locals of some surrounding function.
A projection accessor is then a function that accepts a local lambda from its client. This lambda represents the client code until the end of the scope where the projection is initiated (the length can be narrowed by in many cases, but it never extends beyond the end of the scope). This lambda itself accepts another lambda representing the slide (the code in the projection accessor after the yield,) which the first lambda invokes when the lifetime of the projection ends. Later projections in the client scope cause a similar breaking up of the first local lambda into other local lambdas.
That's it. I hope this ends up being helpful. Thanks for reading.
-Dave
Beta Was this translation helpful? Give feedback.
All reactions