<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Oct 7, 2016, at 6:04 PM, Michael Gottesman &lt;<a href="mailto:mgottesman@apple.com" class="">mgottesman@apple.com</a>&gt; wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Oct 7, 2016, at 5:09 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><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="">On Oct 7, 2016, at 2:38 PM, Michael Gottesman &lt;<a href="mailto:mgottesman@apple.com" class="">mgottesman@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">Attached below is an updated version of the proposal. Again a rendered version is located at:</div><div class=""><br class=""></div><div class=""><a href="https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html" class="">https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html</a></div><div class=""><br class=""></div><div class="">Michael</div><div class=""><br class=""></div><div class="">----</div><div class=""><br class=""></div><div class=""><div class=""># Summary</div><div class=""><br class=""></div><div class="">This document proposes:</div><div class=""><br class=""></div><div class="">1. adding the following ownership qualifiers to `load`: `[take]`, `[copy]`,</div><div class="">&nbsp; &nbsp;`[borrow]`, `[trivial]`.</div><div class="">2. adding the following ownership qualifiers to `store`: `[init]`, `[assign]`,</div><div class="">&nbsp; &nbsp;`[trivial]`.</div><div class="">3. requiring all `load` and `store` operations to have ownership qualifiers.</div><div class="">4. banning the use of `load [trivial]`, `store [trivial]` on memory locations of</div><div class="">&nbsp; &nbsp;`non-trivial` type.</div><div class=""><br class=""></div><div class="">This will allow for:</div><div class=""><br class=""></div><div class="">1. eliminating optimizer miscompiles that occur due to releases being moved into</div><div class="">&nbsp; &nbsp;the region in between a `load`/`retain`, `load`/`release`,</div><div class="">&nbsp; &nbsp;`store`/`release`. (For a specific example, see the appendix).</div><div class="">2. explicitly modeling `load [trivial]`/`store [trivial]` as having `unsafe</div><div class="">&nbsp; &nbsp;unowned` ownership semantics. This will be enforced via the verifier.</div><div class="">3. more aggressive ARC code motion.</div><div class=""><br class=""></div><div class=""># Definitions</div><div class=""><br class=""></div><div class="">## ownership qualified load</div><div class=""><br class=""></div><div class="">We propose four different ownership qualifiers for load. Define `load [trivial]`</div><div class="">as:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load [trivial] %x_ptr : $*Int</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*Int</div><div class=""><br class=""></div><div class="">A `load [trivial]` can not be used to load values of non-trivial type.</div></div></div></div></blockquote><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Should we mandate the reverse as well, that e.g. load [copy] cannot be used to</div><div 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-stroke-width: 0px;" class="">load values of trivial type? &nbsp;That's a little more work for substituting cloners, but it</div><div 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-stroke-width: 0px;" class="">keeps everything nice and canonical.</div></div></blockquote><div class=""><br class=""></div><div class="">No. I think that in the trivial case, load [copy] optimizes to load [trivial] as a canonicalization. This is just like applying a retain_value to a trivial type.</div></div></div></div></blockquote><div><br class=""></div>I guess I'm fine with that.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">Define</div><div class="">`load [copy]` as:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load [copy] %x_ptr : $*C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*C</div><div class="">&nbsp; &nbsp; retain_value %x : $C</div><div class=""><br class=""></div><div class="">Then define `load [take]` as:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load [take] %x_ptr : $*Builtin.NativeObject</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*Builtin.NativeObject</div><div class=""><br class=""></div><div class="">**NOTE** `load [take]` implies that the loaded from memory location no longer</div><div class="">owns the result object (i.e. a take is a move). Loading from the memory location</div><div class="">again without reinitialization is illegal.</div><div class=""><br class=""></div><div class="">Next we provide `load [borrow]`:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load [borrow] %x_ptr : $*Builtin.NativeObject</div><div class="">&nbsp; &nbsp; ...</div><div class="">&nbsp; &nbsp; endBorrow(%x, %x_ptr)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*Builtin.NativeObject</div><div class="">&nbsp; &nbsp; ...</div><div class="">&nbsp; &nbsp; endBorrow(%x, %x_ptr)</div><div class=""><br class=""></div><div class="">`load [borrow]` implies that in the region between the `load` and the</div><div class="">`endBorrow`, the loaded object must semantically remain alive.</div></div></div></div></blockquote><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">For consistency with other multi-word SIL instructions, this should be end_borrow.</div></div></blockquote><div class=""><br class=""></div><div class="">Sure.</div><br class=""><blockquote type="cite" class=""><div class=""><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">I wonder whether it might make more sense for load [borrow] to be a different instruction.</div><div class="">There's a couple reasons for that first. &nbsp;The first is that it's the only load which introduces</div><div class="">a scope, which is a really big difference structurally. &nbsp;The second is that it's the only load</div><div class="">which returns a non-owned value, which will be a typing difference when we record</div><div class="">ownership in the type system.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I am fine with a load_borrow. If this is the only change left that you want can I just send out a proposal with that small change and start implementing. I am nervous about perfection being the enemy of the good (and I want to start implementing this weekend if possible *evil smile*).</div></div></div></div></blockquote><div><br class=""></div>Yes, it's fine to introduce this incrementally.</div><div><br class=""></div><div>We can discuss the formation rules on scopes concurrently. &nbsp;I think the same theoretical</div><div>foundation is probably what we'll use for pseudo-linearity, memory-initialization soundness,</div><div>and so on.</div><div><br class=""></div><div>John.</div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class=""><div 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-stroke-width: 0px;" class="">Anyway, I really like that load [borrow] is scoped.. &nbsp;Are you planning to include the formation</div><div 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-stroke-width: 0px;" class="">restrictions on scopes instructions immediately, or will you do that in a later proposal?</div></div></blockquote><div class=""><br class=""></div><div class="">It will be done in a later proposal. We are just trying to set the stage for verification.</div><br class=""><blockquote type="cite" class=""><div class=""><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The requirements we need from scopes are:</div><div 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-stroke-width: 0px;" class="">&nbsp; - there has to be a well-defined set of IPs that lie within the scope and</div><div 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-stroke-width: 0px;" class="">&nbsp; - there can't be a non-explicit transition into or out of the scope.</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">One way to get the first condition is to say that there has to be a unique scope-ender that</div><div 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-stroke-width: 0px;" class="">post-dominates the scope-beginner, but that's a pretty hard restriction for SILGen to satisfy</div><div 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-stroke-width: 0px;" class="">(as well as the optimizer, I imagine), and it doesn't handle "unreachable" or infinite loops.</div><div 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-stroke-width: 0px;" class="">We need to allow multiple scope-enders, and we need to allow scope-enders to be missing</div><div 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-stroke-width: 0px;" class="">in some cases. </div></div></blockquote><div class=""><br class=""></div><div class="">I agree with you here. We definitely want to be able to support multiple scope-enders.</div><br class=""><blockquote type="cite" class=""><div class=""><div 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-stroke-width: 0px;" class="">&nbsp;Here's the right formalism, I think:</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">For all walks W beginning from the entry point of the function:</div><div 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-stroke-width: 0px;" class="">&nbsp; For each node B in the CFG which is a scope-beginner:</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; Let E be the set of scope-enders for B, and consider just the sub-sequence S of nodes</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; of W where the node is a member of {B} U E. &nbsp;Then the elements of S at even</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; positions (starting from 0) must be B, and the elements at odd positions must be</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; members of E. &nbsp;Furthermore, if the walk ends in a return or throw instruction, then</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; S must have even length.</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Note that for this to be true, all the scope-enders must be dominated by the scope-beginner.</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">It is sufficient to just consider the set of "beeline" paths, i.e. acyclic paths ending in either a true</div><div 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-stroke-width: 0px;" class="">terminator (a return, throw, or unreachable) or an edge back to a node already in the path.</div><div 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-stroke-width: 0px;" class="">No such path may include multiple scope-enders for the same scope-beginner. &nbsp;If the path ends</div><div 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-stroke-width: 0px;" class="">in a return or throw, it must include a matching scope-ender after every scope-beginner. &nbsp;If</div><div 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-stroke-width: 0px;" class="">it ends in a loop back, then for every scope-beginner in the path, if the path contains a scope-ender</div><div 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-stroke-width: 0px;" class="">then the loop destination must either precede the scope-beginner or follow the scope-ender;</div><div 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-stroke-width: 0px;" class="">otherwise, the loop destination must follow the scope-beginner.</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Or, as a decision algorithm in Swift for a single scope-beginner:</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; var blockEntryIsInScope = [Block: Bool]()</div><div 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-stroke-width: 0px;" class="">&nbsp; func scan(startingFrom inst: Instruction, isInScope: Bool) {</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; if inst is ReturnInst || inst is ThrowInst {</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; &nbsp; guard !isInScope else { invalid("ended function while in scope") }</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; &nbsp; return</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; }</div><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">&nbsp; &nbsp; if let term = inst as? TerminatorInst {</div><div class="">&nbsp; &nbsp; &nbsp; for successor in term.successors {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; guard begin.dominates(successor) else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; guard !isInScope else { invalid("branch out of scope while in scope") }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; if let cachedValue = blockEntryIsInScope[successor] {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if cachedValue != isInScope {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; invalid(isInScope ? "branch out of scope while in scope" : "branch into scope after exiting scope")</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; } else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; blockEntryIsInScope[successor] = isInScope</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scan(startingFrom: successor.begin, isInScope: isInScope)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; return</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div></div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; if inst.endsScopeOf(begin) {</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; &nbsp; guard isInScope else { invalid("ending scope that was already ended") }</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; &nbsp; scan(startingFrom: inst.next, isInScope: false)</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; } else {</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; &nbsp; scan(startingFrom: inst.next, isInScope: isInScope)</div><div 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-stroke-width: 0px;" class="">&nbsp; &nbsp; }</div><div 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-stroke-width: 0px;" class="">&nbsp; }</div><div 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-stroke-width: 0px;" class="">&nbsp; scan(startingFrom: begin, isInScope: true)</div></div></blockquote><div class=""><br class=""></div><div class="">Since this is tangential to the current proposal, can we introduce a side thread?</div><br class=""><blockquote type="cite" class=""><div class=""><div 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-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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div><div 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-stroke-width: 0px;" class=""><br class=""></div><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="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">The `endBorrow` communicates to the optimizer:</div><div class=""><br class=""></div><div class="">1. That the value in `%x_ptr` should not be destroyed before endBorrow.</div><div class="">2. Uses of `%x` should not be sunk past endBorrow since `%x` is only a shallow</div><div class="">&nbsp; &nbsp;copy of the value in `%x_ptr` and past that point `%x_ptr` may not remain</div><div class="">&nbsp; &nbsp;alive.</div><div class=""><br class=""></div><div class="">An example of where this construct is useful is when one has a let binding to a</div><div class="">class instance `c` that contains a let field `f`. In that case `c`'s lifetime</div><div class="">guarantees `f`'s lifetime meaning that returning `f` over the function call</div><div class="">boundary is safe.</div><div class=""><br class=""></div><div class="">## ownership qualified store</div><div class=""><br class=""></div><div class="">First define a `store [trivial]` as:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to [trivial] %x_ptr : $*Int</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to %x_ptr : $*Int</div><div class=""><br class=""></div><div class="">The verifier will prevent this instruction from being used on types with</div><div class="">non-trivial ownership. Define a `store [assign]` as follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to [assign] %x_ptr : $*C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;=&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %old_x = load %x_ptr : $*C</div><div class="">&nbsp; &nbsp; store %new_x to %x_ptr : $*C</div><div class="">&nbsp; &nbsp; release_value %old_x : $C</div><div class=""><br class=""></div><div class="">*NOTE* `store` is defined as a consuming operation. We also provide</div><div class="">`store [init]` in the case where we know statically that there is no</div><div class="">previous value in the memory location:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to [init] %x_ptr : $*C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;=&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %new_x to %x_ptr : $*C</div><div class=""><br class=""></div><div class=""># Implementation</div><div class=""><br class=""></div><div class="">## Goals</div><div class=""><br class=""></div><div class="">Our implementation strategy goals are:</div><div class=""><br class=""></div><div class="">1. zero impact on other compiler developers until the feature is fully</div><div class="">&nbsp; &nbsp;developed. This implies all work will be done behind a flag.</div><div class="">2. separation of feature implementation from updating passes.</div><div class=""><br class=""></div><div class="">Goal 2 will be implemented via a pass that transforms ownership qualified</div><div class="">`load`/`store` instructions into unqualified `load`/`store` right after SILGen.</div><div class=""><br class=""></div><div class="">## Plan</div><div class=""><br class=""></div><div class="">We begin by adding initial infrastructure for our development. This means:</div><div class=""><br class=""></div><div class="">1. Adding to SILOptions a disabled by default flag called</div><div class="">&nbsp;"EnableSILOwnershipModel". This flag will be set by a false by default frontend</div><div class="">&nbsp;option called "-enable-sil-ownership-mode".</div><div class=""><br class=""></div><div class="">2. Bots will be brought up to test the compiler with</div><div class="">&nbsp; &nbsp;"-enable-sil-ownership-model" set to true. The specific bots are:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;* RA-OSX+simulators</div><div class="">&nbsp; &nbsp;* RA-Device</div><div class="">&nbsp; &nbsp;* RA-Linux.</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;The bots will run once a day until the feature is close to completion. Then a</div><div class="">&nbsp; &nbsp;polling model will be followed.</div><div class=""><br class=""></div><div class="">Now that change isolation is borrow, we develop building blocks for the</div><div class="">optimization:</div><div class=""><br class=""></div><div class="">1. Two enums will be defined: `LoadInstOwnershipQualifier`,</div><div class="">&nbsp; &nbsp;`StoreInstOwnershipQualifier`. The exact definition of these enums are as</div><div class="">&nbsp; &nbsp;follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;enum class LoadOwnershipQualifier {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Unqualified, Take, Copy, Borrow, Trivial</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;};</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;enum class StoreOwnershipQualifier {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Unqualified, Init, Assign, Trivial</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;};</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; *NOTE* `LoadOwnershipQualifier::Unqualified` and</div><div class="">&nbsp; &nbsp; `StoreOwnershipQualifier::Unqualified` are only needed for staging purposes.</div><div class=""><br class=""></div><div class="">2. Creating a `LoadInst`, `StoreInst` will be changed to require an ownership</div><div class="">qualifier. At this stage, this argument will default to `Unqualified`. "Bare"</div><div class="">`load`, `store` when parsed via textual SIL will be considered to be</div><div class="">unqualified. This implies that the rest of the compiler will not have to be</div><div class="">changed as a result of this step.</div><div class=""><br class=""></div><div class="">3. Support will be added to SIL, IRGen, Serialization, SILPrinting, and SIL</div><div class="">Parsing for the rest of the qualifiers. SILGen will not be modified at this</div><div class="">stage.</div><div class=""><br class=""></div><div class="">4. A pass called the "OwnershipModelEliminator" will be implemented. It will</div><div class="">&nbsp; &nbsp;blow up all `load`, `store` instructions with non `*::Unqualified` ownership</div><div class="">&nbsp; &nbsp;into their constituant ARC operations and `*::Unqualified` `load`, `store`</div><div class="">&nbsp; &nbsp;insts.</div><div class=""><br class=""></div><div class="">3. An option called "EnforceSILOwnershipMode" will be added to the verifier. If</div><div class="">the option is set, the verifier will assert if:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;a. `load`, `store` operations with trivial ownership are applied to memory</div><div class="">&nbsp; &nbsp; &nbsp; locations with non-trivial type.</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;b. `load`, `store` operation with unqualified ownership type are present in</div><div class="">&nbsp; &nbsp;the IR.</div><div class=""><br class=""></div><div class="">Finally, we wire up the building blocks:</div><div class=""><br class=""></div><div class="">1. If SILOption.EnableSILOwnershipModel is true, then the after SILGen SIL</div><div class="">&nbsp; &nbsp;verification will be performed with EnforceSILOwnershipModel set to true.</div><div class="">2. If SILOption.EnableSILOwnershipModel is true, then the pass manager will run</div><div class="">&nbsp; &nbsp;the OwnershipModelEliminator pass right after SILGen before the normal pass</div><div class="">&nbsp; &nbsp;pipeline starts.</div><div class="">3. SILGen will be changed to emit non-unqualified ownership qualifiers on load,</div><div class="">&nbsp; &nbsp;store instructions when the EnableSILOwnershipModel flag is set. We will use</div><div class="">&nbsp; &nbsp;the verifier throwing to guarantee that we are not missing any specific</div><div class="">&nbsp; &nbsp;cases.</div><div class=""><br class=""></div><div class="">Then once all of the bots are green, we change SILOption.EnableSILOwnershipModel</div><div class="">to be true by default. After a cooling off period, we move all of the code</div><div class="">behind the SILOwnershipModel flag in front of the flag. We do this so we can</div><div class="">reuse that flag for further SILOwnershipModel changes.</div><div class=""><br class=""></div><div class="">## Optimizer Changes</div><div class=""><br class=""></div><div class="">Since the SILOwnershipModel eliminator will eliminate the ownership qualifiers</div><div class="">on load, store instructions right after ownership verification, there will be no</div><div class="">immediate affects on the optimizer and thus the optimizer changes can be done in</div><div class="">parallel with the rest of the ARC optimization work.</div><div class=""><br class=""></div><div class="">But, in the long run, we want to enforce these ownership invariants all</div><div class="">throughout the SIL pipeline implying these ownership qualified `load`, `store`</div><div class="">instructions must be processed by IRGen, not eliminated by the SILOwnershipModel</div><div class="">eliminator. Thus we will need to update passes to handle these new</div><div class="">instructions. The main optimizer changes can be separated into the following</div><div class="">areas: memory forwarding, dead stores, ARC optimization. In all of these cases,</div><div class="">the necessary changes are relatively trivial to respond to. We give a quick</div><div class="">taste of two of them: store-&gt;load forwarding and ARC Code Motion.</div><div class=""><br class=""></div><div class="">### store-&gt;load forwarding</div><div class=""><br class=""></div><div class="">Currently we perform store-&gt;load forwarding as follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to %x_ptr : $C</div><div class="">&nbsp; &nbsp; ... NO SIDE EFFECTS THAT TOUCH X_PTR ...</div><div class="">&nbsp; &nbsp; %y = load %x_ptr : $C</div><div class="">&nbsp; &nbsp; use(%y)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to %x_ptr : $C</div><div class="">&nbsp; &nbsp; ... NO SIDE EFFECTS THAT TOUCH X_PTR ...</div><div class="">&nbsp; &nbsp; use(%x)</div><div class=""><br class=""></div><div class="">In a world, where we are using ownership qualified load, store, we have to also</div><div class="">consider the ownership implications. *NOTE* Since we are not modifying the</div><div class="">store, `store [assign]` and `store [init]` are treated the same. Thus without</div><div class="">any loss of generality, lets consider solely `store`.</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to [assign] %x_ptr : $C</div><div class="">&nbsp; &nbsp; ... NO SIDE EFFECTS THAT TOUCH X_PTR ...</div><div class="">&nbsp; &nbsp; %y = load [copy] %x_ptr : $C</div><div class="">&nbsp; &nbsp; use(%y)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; store %x to [assign] %x_ptr : $C</div><div class="">&nbsp; &nbsp; ... NO SIDE EFFECTS THAT TOUCH X_PTR ...</div><div class="">&nbsp; &nbsp; strong_retain %x</div><div class="">&nbsp; &nbsp; use(%x)</div><div class=""><br class=""></div><div class="">### ARC Code Motion</div><div class=""><br class=""></div><div class="">If ARC Code Motion wishes to move the ARC semantics of ownership qualified</div><div class="">`load`, `store` instructions, it must now consider read/write effects. On the</div><div class="">other hand, it will be able to now not consider the side-effects of destructors</div><div class="">when moving retain/release operations.</div><div class=""><br class=""></div><div class="">### Normal Code Motion</div><div class=""><br class=""></div><div class="">Normal code motion will lose some effectiveness since many of the load/store</div><div class="">operations that it used to be able to move now must consider ARC information. We</div><div class="">may need to consider running ARC code motion earlier in the pipeline where we</div><div class="">normally run Normal Code Motion to ensure that we are able to handle these</div><div class="">cases.</div><div class=""><br class=""></div><div class="">### ARC Optimization</div><div class=""><br class=""></div><div class="">The main implication for ARC optimization is that instead of eliminating just</div><div class="">retains, releases, it must be able to recognize ownership qualified `load`,</div><div class="">`store` and set their flags as appropriate.</div><div class=""><br class=""></div><div class="">### Function Signature Optimization</div><div class=""><br class=""></div><div class="">Semantic ARC affects function signature optimization in the context of the owned</div><div class="">to borrow optimization. Specifically:</div><div class=""><br class=""></div><div class="">1. A `store [assign]` must be recognized as a release of the old value that is</div><div class="">&nbsp; &nbsp;being overridden. In such a case, we can move the `release` of the old value</div><div class="">&nbsp; &nbsp;into the caller and change the `store [assign]` into a `store [init]`.</div><div class="">2. A `load [copy]` must be recognized as a retain in the callee. Then function</div><div class="">&nbsp; &nbsp;signature optimization will transform the `load [copy]` into a `load</div><div class="">&nbsp; &nbsp;[borrow]`. This would require the addition of a new `@borrow` return</div><div class="">&nbsp; &nbsp;value convention.</div><div class=""><br class=""></div><div class=""># Appendix</div><div class=""><br class=""></div><div class="">## Partial Initialization of Loadable References in SIL</div><div class=""><br class=""></div><div class="">In SIL, a value of non-trivial loadable type is loaded from a memory location as</div><div class="">follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*S</div><div class="">&nbsp; &nbsp; ...</div><div class="">&nbsp; &nbsp; retain_value %x_ptr : $S</div><div class=""><br class=""></div><div class="">At first glance, this looks reasonable, but in truth there is a hidden drawback:</div><div class="">the partially initialized zone in between the load and the retain</div><div class="">operation. This zone creates a period of time when an "evil optimizer" could</div><div class="">insert an instruction that causes x to be deallocated before the copy is</div><div class="">finished being initialized. Similar issues come up when trying to perform a</div><div class="">store of a non-trival value into a memory location.</div><div class=""><br class=""></div><div class="">Since this sort of partial initialization is allowed in SIL, the optimizer is</div><div class="">forced to be overly conservative when attempting to move releases passed retains</div><div class="">lest the release triggers a deinit that destroys a value like `%x`. Lets look at</div><div class="">two concrete examples that show how semantically providing ownership qualified</div><div class="">load, store instructions eliminate this problem.</div><div class=""><br class=""></div><div class="">**NOTE** Without any loss of generality, we will speak of values with reference</div><div class="">semantics instead of non-trivial values.</div><div class=""><br class=""></div><div class="">## Case Study: Partial Initialization and load [copy]</div><div class=""><br class=""></div><div class="">### The Problem</div><div class=""><br class=""></div><div class="">Consider the following swift program:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; func opaque_call()</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; final class C {</div><div class="">&nbsp; &nbsp; &nbsp; var int: Int = 0</div><div class="">&nbsp; &nbsp; &nbsp; deinit {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; opaque_call()</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; final class D {</div><div class="">&nbsp; &nbsp; &nbsp; var int: Int = 0</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; var GLOBAL_C : C? = nil</div><div class="">&nbsp; &nbsp; var GLOBAL_D : D? = nil</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; func useC(_ c: C)</div><div class="">&nbsp; &nbsp; func useD(_ d: D)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; func run() {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let c = C()</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; GLOBAL_C = c</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let d = D()</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; GLOBAL_D = d</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; useC(c)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; useD(d)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">Notice that both `C` and `D` have fixed layouts and separate class hierarchies,</div><div class="">but `C`'s deinit has a call to the function `opaque_call` which may write to</div><div class="">`GLOBAL_D` or `GLOBAL_C`. Additionally assume that both `useC` and `useD` are</div><div class="">known to the compiler to not have any affects on instances of type `D`, `C`</div><div class="">respectively and useC assigns `nil` to `GLOBAL_C`. Now consider the following</div><div class="">valid SIL lowering for `run`:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil_global GLOBAL_D : $D</div><div class="">&nbsp; &nbsp; sil_global GLOBAL_C : $C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; final class C {</div><div class="">&nbsp; &nbsp; &nbsp; var x: Int</div><div class="">&nbsp; &nbsp; &nbsp; deinit</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; final class D {</div><div class="">&nbsp; &nbsp; &nbsp; var x: Int</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @useC : $@convention(thin) () -&gt; ()</div><div class="">&nbsp; &nbsp; sil @useD : $@convention(thin) () -&gt; ()</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %c2 = load %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (3)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c2 : $C &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; (4)</div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d2 : $D &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; (6)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c2) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_release %d : $D &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; (9)</div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">Lets optimize this function! First we perform the following operations:</div><div class=""><br class=""></div><div class="">1. Since `(2)` is storing to an identified object that can not be `GLOBAL_C`, we</div><div class="">&nbsp; &nbsp;can store to load forward `(1)` to `(3)`.</div><div class="">2. Since a retain does not block store to load forwarding, we can forward `(2)`</div><div class="">&nbsp; &nbsp;to `(5)`. But lets for the sake of argument, assume that the optimizer keeps</div><div class="">&nbsp; &nbsp;such information as an analysis and does not perform the actual load-&gt;store</div><div class="">&nbsp; &nbsp;forwarding.</div><div class="">3. Even though we do not foward `(2)` to `(5)`, we can still move `(4)` over</div><div class="">&nbsp; &nbsp;`(6)` so that `(4)` is right before `(7)`.</div><div class=""><br class=""></div><div class="">This yields (using the ' marker to designate that a register has had load-store</div><div class="">forwarding applied to it):</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C &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;(4')</div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d2 : $D &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; (6)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (7')</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_release %d : $D &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; (9)</div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">Then by assumption, we know that `%useC` does not perform any releases of any</div><div class="">instances of class `D`. Thus `(6)` can be moved past `(7')` and we can then pair</div><div class="">and eliminate `(6)` and `(9)` via the rules of ARC optimization using the</div><div class="">analysis information that `%d2` and `%d` are th same due to the possibility of</div><div class="">performing store-&gt;load forwarding. After performing such transformations, `run`</div><div class="">looks as follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C &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;(4')</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (7')</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">Now by assumption, we know that `%useD_func` does not touch any instances of</div><div class="">class `C` and `%c` does not contain any ivars of type `D` and is final so none</div><div class="">can be added. At first glance, this seems to suggest that we can move `(10)`</div><div class="">before `(8')` and then pair/eliminate `(4')` and `(10)`. But is this a safe</div><div class="">optimization perform? &nbsp;Absolutely Not! Why? Remember that since `useC_func`</div><div class="">assigns `nil` to `GLOBAL_C`, after `(7')`, `%c` could have a reference count</div><div class="">of 1. &nbsp;Thus `(10)` _may_ invoke the destructor of `C`. Since this destructor</div><div class="">calls an opaque function that _could_ potentially write to `GLOBAL_D`, we may be</div><div class="">be passing `%d2`, an already deallocated object to `%useD_func`, an illegal</div><div class="">optimization!</div><div class=""><br class=""></div><div class="">Lets think a bit more about this example and consider this example at the</div><div class="">language level. Remember that while Swift's deinit are not asychronous, we do</div><div class="">not allow for user level code to create dependencies from the body of the</div><div class="">destructor into the normal control flow that has called it. This means that</div><div class="">there are two valid results of this code:</div><div class=""><br class=""></div><div class="">- Operation Sequence 1: No optimization is performed and `%d2` is passed to</div><div class="">&nbsp; `%useD_func`.</div><div class="">- Operation Sequence 2: We shorten the lifetime of `%c` before `%useD_func` and</div><div class="">&nbsp; &nbsp;a different instance of `$D` is passed into `%useD_func`.</div><div class=""><br class=""></div><div class="">The fact that 1 occurs without optimization is just as a result of an</div><div class="">implementation detail of SILGen. 2 is also a valid sequence of operations.</div><div class=""><br class=""></div><div class="">Given that:</div><div class=""><br class=""></div><div class="">1. As a principle, the optimizer does not consider such dependencies to avoid</div><div class="">&nbsp; &nbsp;being overly conservative.</div><div class="">2. We provide constructs to ensure appropriate lifetimes via the usage of</div><div class="">&nbsp; &nbsp;constructs such as fix_lifetime.</div><div class=""><br class=""></div><div class="">We need to figure out how to express our optimization such that 2</div><div class="">happens. Remember that one of the optimizations that we performed at the</div><div class="">beginning was to move `(6)` over `(7')`, i.e., transform this:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d_addr = global_addr GLOBAL_D : $D</div><div class="">&nbsp; &nbsp; &nbsp; %d = load %global_d_addr : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(6)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; // Call the user functions passing in the instances that we loaded from the globals.</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7')</div><div class=""><br class=""></div><div class="">into:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %global_d_addr = global_addr GLOBAL_D : $D</div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d_addr : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; // Call the user functions passing in the instances that we loaded from the globals.</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7')</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d2 : $D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(6)</div><div class=""><br class=""></div><div class="">This transformation in Swift corresponds to transforming:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; let d = GLOBAL_D</div><div class="">&nbsp; &nbsp; &nbsp; useC(c)</div><div class=""><br class=""></div><div class="">to:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; let d_raw = load_d_value(GLOBAL_D)</div><div class="">&nbsp; &nbsp; &nbsp; useC(c)</div><div class="">&nbsp; &nbsp; &nbsp; let d = take_ownership_of_d(d_raw)</div><div class=""><br class=""></div><div class="">This is clearly an instance where we have moved a side-effect in between the</div><div class="">loading of the data and the taking ownership of such data, that is before the</div><div class="">`let` is fully initialized. What if instead of just moving the retain, we moved</div><div class="">the entire let statement? This would then result in the following swift code:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; useC(c)</div><div class="">&nbsp; &nbsp; &nbsp; let d = GLOBAL_D</div><div class=""><br class=""></div><div class="">and would correspond to the following SIL snippet:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %global_d_addr = global_addr GLOBAL_D : $D</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; // Call the user functions passing in the instances that we loaded from the globals.</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7')</div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d_addr : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d2 : $D &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;(6)</div><div class=""><br class=""></div><div class="">Moving the load with the strong_retain to ensure that the full initialization is</div><div class="">performed even after code motion causes our SIL to look as follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C &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;(4')</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (7')</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (5)</div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">Giving us the exact result that we want: Operation Sequence 2!</div><div class=""><br class=""></div><div class="">### Defining load [copy]</div><div class=""><br class=""></div><div class="">Given that we wish the load, store to be tightly coupled together, it is natural</div><div class="">to express this operation as a `load [copy]` instruction. Lets define the `load</div><div class="">[copy]` instruction as follows:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %1 = load [copy] %0 : $*C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %1 = load %0 : $*C</div><div class="">&nbsp; &nbsp; retain_value %1 : $C</div><div class=""><br class=""></div><div class="">Now lets transform our initial example to use this instruction:</div><div class=""><br class=""></div><div class="">Notice how now if we move `(7)` over `(3)` and `(6)` now, we get the following SIL:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %c2 = load [copy] %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(3)</div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load [copy] %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(5)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c2) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; strong_release %d : $D &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; (9)</div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">We then perform the previous code motion:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %c2 = load [copy] %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(3)</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c2) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7)</div><div class="">&nbsp; &nbsp; &nbsp; strong_release %d : $D &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; (9)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load [copy] %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(5)</div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class="">&nbsp; &nbsp; &nbsp; strong_release %c : $C &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; (10)</div><div class="">&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">We then would like to eliminate `(9)` and `(10)` by pairing them with `(3)` and</div><div class="">`(8)`. Can we still do so? One way we could do this is by introducing the</div><div class="">`[take]` flag. The `[take]` flag on a `load [take]` says that one is</div><div class="">semantically loading a value from a memory location and are taking ownership of</div><div class="">the value thus eliding the retain. In terms of SIL this flag is defined as:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load [take] %x_ptr : $*C</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; =&gt;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; %x = load %x_ptr : $*C</div><div class=""><br class=""></div><div class="">Why do we care about having such a `load [take]` instruction when we could just</div><div class="">use a `load`? The reason why is that a normal `load` has unsafe unowned</div><div class="">ownership (i.e. it has no implications on ownership). We would like for memory</div><div class="">that has non-trivial type to only be able to be loaded via instructions that</div><div class="">maintain said ownership. We will allow for casting to trivial types as usual to</div><div class="">provide such access if it is required.</div><div class=""><br class=""></div><div class="">Thus we have achieved the desired result:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; sil @run : $@convention(thin) () -&gt; () {</div><div class="">&nbsp; &nbsp; bb0:</div><div class="">&nbsp; &nbsp; &nbsp; %c = alloc_ref $C</div><div class="">&nbsp; &nbsp; &nbsp; %global_c = global_addr @GLOBAL_C : $*C</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %c : $C</div><div class="">&nbsp; &nbsp; &nbsp; store %c to %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d = alloc_ref $D</div><div class="">&nbsp; &nbsp; &nbsp; %global_d = global_addr @GLOBAL_D : $*D</div><div class="">&nbsp; &nbsp; &nbsp; strong_retain %d : $D</div><div class="">&nbsp; &nbsp; &nbsp; store %d to %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %c2 = load [take] %global_c : $*C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(3)</div><div class="">&nbsp; &nbsp; &nbsp; %useC_func = function_ref @useC : $@convention(thin) (@owned C) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useC_func(%c2) : $@convention(thin) (@owned C) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(7)</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; %d2 = load [take] %global_d : $*D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(5)</div><div class="">&nbsp; &nbsp; &nbsp; %useD_func = function_ref @useD : $@convention(thin) (@owned D) -&gt; ()</div><div class="">&nbsp; &nbsp; &nbsp; apply %useD_func(%d2) : $@convention(thin) (@owned D) -&gt; () &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(8)</div><div class="">&nbsp; &nbsp; }</div></div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Oct 6, 2016, at 3:03 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div 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-stroke-width: 0px;"><blockquote type="cite" class=""><div class="">On Oct 5, 2016, at 4:48 PM, Michael Gottesman &lt;<a href="mailto:mgottesman@apple.com" class="">mgottesman@apple.com</a>&gt; wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class="">On Oct 5, 2016, at 4:40 PM, Michael Gottesman via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div 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-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Oct 4, 2016, at 1:04 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div 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-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Sep 30, 2016, at 11:54 PM, Michael Gottesman via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">The document attached below contains the first "Semantic ARC" mini proposal: the High Level ARC Memory Operations Proposal.</div><div class=""><br class=""></div><div class="">An html rendered version of this markdown document is available at the following URL:</div><div class=""><br class=""></div><div class=""><a href="https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html" class="">https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html</a></div><div class=""><br class=""></div><div class="">----</div><div class=""><br class=""></div><div class=""><div class=""># Summary</div><div class=""><br class=""></div><div class="">This document proposes:</div><div class=""><br class=""></div><div class="">1. adding the `load_strong`, `store_strong` instructions to SIL. These can only</div><div class="">&nbsp; &nbsp;be used with memory locations of `non-trivial` type.</div></div></div></div></blockquote><div class=""><br class=""></div>I would really like to avoid using the word "strong" here. &nbsp;Under the current proposal, these instructions will be usable with arbitrary non-trivial types, not just primitive class references. &nbsp;Even if you think of an aggregate that happens to contain one or more strong references as some sort of aggregate strong reference (which is questionable but not completely absurd), we already have loadable non-strong class references that this operation would be usable with, like native unowned references. &nbsp;"load_strong %0 : $*@sil_unowned T" as an operation yielding a scalar "@sil_unowned T" is ridiculous, and it will only get more ridiculous when we eventually allow this operation to work with types that are currently address-only, like weak references.</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">Brainstorming:</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">Something like load_copy and store_copy would be a bit unfortunate, since store_copy doesn't actually copy the source operand and we want to have a load_copy [take].</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">load_value and store_value seem excessively generic. &nbsp;It's not like non-trivial types aren't values.</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">One question that comes to mind: do we actually need new instructions here other than for staging purposes? &nbsp;We don't actually need new instructions for pseudo-linear SIL to work; we just need to say that we only enforce pseudo-linearity for non-trivial types.</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">If we just want the instruction to be explicit about ownership so that we can easily distinguish these cases, we can make the rule always explicit, e.g.:</div><div 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-stroke-width: 0px;">&nbsp; load [take] %0 : $*MyClass</div><div 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-stroke-width: 0px;">&nbsp; load [copy] %0 : $*MyClass</div><div 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-stroke-width: 0px;"><div class="">&nbsp; load [trivial] %0 : $*Int</div><div class=""><br class=""></div><div class=""><div class="">&nbsp; store %0 to [initialization] %1 : $*MyClass</div><div class="">&nbsp; store %0 to [assignment] %1 : $*MyClass</div><div class=""><div class="">&nbsp; store %0 to [trivial] %1 : $*Int</div><div class=""><br class=""></div></div></div></div><div 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-stroke-width: 0px;">John.</div></div></blockquote><div class=""><br class=""></div><div class="">The reason why I originally suggested to go the load_strong route is that we already have load_weak, load_unowned instructions. If I could add a load_strong instruction, then it would make sense to assign an engineer to do a pass over all 3 of these instructions and combine them into 1 load instruction. That is, first transform into a form amenable for canonicalization and then canonicalize all at once.</div><div class=""><br class=""></div><div class="">As you pointed out, both load_unowned and load_weak involve representation changes in type (for instance the change of weak pointers to Optional&lt;T&gt;). Such a change would be against the "spirit" of a load instruction to perform such representation changes versus ownership changes.</div><div class=""><br class=""></div><div class="">In terms of the properties that we actually want here, what is important is that we can verify that no non-trivially typed values are loaded in an unsafe unowned manner. That can be done also with ownership flags on load/store.</div><div class=""><br class=""></div><div class="">Does this sound reasonable:</div><div class=""><br class=""></div><div class="">1. We introduce two enums that define memory ownership changes, one for load and one for store. Both of these enums will contain a [trivial] ownership.</div><div class="">2. We enforce in the verifier that non-trivial types must have a non-trivial ownership modifier on any memory operations that they are involved in.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Sorry for not being explicit. I will not add new instructions, just modifiers. Assuming that this is agreeable to you, I am going to prepare a quick additional version of the proposal document.</div></div></div></div></blockquote><div class=""><br class=""></div>That sounds great, thanks.</div><div 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-stroke-width: 0px;"><br class=""></div><div 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-stroke-width: 0px;">John.</div></div></blockquote></div></div></blockquote></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>