[swift-dev] statically initialized arrays

Joe Groff jgroff at apple.com
Mon Jun 19 11:04:41 CDT 2017


> On Jun 14, 2017, at 11:24 AM, Erik Eckstein via swift-dev <swift-dev at swift.org> wrote:
> 
> Hi,
> 
> I’m about implementing statically initialized arrays. It’s about allocating storage for arrays in the data section rather than on the heap.
> 
> Info: the array storage is a heap object. So in the following I’m using the general term “object” but the optimization will (probably) only handle array buffers.
> 
> This optimization can be done for array literals containing only other literals as elements.
> Example:
> 
> func createArray() -> [Int] {
>   return [1, 2, 3]
> }
> 
> The compiler can allocate the whole array buffer as a statically initialized global llvm-variable with a reference count of 2 to make it immortal.
> It avoids heap allocations for array literals in cases stack-promotion can’t kick in. It also saves code size.
> 
> What’s needed for this optimization?
> 
> 1) An optimization pass (GlobalOpt) which detects such array literal initialization patterns and “outlines” those into a statically initialized global variable
> 2) A representation of statically initialized global variables in SIL
> 3) IRGen to create statically initialized objects as global llvm-variables
> 
> ad 2) Changes in SIL:
> 
> Currently a static initialized sil_global is represented by having a reference to a globalinit function which has to match a very specific pattern (e.g. must contain a single store to the global).
> This is somehow quirky and would get even more complicated for statically initialized objects.
> 
> I’d like to change that so that the sil_global itself contains the initialization value.
> This part is not yet related to statically initialized objects. It just improves the representation of statically initialized global in general.
> 
> @@ -1210,7 +1210,9 @@ Global Variables
>  ::
>  
>    decl ::= sil-global-variable
> +  static-initializer ::= '{' sil-instruction-def* '}'
>    sil-global-variable ::= 'sil_global' sil-linkage identifier ':' sil-type
> +                             (static-initializer)?
>  
>  SIL representation of a global variable.
>  
> @@ -1221,6 +1223,19 @@ SIL instructions. Prior to performing any access on the global, the
>  Once a global's storage has been initialized, ``global_addr`` is used to
>  project the value.
>  
> +A global can also have a static initializer if it's initial value can be
> +composed of literals. The static initializer is represented as a list of
> +literal and aggregate instructions where the last instruction is the top-level
> +value of the static initializer::
> +
> +  sil_global hidden @_T04test3varSiv : $Int {
> +    %0 = integer_literal $Builtin.Int64, 27
> +    %1 = struct $Int (%0 : $Builtin.Int64)
> +  }
> +
> +In case a global has a static initializer, no ``alloc_global`` is needed before
> +it can be accessed.
> +

This sounds reasonable.

> Now to represent a statically initialized object, we need a new instruction. Note that this “instruction" can only appear in the initializer of a sil_global.
> 
> +object
> +``````
> +::
> +
> +  sil-instruction ::= 'object' sil-type '(' (sil-operand (',' sil-operand)*)? ')'
> +
> +  object $T (%a : $A, %b : $B, ...)
> +  // $T must be a non-generic or bound generic reference type
> +  // The first operands must match the stored properties of T
> +  // Optionally there may be more elements, which are tail-allocated to T
> +
> +Constructs a statically initialized object. This instruction can only appear
> +as final instruction in a global variable static initializer list.
> 
> Finally we need an instruction to use such a statically initialized global object.
> 
> +global_object
> +`````````````
> +::
> +
> +  sil-instruction ::= 'global_object' sil-global-name ':' sil-type
> +
> +  %1 = global_object @v : $T
> +  // @v must be a global variable with a static initialized object
> +  // $T must be a reference type
> +
> +Creates a reference to the address of a global variable which has a static
> +initializer which is an object, i.e. the last instruction of the global's
> +static initializer list is an ``object`` instruction.

The designs here both sound good to me. If we need to introduce a higher-level global access function in `global_object`, perhaps we should instead raise the abstraction level of global_addr and sil_global to hide the details of the once-style access, so that the `sil_global` declaration for a runtime-initialized variable declares its relationship to an initialization token, and global_addr includes whatever access protocol is needed to access the referenced global. It might be nice for SIL not to have to pattern-match the details of how we `once`-initialize global values, and it might make it easier to use specialized access patterns for single- or double-word globals like Greg mentioned.

-Joe


More information about the swift-dev mailing list