Commit Graph

140 Commits

Author SHA1 Message Date
Chris Lattner
7ee082c542 rework general accesses to self to be modeled as full loads, instead of as escapes,
and simplify some code.  The notable aspect of this change is that it improves 
diagnostics for method calls before super.init.



Swift SVN r11081
2013-12-10 17:51:09 +00:00
Chris Lattner
4b24b7f567 Two more QoI improvements to DI diagnostics. For enums,
diagnose failure to initialize with:
  "return from enum initializer method without storing to 'self'"
instead of:
  "variable 'self' used before being initialized"

For partially initialized super.init() calls, emit:
  "super.init not called on all paths leading to use of base object 'SomeClass'"
instead of:
  "use of base object 'SomeClass' before super.init call to initializes it on some paths"

... which didn't make any sense.



Swift SVN r11075
2013-12-10 04:52:56 +00:00
Chris Lattner
12db3b2880 Implement support for validating super.init invariants.
This builds on the infrastructure we have for liveness tracking, by tracking
the "super.init'd" state as another faux memory object that has a liveness.
Each escape/base class use requires super.init to have happened, and super.init
requires super.init to NOT have happened.  This gives us pretty great QoI,
full fidelity to the model, and is pretty simple.

This implements:
<rdar://problem/15579247> We need to validate super.init() invariants in initializers




Swift SVN r11073
2013-12-10 04:15:29 +00:00
Chris Lattner
3c03c0b5e4 rework emitOptionalToRef to use an optional code sequence to get a null class
reference, eliminating the last thing that creates a SIL builtin zero.


Swift SVN r11051
2013-12-09 23:37:51 +00:00
Chris Lattner
7c64fc4a60 remove some dead code: this eliminates the scan of an initializer body
that attempted to detect whether there was an explicit init in the body.
DI takes care of this now.  It also removes the logic for generating code
to default init ivars.


Swift SVN r11044
2013-12-09 23:04:29 +00:00
Chris Lattner
18ae5c62fa Improve the diagnostic for root classes that fail to initialize something. The location
of this diagnostic still doesn't make sense (pointing the the { of the function) but that
is tracked by rdar://15581664.

