Commit Graph

4277 Commits

Author SHA1 Message Date
Slava Pestov
0937c905cf Merge pull request #28399 from slavapestov/track-cast-formal-type
Track cast target formal type
2019-11-21 02:36:43 -05:00
Andrew Trick
191f9db59f EscapeAnalysis: eliminate dangling pointers.
Avoid dangling pointers in the connection graph when SILValues are
deleted. This didn't show up in normal compilation because the values
were only used for printing the graph. But now we have more assertions
that check for well-formed graph. These could hit the dangling
pointers.

To guarantee this can't happen, establish a strict invariant that the
mappedValue is only used for nodes that exist in the value-to-node
map. Then clear out mappedValue whenever a value is deleted. Add
verification to ensure that each node's mappedValue is valid and catch
dangling pointers quickly.

This completely changes the way that a node values are set and used
which in turn makes it *much* easier to debug the graph and associate
the nodes with the SIL function. For example, it's normal to view or
dump the graph at a key point. When the nodes are printed, the
associated SILValues are now more precise and consistent. However,
it's also normal to call CGNode::dump() from tracing code or within a
debugger. Previously, there was no way to assocate the output of
CGNode::dump() with the printed or displayed connection graph. Now
both forms of output have identical node IDs!

While we're at it, make sure the hasRC flag is always merged
conservatively in a couple more places.

Fixed <rdar://57290845> While running SILFunctionTransform "TempRValueOpt"
2019-11-20 23:06:10 -08:00
Michael Gottesman
bfb10c8537 Merge pull request #28363 from gottesmm/pr-d097386463f35a7609fbf264df06cb5904d9746f
[silopt] Wire up the SerializeSIL pass pipeline so we always serialize at -O even if we don't run all or a subset of the passes.
2019-11-20 23:05:14 -08:00
Andrew Trick
22f6a52bbe Merge pull request #28391 from gottesmm/pr-387c0c7db76bf23d1538f79b329f5657a6431965
[existential-specializer] Do not process callees with ownership as well as callers without ownership.
2019-11-20 22:35:00 -08:00
Ravi Kandhadai
ba7996712a Merge pull request #28350 from ravikandhadai/oslog-exec-test-enable
[OSLogOptimization] Fix a bug in the replaceAllUsesAndFixLifetimes function of the OSLogOptimization pass
2019-11-20 19:38:35 -08:00
Slava Pestov
53bfc767a3 SIL: Track target formal type for casts
SIL type lowering erases DynamicSelfType, so we generate
incorrect code when casting to DynamicSelfType. Fixing this
requires a fair amount of plumbing, but most of the
changes are mechanical.

Note that the textual SIL syntax for casts has changed
slightly; the target type is now a formal type without a '$',
not a SIL type.

Also, the unconditional_checked_cast_value and
checked_cast_value_br instructions now take the _source_
formal type as well, just like the *_addr forms they are
intended to replace.
2019-11-20 21:30:28 -05:00
Michael Gottesman
47de65c17a [ownership] Add an additional run of the SemanticARCOpts at the beginning of the perf pipeline.
I left in the run before DestroyHoisting since I believe that DestroyHoisting
depends a bit on SemanticARCOpts running, but at the same time I don't want to
deal with any regressions that may come from moving DestroyHoisting.
2019-11-20 17:08:03 -08:00
Michael Gottesman
5224218a1d [existential-specializer] Do not process callees with ownership as well as callers without ownership.
I already turned this off for callers. I just didn't do it for callees. Just an
oversight.

rdar://57291312
2019-11-20 14:21:06 -08:00
Slava Pestov
291364b2f1 Merge pull request #28037 from zoecarver/semantics-def
Semantics attribute definition file
2019-11-20 16:42:29 -05:00
zoecarver
2070821df7 Add tests 2019-11-20 10:36:13 -08:00
Erik Eckstein
bb38711894 DestoyHoisting: handle infinite loops correctly
Ignore blocks in infinite loops and don't insert destroys where they don't belong.

