<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 19, 2017, at 8:53 AM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class="Apple-interchange-newline">On Jun 14, 2017, at 11:24 AM, Erik Eckstein via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:<br class=""><br class="">Hi,<br class=""><br class="">I’m about implementing statically initialized arrays. It’s about allocating storage for arrays in the data section rather than on the heap.<br class=""><br class="">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.<br class=""><br class="">This optimization can be done for array literals containing only other literals as elements.<br class="">Example:<br class=""><br class="">func createArray() -&gt; [Int] {<br class="">&nbsp;return [1, 2, 3]<br class="">}<br class=""><br class="">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.<br class="">It avoids heap allocations for array literals in cases stack-promotion can’t kick in. It also saves code size.<br class=""><br class="">What’s needed for this optimization?<br class=""><br class="">1) An optimization pass (GlobalOpt) which detects such array literal initialization patterns and “outlines” those into a statically initialized global variable<br class="">2) A representation of statically initialized global variables in SIL<br class="">3) IRGen to create statically initialized objects as global llvm-variables<br class=""><br class="">ad 2) Changes in SIL:<br class=""><br class="">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).<br class="">This is somehow quirky and would get even more complicated for statically initialized objects.<br class=""><br class="">I’d like to change that so that the sil_global itself contains the initialization value.<br class="">This part is not yet related to statically initialized objects. It just improves the representation of statically initialized global in general.<br class=""><br class="">@@ -1210,7 +1210,9 @@ Global Variables<br class="">::<br class=""><br class="">&nbsp;&nbsp;decl ::= sil-global-variable<br class="">+ &nbsp;static-initializer ::= '{' sil-instruction-def* '}'<br class="">&nbsp;&nbsp;sil-global-variable ::= 'sil_global' sil-linkage identifier ':' sil-type<br class="">+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(static-initializer)?<br class=""><br class="">SIL representation of a global variable.<br class=""><br class="">@@ -1221,6 +1223,19 @@ SIL instructions. Prior to performing any access on the global, the<br class="">Once a global's storage has been initialized, ``global_addr`` is used to<br class="">project the value.<br class=""><br class="">+A global can also have a static initializer if it's initial value can be<br class="">+composed of literals. The static initializer is represented as a list of<br class="">+literal and aggregate instructions where the last instruction is the top-level<br class="">+value of the static initializer::<br class="">+<br class="">+ &nbsp;sil_global hidden @_T04test3varSiv : $Int {<br class="">+ &nbsp;&nbsp;&nbsp;%0 = integer_literal $Builtin.Int64, 27<br class="">+ &nbsp;&nbsp;&nbsp;%1 = struct $Int (%0 : $Builtin.Int64)<br class="">+ &nbsp;}<br class="">+<br class="">+In case a global has a static initializer, no ``alloc_global`` is needed before<br class="">+it can be accessed.<br class="">+<br class=""><br class="">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.<br class=""><br class="">+object<br class="">+``````<br class="">+::<br class="">+<br class="">+ &nbsp;sil-instruction ::= 'object' sil-type '(' (sil-operand (',' sil-operand)*)? ')'<br class="">+<br class="">+ &nbsp;object $T (%a : $A, %b : $B, ...)<br class="">+ &nbsp;// $T must be a non-generic or bound generic reference type<br class="">+ &nbsp;// The first operands must match the stored properties of T<br class="">+ &nbsp;// Optionally there may be more elements, which are tail-allocated to T<br class="">+<br class="">+Constructs a statically initialized object. This instruction can only appear<br class="">+as final instruction in a global variable static initializer list.<br class=""><br class="">Finally we need an instruction to use such a statically initialized global object.<br class=""><br class="">+global_object<br class="">+`````````````<br class="">+::<br class="">+<br class="">+ &nbsp;sil-instruction ::= 'global_object' sil-global-name ':' sil-type<br class="">+<br class="">+ &nbsp;%1 = global_object @v : $T<br class="">+ &nbsp;// @v must be a global variable with a static initialized object<br class="">+ &nbsp;// $T must be a reference type<br class="">+<br class="">+Creates a reference to the address of a global variable which has a static<br class="">+initializer which is an object, i.e. the last instruction of the global's<br class="">+static initializer list is an ``object`` instruction.<br class=""><br class=""><br class="">ad 3) IRGen support<br class=""><br class="">Generating statically initialized globals is already done today for structs and tuples.<br class="">What’s needed is the handling of objects.<br class="">In addition to creating the global itself, we also need a runtime call to initialize the object header. In other words: the object is statically initialized, except the header.<br class=""><br class="">HeapObject *swift::swift_initImmortalObject(HeapMetadata const *metadata, HeapObject *object)<br class=""><br class="">There are 2 reasons for that: first, the object header format is not part of the ABI. And second, in case of a bound generic type (e.g. array buffers) the metadata is not statically available.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">I did some work along these lines already so that KeyPaths could be immortal heap objects. I added an entry point _swift_instantiateInertHeapObject that does exactly this. We could un-underscore it and promote it to a SWIFT_RUNTIME_EXPORT.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>sounds good. If I understood it correctly, _swift_instantiateInertHeapObject currently initializes the object with a reference count of 1. For array buffers we would need 2. But I think for KeyPaths you are fine with 2 as well.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">-Joe</span></div></blockquote></div><br class=""></body></html>