- Support propagation of let properties values on tuples
- Do not treat initial assignment to a let-property as MemBehavior::None
- Improve comments
- Add more tests.
Swift SVN r28069
Teach LoadStoreOpts to handle "let" variables properly. Such variables should be loaded only once and their loaded values can be reused. This is safe, because once assigned these variables cannot change their value.
Swift SVN r27915
Preparation to fix <rdar://problem/18151694> Add Builtin.checkUnique
to avoid lost Array copies.
This adds the following new builtins:
isUnique : <T> (inout T[?]) -> Int1
isUniqueOrPinned : <T> (inout T[?]) -> Int1
These builtins take an inout object reference and return a
boolean. Passing the reference inout forces the optimizer to preserve
a retain distinct from what’s required to maintain lifetime for any of
the reference's source-level copies, because the called function is
allowed to replace the reference, thereby releasing the referent.
Before this change, the API entry points for uniqueness checking
already took an inout reference. However, after full inlining, it was
possible for two source-level variables that reference the same object
to appear to be the same variable from the optimizer's perspective
because an address to the variable was longer taken at the point of
checking uniqueness. Consequently the optimizer could remove
"redundant" copies which were actually needed to implement
copy-on-write semantics. With a builtin, the variable whose reference
is being checked for uniqueness appears mutable at the level of an
individual SIL instruction.
The kind of reference count checking that Builtin.isUnique performs
depends on the argument type:
- Native object types are directly checked by reading the
strong reference count:
(Builtin.NativeObject, known native class reference)
- Objective-C object types require an additional check that the
dynamic object type uses native swift reference counting:
(Builtin.UnknownObject, unknown class reference, class existential)
- Bridged object types allow the dymanic object type check to be
bypassed based on the pointer encoding:
(Builtin.BridgeObject)
Any of the above types may also be wrapped in an optional. If the
static argument type is optional, then a null check is also performed.
Thus, isUnique only returns true for non-null, native swift object
references with a strong reference count of one.
isUniqueOrPinned has the same semantics as isUnique except that it
also returns true if the object is marked pinned regardless of the
reference count. This allows for simultaneous non-structural
modification of multiple subobjects.
In some cases, the standard library can dynamically determine that it
has a native reference even though the static type is a bridge or
unknown object. Unsafe variants of the builtin are available to allow
the additional pointer bit mask and dynamic class lookup to be
bypassed in these cases:
isUnique_native : <T> (inout T[?]) -> Int1
isUniqueOrPinned_native : <T> (inout T[?]) -> Int1
These builtins perform an implicit cast to NativeObject before
checking uniqueness. There’s no way at SIL level to cast the address
of a reference, so we need to encapsulate this operation as part of
the builtin.
Swift SVN r27887
reference to something of class type. This is required to model
RebindSelfInConstructorExpr correctly to DI, since in the class case,
self.init and super.init *take* a value out of class box so that it
can pass the +1 value without performing an extra retain. Nothing
else in the compiler uninitializes a DI-controlled memory object
like this, so nothing else needs this. DI really doesn't like something
going from initialized to uninitialized.
Yes, I feel super-gross about this and am really unhappy about it. I
may end up reverting this if I can find an alternate solution to this
problem.
Swift SVN r27525
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
These aren't really orthogonal concerns--you'll never have a @thick @cc(objc_method), or an @objc_block @cc(witness_method)--and we have gross decision trees all over the codebase that try to hopscotch between the subset of combinations that make sense. Stop the madness by eliminating AbstractCC and folding its states into SILFunctionTypeRepresentation. This cleans up a ton of code across the compiler.
I couldn't quite eliminate AbstractCC's information from AST function types, since SIL type lowering transiently created AnyFunctionTypes with AbstractCCs set, even though these never occur at the source level. To accommodate type lowering, allow AnyFunctionType::ExtInfo to carry a SILFunctionTypeRepresentation, and arrange for the overlapping representations to share raw values.
In order to avoid disturbing test output, AST and SILFunctionTypes are still printed and parsed using the existing @thin/@thick/@objc_block and @cc() attributes, which is kind of gross, but lets me stage in the real source-breaking change separately.
Swift SVN r27095
Specifically we teach ARC:
1. StrongPin never decrements ref counts.
2. CheckedCastAddrBranchInst only decrements ref counts if we are taking the
source value.
<rdar://problem/20368790>
Swift SVN r27000
Changes compared to the original version:
I fixed the 2 bugs and added a test for the so far undetected missing range check bug.
To keep the SIL simple (4 basic blocks for arr[x]) I extracted the slow path for getElement into a
non-inlinable function.
On the other hand I inlined _typeCheck into the slow-path function.
This speeds up NSArray accesses because now only a single objectAtIndex is required for both
type checking and element retrieving.
Update on performance: DeltaBlue is now only 12% better (and not 25%). I suspect this is because
now Arnold's tail duplication cannot detect the ObjC call in the slow path.
Swift SVN r26935
This allows for the state transition kind caused by an instruction to change how
we process it. It also decouples this effect from the actual CFG visiting code.
This will give us the flexibility to teach the ARC optimizer in a clean way
about many more types of instructions.
Swift SVN r26901
Previously some parts of the compiler referred to them as "fields",
and most referred to them as "elements". Use the more generic 'elements'
nomenclature because that's what we refer to other things in the compiler
(e.g. the elements of a bracestmt).
At the same time, make the API better by providing "getElement" consistently
and using it, instead of getElements()[i].
NFC.
Swift SVN r26894
Use FullApplySite rather than ApplyInst through data structures and
function signatures.
This change does not update the call graph to actually look at
TryApply. That will happen in a future change.
Swift SVN r26893
Instead, add a removeEdge() and update code to use
getCallGraphEdge()/removeEdge() in cases where the apply may not be
represented in the call graph.
Swift SVN r26881
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
Now that we can check isNative and NoDTC (no deffered type check needed) with a single bit-mask operation,
it makes sense to have a single array property call for it.
I replaced the the semantics call array.props.needsElementTypeCheck with array.props.isNativeNoDTC,
which is the combination of isNative && !needsElementTypeCheck. I kept array.props.isNative, which is not used for now,
but might be useful in the future, e.g. for array operations which don't care about type checks.
The optimized SIL for a class array access arr[i] now contains the minimum of 4 basic blocks.
PerfTests show +25% for DeltaBlue and some improvemements for -Onone.
Swift SVN r26871
We ignore calls to ArraySemantic functions when we hoist uniqueness checks. With
+0 self, this is disrupted by the release that now is in the caller instead of
the callee.
This patch fixes that problem by teaching COWArrayOpts about "guaranteed call
sequences". This is the following pattern:
retain(x)
... nothing that decrements reference counts ...
call f1(@guaranteed_self x)
... nothing that decrements or uses ref counts ...
call f2(@guaranteed_self x)
... nothing that decrements or uses ref counts ...
...
... nothing that decrements or uses ref counts ...
call f$(n-1)(@guaranteed_self x)
... nothing that decrements or uses ref counts ...
call fn(@guaranteed_self x)
... nothing that uses ref counts ...
release(x)
This pattern is created when there are a bunch of guaranteed calls together in a
row (which seems to happen at the "semantic" SIL level). We pattern match the
sequence and then verify that all of the calls are semantic calls. If the
verification succeeds, we can hoist the uniqueness check.
rdar://20340699
Swift SVN r26835
Perf Results:
RIGHT - Before (ms)
LEFT - After (ms)
TITLE LEFT RIGHT RIGHT/LEFT
InsertionSort 103721.00 110326.00 1.06
NSXMLParser 27031.00 29763.00 1.10
rdar://20355793
Swift SVN r26784
This is apart of the work to change ARC so that all of the dataflow operations
are delegated to visitors which allow for behavior to be specialized depending
on the transformation kind. This will allow for users to add new behavior to the
ARC optimizer will minimally touching the actual dataflow.
Swift SVN r26777
It avoids that a pass runs a second time if didn't make any changes in the previous run and no other pass changed the function in between.
rdar://problem/20336764
In this change I also removed the CompleteFunctions analysis which is now obsolete.
Some measurements with swiftbench (-wmo, single threaded):
It reduces the number of pass runs by about 28%. Because only passes are skipped that don't do anything, the effect on compile time is not so dramatic.
The time spent in runSILOptimizationPasses is reduced by ~9% which gives a total compile time reduction of about 3%.
Swift SVN r26757
threaded into IRGen; tests to follow when that's done.
I made a preliminary effort to make the inliner do the
right thing with try_apply, but otherwise tried to avoid
touching the optimizer any more than was required by the
removal of ApplyInstBase.
Swift SVN r26747
We were always treating terminators (even without arguments) as uses. This is
incorrect. With this patch we now say that a terminator can not use a ref count
pointer if all of the terminator's arguments conservatively can not alias the
pointer.
rdar://20335297
Swift SVN r26664
Given a strong_pin for which we have not yet seen a strong_unpin, a safe
guaranteed call sequence is of the following form:
retain(x)
call f(@guaranteed x)
release(x)
where f is an array semantic call that we know does not touch globals and thus
are known to not change ref counts.
rdar://20305817
Swift SVN r26662