Fixes an ownership verifier crash.
2019-11-20 11:16:05 +01:00
zoecarver
4dcbc42409 Move collection into collect method 2019-11-19 20:56:06 -08:00
zoecarver
0e389cee87 Cleanup 2019-11-19 18:05:23 -08:00
Michael Gottesman
bbbad03a27 [silopt] Wire up the SerializeSIL pass pipeline so we always serialize at -O even if we don't run all or a subset of the passes. 2019-11-19 13:56:32 -08:00
zoecarver
12883d07d9 Merge branch 'master' into semantics-def 2019-11-19 13:02:47 -08:00
Ravi Kandhadai
f319f15655 [OSLogOptimization] Fix a bug in the replaceAllUsesAndFixLifetimes
function of the OSLogOptimization pass that happens when folding a
guaranteed value with a constant (owned) value. The fix inserts the
constant value at the beginning of the borrowed scope of the guaranteed
value rather than at the definition of the guaranteed value.

Update the SIL tests for the new folding pattern and add a test that
catches this bug.

Also, re-enable the OSLogPrototypeExecTest.swift that was disabled
due to this bug.
2019-11-19 11:50:08 -08:00
Michael Gottesman
8de96f3959 [silopt] Add a new SerializeSIL utility pipeline.
This pipeline just runs the Serialize SIL pass. The reason I am adding this is
that currently if one passes -disable-sil-perf-optzns or mess with
-sil-opt-pass-count, one can cause serialization to not occur, making it
difficult to bisect/turn off-on opts.
2019-11-18 16:14:57 -08:00
Michael Gottesman
1a4b362503 [oslog] Fix bug where OSLog was not invalidating any state that it was changing.
This is important both for correctness reasons and for triaging reasons. The
correctness is obvious, but for those unaware there are many triaging utilities
that only verify or print pass output if the pass makes a change as indicated by
invalidating state.
2019-11-18 13:26:50 -08:00
zoecarver
f52a6f3317 Refactor and add tests 2019-11-18 08:59:50 -08:00
zoecarver
9cd11a6b75 Add optimization to remove unused global private variables 2019-11-17 20:17:19 -08:00
Michael Gottesman
07c625b4b0 [pmo] Eliminate non-determinism by unmixing some iteration order/sorting bisection code.
Specifically, I was abusing some sorting behavior on some arrays that I really
needed to iterate over == non-determinism. To work around these issues, I made
two changes:

1. Rather than using a bit vector to mark copy_values that were handled as part
of phi handling and thus needing a way to map copy_value -> bit vector index, I
instead just added a separate small ptr set called
copyValueProcessedWithPhiNodes.

2. I refactored/changed how copy cleanups were inserted for phi nodes by
constructing a flat 2d-array that is stable sorted by the index of the incoming
value associated with the cleanups. An incoming value's index is the count of
the copy cleanup when we see it for the first time. Thus when we do the stable
sort we will be visiting in cleanup insertion order and also will be doing
insertion order along the incomingValue axis.
2019-11-17 03:48:00 -08:00
Michael Gottesman
6759d82dad Revert "Revert "[pmo] Fix load [copy] like I fixed load_borrow.""
This reverts commit 2b8e266694.

That reapplies 7623367208.
2019-11-17 03:48:00 -08:00
Brent Royal-Gordon
2b8e266694 Revert "[pmo] Fix load [copy] like I fixed load_borrow." 2019-11-16 15:54:12 -08:00
Robert Widmann
9732f811fd Merge pull request #23070 from gottesmm/pr-593fd7aed5142c9e2b0b2f18bf47074e65a04005
[cast-opt] Fix obvious bug.
2019-11-16 13:53:44 -08:00
Michael Gottesman
95de4d2929 [pmo] Fix load [copy] like I fixed load_borrow.
This involved fixing a few issues exposed by trying to use the load_borrow code
with load [copy] that were caught in our tests by the ownership
verifier. Specifically:

1. In getUnderlyingBorrowIntroducingValues we were first checking if a user was
a guaranteed forwarding instruction and then doing a check if our value was a
value with None ownership that we want to skip. This caused weird behavior where
one could get the wrong borrow introducers if that trivial value came from a
different guaranteed value.

