Skip to content

Commit 7719582

Browse files
committed
[DI] sink injectActorHops() after processing destroys
While trying to reuse the liveness-points analysis originally in DI for injecting actor hops for more general purposes, Pavel and I discovered that the point at which we are injecting the hops might not have fully-computed the liveness information. That appears to be the case because we were computing the fully-initialized points before having processed destroy/releases of TheMemory. While this most likely had no influence on the actor hop injection, it does affect what the outgoing AvailabilitySet contains for a block. In particular, for this example: ```swift struct X { init(cond: Bool) { var _storage: (name: String, age: Int) _storage.name = "" if cond { _storage.age = 30 } else { _storage.age = 40 } } } ``` But because we are determine the full initialization points before processing the destroy, the liveness analysis doesn't iterate to correctly determine the out-availability of block 1 and 3 (corresponding to the then and else blocks in the example above). Here's the debug output showing that issue: ``` *** Definite Init looking at: %5 = mark_uninitialized [var] %4 : $*(name: String, age: Int) // users: %37, %12, %22, %32 Get liveness 0, #1 at assign %11 to %13 : $*String // id: %14 Get liveness 1, #1 at assign %21 to %23 : $*Int // id: %24 Get liveness for block 1 Iteration 0 Result: (yn) Get liveness 1, #1 at assign %31 to %33 : $*Int // id: %34 Get liveness for block 3 add block 2 to worklist Iteration 0 Block 2 out: (yn) Iteration 1 Block 2 out: (yn) Result: (yn) full-init-finder: rejecting bb0 b/c non-Yes OUT avail full-init-finder: rejecting bb1 b/c non-Yes OUT avail full-init-finder: rejecting bb2 b/c no non-load uses. full-init-finder: rejecting bb3 b/c non-Yes OUT avail full-init-finder: rejecting bb4 b/c no non-load uses. Get liveness 0, swiftlang#2 at destroy_addr %5 : $*(name: String, age: Int) // id: %37 Get liveness for block 4 add block 3 to worklist add block 1 to worklist Iteration 0 Block 1 out: (yy) Block 3 out: (yy) Iteration 1 Block 1 out: (yy) Block 3 out: (yy) Result: (yy) ``` So, this patch basically just sinks the computation so it happens after, so that we force the incremental liveness analysis to also consider the liveness at the point of the destroy, but before having done any other transformations or modifications to the CFG to handle a destroy of something partially initialized.
1 parent 6dda91c commit 7719582

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,9 +1142,6 @@ void LifetimeChecker::doIt() {
11421142
// If we emitted an error, there is no reason to proceed with load promotion.
11431143
if (!EmittedErrorLocs.empty()) return;
11441144

1145-
// Insert hop_to_executor instructions for actor initializers, if needed.
1146-
injectActorHops();
1147-
11481145
// If the memory object has nontrivial type, then any destroy/release of the
11491146
// memory object will destruct the memory. If the memory (or some element
11501147
// thereof) is not initialized on some path, the bad things happen. Process
@@ -1155,6 +1152,15 @@ void LifetimeChecker::doIt() {
11551152
processNonTrivialRelease(i);
11561153
}
11571154

1155+
/// At this point, we should have computed enough liveness information to
1156+
/// provide accurate information about initialization points, even for
1157+
/// local variables within a function, because we've now processed the
1158+
/// destroy/releases.
1159+
1160+
// Insert hop_to_executor instructions for actor initializers, if needed.
1161+
injectActorHops();
1162+
1163+
11581164
// If the memory object had any non-trivial stores that are init or assign
11591165
// based on the control flow path reaching them, then insert dynamic control
11601166
// logic and CFG diamonds to handle this.

0 commit comments

Comments
 (0)