This updates the performance inliner to iterate on inlining in cases
where devirtualization or specialization after the first pass of
inlining expose new opportunities for inlining. Similarly, in some cases
inlining exposes new opportunities for devirtualization, e.g. when we
inline an initializer and can now see an alloc_ref that allows us to
devirtualize some class_methods.
The implementation currently has some inefficiencies which increase the
swift compilation time for the stdlib by around 3% (this is swift-time
only, no LLVM time, so overall time does not grow by this much).
Unfortunately the (unchanged) current implementation of the core
inlining trades off improved estimates of code growth for increased
compile time, and that plays a part in why compile time increases as
much as it does. Despite this, I have some ideas on how to win some of
that time back in future patches.
Performance differences are mixed, and this will likely require some
further inliner tuning to reduce or remove some of the losses seen here
at -O. I will open radars for the losses.
Wins:
DeltaBlue 10.2%
EditDistance 13.8%
SwiftStructuresInsertionSort 32.6%
SwiftStructuresStack 34.9%
Losses:
PopFrontArrayGeneric -12.7%
PrimeNum -19.0%
RC4 -30.7%
Sim2DArray -14.6%
There were a handful of wins and losses at Onone and Ounchecked as
well. I'll review the perf testing output and open radars accordingly.
The new test case shows an example of the power of the closer
integration here. We are able to completely devirtualize and inline a
series of class_method applies (10 deep in this case, but in theory
substantially deeper) in a single pass of the inliner, whereas before we
could only do a single level per pass of inlining & devirtualization.
Swift SVN r27561
This commit adds a flag to disable optimizations on a specific functions. The
primary motivation of this patch is to allow the optimizer developers to reduce
testcasese by disabling optimizations of parts of the code without having to
recompile the compiler or inspect SIL. The annotations "inline(never)"
and "optimize.none" can go a long way.
The second motivation for this patch is to allow our internal adopters to work
around compiler bugs.
rar://19745484
Usage:
@semantics("optimize.never")
public func miscompile() { ... }
Swift SVN r27475
During inlining we'll now attempt to first devirtualize and specialize
within the function that we're going to inline into. If we're successful
devirtualizing and inlining, and we'll attempt to inline into the newly
exposed callees first, before inlining into the function we began with.
This does not remove any existing passes of devirtualization or
specialization yet, partially because we don't completely handle all
cases that they handle at this point (e.g. specializing partial
applies).
We do end up specializing deeper into the call graph with this approach
than we did prior to this commit.
I will have some follow-on changes that integrate things further,
allowing us to devirtualize in more cases after inlining into a given
function.
I will also add some directed tests in a future commit.
I tested the stdlib build and this made no difference in build
times. Perhaps after removing other existing phases we'll recapture some
build time.
I'm not seeing reproducible performance differences with this change,
which is not a big surprise at this point. This sets us up for being
able to improve the compilation pipeline in a future release.
Swift SVN r27327
Previous attempts to update the callgraph explicitly after calls to
linkFunction() weren't completely effective because we can deserialize
deeply and introduce multiple new function bodies in the process.
This gets us a bit closer, but only adds new call graph nodes. It does
not currently add edges for everything that gets deserialized (and this
is not fatal, so it is a step forward).
Swift SVN r27120
We claim to maintain the call graph in these passes, so we really need
to add nodes for new functions we pull in.
Also, link in functions when building the call graph, and only allow
functions with bodies to be added to the call graph.
This makes the call graph more consistent.
At some point we need to revisit our linking story because we've got
code spread out over several phases now where it might make sense to do
a single up-front linking pass that potentially pulls in
never-referenced functions (e.g. pull in all foo() that could be reached
in a given class hierarchy up front, even if in reality only C.foo() is
ever called).
Swift SVN r27096
Before this commit, passes that were attempting to maintain the call
graph would actually build it if it wasn't already valid, just for the
sake of maintaining it.
Now we only maintain it if we already had a valid call graph built.
Swift SVN r26873
This leaves nothing but the helper for specializing an ApplySite in
Generics.h/Generics.cpp, and I expect to rename these files accordingly
at some point.
Swift SVN r26827
Another refactoring step towards splitting the generic specializer into
a pass vs. the cloner vs. a utility that can specialize a given
ApplySite.
Swift SVN r26817
More refactoring of generic specializer, on the path to making the this
new function the primary utility that can be used from other passes.
Swift SVN r26791
The old invalidation lattice was incorrect because changes to control flow could cause changes to the
call graph, so we've decided to change the way passes invalidate analysis. In the new scheme, the lattice
is replaced with a list of traits that passes preserve or invalidate. The current traits are Calls and Branches.
Now, passes report which traits they preserve, which is the opposite of the previous implementation where
passes needed to report what they invalidate.
Node: I tried to limit the changes in this commit to mechanical changes to ease the review. I will cleanup some
of the code in a following commit.
Swift SVN r26449
This will have an effect on inlining into thunks.
Currently this flag is set for witness thunks and thunks from function signature optimization.
No change in code generation, yet.
Swift SVN r24998
1. Eliminate unused variable warnings.
2. Change field names to match capitalization of the rest of the field names in the file.
3. Change method names to match rest of the file.
4. Change get,set method for a field to match the field type.
Swift SVN r24501
The underlying problem is that e.g. even if a method is private but its class is public, the method can be referenced from another module - from the vtable of a derived class.
So far we handled this by setting the SILLinkage of such methods according to the visibility of the class. But this prevented dead method elimination.
Now I set the SILLinkage according to the visibility of the method. This enables dead method elimination, but it requires the following:
1) Still set the linkage in llvm so that it can be referenced from outside.
2) If the method is dead and eliminated, create a stub for it (which calls swift_reportMissingMethod).
Swift SVN r23889
This is apart of creating the infrastructure for creating special manglings for
all of the passes that we specialize. The main motiviations for this
infrastructure is:
1. Create an easy method with examples on how to create these manglings.
2. Support multiple specializations. This is important once we allow for partial
specialization and can already occur if we perform function signature
optimizations on specialized functions.
The overall scheme is as follows:
_TTS<MANGLINGINFO>__<FUNCNAME>
Thus if we specialize twice, the first specialization will just be treated as
the function name for the second specialization.
<MANGLINGINFO> is defined as:
_<SPECIALIZATIONKINDID>_<SPECIALIZATIONUNIQUEINFO>
Where specialization kind is an enum that specifies the specific sort of
specialization we are performing and specialization unique info is enough
information to ensure that the identity of the function is appropriately
preserved.
Swift SVN r23801
Change the function insert policy to insert specializations before the
function we are specializing rather than at the end of the module in
order to make the -emit-sil output a little less dependent on the actual
order we specialize in.
Swift SVN r22595
Now the SILLinkage for functions and global variables is according to the swift visibility (private, internal or public).
In addition, the fact whether a function or global variable is considered as fragile, is kept in a separate flag at SIL level.
Previously the linkage was used for this (e.g. no inlining of less visible functions to more visible functions). But it had no effect,
because everything was public anyway.
For now this isFragile-flag is set for public transparent functions and for everything if a module is compiled with -sil-serialize-all,
i.e. for the stdlib.
For details see <rdar://problem/18201785> Set SILLinkage correctly and better handling of fragile functions.
The benefits of this change are:
*) Enable to eliminate unused private and internal functions
*) It should be possible now to use private in the stdlib
*) The symbol linkage is as one would expect (previously almost all symbols were public).
More details:
Specializations from fragile functions (e.g. from the stdlib) now get linkonce_odr,default
linkage instead of linkonce_odr,hidden, i.e. they have public visibility.
The reason is: if such a function is called from another fragile function (in the same module),
then it has to be visible from a third module, in case the fragile caller is inlined but not
the specialized function.
I had to update lots of test files, because many CHECK-LABEL lines include the linkage, which has changed.
The -sil-serialize-all option is now handled at SILGen and not at the Serializer.
This means that test files in sil format which are compiled with -sil-serialize-all
must have the [fragile] attribute set for all functions and globals.
The -disable-access-control option doesn't help anymore if the accessed module is not compiled
with -sil-serialize-all, because the linker will complain about unresolved symbols.
A final note: I tried to consider all the implications of this change, but it's not a low-risk change.
If you have any comments, please let me know.
Swift SVN r22215
This will let the performance inliner inline a function even if the costs are too high.
This attribute is only a hint to the inliner.
If the inliner has other good reasons not to inline a function,
it will ignore this attribute. For example if it is a recursive function (which is
currently not supported by the inliner).
Note that setting the inline threshold to 0 does disable performance inlining at all and in
this case also the @inline(__always) has no effect.
Swift SVN r21452
Expose Substitution's archetype, replacement, and conformances only through getters so we can actually assert invariants about them. To start, require replacement types to be materializable in order to catch cases where the type-checker tries to bind type variables to lvalue or inout types, and require the conformance array to match the number of protocol conformances required by the archetype. This exposes some latent bugs in the test suite I've marked as failures for now:
- test/Constraints/overload.swift was quietly suffering from <rdar://problem/17507421>, but we didn't notice because we never tried to codegen it.
- test/SIL/Parser/array_roundtrip.swift doesn't correctly roundtrip substitutions, which I filed as <rdar://problem/17781140>.
Swift SVN r20418
Enable SIL parsing and SIL serialization of semantics.
We add one more field to SILFunctionLayout for semantics. We should refactor
handling of attributes at SIL level, right now they are in SILFunction as bool
or std::string and in SIL serializer as a 1-bit field or an ID field.
rdar://17525564
Swift SVN r19434
info for them and generally clean up the inline scope handling a bit.
Fix the debug scope handling for all clients of SILCloner, especially
the SIL-level spezializers and inliners.
This also adds a ton of additional assertions that will ensure that
future optimization passes won't mess with the debug info in a way that
could confuse the LLVM backend.
Swift SVN r18984
Rather than calling getSubstitutions() in various places on the apply
that we are cloning the body of, pass the substitution list in
directly when creating the cloner.
This is not interesting for the generic specializer, but is important in
mandatory inlining when we go to inline an apply of a partial apply,
where we need to use the full list of substitutions for both.
Swift SVN r18951
Mandatory-inlined (aka transparent functions) are still treated as if they
had the location and scope of the call site. <rdar://problem/14845844>
Support inline scopes once we have an optimizing SIL-based inliner
Patch by Adrian Prantl.
Swift SVN r18835
Add a new SpecializingCloner that will contain the
generic-specialization-specific functionality needed by that pass. This
inherits from TypeSubCloner, which I will move into a separate file in a
future commit after further refactoring.
Swift SVN r18791