Commit Graph

440 Commits

Author SHA1 Message Date
Adam Nemet
5d7b8106c3 Add opt-remarks to the Speculative Devirtualizer pass 2017-12-18 13:29:46 -08:00
Adam Nemet
3a9012d742 Add opt-remarks to the Devirtualizer pass 2017-12-18 10:18:13 -08:00
Slava Pestov
47a3a66e52 SILOptimizer: Kill off duplicated getAllSubclasses() algorithm 2017-11-27 22:20:14 -08:00
Andrew Trick
8ffcf761af [sil-opaque-values] Fix EscapeAnalysis to track opaque values.
This is trivially tested by simply building generic code with opaque values at
-O.
2017-11-18 17:13:57 -08:00
swift-ci
012cc4a6e7 Merge pull request #12933 from anemet/opt-remark-generic-specialization 2017-11-17 10:05:22 -08:00
Adam Nemet
bd8764caaa Add opt remarks to Generic Specializer pass
Adds a combined API to output both debug message and optimization remarks.

The previously added test partial_specialization_debug.sil ensures that it's an
NFC for debug output.
2017-11-16 10:10:24 -08:00
Michael Gottesman
49adf11a00 [cfg] Add back in bool return value, returning a value to it this time. 2017-11-15 21:52:50 -08:00
Slava Pestov
2aa126e680 SILOptimizer: Fix a warning 2017-11-15 20:58:58 -08:00
swift-ci
00e71a1a38 Merge pull request #12926 from gottesmm/pr-7d7ad787aa26105e196576774cbf2188fdd8b1b0 2017-11-14 23:36:25 -08:00
Michael Gottesman
1c33bc19c4 [cfg] Add Ownership SIL utility method splitAllCondBrCriticalEdgesWithNonTrivialArgs.
Currently, the ownership verifier assumes that all cond_br with critical edges
do not have non-trivial arguments. This utility method fixes any such issues and
should be run /after/ any passes that mess with the CFG in ownership SIL if this
could come up.

Chopping this off of a larger commit.

rdar://31521023
2017-11-14 12:04:58 -08:00
Erik Eckstein
90c21be191 Unify the implementation of optimization mode in various option classes.
This commit is mostly refactoring.

*) Introduce a new OptimizationMode enum and use that in SILOptions and IRGenOptions
*) Allow the optimization mode also be specified for specific SILFunctions. This is not used in this commit yet and thus still a NFC.

Also, fixes a minor bug: we didn’t run mandatory IRGen passes for functions with @_semantics("optimize.sil.never")
2017-11-14 11:25:02 -08:00
Michael Gottesman
1288bff937 [cfg] Add utility method completeJointPostDominanceSet.
This helper utility given a set of uses/defs determines the set of blocks that
together with the user blocks jointly post-dominate the def blocks. In a sense
this is completing the providing set of user blocks to a joint-post dominating
set. This completion is not unique.

I am adding this method because often times when working with Ownership SIL, one
needs to hoist/sink operations and then compensate to ensure that ownership
properties are still preserved.