2. I found via a test case in predictable_memaccess_opts that we needed to
insert compensating destroys for phi nodes after we process all of the incoming
values. The reason why this is needed is that multiple phi nodes could use the
same incoming value. In such a case, we need to treat all of the copy_values
inserted for each phi node as users of that incoming value to prevent us from
inserting too many destroy_value. Consider:

```
bb0:
  %0 = copy_value
  cond_br ..., bb1, bb2

bb1:
  br bb3(%0)

bb2:
  br bb4(%0)
```

If we processed the phi args in bb3, bb4 separately, we would insert an extra 2
destroys in bb1, bb2.

The implementation works by processing each phi and for each incoming value of
the phi appending the value, copy we made for the value to an array. We then
stable sort the array only by value. This then allows us to process ranges of
copies with the same underlying incoming value in a 2nd loop taking advantage of
all of the copies for an incoming value being contiguous in said array. We still
lifetime extend to the load/insert destroy_value for the actual phi (not its
incoming values) in that first loop.

3. I tightened up the invariant in the AvailableValueAggregator that it always
returns values that are newly copied unless we are performing a take. This
involved changing the code in handlePrimitiveValues to always insert copies when
ownership is enabled.

4. I tightened up the identification of intermediate phi nodes by instead of
just checking if the phi node has a single terminator user to instead it having
a single terminator user that has a successor with an inserted phi node that we
know about.
2019-11-15 15:16:58 -08:00
Andrew Trick
84e1d7e84d Merge pull request #28273 from atrick/escape-initializePointsTo
Cleanup EscapeAnalysis::ConnectionGraph::initializePointsTo.
2019-11-15 11:03:45 -08:00
Andrew Trick
9a71f235d7 Merge pull request #27444 from atrick/fix-sink-address
Generalize and fix SinkAddressProjections.
2019-11-15 09:54:04 -08:00
Andrew Trick
e66e033b00 Cleanup EscapeAnalysis::ConnectionGraph::initializePointsTo.
Remove cruft that I added in the previous commit. This eliminates
unnecessary cleverness so initializePointsTo is now very simple.

