The only caveat is that:
1. We do not properly recognize when we have a let binding and we
perform a guaranteed dynamic call. In such a case, we add an extra
retain, release pair around the call. In order to get that case I will
need to refactor some code in Callee. I want to make this change, but
not at the expense of getting the rest of this work in.
2. Some of the protocol witness thunks generated have unnecessary
retains or releases in a similar manner.
But this is a good first step.
I am going to send a large follow up email with all of the relevant results, so
I can let the bots chew on this a little bit.
rdar://19933044
Swift SVN r27241
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
- Rename getParentPattern() -> getParentPatternBinding(), since
it returns the pattern binding, not the pattern.
- Introduce new getParentPattern()/getParentInitializer() methods,
covering the most common uses of getParentPatternBinding().
NFC.
Swift SVN r26175
in a failable initializer. Previously, it would always just say "properties of a class
instance must be initialized before returning nil".
Now, in designated inits, it adds to that message with notes for each member that is not
initialized but must be. It also adds a note saying that super.init() must be called if
that is the problem.
In convenience inits, it says:
"failable convenience initializer must delegate to self.init() before returning nil"
For example, in:
class B : A {
var x : Int
override init?() { return nil }
We now produce:
t.swift:13:15: error: all stored properties of a class instance must be initialized before returning nil from an initializer
t.swift:11:7: note: 'self.x' not initialized
t.swift:13:15: note: super.init must be called before returning nil
I don't see any radars about this, but someone was confused on the dev forums:
https://devforums.apple.com/message/1113604#1113604
Swift SVN r26166
TerminatorInsts. Now you can walk over the successor list of a terminator
and actually modify the SILSuccessor directly, allowing better CFG
transformations. NFC.
Swift SVN r26140
Teach DI about a pattern in address-only struct/enum initializers, improving diagnostics
on code like:
struct S<T, U> {
let a : T?
let b : U?
init(a : T) {
self.a = a
}
}
enum E<T> {
case X(T), Y
init() {
}
}
from:
t.swift:7:5: error: variable 'self.b' used before being initialized
}
^
t.swift:14:3: error: variable 'self' used before being initialized
}
^
To:
t.swift:7:5: error: return from initializer without initializing all stored properties
}
^
t.swift:3:9: note: 'self.b' not initialized
let b : U?
^
t.swift:14:3: error: return from enum initializer method without storing to 'self'
}
^
Swift SVN r25528
The old recursive algorithm had exponential complexity in worst case.
The new algorithm is a simple iterative dataflow algorithm.
This fixes <rdar://problem/19259710> Swift project locks up "indexing" or building (LifetimeChecker::doIt())
In the new algorithm I didn't specialize for the NumElements==1 case (as the old algorithm did),
because IMO it does not make a significant difference.
Swift SVN r24309
them in a more consistent and principled way. Two changes here: MUI is generated
when a vardecl is emitted, not as a separate "MarkPatternUninitialized" pass. Second,
when generating a MUI for self parameters with a temporary alloc_stack (due to the
possibility of superclass remapping of self) emit the MUI on the allocation itself,
not on the incoming argument. This is a lot more consistent (dissolving a bunch of
hacks in DI).
In terms of behavior changes, this only changes the raw sil generated by SILGen and
consumed by DI, so there is no user-visible change. This simply unblocks future work.
Swift SVN r23823
- We switch to a model where let properties may be "initialized", but never
reassigned. Specifically, immutable properties in structs/classes may have
an init value specified in their declaration (but can then never be reset
in any init implementation) or not (in which case they must be initialized
exactly once on all paths through every init. This makes a lot more sense
for immutability, defines several problems away, and provides a path to
supporting things like (rdar://16181314)
- We now *never* default initialize an immutable property. Formerly
we would default initialize optional let properties to nil, but this
isn't actually useful, and allows an error of omission with let
properties.
This resolves: <rdar://problem/19035287> let properties should only be initializable, not reassignable
and possibly other radars.
Swift SVN r23779
without a valid SILDebugScope. An assertion in IRGenSIL prevents future
optimizations from regressing in this regard.
Introducing SILBuilderWithScope and SILBuilderwithPostprocess to ease the
transition.
This patch is large, but mostly mechanical.
<rdar://problem/18494573> Swift: Debugger is not stopping at the set breakpoint
Swift SVN r22978
Dramatically improve DI diagnostics in initializers fixing rdar://18414728.
As one small example of the improvement, where an initializer like this:
class Foo {
var path:String? {
return "boo"
}
let aaaaa:String
init() {
if let p1 = path {
used to produce the error: "error: variable 'self.aaaaa' used before being initialized" on path,
we now produce:
x.swift:9:21: error: use of 'self' in property access 'path' before all stored properties are initialized
if let p1 = path {
^
x.swift:6:9: note: 'self.aaaaa' not initialized
let aaaaa:String
^
which is more useful.
Swift SVN r22238
As one small example of the improvement, where an initializer like this:
class Foo {
var path:String? {
return "boo"
}
let aaaaa:String
init() {
if let p1 = path {
used to produce the error: "error: variable 'self.aaaaa' used before being initialized" on path,
we now produce:
x.swift:9:21: error: use of 'self' in property access 'path' before all stored properties are initialized
if let p1 = path {
^
x.swift:6:9: note: 'self.aaaaa' not initialized
let aaaaa:String
^
which is more useful.
Swift SVN r22223
When analyzing a super.init call, we have several instructions involved including an upcast
to the parent type and an applyinst to call super.init. DI was using the location of the upcast
as the point at which it modeled the super.init requirement, not at the point of the applyinst. This
meant that code like:
%x = upcast self to basetype
... stuff ...
apply super.init(%x)
would not catch invalid uses of super in the "stuff" range, because DI thought that super.init was
called at the upcast. Fix this by using the apply as the super.init use, not the upcast.
Swift SVN r22101
initialized to also cover the delegating init case. The location info is pretty awful
on these, but it is more important that we reject these in Beta 1 than it is to be pretty.
Swift SVN r21673
This raises an error for some cases we don't implement correctly yet, though not ones that require super.init or self.init delegation yet.
Swift SVN r21669
self box as well as the address result, so that it picks up retains and releases.
Classify releases as interesting usepoints, and ignore the dealloc_stack.
Similarly, teach the logic in DefiniteInit's conditional destruction stuff to handle
the derived self case (basically, teaching it to special case the self box).
Swift SVN r21622
allowing partially initialized and conditionally uninitialized elements at failure points.
For example, we compile (with optimizations enabled to clean up the branching) this code:
class SomeClass {}
class RootClassWithNontrivialStoredProperties {
let x, y: SomeClass
init?(failAfterPartialInitialization: ()) {
x = SomeClass()
return nil
}
}
into:
sil @...
bb0(%0 : $RootClassWithNontrivialStoredProperties):
%1 = alloc_ref $SomeClass // users: %3, %4
%2 = ref_element_addr %0 : $RootClassWithNontrivialStoredProperties, #RootClassWithNontrivialStoredProperties.x // user: %3
store %1 to %2 : $*SomeClass // id: %3
strong_release %1 : $SomeClass // id: %4
dealloc_ref %0 : $RootClassWithNontrivialStoredProperties // id: %5
%6 = enum $Optional<RootClassWithNontrivialStoredProperties>, #Optional.None!enumelt // user: %7
return %6 : $Optional<RootClassWithNontrivialStoredProperties> // id: %7
}
where the elements of the class are all individually tracked and destroyed if necessary before the class is dealloc'd.
Swift SVN r21621
to track the release as something that needs the class reference to be alive at.
This implements the first piece of that: if all elements of the class are uninitialized
at the time of the release, just turn the release into a dealloc_ref. This is correct
because we know that the value would have had to be fully initialized at a retain, and
though careful construction, this only triggers in the init case.
This allows us to compile this:
class RootClassWithNontrivialStoredProperties {
let x, y: SomeClass
init?(failBeforeInitialization: ()) {
return nil
}
}
into:
sil @_TFC1t39RootClassWithNontrivialStoredPropertiesCfMS0_FT24failBeforeInitializationT__GSqS0__ : $@thin (@thick RootClassWithNontrivialStoredProperties.Type) -> @owned Optional<RootClassWithNontrivialStoredProperties> {
bb0(%0 : $@thick RootClassWithNontrivialStoredProperties.Type):
%1 = alloc_ref $RootClassWithNontrivialStoredProperties // user: %2
dealloc_ref %1 : $RootClassWithNontrivialStoredProperties // id: %2
%3 = enum $Optional<RootClassWithNontrivialStoredProperties>, #Optional.None!enumelt // user: %4
return %3 : $Optional<RootClassWithNontrivialStoredProperties> // id: %4
}
Swift SVN r21620
This is straight-forward, we just unique based on SourceLoc instead of by SILLocation. In cases
where there are multiple SIL Instructions that map to the same file/line/column, the SourceLoc is
a better approximation of what the user cares about.
This wouldn't be super important, except that not having it causes a QoI regression
in a patch I'm working on.
Swift SVN r21619
When DI processes a delegating initializer of an address-only value type, make sure to
mark the copy_addr as an initialization (as it was already doing for an assign
instruction) to fix a miscompilation.
The change to DIMemoryUseCollector.cpp is just to facilitate writing testcases.
Swift SVN r21478
This has two changes:
- In the case when we have an invalid source loc, DI will default to emitting diagnostics
at the enclosing function's location. This makes it more robust in general against
implicitly synthesized code.
- For this diagnostic in particular, emit a tailored message, since super.init is a commonly
synthesized thing.
Swift SVN r20104
DI has two paths for analyzing initialization state: one optimize for solving a single
fact (e.g. the state of a single non-tuple variable in a function), and one that handles
the full generality of multiple states in parallel (e.g. a tuple in a function or the
fields of a struct/class during its init method).
Unfortunately, the dataflow analysis between these two implementations drifted, and I
fixed a bug in the "N" case (rdar://16119509 back in feb) that didn't get fixed in the "1"
case. This reworks all of the dataflow to make the fact propagation more similar between
the two paths and fix the bug along the way.
Swift SVN r17343
The problem here is that the implicitly generated self.init() call is unreachable,
and DCE runs after DI, so DI doesn't know it is unreachable. Fix this by adding a trivial
reachability check before emitting a diagnostic.
This isn't a wholesome solution though, as certain infinite loops and other scenarios that
rely on constant folding won't be handled properly. If anyone runs into this, we could consider
moving constant prop and DCE earlier, though that comes with its own tradeoffs.
Swift SVN r16898
These bits are orthogonal to each other, so combine them into one, and diagnose attempts to produce a type that's both. Spot-fix a bunch of places this revealed by inspection that we would have crashed in SILGen or IRGen if blocks were be handled.
Swift SVN r16088
property in a base class before calling super.init. This is a nice improvement,
and also avoids regressing on QoI when a patch I'm working on finally lands.
Swift SVN r15379
This is a problem whereby the parallel bitvector dataflow stuff in DI was
incorrectly caching speculated results in cycles. In principle, this algorithm
should be reworked to use standard oldschool RPO bitwise dataflow algorithms, but
this patch is a minimal fix and the performance of this code is unlikely to be an issue
anyway.
Swift SVN r14322
There are some straggling references to the context generic param list, but nothing uses the non-interface param or result types anymore!
Swift SVN r13725
Now the pass does not need to know about the pass manager. We also don't have
runOnFunction or runOnModule anymore because the trnasformation knows
which module it is processing. The Pass itself knows how to invalidate the
analysis, based on the injected pass manager that is internal to the
transformation.
Now our DCE transformation looks like this:
class DCE : public SILModuleTransform {
void run() {
performSILDeadCodeElimination(getModule());
invalidateAnalysis(SILAnalysis::InvalidationKind::All);
}
};
Swift SVN r13598