t.swift:4:3: error: instance variable 'self.x' not initialized at end of initializer
  init() {
  ^




Swift SVN r11042
2013-12-09 22:27:21 +00:00
Chris Lattner
99a3e68b32 don't emit a bogus "variable defined here" diagnostic for 'self'
related diagnostics.


Swift SVN r11037
2013-12-09 21:51:25 +00:00
Chris Lattner
8a5d66dc9d Start improving "DI for init methods" diagnostics. New additions:
t.swift:10:5: error: instance variable 'self.y' not initialized at super.init call
    super.init()
    ^
<unknown>:0: note: variable defined here
t.swift:15:5: error: use of base object 'SomeClass' before super.init call initializes it
    x = 17 
    ^

instead of:

variable 'self.y' captured by a closure before being initialized

for each of them.  <unknown> is in the crosshairs next.



Swift SVN r11036
2013-12-09 21:37:39 +00:00
Chris Lattner
0566ebd40b Fix a bug in in our tuple-element dataflow propagation, where
global "partial liveness" would overwrite local "always live"ness.
Always liveness on a local level always makes a value live-out,
even if it is partially live in.


Swift SVN r11005
2013-12-09 05:44:09 +00:00
Chris Lattner
aed29b4e92 When r10841 turned on DI for struct init methods, it started SILGen generating
new mark_unitialized instructions.  These defeated the alloc_box to stack promotion
pass, so everything ended up on the heap, leading to really terrible performance.
This updates things to understand mark_uninitialized, allowing us to promote them.

This fixes rdar://15607469.


Swift SVN r10985
2013-12-07 23:38:09 +00:00
Michael Gottesman
4379283013 Remove inclusion of SILPasses/Passes.h into Subsystems.h and update all relevant files.
Swift SVN r10880
2013-12-05 19:58:21 +00:00
Chris Lattner
15be357ee1 when DI is reporting an error about a multi-element access,
indicate the first element that is undefined, not the first
element being accessed.  In the example, passing the tuple
inout uses both elements, but the first element is initialized,
so we should complain about t2.1 being uninitialized, not t2.0


Swift SVN r10822
2013-12-05 00:01:21 +00:00
Chris Lattner
51acb02bfb Element analysis applies to more than just tuple elements now,
just refer to them as elements of the memory object, not as 
tuple elements.


Swift SVN r10813
2013-12-04 23:22:14 +00:00
Chris Lattner
5a878c2185 Move tuple flattening functions into DIMemoryObjectInfo
now that they fit there.


Swift SVN r10782
2013-12-04 17:27:47 +00:00
Chris Lattner
6fdb5f9ce1 introduce a new abstraction for handling the memory object being
analyzed, and use it as common currency between the element use
collector and its clients.  Element collection is about to become
more nuanced.  NFC.


Swift SVN r10781
2013-12-04 17:07:29 +00:00
Chris Lattner
3289b6e455 Start emitting "mark_unitialized [rootself]" for the self argument of
enum ctors, and add minimal updates to DI to tolerate this.  Doing so 
exposed a bug that would cause DI to crash handling conditional 
destruction of mark_unintialized (which was never possible
before since globals aren't destructed).



Swift SVN r10778
2013-12-04 06:13:35 +00:00
Chris Lattner
8640266bf7 remove the RemoveDeadAddressingInstructions helper, in favor of
the more fully featured "recursivelyDeleteTriviallyDeadInstructions".


Swift SVN r10724
2013-12-02 01:47:53 +00:00
Chris Lattner
d2adddd34c Now that memopt is its own SIL pass, split it out to its own file. Now
the file sizes are more reasonable and better structured.


Swift SVN r10722
2013-12-02 01:40:21 +00:00
Chris Lattner
dadc9fc6d1 split predictable memory optimization (load promotion + alloc deletion) out to
its own SIL pass.  The bulk of this patch is updating the DI testcase to detangle
DI tests from load promotion tests.



Swift SVN r10721
2013-12-02 01:33:29 +00:00
Chris Lattner
78e5e9879e move the ElementUseCollector out of DefiniteInitialization.cpp
Swift SVN r10720
2013-12-02 01:04:56 +00:00
Chris Lattner
92594b9b5a DI is over 3000 lines of code now, and should be split into two
separate passes.  Start splitting some utility functions out,
and rearranging code a bit.  While I'm at it, rename some bits
to make more sense now that their purpose has settled.


Swift SVN r10719
2013-12-02 00:55:08 +00:00
Chris Lattner
78dd42e10c more minor cleanups, things are settled now.
Swift SVN r10706
2013-12-01 06:29:39 +00:00
Chris Lattner
722436cdc6 the main liveness analysis loop doesn't need escape analysis, the
load promotion pass doesn't need anything more than a set of blocks
that have local definitions.  Simplify code.


Swift SVN r10705
2013-12-01 06:27:30 +00:00
Chris Lattner
f36e720f64 The AllocOptimize phase doesn't need a full LiveOutBlockState, make do with a single bool instead.
Swift SVN r10703
2013-12-01 06:19:24 +00:00
Chris Lattner
b8d628d073 ingloriously fix the serious DI problem:
<rdar://problem/15511392> DI cannot promote loads until the initialization semantics of an entire function is known

This splits load (+destroy_addr) promotion out to a separate pass that
happens after the DI properties of an entire function are known, resolving
the problem.

The upshot is that with this fix, DI is now feature complete (and correct!) for 
all known local and global variable situations (just leaving initializers to do).

The downshot is that some cleanup is required, because this is a purely mechanical
change to the previous algorithms.



Swift SVN r10702
2013-12-01 06:11:55 +00:00
Chris Lattner
dc9e21ed89 implement support for conditional destruction of tuple elements.
a testcase like this:

func test(cond : Bool) {
  var x : (SomeClass, SomeClass)

  if cond {
    x.0 = getSomeClass()
  } else {
    x.1 = getSomeClass() 
  }
}

now ends up with an epilog to destroy "x" that looks like this:

  %1 = builtin_function_ref "lshr_Int2" : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %37
  %2 = builtin_function_ref "trunc_Int2_Int1" : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // users: %38, %31
...
  %30 = load %4#1 : $*Builtin.Int2                // users: %37, %31
  %31 = apply %2(%30) : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %32
  cond_br %31, bb4, bb5                           // id: %32

bb4:                                              // Preds: bb3
  %33 = tuple_element_addr %7#1 : $*(SomeClass, SomeClass), 0 // user: %34
  destroy_addr %33 : $*SomeClass                  // id: %34
  br bb5                                          // id: %35

bb5:                                              // Preds: bb3 bb4
  %36 = integer_literal $Builtin.Int2, 1          // user: %37
  %37 = apply %1(%30, %36) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %38
  %38 = apply %2(%37) : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %39
  cond_br %38, bb6, bb7                           // id: %39

bb6:                                              // Preds: bb5
  %40 = tuple_element_addr %7#1 : $*(SomeClass, SomeClass), 1 // user: %41
  destroy_addr %40 : $*SomeClass                  // id: %41
  br bb7                                          // id: %42

bb7:                                              // Preds: bb5 bb6
  dealloc_stack %7#0 : $*@local_storage (SomeClass, SomeClass) // id: %43





Swift SVN r10701
2013-12-01 05:22:05 +00:00
Chris Lattner
b84fd18419 implement support for full conditional init/assign processing of tuple elements,
generating the appropriate shifting and or'ing of bits in our liveness mask to
treat each tuple element separately.  This allows us to compile something like:

func test(cond : Bool) {
  var x : (SomeClass, SomeClass)

  if cond {
    x.0 = getSomeClass()
  } else {
    x.1 = getSomeClass() 
  }

  x.0 = getSomeClass()
  x.1 = x.0
}

into:

sil @_T1t4testFT4condSb_T_ : $@thin (Bool) -> () {
bb0(%0 : $Bool):
  %1 = builtin_function_ref "or_Int2" : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // users: %40, %24, %15, %57
  %2 = alloc_stack $Builtin.Int2  // var x        // users: %41, %39, %25, %23, %16, %14, %58, %56, %45, %31, %7, %64
  %3 = alloc_stack $Bool  // var cond             // users: %62, %4
  store %0 to %3#1 : $*Bool                       // id: %4
  %5 = alloc_stack $(SomeClass, SomeClass)  // var x // users: %52, %35, %61, %60, %12, %21, %30, %43, %44
  %6 = integer_literal $Builtin.Int2, 0           // user: %7
  store %6 to %2#1 : $*Builtin.Int2               // id: %7
  %8 = struct_extract %0 : $Bool, #value          // user: %9
  cond_br %8, bb1, bb2                            // id: %9

bb1:                                              // Preds: bb0
  // function_ref t.getSomeClass () -> t.SomeClass
  %10 = function_ref @_T1t12getSomeClassFT_CS_9SomeClass : $@thin () -> @owned SomeClass // user: %11
  %11 = apply %10() : $@thin () -> @owned SomeClass // user: %17
  %12 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 0 // user: %17
  %13 = integer_literal $Builtin.Int2, 1          // user: %15
  %14 = load %2#1 : $*Builtin.Int2                // user: %15
  %15 = apply %1(%14, %13) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %16
  store %15 to %2#1 : $*Builtin.Int2              // id: %16
  store %11 to %12 : $*SomeClass                  // id: %17
  br bb3                                          // id: %18

bb2:                                              // Preds: bb0
  // function_ref t.getSomeClass () -> t.SomeClass
  %19 = function_ref @_T1t12getSomeClassFT_CS_9SomeClass : $@thin () -> @owned SomeClass // user: %20
  %20 = apply %19() : $@thin () -> @owned SomeClass // user: %26
  %21 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 1 // user: %26
  %22 = integer_literal $Builtin.Int2, -2         // user: %24
  %23 = load %2#1 : $*Builtin.Int2                // user: %24
  %24 = apply %1(%23, %22) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %25
  store %24 to %2#1 : $*Builtin.Int2              // id: %25
  store %20 to %21 : $*SomeClass                  // id: %26
  br bb3                                          // id: %27

bb3:                                              // Preds: bb2 bb1
  // function_ref t.getSomeClass () -> t.SomeClass
  %28 = function_ref @_T1t12getSomeClassFT_CS_9SomeClass : $@thin () -> @owned SomeClass // user: %29
  %29 = apply %28() : $@thin () -> @owned SomeClass // user: %42
  %30 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 0 // user: %42
  %31 = load %2#1 : $*Builtin.Int2                // user: %33
  %32 = builtin_function_ref "trunc_Int2_Int1" : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %33
  %33 = apply %32(%31) : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %34
  cond_br %33, bb4, bb5                           // id: %34

bb4:                                              // Preds: bb3
  %35 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 0 // user: %36
  destroy_addr %35 : $*SomeClass                  // id: %36
  br bb5                                          // id: %37

bb5:                                              // Preds: bb3 bb4
  %38 = integer_literal $Builtin.Int2, 1          // user: %40
  %39 = load %2#1 : $*Builtin.Int2                // user: %40
  %40 = apply %1(%39, %38) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %41
  store %40 to %2#1 : $*Builtin.Int2              // id: %41
  store %29 to %30 : $*SomeClass                  // id: %42
  %43 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 0 // user: %59
  %44 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 1 // user: %59
  %45 = load %2#1 : $*Builtin.Int2                // user: %48
  %46 = builtin_function_ref "lshr_Int2" : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %48
  %47 = integer_literal $Builtin.Int2, 1          // user: %48
  %48 = apply %46(%45, %47) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %50
  %49 = builtin_function_ref "trunc_Int2_Int1" : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %50
  %50 = apply %49(%48) : $@thin @callee_owned (Builtin.Int2) -> Builtin.Int1 // user: %51
  cond_br %50, bb6, bb7                           // id: %51

bb6:                                              // Preds: bb5
  %52 = tuple_element_addr %5#1 : $*(SomeClass, SomeClass), 1 // user: %53
  destroy_addr %52 : $*SomeClass                  // id: %53
  br bb7                                          // id: %54

bb7:                                              // Preds: bb5 bb6
  %55 = integer_literal $Builtin.Int2, -2         // user: %57
  %56 = load %2#1 : $*Builtin.Int2                // user: %57
  %57 = apply %1(%56, %55) : $@thin @callee_owned (Builtin.Int2, Builtin.Int2) -> Builtin.Int2 // user: %58
  store %57 to %2#1 : $*Builtin.Int2              // id: %58
  copy_addr %43 to [initialization] %44 : $*SomeClass // id: %59
  destroy_addr %5#1 : $*(SomeClass, SomeClass)    // id: %60
  dealloc_stack %5#0 : $*@local_storage (SomeClass, SomeClass) // id: %61
  dealloc_stack %3#0 : $*@local_storage Bool      // id: %62
  %63 = tuple ()                                  // user: %65
  dealloc_stack %2#0 : $*@local_storage Builtin.Int2 // id: %64
  return %63 : $()                                // id: %65
}

Which ends up producing this LLVM IR at -O3:

define void @_T1t4testFT4condSb_T_(i1) #0 {
entry:
  %1 = tail call noalias %swift.refcounted* @swift_allocObject(...
  %2 = tail call noalias %swift.refcounted* @swift_allocObject(...
  tail call void @swift_release(%swift.refcounted* %2) #0
  tail call void @swift_release(%swift.refcounted* %1) #0
  ret void
}



Swift SVN r10700
2013-12-01 05:10:48 +00:00
Chris Lattner
f0f997a391 rework the conditional init/assign algorithm to generate destroy_addrs instead
of generating a CFG diamond with a copy of the store (in init and assign forms)
on each arm.  This generalizes to operations that touch multiple tuple elements
better.


Swift SVN r10698
2013-12-01 02:40:01 +00:00
Chris Lattner
1a612b6d13 rewrite the logic to handle conditional destroys to use the same control variable
as is used by conditional inits.  This allows some simplifications and sharing
of concepts, and makes sure that we emit at most one control variable for each
memory object being DI'd.


Swift SVN r10688
2013-11-30 00:19:35 +00:00
Chris Lattner
583d93fd3d Implement support for DI emitting conditional control variable that tracks the
liveness of a memory object throughout the flow graph.  This implements support
for conditional liveness (e.g. the testcase) of general types, but top level
tuples are not handled properly yet.  This is progress to implementing 
rdar://15530750.


Swift SVN r10687
2013-11-29 23:38:29 +00:00
Chris Lattner
b312116ee9 adopt IsInitialization_t in LowerAssignInstruction,
and inline handleInconsistentInitOrAssign into its
caller, since it will remain simple.  Also, add an
assert to make sure the handleStoreUse covers all 
instructions possible in it.  NFC.


Swift SVN r10685
2013-11-29 16:57:57 +00:00
Chris Lattner
eeb1b16830 now that things are rearranged to our liking, introduce a new function
to handle stores that are either an assign or an init, depending on the
control flow leading to them.  This case needs to have a diamond inserted
in the CFG in the general case.  For now, we whitelist trivial types,
since init and assign are the same for them.  This fixes rdar://15530750
for trivial types.


Swift SVN r10684
2013-11-29 07:09:35 +00:00
Chris Lattner
4a50ba45e3 further improve classification: coming out of silgen, we don't know if
anything is a proper reassignment: we only know that it could be either
InitOrAssign or Init.  Classify stores as such, and then have DI classify
things into Assign when it is clearly an overwrite.  This allows later
iterations to avoid reanalyzing generated instructions and allows more
precise reasoning about ambiguous initializations.



Swift SVN r10683
2013-11-29 06:44:15 +00:00
Chris Lattner
8e1b68e4e8 refactor a "InsertCFGDiamond" function out of the conditional destroy logic. NFC.
Swift SVN r10682
2013-11-28 21:28:31 +00:00
Chris Lattner
3e20621708 introduce a new store classification "InitOrAssign" since the trivial type
stores coming out of SILGen are unknown whether they are init or assign.
No functionality change.



Swift SVN r10681
2013-11-28 20:58:55 +00:00
Chris Lattner
510ed4ccfa Introduce a new use classifier: "Initialization". This allows us to
tag things known from SILGen to be initializers (e.g., copyaddrs with
the bit set) and when we analyze the DI properties for an assign, we
can move it to this classification.  This allows stuff that wants to
reason about the difference (e.g. the conditional destroy logic) to
do so precisely.


Swift SVN r10658
2013-11-22 06:17:32 +00:00
Chris Lattner
795656f3f7 Have DI generate control variables and conditional destruction
logic for destroy_addrs of memory that is only live on some 
paths.  This finally wraps up rdar://15209088.

The final missing DI feature for local/global variables is the
conditional "assign" vs "init" case now.



Swift SVN r10654
2013-11-22 00:48:42 +00:00
Chris Lattner
b8e7ca2996 Only check elements that we care about. This is only a cleanup, no
functionality change.


Swift SVN r10630
2013-11-21 07:28:54 +00:00
Chris Lattner
1f55287ad2 teach definite init to correctly handle releases of tuples where
each element has a known yes/no liveness, as a generalization of the
"none are alive" logic.  Now the only piece missing is the
flow sensitive liveness case.

It is pretty nice that DI is able to transform the testcase into this
simple logic:

sil @release_some_constructed : $@thin () -> () {
bb0:
  %0 = tuple ()
  %1 = function_ref @getSomeClass : $@thin () -> @owned SomeClass // user: %2
  %2 = apply %1() : $@thin () -> @owned SomeClass // user: %3
  strong_release %2 : $SomeClass                  // id: %3
  %4 = tuple ()                                   // user: %5
  return %4 : $()                                 // id: %5
}




Swift SVN r10629
2013-11-21 07:20:56 +00:00
Chris Lattner
2c109ff75d Rename checkDefinitelyInit -> getLivenessAtUse, and split it
into two methods: one that determines the liveness of a set of
elements at a point in the CFG, and one the merges the result
across the elements used by a particular access.  The 
getLivenessAtUse is useful for traditional DI properties, but
the vector-returning one is important for analyzing the liveness
at a release.  Still no functionality change.


Swift SVN r10625
2013-11-21 05:46:21 +00:00
Chris Lattner
78cc047f5b improve encapsulation by introducing a new AvailabilitySet type
that wraps llvm::SmallVector of bit pairs - centralizing the logic
for working on it, and abstracting the bit pair encoding.  Also
add a comment describing what this is doing in lattice theoretic
terms.


Swift SVN r10624
2013-11-21 05:05:40 +00:00
Adrian Prantl
5c812906ca Revert "Revert r10613, the debug info problems are significant."
This reverts commit 41a6515ba08219c284a408448d790a783e64dad1.

Swift SVN r10616
2013-11-21 00:50:51 +00:00
Chris Lattner
c5034f8504 Revert r10613, the debug info problems are significant.
Swift SVN r10614
2013-11-21 00:12:34 +00:00
Chris Lattner
41e3d0fc23 Re-commit Stephen's patch: Enable capture promotion pass by default
This fixes up various testcases.  Note that 3 debug info tests are asserting
in IRGen for a common but unknown-to-me reason, I've XFAILed them for now.


Swift SVN r10613
2013-11-21 00:09:35 +00:00
Chris Lattner
07ce5306f3 add a SILType::isTrivial helper function.
Swift SVN r10610
2013-11-20 22:53:49 +00:00
Chris Lattner
c3907b3867 Teach DI to remove destroy_addrs on paths where the memory is always uninitialized.
Doing this exposed that the dataflow analysis in DI was pretty fundamentaly broken:
it was trying to compute blocks where the (tuple elements of the) memory were either
initialized, uninitialized, or partially initialized (initialized only on some paths)
but it conflated partial with its unknown state, causing it to get the wrong results
a lot of the time.  Rewrite things so that it is correct.



Swift SVN r10594
2013-11-20 16:50:45 +00:00
John McCall
20e58dcf93 Change the type of function values in SIL to SILFunctionType.
Perform major abstraction remappings in SILGen.  Introduce
thunking functions as necessary to map between abstraction
patterns.

Swift SVN r10562
2013-11-19 22:55:09 +00:00
Chris Lattner
614ab66d6b Fix a bug Joe found in DI: when exploding a copyaddr that is
loading from our current allocation, we'd sometimes add loads
corresponding to the "assign" to the use list for this memory
object.

No testcase as this will be tested by Joe's forthcoming patch
to produce more copyaddrs from silgen.


Swift SVN r10559
2013-11-19 19:52:05 +00:00
Chris Lattner
5e94be5073 Fix rdar://15492647 - destroy_addr dropped by DI, causing leaks
Fix DI to not delete non-trivial memory allocations that are still 
used by destroy_addr or strong_release, since just dropping those operations
will cause a memory leak.

This is simple, but prevents DI from removing most allocations.  To
avoid having to update all the testcases :), teach it also to promote
non-address-only destroy_addrs into a load+release sequence when the
load's value is available, as part of normal load promotion.



Swift SVN r10542
2013-11-18 17:35:56 +00:00
Chris Lattner
ae2bdb8d6a Enhance DI to know that trivial types don't have complicated cleanup semantics,
so they don't need code motion on releases.  This fixes Jordan's testcase from
rdar://15209088, though non-trivial types still don't work.


Swift SVN r10539
2013-11-18 15:47:34 +00:00