Add hand-coded SIL test cases to somewhat verify that the new
algorithm works.
2019-11-15 09:11:35 -08:00
swift-ci
16ea9fa3f0 Merge pull request #28277 from gottesmm/pr-fe75266370825e5d95381c70f6bf20f16b738542 2019-11-14 18:20:30 -08:00
Michael Gottesman
b30efa7566 [pmo] Refactor addHandOffCopyDestroysForPhis to be able to take a load or load_borrow.
Just some small changes to types. NFC.
2019-11-14 16:46:11 -08:00
Andrew Trick
38c29e231e Generalize and fix SinkAddressProjections.
Fixes a potential real bug in the case that SinkAddressProjections moves
projections without notifying SimplifyCFG of the change. This could
fail to update Analyses (probably won't break anything in practice).

Introduce SILInstruction::isPure. Among other things, this can tell
you if it's safe to duplicate instructions at their
uses. SinkAddressProjections should check this before sinking uses. I
couldn't find a way to expose this as a real bug, but it is a
theoretical bug.

Add the SinkAddressProjections functionality to the BasicBlockCloner
utility. Enable address projection sinking for all BasicBlockCloner
clients (the four different kinds of jump-threading that use it). This
brings the compiler much closer to banning all address phis.

The "bugs" were originally introduced a week ago here:

commit f22371bf0b (fork/fix-address-phi, fix-address-phi)
Author: Andrew Trick <atrick@apple.com>
Date:   Tue Sep 17 16:45:51 2019

    Add SIL SinkAddressProjections utility to avoid address phis.

    Enable this utility during jump-threading in SimplifyCFG.

    Ultimately, the SIL verifier should prevent all address-phis and we'll
    need to use this utility in a few more places.

    Fixes <rdar://problem/55320867> SIL verification failed: Unknown
    formal access pattern: storage
2019-11-14 16:11:00 -08:00
swift-ci
d5023558af Merge pull request #19048 from kitasuke/fix_typo_of_marked_uninitialized 2019-11-14 11:50:28 -08:00
Andrew Trick
1ca57e06d7 Merge pull request #28249 from atrick/fix-trivially-dup
Fix logic related to isTriviallyDuplicatable.
2019-11-14 09:10:39 -08:00
Andrew Trick
71523642ce Fix logic related to isTriviallyDuplicatable.
In SILInstruction::isTriviallyDuplicatable():

- Make deallocating instructions trivially duplicatable. They are by
  any useful definition--duplicating an instruction does not imply
  reordering it. Tail duplication was already treating deallocations
  as duplicatable, but doing it inconsistently. Sometimes it checks
  isTriviallyDuplicatable, and sometimes it doesn't, which appears to
  have been an accident. Disallowing duplication of deallocations will
  cause severe performance regressions. Instead, consistently allow
  them to be duplicated, making tail duplication more powerful, which
  could expose other bugs.

- Do not duplicate on-stack AllocRefInst (without special
  consideration). This is a correctness fix that apparently was never
  exposed.

Fix SILLoop::canDuplicate():

- Handle isDeallocatingStack. It's not clear how we were avoiding an
  assertion before when a stack allocatable reference was confined to
  a loop--probably just by luck.

- Handle begin/end_access inside a loop. This is extremely important
  and probably prevented many loop optimizations from working with
  exclusivity.

Update LoopRotate canDuplicateOrMoveToPreheader(). This is NFC.
2019-11-13 18:39:23 -08:00
Andrew Trick
166daeba7d Merge pull request #28153 from atrick/escape-refcount
EscapeAnalysis: add a refcount flag to content nodes.
2019-11-13 14:30:35 -08:00
swift-ci
f3b2430d51 Merge pull request #28235 from gottesmm/pr-b17541a0a4d7b1ca7d40f3c80835d603a5698adc 2019-11-13 12:33:41 -08:00
Andrew Trick
999b32e0fd EscapeAnalysis: add a refcount flag to content nodes.
This property will allow alias analysis to be safely optmistic when
querying the connection graph. A node that is known to have a ref
count is know to keep alive everything it points to. Therefore,
calling a deinitializer on a different reference cannot release the RC
node's contents.
2019-11-13 11:41:34 -08:00
Andrew Trick
95c716c0b2 Merge pull request #28139 from atrick/escape-createcontentnode
EscapeAnalysis: rework graph update and merge algorithms
2019-11-13 11:18:02 -08:00
Michael Gottesman
dfb9a80b56 [semantic-arc-opts] Do not perform the (guaranteed (copy)) -> (guaranteed) transform if all destroys are dead end and we have a local borrow scope.
This is an analogous fix to a previous fix where we were eliminating copies that
were post-dominated by dead ends such that the copy_value did not have any
destroys.

rdar://56807157
2019-11-13 11:12:19 -08:00
Ravi Kandhadai
633bc7947d [OSLogOptimization] Improve the OSLogOptimization pass so that it can
fold a symbolic closure, which is the representation of a closure literal
in the constant evaluator. This commit improves the function
emitCodeForSymbolicValue so that given a symbolic closure it can emit
SIL code for constructing the closure.

This improvement enables folding the arguments array, which is an array
of closures, by its constant value inferred by constant evaluating the
new OSLog calls.
2019-11-12 18:39:02 -08:00
Ravi Kandhadai
6f086afee2 [SIL Optimization][OSLogOptimization] Improve the OSLogOptimization
pass so that it constant folds array symbolic values inferred by the
constant evaluator when evaluting os log calls.
2019-11-12 18:14:48 -08:00
Ravi Kandhadai
f2ec557619 [OSLogOptimization] Improve the replaceAndFixLifetimes function
of the OSLogOptimization pass. This commit contain two changes:
 - It handles non-OSSA better (but it is meant to be phased out) so
   that array and closure folding can be supported
 - It fixes a bug in the OSSA folding by making sure that when an
   owned value replaces a guaranteed value, the owned value is
   borrowed and the borrow is used in place of the guaranteed value.
2019-11-12 18:14:48 -08:00
swift-ci
39fb55b616 Merge pull request #28156 from marcrasi/diff-fn-ty-ast-bits 2019-11-12 17:28:47 -08:00
Marc Rasi
6413f4341a [AutoDiff upstream] AST bits for @differentiable fn ty 2019-11-12 15:19:03 -08:00
Andrew Trick
2c7e348814 EscapeAnalysis: rework graph update and merge algorithms
The two major take aways from this patch are:

(1) Impose graph structure and reduce superfluous nodes and edges.

Incrementally make the connection graph and the APIs used to construct
it more structured.

_This allows node properties based on the SILValue to be reliably added to nodes_

Although that was the initial motiviation, there are other
benefits. Non-content nodes now have verifiable SILValues. Content
nodes now have meaningful SILValues even though they can't be
guaranteed due to merging. As a result it is *much* easier to debug
the graph and correlate it with the SIL. Rather than a web of
connection graph nodes with no identity and edges that don't
correspond to anything in SIL, the graph nodes now have value number
that correspond to the instruction used to dereference the node. The
edges also exhibit structure now. A pointsTo edge now (in practice)
always corresponds to a real pointer deference in the SIL. Doing this
required more than just adding some helpers, it was also necessary to
rewrite the graph merge and update algorithms.

(2) Split up underlying functionality into more explicit steps

Breaks apart the most complex parts of the graph algorithms into small
self-contained, self-checked steps. The purpose of each step is clear
and it's possible to reason about correctness from basic
invariants. Each merge step can now run full graph verification.

This was also done to move toward an invariant that the graph is never
mutated during a query. But to finish that goal, we need to add a
use-point query. With that, there will be no node creation, use point
propagation, new defer edges, etc. after graph building. At the very
least, this will make it sane to debug the output of the analysis.

---
Here is a change-by-change description in diff order:

Replace `updatePointsTo` with `initializePointsTo` and
`mergePointsTo`. Merging is very simple on its own. Initialization
requires some extra consideration for graph invariants. This
separation makes it possible to write stong asserts and to
independently reason about the correctness of each step based on
static invariants.

Replace `getContentNode` with `createContentNode`, and add two higher
level APIs `createMergedContent`, and `getFieldContent`. This makes
explicit the important cases of merging nodes and creating a special
nodes for class fields. This slightly simplifies adding properties to
content nodes and helps understand the structure of the graph.

Factor out an `escapeContentsOf` helper for use elsewhere...

Add a `getValueContent` helper. This is where we can tie the
properties of content nodes to the address values that are used to
address that content. This now also ensures that a Value node's
value field is consistent with all SILValues that map to it.

Add -escapes-internal-verify to check that the graph is in a valid
state after every merge or update step. This verification drove the
partial rewrite of mergeAllScheduledNodes.

ConnectionGraph::defer implementation: explictly handle the three
possible cases of pointsTo initialization or pointsTo merging at the
top level, so that those underlying implementations do not need to
dynamically handle weirdly different scenarios.

ConnectionGraph::initializePointsTo implementation: this simplified
implementation is possible by relying on invariants that can be
checked at each merge/update step. The major functional difference is
that it avoids creating unnecessary pointsTo edges. The previous
implementation often created pointsTo edges when adding defer edges
just to be conservative. Fixing this saved my sanity during debugging
because the pointsTo edges now always correspond to a SIL operations
that dereference the pointer. I'm also arguing without evidence that
this should be much more efficient.

ConnectionGraph::mergeAllScheduledNodes implementation: Add
verification to each step so that we can prove the other utilities
that are used while merging aren't making incorrect assumptions about
the graph state. Remove checks for merged nodes now that the graph is
consistently valid. Also remove a loop at the end that didn't seem to
do anything. The diff is impossible to review, but the idea is
basically the same. As long as it's still possible to scan through the
steps in the new code without getting totally lost, then the goal was
achieved.

ConnectionGraph::mergePointsTo: This is extremely simple now. In all
the places where we used to call updatePointsTo, and now call
mergePointsTo, it's a lot easier for someone debugging the code to
reason about what could possibly happen at that point.

`createMergedContent` is a placeholder for transferring node properties.

The `getFieldContent` helper may seem silly, but I find it helpful to
see all the important ways that content can be created in one place
next to the createContentNode, and I like the way that the creation of
the special "field content" node is more explicit in the source.

ConnectionGraph::mergeFrom implementation: this is only a minor
cleanup to remove some control flow nesting and use the CGNodeWorklist
abstraction.

In AnalyzeInstruction, add EscapeAnalysis::getValueContent helper. It
eliminates an extra step of going through the value node to get at its
content node. This is where we can derive content node properties from
the SILValue that dereferences the content. We can update the content
node's associated value 'V' if it's useful. It's also a place to put
assertions specific to the first level of content.

In AnalyzeInstruction, Array semantic calls: add support for
getValueContent so we can derive node properties. This is also nice
because it's explicit about which nodes are value content vs. field
content.

In AnalyzeInstruction, cleanup Release handling: use the explicit
APIs: getValueContent, getFieldContent, and escapeContentsOf.

In AnalyzeInstruction, assert that load-like things can't produce addresses.

In AnalyzeInstruction, add comments to clarify object projection handling.

In AnalyzeInstruction, add comments to explain store handling.

In AnalyzeInstruction, drop the assumption that all partial applies hold pointers.

In AnalyzeInstruction, handle aggregates differently so that Value
nodes are always consistent with their SILValue and can be
verified. Aggregates nodes are still coalesced if they only have a
single pointer-type subelement. If we arbitrarily coalesced an
aggregate with just one of its subelements then there would be no
consistent way to identify the value that corresponds to a connection
graph node.
2019-11-12 14:08:23 -08:00
Arnold Schwaighofer
a30f80457d Merge pull request #28044 from aschwaighofer/sil_type_expansion_context
SIL: Use a TypeExpansionContext in SIL lowering to expand opaque type archetypes as part of lowering
2019-11-12 12:02:20 -08:00
Michael Gottesman
a02fca16e2 [ownership] Add a frontend option -disable-ossa-opts to disable ossa based opts for benchmarking purposes. 2019-11-12 10:12:45 -08:00
Michael Gottesman
eab9be8f2f [pmo] Fix load_borrow for strong control equivalence issues.
This entailed untangling a few issues. I have purposefully only fixed this for
now for load_borrow to make the change in tree smaller (the reason for my
splitting the code paths in a previous group of commits). I am going to follow
up with a load copy version of the patch. I think that the code should be the
same. The interesting part about this is that all of these code conditions are
caught by the ownership verifier, suggesting to me that the code in the
stdlib/overlays is simple enough that we didn't hit these code patterns.

Anyways, the main change here is that we now eliminate control equivalence
issues arising from @owned values that are not control equivalent being
forwarded into aggregates and phis. This would cause our outer value to be
destroyed early since we would be destroying it once for every time iteration in
a loop.

The way that this is done is that (noting that this is only for borrows today):

* The AvailableValueAggregator always copies values at available value points to
  lifetime extend the values to the load block. In the load block, the
  aggregator will take the incoming values and borrow the value to form tuples,
  structs as needed. This new guaranteed aggregate is then copied. If we do not
  need to form an aggregate, we just copy. Since the copy is in our load block,
  we know that we can use it for our load_borrow. Importantly note how we no
  longer allow for these aggregates to forward owned ownership preventing the
  control equivalence problem above.

* Since the aggregator may use the SSA updater if it finds multiple available
  values, we need to also make sure that any phis are strongly control
  equivalent on all of its incoming values. So we insert copies along those
  edges and then lifetime extend the phi as appropriate.

* Since in all of the above all copy_value inserted by the available value
  aggregator are never consumed, we can just add destroy_values in the
  appropriate places and everything works.
2019-11-11 23:47:36 -08:00
Arnold Schwaighofer
f3a5d69672 Adjust to recent change 2019-11-11 14:21:52 -08:00
Arnold Schwaighofer
8a4d61fb1d Remove FIXME in TypeExpansionAnalysis: It's cache needed to be keyed by the type expansion context 2019-11-11 14:21:52 -08:00