Inlining manifesto #1895
Replies: 1 comment
|
Very nice definitions! The use case for
On a second thought, I don't think this is desirable, as it can expose non-public implementation details through a backdoor/trampoline. So Non-transitive inliningI'm not sure if the use case is really useful for optimizations, but I can also imagine that we want to inline a function on its first 1-2 layers, but preserve some leaf calls as non-inlined. This could allow using |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This document describes the design I have in mind for the inlining feature(s) of Hylo. Because inlining relates to resilience and visibility, the document also touches on my vision for Hylo's access control system.
Goals
Definitions
A resilience boundary describes a conceptual boundary between two sets of symbols. The definition (e.g., contents of a function) of a symbol from one side of the boundary is not visible from the other side of the boundary. As a consequence, one cannot (in general) inline the contents of a function or determine the memory footprint of a type defined across a resilience boundary.
Note: In the context of Hylo, a resilience boundary is typically raised around the symbols of a module when that module is compiled with resilience enabled. We reserve the option to introduce other means to define resilience boundaries in the future.
A symbol is exposed if its declaration is accessible across a resilience boundary, or if it has been exposed explicitly with an annotation.
Note: intuitively, exposed symbols include those defined at the top level of a module and symbols whose qualification is also exposed.
A symbol is inlineable if its definition can be accessed across a resilience boundary. Inlineability imposes that the definition of the symbol itself can only refer to exposed symbols.
Access control
By default, all symbols in Hylo are private to the file in which they have been defined. This default can be overridden with the access modifier
public, which makes a symbol accessible from outside the scope of its definition. The access modifierinternalas the same effect aspublicexcept that it does not expose symbols.The following illustrates. We assume that
m0.a.hyloandm0.b.hyloare sources files in some moduleM, and thatm1.hylois a source file in some other module.Note: intuitively, a symbol is exposed iff it is public and all the scopes in which it is enclosed are public as well.
Inlining
By default, the compiler inlines definitions in optimized builds according to some unspecified heuristics, if possible. No definition is inlined in debug builds by default. This behavior can be overridden with the following annotations:
@inline(never): specifies that a function should never be inlined.@inline(short for@inline(always)): specifies that a function must be inlined.A symbol may have only one occurrence of the annotation
@inline(policy).@inline(always)imposes a requirement on the symbol's definition, meaning that the compiler will emit an error diagnostic if that requirement cannot be upheld. Specifically,@inline(always)requires that:The following illustrates:
Relationship to monomorphization
Inlining does not mandate monomorphization. Nonetheless, the definition of a generic function declared with
@inline(always)will be inlined, whether it is existentialized or monomorphized.In the future, we could introduce other annotations controlling monomorphization in a similar fashion as inlining:
@monomorphize(never)would specifiy that the function/type must be existentialized.@monomorphize(always)would specify that the function/type must be monomorphized.Note that
@monomorphize(policy)and@inline(policy)would be orthogonal in this hypothetical system.Exposure
It may be desirable to allow or mandate the inlining of a function across a resilience boundary even if it uses symbols that are not exposed. In this case, one can use the annotation
@exposedto specify that a symbol may be used from an inlined definition, regardless of its accessibility.@exposedimposes a requirement on the symbol's definition, meaning that the compiler will emit an error diagnostic if that requirement cannot be upheld.To illustrate, we can modify the previous example to mandate the inlining of
zim:Note:
@inline(always)does not imply inlineability; it only requires it.Note:
@inline(always)does not mandate exposure, and vice versa.The annotation
@exposedalso applies on struct and enum declarations, specifying that their layout is visible across function boundaries. Again, the annotation imposes a requirement that is verified by the compiler. Specifically, all stored properties of a type introduced by an exposed declaration must be exposed.Transparency
The annotation
@transparentspecifies that a function must be inlined and debugging should skip over its definition when stepping through the calling function.Note:
@transparentimplies@inline(always).All reactions