Skip to content

Commit b33997f

Browse files
authored
Merge pull request #21163 from slavapestov/di-untangle-analysis-from-mutation-5.0
DI: Lower AssignInst in a post-processing pass [5.0]
2 parents ef7dd0f + b73dd3b commit b33997f

File tree

3 files changed

+61
-64
lines changed

3 files changed

+61
-64
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 32 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ namespace {
390390
SmallVectorImpl<DIMemoryUse> &Uses;
391391
TinyPtrVector<SILInstruction *> &StoresToSelf;
392392
SmallVectorImpl<SILInstruction *> &Destroys;
393+
SmallVector<unsigned, 8> NeedsUpdateForInitState;
393394
std::vector<ConditionalDestroy> ConditionalDestroys;
394395

395396
llvm::SmallDenseMap<SILBasicBlock*, LiveOutBlockState, 32> PerBlockInfo;
@@ -459,7 +460,7 @@ namespace {
459460

460461

461462
void handleStoreUse(unsigned UseID);
462-
void handleLoadUse(unsigned UseID);
463+
void handleLoadUse(const DIMemoryUse &Use);
463464
void handleLoadForTypeOfSelfUse(const DIMemoryUse &Use);
464465
void handleInOutUse(const DIMemoryUse &Use);
465466
void handleEscapeUse(const DIMemoryUse &Use);
@@ -471,7 +472,8 @@ namespace {
471472
bool SuperInitDone,
472473
bool FailedSelfUse);
473474

474-
void handleSelfInitUse(DIMemoryUse &Use);
475+
void handleSelfInitUse(unsigned UseID);
476+
475477
void updateInstructionForInitState(DIMemoryUse &Use);
476478

477479

@@ -764,15 +766,9 @@ void LifetimeChecker::doIt() {
764766
handleStoreUse(i);
765767
break;
766768

767-
case DIUseKind::IndirectIn: {
768-
bool IsSuperInitComplete, FailedSelfUse;
769-
// If the value is not definitively initialized, emit an error.
770-
if (!isInitializedAtUse(Use, &IsSuperInitComplete, &FailedSelfUse))
771-
handleLoadUseFailure(Use, IsSuperInitComplete, FailedSelfUse);
772-
break;
773-
}
769+
case DIUseKind::IndirectIn:
774770
case DIUseKind::Load:
775-
handleLoadUse(i);
771+
handleLoadUse(Use);
776772
break;
777773
case DIUseKind::InOutArgument:
778774
case DIUseKind::InOutSelfArgument:
@@ -782,7 +778,7 @@ void LifetimeChecker::doIt() {
782778
handleEscapeUse(Use);
783779
break;
784780
case DIUseKind::SelfInit:
785-
handleSelfInitUse(Use);
781+
handleSelfInitUse(i);
786782
break;
787783
case DIUseKind::LoadForTypeOfSelf:
788784
handleLoadForTypeOfSelfUse(Use);
@@ -811,11 +807,15 @@ void LifetimeChecker::doIt() {
811807
ControlVariable = handleConditionalInitAssign();
812808
if (!ConditionalDestroys.empty())
813809
handleConditionalDestroys(ControlVariable);
814-
}
815810

816-
void LifetimeChecker::handleLoadUse(unsigned UseID) {
817-
DIMemoryUse &Use = Uses[UseID];
811+
// handleStoreUse(), handleSelfInitUse() and handleConditionalInitAssign()
812+
// postpone lowering of assignment instructions to avoid deleting
813+
// instructions that still appear in the Uses list.
814+
for (unsigned UseID : NeedsUpdateForInitState)
815+
updateInstructionForInitState(Uses[UseID]);
816+
}
818817

818+
void LifetimeChecker::handleLoadUse(const DIMemoryUse &Use) {
819819
bool IsSuperInitComplete, FailedSelfUse;
820820
// If the value is not definitively initialized, emit an error.
821821
if (!isInitializedAtUse(Use, &IsSuperInitComplete, &FailedSelfUse))
@@ -1023,7 +1023,7 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
10231023

10241024
// Otherwise, we have a definite init or assign. Make sure the instruction
10251025
// itself is tagged properly.
1026-
updateInstructionForInitState(Use);
1026+
NeedsUpdateForInitState.push_back(UseID);
10271027
}
10281028

10291029
/// Check whether the instruction is an application.
@@ -1764,7 +1764,8 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
17641764

17651765
/// handleSelfInitUse - When processing a 'self' argument on a class, this is
17661766
/// a call to self.init or super.init.
1767-
void LifetimeChecker::handleSelfInitUse(DIMemoryUse &Use) {
1767+
void LifetimeChecker::handleSelfInitUse(unsigned UseID) {
1768+
auto &Use = Uses[UseID];
17681769
auto *Inst = Use.Inst;
17691770

17701771
assert(TheMemory.isAnyInitSelf());
@@ -1799,7 +1800,7 @@ void LifetimeChecker::handleSelfInitUse(DIMemoryUse &Use) {
17991800

18001801
// Lower Assign instructions if needed.
18011802
if (isa<AssignInst>(Use.Inst))
1802-
updateInstructionForInitState(Use);
1803+
NeedsUpdateForInitState.push_back(UseID);
18031804
} else {
18041805
// super.init also requires that all ivars are initialized before the
18051806
// superclass initializer runs.
@@ -1859,14 +1860,13 @@ void LifetimeChecker::updateInstructionForInitState(DIMemoryUse &Use) {
18591860
if (auto *AI = dyn_cast<AssignInst>(Inst)) {
18601861
// Remove this instruction from our data structures, since we will be
18611862
// removing it.
1862-
auto Kind = Use.Kind;
18631863
Use.Inst = nullptr;
18641864
NonLoadUses.erase(Inst);
18651865

18661866
PartialInitializationKind PartialInitKind;
18671867

18681868
if (TheMemory.isClassInitSelf() &&
1869-
Kind == DIUseKind::SelfInit) {
1869+
Use.Kind == DIUseKind::SelfInit) {
18701870
assert(InitKind == IsInitialization);
18711871
PartialInitKind = PartialInitializationKind::IsReinitialization;
18721872
} else {
@@ -1875,27 +1875,8 @@ void LifetimeChecker::updateInstructionForInitState(DIMemoryUse &Use) {
18751875
: PartialInitializationKind::IsNotInitialization);
18761876
}
18771877

1878-
unsigned FirstElement = Use.FirstElement;
1879-
unsigned NumElements = Use.NumElements;
1880-
1881-
SmallVector<SILInstruction*, 4> InsertedInsts;
1882-
SILBuilderWithScope B(Inst, &InsertedInsts);
1878+
SILBuilderWithScope B(Inst);
18831879
lowerAssignInstruction(B, AI, PartialInitKind);
1884-
1885-
// If lowering of the assign introduced any new loads or stores, keep track
1886-
// of them.
1887-
for (auto I : InsertedInsts) {
1888-
if (isa<StoreInst>(I)) {
1889-
NonLoadUses[I] = Uses.size();
1890-
Uses.push_back(DIMemoryUse(I, Kind, FirstElement, NumElements));
1891-
} else if (isa<LoadInst>(I)) {
1892-
// If we have a re-initialization, the value must be a class,
1893-
// and the load is just there so we can free the uninitialized
1894-
// object husk; it's not an actual use of 'self'.
1895-
if (PartialInitKind != PartialInitializationKind::IsReinitialization)
1896-
Uses.push_back(DIMemoryUse(I, Load, FirstElement, NumElements));
1897-
}
1898-
}
18991880
return;
19001881
}
19011882

@@ -2193,6 +2174,12 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
21932174

21942175
// Ignore deleted uses.
21952176
if (Use.Inst == nullptr) continue;
2177+
2178+
// If this ambiguous store is only of trivial types, then we don't need to
2179+
// do anything special. We don't even need keep the init bit for the
2180+
// element precise.
2181+
if (Use.onlyTouchesTrivialElements(TheMemory))
2182+
continue;
21962183

21972184
B.setInsertionPoint(Use.Inst);
21982185

@@ -2208,23 +2195,12 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
22082195

22092196
case DIUseKind::SelfInit:
22102197
case DIUseKind::Initialization:
2211-
// If this is an initialization of only trivial elements, then we don't
2212-
// need to update the bitvector.
2213-
if (Use.onlyTouchesTrivialElements(TheMemory))
2214-
continue;
2215-
22162198
APInt Bitmask = Use.getElementBitmask(NumMemoryElements);
22172199
SILBuilderWithScope SB(Use.Inst);
22182200
updateControlVariable(Loc, Bitmask, ControlVariableAddr, OrFn, SB);
22192201
continue;
22202202
}
22212203

2222-
// If this ambiguous store is only of trivial types, then we don't need to
2223-
// do anything special. We don't even need keep the init bit for the
2224-
// element precise.
2225-
if (Use.onlyTouchesTrivialElements(TheMemory))
2226-
continue;
2227-
22282204
// If this is the interesting case, we need to generate a CFG diamond for
22292205
// each element touched, destroying any live elements so that the resulting
22302206
// store is always an initialize. This disambiguates the dynamic
@@ -2269,15 +2245,12 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
22692245
// Finally, now that we know the value is uninitialized on all paths, it is
22702246
// safe to do an unconditional initialization.
22712247
Use.Kind = DIUseKind::Initialization;
2272-
2273-
// Now that the instruction has a concrete "init" form, update it to reflect
2274-
// that. Note that this can invalidate the Uses vector and delete
2275-
// the instruction.
2276-
updateInstructionForInitState(Use);
2277-
2278-
// Revisit the instruction on the next pass through the loop, so that we
2279-
// emit a mask update as appropriate.
2280-
--i;
2248+
NeedsUpdateForInitState.push_back(i);
2249+
2250+
// Update the control variable.
2251+
APInt Bitmask = Use.getElementBitmask(NumMemoryElements);
2252+
SILBuilderWithScope SB(Use.Inst);
2253+
updateControlVariable(Loc, Bitmask, ControlVariableAddr, OrFn, SB);
22812254
}
22822255

22832256
// At each block that stores to self, mark the self value as having been

test/SILOptimizer/definite_init_diagnostics.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,3 +1551,31 @@ func testOptionalUnwrapNoError() -> Int? {
15511551
x = 0
15521552
return x!
15531553
}
1554+
1555+
// <https://bugs.swift.org/browse/SR-9451>
1556+
class StrongCycle {
1557+
var c: StrongCycle
1558+
var d: Int
1559+
init(first: ()) {
1560+
self.d = 10
1561+
self.c = self // expected-error {{variable 'self.c' used before being initialized}}
1562+
}
1563+
1564+
init(second: ()) {
1565+
self.c = self // expected-error {{variable 'self.c' used before being initialized}}
1566+
self.d = 10
1567+
}
1568+
}
1569+
1570+
class WeakCycle {
1571+
weak var c: WeakCycle?
1572+
var d: Int
1573+
init(first: ()) { // FIXME: This is inconsistent with the strong reference behavior above
1574+
self.d = 10
1575+
self.c = self
1576+
}
1577+
init(second: ()) {
1578+
self.c = self // expected-error {{variable 'self.d' used before being initialized}}
1579+
self.d = 10
1580+
}
1581+
}

test/SILOptimizer/definite_init_markuninitialized_var.sil

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,7 @@ bb0:
260260

261261
%b = alloc_box $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>
262262
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>, 0
263-
%c = mark_uninitialized [var] %ba : $*@sil_weak Optional<SomeClass> // expected-note {{variable defined here}}
264-
265-
// Invalid load to keep the alloc_box around so we can check init semantics.
266-
%c_loaded = load_weak %c : $*@sil_weak Optional<SomeClass> // expected-error {{used before being initialized}}
267-
destroy_value %c_loaded : $Optional<SomeClass>
263+
%c = mark_uninitialized [var] %ba : $*@sil_weak Optional<SomeClass>
268264

269265
%f = function_ref @getSomeOptionalClass : $@convention(thin) () -> @owned Optional<SomeClass>
270266

0 commit comments

Comments
 (0)