I think with a little bit of work I can get the ownership model eliminator to
use this routine (since the condition for ownership to be correct on an @owned
value is an empty joint-post dominating completion. I wrote it b/c I need it in
pred-memopts and I expect it to be a general useful routine for Ownership SIL.

rdar://31521023
2017-11-14 09:46:51 -08:00
John McCall
14d6390352 Add "yield" and "unwind" instructions to SIL. 2017-11-07 03:51:54 -05:00
Michael Gottesman
4c80c4d66f Address John's feedback.
Specifically to commits:

36a8d0d5c0
6df5462ee2

rdar://31521023
2017-10-25 13:48:51 -07:00
Michael Gottesman
6df5462ee2 [sil] Add support for multiple value instructions by adding MultipleValueInstruction{,Result}.
rdar://31521023
2017-10-24 18:36:37 -07:00
Andrew Trick
d369aa4070 Support @noescape SIL function types. (#12420)
Support for @noescape SILFunctionTypes.

These are the underlying SIL changes necessary to implement the new
closure capture ABI.

Note: This includes a change to function name mangling that
primarily affects reabstraction thunks.

The new ABI will allow stack allocation of non-escaping closures as a
simple optimization.

The new ABI, and the stack allocation optimization, also require
closure context to be @guaranteed. That will be implemented as the
next step.

Many SIL passes pattern match partial_apply sequences. These all
needed to be fixed to handle the convert_function that SILGen now
emits. The conversion is now needed whenever a function declaration,
which has an escaping type, is passed into a @NoEscape argument.

In addition to supporting new SIL patterns, some optimizations like
inlining and SIL combine are now stronger which could perturb some
benchmark results.

These underlying SIL changes should be merged now to avoid conflicting
with other work. Minor benchmark discrepancies can be investigated as part of
the stack-allocation work.

* Add a noescape attribute to SILFunctionType.

And set this attribute correctly when lowering formal function types to SILFunctionTypes based on @escaping.

This will allow stack allocation of closures, and unblock a related ABI change.

* Flip the polarity on @noescape on SILFunctionType and clarify that
we don't default it.

* Emit withoutActuallyEscaping using a convert_function instruction.

It might be better to use a specialized instruction here, but I'll leave that up to Andy.

Andy: And I'll leave that to Arnold who is implementing SIL support for guaranteed ownership of thick function types.

* Fix SILGen and SIL Parsing.

* Fix the LoadableByAddress pass.

* Fix ClosureSpecializer.

* Fix performance inliner constant propagation.

* Fix the PartialApplyCombiner.

* Adjust SILFunctionType for thunks.

* Add mangling for @noescape/@escaping.

* Fix test cases for @noescape attribute, mangling, convert_function, etc.

* Fix exclusivity test cases.

* Fix AccessEnforcement.

* Fix SILCombine of convert_function -> apply.

* Fix ObjC bridging thunks.

* Various MandatoryInlining fixes.

* Fix SILCombine optimizeApplyOfConvertFunction.

* Fix more test cases after merging (again).

* Fix ClosureSpecializer. Hande convert_function cloning.

Be conservative when combining convert_function. Most of our code doesn't know
how to deal with function type mismatches yet.

* Fix MandatoryInlining.

Be conservative with function conversion. The inliner does not yet know how to
cast arguments or convert between throwing forms.

* Fix PartialApplyCombiner.
2017-10-17 13:07:25 -07:00
Roman Levenstein
53754a7a69 Add a new simple utility optimization pass for serialization of SILModules 2017-10-13 23:19:19 -07:00
Roman Levenstein
6f3b326d12 IRGen should not emit bodies of public_external functions unless it is a transparent function.
Recent changes that eliminated the -sil-serialize-all mode and adding this check to IRGen allow us to get rid of ExternalFunctionDefinitionsElimination and ExternalDefsToDecls passes, which are not needed anymore.
2017-10-11 08:29:46 -07:00
John McCall
ab3f77baf2 Make SILInstruction no longer a subclass of ValueBase and
introduce a common superclass, SILNode.

This is in preparation for allowing instructions to have multiple
results.  It is also a somewhat more elegant representation for
instructions that have zero results.  Instructions that are known
to have exactly one result inherit from a class, SingleValueInstruction,
that subclasses both ValueBase and SILInstruction.  Some care must be
taken when working with SILNode pointers and testing for equality;
please see the comment on SILNode for more information.

A number of SIL passes needed to be updated in order to handle this
new distinction between SIL values and SIL instructions.

Note that the SIL parser is now stricter about not trying to assign
a result value from an instruction (like 'return' or 'strong_retain')
that does not produce any.
2017-09-25 02:06:26 -04:00
Michael Gottesman
baf293a0f6 Merge pull request #11846 from gottesmm/pr-0b7638743feaaad8531e324038be3fe1cd536022
[mandatory-inlining] Make fixupReferenceCounts not delete instructions.
2017-09-12 14:15:46 -07:00
Roman Levenstein
f0a39e9e14 Add support for collecting various SIL optimizer counters
This patch implements collection and dumping of statistics about SILModules, SILFunctions and memory consumption during the execution of SIL optimization pipelines.

The following statistics can be collected:
  *  For SILFunctions: the number of SIL basic blocks, the number of SIL instructions, the number of SIL instructions of a specific kind, duration of a pass
  *  For SILModules: the number of SIL basic blocks, the number of SIL instructions, the number of SIL instructions of a specific kind, the number of SILFunctions, the amount of memory used by the compiler, duration of a pass

By default, any collection of statistics is disabled to avoid affecting compile times.

One can enable the collection of statistics and dumping of these statistics for the whole SILModule and/or for SILFunctions.

To reduce the amount of produced data, one can set thresholds in such a way that changes in the statistics are only reported if the delta between the old and the new values are at least X%. The deltas are computed as using the following formula:

   Delta = (NewValue - OldValue) / OldValue

Thresholds provide a simple way to perform a simple filtering of the collected statistics during the compilation. But if there is a need for a more complex analysis of collected data (e.g. aggregation by a pipeline stage or by the type of a transformation), it is often better to dump as much data as possible into a file using e.g. -sil-stats-dump-all -sil-stats-modules -sil-stats-functions and then e.g. use the helper scripts to store the collected data into a database and then perform complex queries on it. Many kinds of analysis can be then formulated pretty easily as SQL queries.
2017-09-10 21:47:55 -07:00
Michael Gottesman
49bf82245b [mandatory-inlining] Make fixupReferenceCounts not delete instructions.
The main loop of mandatory inlining is spending a lot of time managing complex
iterator invalidation issues. This is the first in a series of commits that move
the main inlining loop to only delete the callee and to do all cleanups after we
have finished inlining.

This specific optimization (the quick retain/release peephole), I am not going
to do in MandatoryInlining, we already have guaranteed arc opts afterwards that
will be able to hit such a peephole so no perf should be lost.

*NOTE* The reason why I had to touch some of the code motion tests is that the
routine I am using to ensure that strong_retain/release_value is emitted as
appropriate is also used by codemotion. Code motion tests had cargo culted some
code from previous tests that retained Builtin.Int32. I changed the routines
though so that when a retain/release is inserted, if it is trivial, nothing is
inserted. No routine was relying on the actual usage of the inserted
retain/releases, so everything will be safe. This addition to the relevant code
caused me to need to change the tests in code motion to use actual non-trivial
values. The same code paths are being tested in terms of blocking code
motion/etc.

rdar://31521023
2017-09-10 13:23:48 -07:00
Michael Gottesman
9f53380824 [gardening] Add a note to DevirtualizationResult explaining that it can contain an Argument. 2017-09-09 15:54:47 -07:00
Michael Gottesman
430f865f73 [inliner] Extract out checking if we can inline from inlineFunction into canInlineFunction. NFC.
The reason to do this is:

1. The check in SILInliner if we can inline can be done without triggering
side-effects.

2. This enables us to know if inlining will succeed before attempting to inline.
This enables for arguments to be adjusted with new SILInstructions and the like
before inlining occurs. I use this in a forthcoming patch that updates mandatory
inlining for ownership.

rdar://31521023
2017-09-08 18:25:57 -07:00
Arnold Schwaighofer
b625d4da8a Osize: Add a SIL Outliner pass that outlines the bridging of objective c calls.
Implements outlining of bridged objective c property and method calls.

rdar://33387700
2017-09-06 08:37:37 -07:00
Jordan Rose
f8b7db4e76 Excise the terms "blacklist" and "whitelist" from Swift source. (#11687)
The etymology of these terms isn't about race, but "black" = "blocked"
and "white" = "allowed" isn't really a good look these days. In most
cases we weren't using these terms particularly precisely anyway, so
the rephrasing is actually an improvement.
2017-08-30 09:28:00 -07:00
Joe Shajrawi
570a82aea5 Reduce expansion of large types in the optimizer 2017-08-25 13:56:26 -07:00
Michael Gottesman
b1debfc401 [epilogue-arc-analysis] Be more efficient with memory usage.
This patch fixes a number of issues:

The analysis was using EpilogueARCContext as a temporary when computing. This is
an performance problem since EpilogueARCContext contains all of the memory used
in the analysis. So essentially, we were mallocing tons of memory every time we
missed the analyses cache. This patch changes the pass to instead have 1
EpilogueARCContext whose internal state is cleared in between invocations. Since
the data structures (see below) used after this patch do not shrink memory after
being cleared, this should cause us to have far less memory churn.

The analysis was managing its block state data structure by allocating the
individual block state structs using a BumpPtrAllocator/DenseMap stored in
EpilogueARCContext. The individual state structures were allocated from the
BumpPtrAllocator and the DenseMap then mapped a specific SILBasicBlock to its
State data structure. Ignoring that we were mallocing this memory every time we
computed rather than reusing global state, this pessimizes performance on small
functions significantly. This is because the BumpPtrAllocator by default heap
allocates initially a page and DenseMap initially mallocs a 64 entry hash
table. Thus for a 1 block function, we would be allocating a large amount of
memory that is just unneeded.

Instead this patch changes the analysis to use a std::vector in combination with
PostOrderFunctionInfo to manage the per block state. The way this works is that
PostOrderFunctionInfo already contains a map from a SILBasicBlock to its post
order number. So, when we are allocating memory for each block, we visit the CFG
in post order. Thus we know that each block's state will be stored in the vector
at vector[post order number].

This has a number of nice effects:

1. By eliminating the need for the DenseMap, in large test cases, we are
signficiantly reducing the memory overhead (by 24 bytes per basic block assuming
8 byte ptrs).
2. We will use far less memory when applying this analysis to small functions.

rdar://33841629
2017-08-11 18:18:39 -07:00
Michael Gottesman
b70c8b64a1 [sil-analysis] Add a new utility class for FunctionBaseInfo based analyses: LazyFunctionInfo.
Commonly when an analysis uses subanalyses, we eagerly create the sub function
info when constructing the main function info. This is not always necessary and
when the subanalyses do work in their constructor, can be actively harmful if
the parent analysis is never invoked.

This utility class solves this problem by being a very easy way to perform a
delayed call to the sub-analysis to get the sub-functioninfo combined with a
cache so that after the LazyFunctionInfo is used once, we do not reuse the
DenseMap in the sub-analysis unnecessarily.

An example of where this can happen is in EpilogueARCAnalysis in combination
with PostOrderFunctionInfo. PostOrderFunctionInfo eagerly creates a new post
order. So, if we were to eagerly create the PostOrderFunctionInfo (the
sub-functioninfo) when we created an EpilogueARCFunctionInfo, we would be
creating a post order even if we never actually invoke EpilogueARCFunctionInfo.
2017-08-11 18:18:39 -07:00
Michael Gottesman
ae25f44408 [epilogue-arc] Use maybeGet instead of get when handling delete notifications.
By using this the maybeGet API on FunctionAnalysisBase instead of get, we stop
EpilogueARCAnalysis from building itself if it does not yet exist, only to
invalidate itself.

rdar://33841629
2017-08-11 14:41:57 -07:00
Michael Gottesman
eb4d94f10b [sil-analysis] Add FunctionAnalysisBase::{hasAnalysis,maybeGet}(SILFunction *F).
Today, if one wants to invalidate state relative to your own function analysis,
you have to use FunctionAnalysisBase::get() to get the analysis. The problem
here is that if the analysis does not exist yet, then you are actually creating
the analysis. This is an issue when one wants to perform an action on an
analysis only if the analysis has already been built. An example of such a
situation is when one is processing a delete notification. If one does not have
an analysis for a function, one should just do nothing.

I am going to use this to fix a delete notification problem in
EpilogueARCAnalysis.

rdar://33841629
2017-08-11 14:41:57 -07:00
Michael Gottesman
6b54531455 Move the include guard of Analysis.h /above/ the includes.
Otherwise, every time we include Analysis.h, we will try to include those other
files even if we have already included Analysis.h. This can increase compile
time.

rdar://33841629
2017-08-11 14:40:36 -07:00
Erik Eckstein
21ab99bf80 SILOptimizer: fix performance problem in EpilogueARCAnalysis
The cache for analysis result was never set. This resulted in a pretty bad quadratic behavior.
2017-08-09 14:24:44 -07:00
Roman Levenstein
d493859d4b Merge pull request #11251 from swiftix/generic-specialization-fixes
Implement a more robust way to avoid infinite generic specialization loops
2017-08-07 09:05:56 -07:00
Roman Levenstein
8503daee0d Implement a more robust way to avoid infinite generic specialization loops
The existing simple mechanism for avoiding infinite generic specialization loops is based on checking the structural depth and width of types passed as generic type parameters. If the depth or the width of a type is above a certain threshold, the type is considered too complex for generic specialization and no specialization is produced. While this approach prevents the possibility of producing an infinite number of generic specializations for ever-growing generic type parameters, it catches the issue too late in some cases, leading to excessive CPU and memory usage.

Therefore, the new method tries to solve the problem at its root. An infinite generic specialization loop can be triggered by specializing a given generic call-site if and only if:
-  Doing so would result in a loop inside the specialization graph represented by the `GenericSpecializationInformations`, i.e. it would produce direct or indirect recursion involving a generic call
-  The substitutions used by the current generic call-site are structurally more complex than the substitutions used by the same call-site in the previous iteration inside specialization graph. More complex in this context means that the new generic type parameter structurally contains the generic type parameter from a previous iteration inside the specialization graph and has greater structural depth, e.g. `Array<Int>` is more complex than `Int`.

The generic specializer now records all the required information about specializations it produces and uses it later to detect and prevent any generic specializations which would result in an infinite specialization loop. It detects them as early as possible and thus reduces compile times, memory consumption and potentially also reduces the code-size by not generating useless specializations.
2017-08-06 12:51:49 -07:00
Erik Eckstein
6c93798acc SILOptimizer: Add a new TempRValue optimization pass
This is a separate optimization that detects short-lived temporaries that can be eliminated.
This is necessary now that SILGen no longer performs basic RValue forwarding in some cases.

SR-5508: Performance regression in benchmarks caused by removing SILGen peephole for LoadExpr in +0 context
2017-08-05 17:23:51 -07:00
Erik Eckstein
6377cc095a SIL: Replace TransitivelyUnreachableBlocks with DeadEndBlocks
We had both utilities doing the same thing.
NFC
2017-07-24 09:50:42 -07:00
Erik Eckstein
f561176f14 EsacpeAnalysis: add a utility to get the list of use-points of a node 2017-07-21 10:47:26 -07:00
Erik Eckstein
a0e6082d25 SILOptimizer: change the way how ValueLifetimeAnalysis handles dead-end (unreachable) CFG paths.
In dead-array elimination we assume that the array allocation is post-dominated by all its final releases.
The only exception are branches to dead-end ("unreachable") blocks. So we just ignored all paths which didn't end up in a final release.
Now we explicitly pass the set of dead-end blocks and just ignore those blocks.
This is safer and it's also needed in the upcoming re-write of StackPromotion.
2017-07-21 10:46:03 -07:00
Erik Eckstein
3b54966ff2 SILOptimizer: Add a utility to find dead-end blocks. 2017-07-21 10:37:54 -07:00
Devin Coughlin
47d9de9751 [Exclusivity] Relax closure enforcement on separate stored properties (#10789)
Make the static enforcement of accesses in noescape closures stored-property
sensitive. This will relax the existing enforcement so that the following is
not diagnosed:

struct MyStruct {
   var x = X()
   var y = Y()

  mutating
  func foo() {
    x.mutatesAndTakesClosure() {
      _ = y.read() // no-warning
   }
  }
}

To do this, update the access summary analysis to summarize accesses to
subpaths of a capture.

rdar://problem/32987932
2017-07-10 13:33:22 -07:00
Michael Gottesman
9933f0f3b2 Fix the swap_refcnt test on linux.
The problem here is that we were performing a naive negative FileCheck test for
retain/release. In certain modes, we would not have any retains/releases along
normal control paths but would have retains on unreachable paths. This test only
is trying to test if normal code paths have this issue.

To work around this issue, I created a small utility pass that prunes all
non-unreachable instructions from blocks with an unreachable terminator. This is
useful functionality in general when analyzing SIL since often times one will
have large fatal error blocks that disguise the true behavior of the
function. In this specific case, I just pipe in the normal sil output and run it
through sil-opt. sil-opt then runs just the utility pass and I then FileCheck
that sil-opt output.

rdar://30181104
2017-07-07 13:03:25 -06:00
Andrew Trick
89985ebacd Use the pass's "tag" for command-line options.
A pass has an ID (C++ identifier), Tag (shell identifier),
and Name (human identifier).

Command line options that identify passes should obviously be compatibile with
with the pass' command line identifier. This is also what the user is used to
typing for the -debug-only option.
2017-07-06 14:10:23 -07:00
Devin Coughlin
2501dd71de Revert "[Exclusivity] Relax closure enforcement on separate stored properties" 2017-07-05 20:19:50 -07:00
swift-ci
eb5d21b6e2 Merge pull request #10595 from devincoughlin/exclusivity-interprocedural-separate-stored-structs 2017-07-05 18:52:57 -07:00
Devin Coughlin
86dff5c0a7 [Exclusivity] Relax closure enforcement on separate stored properties
Make the static enforcement of accesses in noescape closures stored-property
sensitive. This will relax the existing enforcement so that the following is
not diagnosed:

struct MyStruct {
   var x = X()
   var y = Y()

  mutating
  func foo() {
    x.mutatesAndTakesClosure() {
      _ = y.read()
   }
  }
}

To do this, update the access summary analysis to be stored-property sensitive.

rdar://problem/32987932
2017-07-05 16:09:54 -07:00
Andrew Trick
d45f171c98 Cleanup AccessMarkerElimination.
In raw SIL, access markers are unconditionally retained. In canonical SIL,
markers are still removed prior to optimization.

A new flag, -sil-optimized-access-markers, allows testing access markers in
optimized builds, but it is not yet fully supported.
2017-07-05 15:18:48 -07:00
Andrew Trick
4575525786 NFC: Cleanup ClosureScope/AccessEnforcementSelection/Tests.
Per Devin and John's review.
2017-06-20 14:57:56 -07:00
Andrew Trick
00a72b8517 Comment typo. 2017-06-17 16:27:02 -07:00
Andrew Trick
0ce81c90f0 Doxygen formatting. 2017-06-17 16:19:16 -07:00