and eliminate dead code. This is meant to be a replacement for the utility:
recursivelyDeleteTriviallyDeadInstructions. The new utility performs more aggresive
dead-code elimination for ownership SIL.
This patch also migrates most non-force-delete uses of
recursivelyDeleteTriviallyDeadInstructions to the new utility.
and migrates one force-delete use of recursivelyDeleteTriviallyDeadInstructions
(in IRGenPrepare) to use the new utility.
Correctness: do not make any unenforced assumptions about how the
connection graph is built (I don't think the previous assumption about
the structure of the graph node mapped to a reference-type value would
always hold if content nodes can be arbitrarily merged). Only make one
assumption about the client code: the access being checked must be to
some address within the provided value, not another object indirectly
reachable from that value.
Optimization: Allow escape analysis to prove that an addressable
object does not escape even when one of its reference-type fields
escapes.
That appears to have been a partial workaround for the real
problem that usepoints need to be propagated across the entire
defer web. This is now solved by considering use points on the
reference node's content, not the reference node itself.
For alias analysis query to be generally correct, we need to
effectively merge the escape state and use points for everything in a
defer web.
It was unclear from the current design whether the "escaping" property
applied to the pointer value or its content. The implementation is
inconsistent in how it was treated. It appears that some bugs have
been worked around by propagating forward through defer edges, some
have been worked around by querying the content instead of the
pointer, and others have been worked around be creating fake use
points at block arguments.
If we always simply query the content for escape state and use points,
then we never need to propagate along defer edges. The current code
that propagates escape state along defer edges in one direction is
simply incorrect from the perspective of alias analysis.
One very attractive solution is to merge nodes eagerly without
creating any defer edges, but that would be a much more radical change
even than what I've done here. It would also pose some new issues: how
to resolve the current "node types" when merging and how to deal with
missing content nodes.
This solution of applying escape state to content nodes solves all
these problems without too radical of a change at the expense of
eagerly creating content nodes. (The potential graph memory usage is
not really an issue because it's possible to drastically shrink the
size of the graph anyway in a future commit--I've been able to fit a
node within one cache line). This solution nicely preserves graph
structure which makes it easy to debug and relate to the IR.
Eagerly creating content nodes also solves the missing content node
problem. For example, when querying canEscapeTo, we need to know
whether to look at the escape state for just the pointer value itself,
or also for its content. It may be possible the its content node is
actually part of the same object at the IR level. If the content node
is missing, then we don't know if the object's interior address is not
recognizable/representable or whether we simply never saw an access to
the interior address. We can't simply look at whether the current IR
value happens to be a reference, because that doesn't tell us whether
the graph node may have been merged with a non-reference node or even
with it's own content node. To be correct in general, this query would
need to be extremely conservative. However, if content nodes are
always created for references, then we only need to query the escape
state of a pointer's content node. The content node's flag tells us if
it's an interior node, in which case it will always point to another
content node which also needs to be queried.
Categorize three kinds of pointers:
NoPointer (don't create a node)
ReferenceOnly (safe to make normal assumptions)
AnyPointer (may have addresses, rawpointers, or any mix of thoses with references)
Flag ConnectionGraph nodes as
- hasReferenceOnly
- isInterior
An interior node always has an additional content node.
All sorts of arbitrary node merging is supported. Nodes with totally
different properties can be safely merged. Interior nodes can safely
be merged with their field content (which does happen surprisingly
often).
Alias analysis will use these flags to safely make assumptions about
properties of the connection graph.
We have to handle undef partial_apply arguments to handle the following
source gracefully during the diagnosis pipeline.
```
class TestUndefined {
private var stringList: [String]!
func dontCrash(strings: [String]) {
assert(stringList.allSatisfy({ $0 == stringList.first!}))
let stringList = strings.filter({ $0 == "a" })
}
}
```
rdar://57893008
We generally do not use a for loop for worklist iteration since one runs into
weird issues around always needing to recompute the worklist size since it may
change per iteration. In contrast, using the while loop approach that just pops
off the back avoids such implicit weirdness.
It must be consistent, otherwise the specialized function types may not match for calls in functions with different resilience expansions.
Fixes an assertion crash in the generic specializer.
rdar://problem/57844964
Specifically:
1. I renamed the method insertAfter -> insertAfterInvocation and added an
ehaustive switch to ensure that we properly update this code if we add new apply
sites.
2. I added a new method insertAfterFullEvaluation that is like
insertAfterInvocation except that the callback is called with insertion points
after the end/abort apply instead of after the initial invocation of the
begin_apply.
Outliner: Add comment explaining that getBridgeTo/FromObjectiveC returns an invalid SILDeclRef to signal that the type does not conform to the bridgeable protocol
Specifically:
1. I converted a bunch of cases where we were emitting releases/unqualified
loads to use instead the *Operation commands that work in both modes.
2. I renamed some methods/variables that referred to releases to instead refer
to destroys.
All non cond_br SILInstructions are layout compatible with BranchPropagatedUser
since BPU just stores a PointerIntPair that leaves its low bits as zero unless
one adds a cond_br. Since in these cases, the SILInstructions are all not
cond_br, we can use this alternative API.
I also added some asserts to validate that the assumption that all such
SILInstructions are not cond_br is respected.
Specifically if we had:
```
%1 = enum $Enum, %0
switch_enum %1
```
We would propagate %0 without eliminating the enum in certain cases. Instead, we
insert unchecked_enum_data right before the branch to ensure that:
1. The types line up.
2. The enum is only consumed along the path through the switch_enum instead of
dealing with the lifetime of the enum along other paths.
To avoid duplicate-symbol linker errors. Instead make them alwaysEmitIntoClient.
But only do that for thunks to limit the code size impact. Anyway, it's only important for thunks because thunks are generated at SILGen, i.e. before CrossModuleSerializationSetup.
Other shared functions, e.g. specializations are created after CrossModuleSerializationSetup, so we don't have to deal with them.
Otherwise it can happen that e.g. specialization runs between CrossModuleSerializationSetup and serialization, resulting that an inlinable function references a shared function (which doesn't have a public linkage).
The solution is to move serialization right after CrossModuleSerializationSetup. But only do that if cross-module-optimization is enabled (it would be a disruptive change to move serialization in general).
maps in the handling of partial applies. In particular, when using
substMap.subst(otherSubstMap), ensure that otherSubstMap is not empty.
Also, store the partial-apply instruction in the symbolic closure,
which makes it easier to debug errors in the folding of partial applies.
In a forthcoming commit, I am going to need access to the "escaping" uses of a
dead live range. Rather than add /another/ argument to isDeadLiveRange, this
commit refactors the code to be a constructor on a general LiveRange class that
internally contains the lists of destroys, forwarding instructions we can
convert to be guaranteed, and consuming instructions that we do not understand.
Should be NFC.