<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Folks working on the SIL optimizer, particularly those interested in faster builds:<div class=""><br class=""></div><div class="">If I understand the SIL optimizer correctly, it seems that when the current program references an external symbol declared as @_inlinable, that SILModule::linkFunction eagerly deserializes the @_inlinable body and splat it into the current module. &nbsp;That SIL function exists in the current module, gets optimized, inlined, etc along with existing functions, then gets dropped on the floor at IRGen time if it still exists.</div><div class=""><br class=""></div><div class="">If this is true, this seems like an incredibly wasteful approach, particularly given how many @_inlinable functions exist in the standard library, and particularly for programs that have lots of small files. &nbsp;Try this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">$ cat u.swift&nbsp;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">func f() {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">&nbsp; print("hello")</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255); min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">$ swiftc u.swift -emit-sil -o - | wc -l</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">&nbsp; &nbsp; 7191</span></div></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><br class=""></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">That is a *TON* of SIL, most having to do with array internals, string internals, and other stuff. &nbsp;</span>This eats memory and costs a ton of compile time to deserialize and slog this around, which gets promptly dropped on the floor by IRGen. &nbsp;It also makes the -emit-sil output more difficult to work with...</div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class="">Optimized builds are also bad:</div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">$ swiftc u.swift -emit-sil -o - -O | wc -l</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">&nbsp;&nbsp; &nbsp;&nbsp;861</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">If you look at it, only about 70 lines of that is the actual program being compiled, the rest is dropped on the floor by IRGen. This costs a ton of memory and compile time to deserialize and represent this, then even more is wasted running the optimizer on code which was presumably optimized when the stdlib was built.</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class="">I imagine that this approach was inspired by LLVM’s available_externally linkage, which does things the same way. &nbsp;This is a simple way to make sure that interprocedural optimizations can see the bodies of external functions to inline them, etc. &nbsp; However, LLVM doesn’t have the benefit of a module system like Swift’s, so it has no choice.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">So here are the questions: &nbsp;:-)</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">1. It looks like the MandatoryInliner is the biggest culprit at -O0 here: it deserializes the referenced function (MandatoryInlining.cpp:384) and *then* checks to see if the callee is @_transparent. &nbsp;Would it make sense to change this to check for @_transparent first (which might require a SIL change?), and only deserialize if so?</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">2. The performance inliner will have the same issue after this, and deserializing the bodies of all inlinable referenced functions is unavoidable for it. &nbsp;However, we don’t have to copy the SIL into the current module and burn compile time by subjecting it to all of the standard optimizations again. &nbsp;Would it make sense to put deserialized function bodies into a separate SIL module, and teach the (few) IPA/IPO optimizations about this fact? &nbsp;This should be very straight-forward to do for all of the optimizations I’m aware of.</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class="">I haven’t done any measurements, but this seems like it could be a big speedup, particularly for programs containing a bunch of relatively small files and not using WMO.</div><div class=""><br class=""></div><div class="">-Chris</div><div class=""><br class=""></div></span></div></body></html>