<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="">On Oct 8, 2017, at 3:30 PM, Erik Eckstein &lt;<a href="mailto:eeckstein@apple.com" class="">eeckstein@apple.com</a>&gt; wrote:<br class=""><div><blockquote type="cite" class=""><div class=""><blockquote type="cite" class="" 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;"><div class=""><blockquote type="cite" class="" 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;">We definitely already have a heap-&gt;stack for classes in the guise of the StackPromotion optimization is that what you are talking about with the "array outlining" optimization? (outlining to me is referring to specifically code outlining). IIRC Erik (+CC) do special work to make it work for fixed size array. I would ask why that optimization is not kicking in for varargs. Perhaps, we could add a special recognition that the given array will not escape through a varargs? Or provide some way of saying, trust me this doesn't escape.<br class=""></blockquote></div></blockquote><div 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=""><br class=""></div><div 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="">We already do heap-&gt;stack promotion for array buffers. This is done in the StackPromotion pass. It uses interprocedural escape analysis to check if it can be done. So if the callee is known it should work with the varargs array. BTW it also works in your example, in testAPI():</div><div 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=""><br class=""></div><div 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="">%1 = alloc_ref<span class="Apple-converted-space">&nbsp;</span><b class="">[stack]</b><span class="Apple-converted-space">&nbsp;</span>[tail_elems $Int * %0 : $Builtin.Word] $_ContiguousArrayStorage&lt;Int&gt;</div><div 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=""><br class=""></div><div 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="">But it’s not zero cost, because we initialize the metadata pointer + refcount in a runtime function. Also we do ref-count operations on the array in the callee (this will improve as soon as we have a ref count representation for immortal objects).</div></div></blockquote></div><br class=""><div class="">This is fantastic, I didn’t notice the [stack] marker there! &nbsp;I’m thrilled you’re on top of this. &nbsp;It looks like you have a well-developed framework here, which I haven’t fully ingested. &nbsp;As such, I have a few questions for you:</div><div class=""><br class=""></div><div class="">1) With a debug build of the stdlib, the “isNative” and other sanity checks in the stdlib create a lot of bridge_object_to_word -&gt; zext to i64 -&gt; and-with-magic-arch-specific-constant checks to validate that the array is properly in a native state. &nbsp;Have you considered introducing a “bridge_object_classify” SIL instruction which translates a bridge object value into a tuple of bits (isNative, isObjC, etc) &nbsp;+ unbitmangled value? &nbsp;It seems super weird to me that there are a bunch of architecture-specific magic constants in stdlib/public/core/Builtin.swift. &nbsp;It seems that these should be encapsulated into a SIL instruction, which would then allow the SIL optimizer to eliminate these checks. &nbsp;</div><div class=""><br class=""></div><div class="">Particularly with a debug stdlib, it is super common to see an “array.uninitialized” call which then gets bitwise queried through a super-verbose series of SIL instructions that are opaque to the SIL optimizer (because they are arch specific). &nbsp;Encapsulating this into SIL seems like a good call both from putting the arch-specific bits into the SIL layer which can expand it in IRGen (if it survives that long) and also optimize it away in the common case when it is knowable if these bits are 0 or 1 (as when coming from an array literal or other common known-native construct).&nbsp;</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">2) You have an apparently great infra for escape analysis of arrays. &nbsp;Have you considered adding one more check? &nbsp;If the only uses of the reference counted object is a single release in the current function (common when passing array literals to C functions) then you can eliminating the heap allocation AND all the refcounting instructions and use a simple alloc_stack (of an array of tuples?) and put the dealloc stack where the single release is. &nbsp;This seems like it would be a particularly bit win for the simple case of things like:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>memcpy(dest, [1,2,3,4], sizeof(Int)*4)&nbsp;</div><div class=""><br class=""></div><div class="">among others. &nbsp;Because the array literal would turn into the C-equivalent construct with zero overhead.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">3) There are other optimizations like ArrayElementValuePropagation, which don’t handle the&nbsp;BridgeObjectToWordInst or&nbsp;AddressToPointer or&nbsp;UncheckedRefCastInst, and thus give up. &nbsp;This causes a number of limitations (though I have no idea if they are important in practice or not): since conversions to UnsafePointer cannot mutate the array, they should not prevent element optimizations, count propagation optimizations, etc.</div><div class=""><br class=""></div><div class="">In any case, I’m super-thrilled you and your team have been pushing this forward, since arrays are really fundamental to all swift programs. &nbsp; I’m very much looking forward to the time when we can pass borrowed array slices down the stack with zero overhead.</div><div class=""><br class=""></div><div class="">-Chris</div><div class=""><br class=""></div><div class=""><br class=""></div></body></html>