@@ -123,8 +123,7 @@ class LiveValues {
123
123
}
124
124
125
125
void endLexicalLifetimeBeforeInst (AllocStackInst *asi,
126
- SILInstruction *beforeInstruction,
127
- SILBuilderContext &ctx);
126
+ SILInstruction *beforeInstruction);
128
127
};
129
128
struct Guaranteed {
130
129
SILValue stored = SILValue();
@@ -173,8 +172,7 @@ class LiveValues {
173
172
}
174
173
175
174
void endLexicalLifetimeBeforeInst (AllocStackInst *asi,
176
- SILInstruction *beforeInstruction,
177
- SILBuilderContext &ctx);
175
+ SILInstruction *beforeInstruction);
178
176
};
179
177
struct None {
180
178
SILValue stored = SILValue();
@@ -190,8 +188,7 @@ class LiveValues {
190
188
bool canEndLexicalLifetime () { return false ; }
191
189
192
190
void endLexicalLifetimeBeforeInst (AllocStackInst *asi,
193
- SILInstruction *beforeInstruction,
194
- SILBuilderContext &ctx);
191
+ SILInstruction *beforeInstruction);
195
192
};
196
193
197
194
private:
@@ -289,23 +286,22 @@ class LiveValues {
289
286
}
290
287
291
288
void endLexicalLifetimeBeforeInst (AllocStackInst *asi,
292
- SILInstruction *beforeInstruction,
293
- SILBuilderContext &ctx) {
289
+ SILInstruction *beforeInstruction) {
294
290
if (auto *owned = storage.dyn_cast <Owned>()) {
295
- return owned->endLexicalLifetimeBeforeInst (asi, beforeInstruction, ctx );
291
+ return owned->endLexicalLifetimeBeforeInst (asi, beforeInstruction);
296
292
} else if (auto *none = storage.dyn_cast <None>()) {
297
- return none->endLexicalLifetimeBeforeInst (asi, beforeInstruction, ctx );
293
+ return none->endLexicalLifetimeBeforeInst (asi, beforeInstruction);
298
294
}
299
295
auto &guaranteed = storage.get <Guaranteed>();
300
- return guaranteed.endLexicalLifetimeBeforeInst (asi, beforeInstruction, ctx );
296
+ return guaranteed.endLexicalLifetimeBeforeInst (asi, beforeInstruction);
301
297
}
302
298
303
299
bool endLexicalLifetimeBeforeInstIfPossible (AllocStackInst *asi,
304
300
SILInstruction *beforeInstruction,
305
301
SILBuilderContext &ctx) {
306
302
if (!canEndLexicalLifetime ())
307
303
return false ;
308
- endLexicalLifetimeBeforeInst (asi, beforeInstruction, ctx );
304
+ endLexicalLifetimeBeforeInst (asi, beforeInstruction);
309
305
return true ;
310
306
}
311
307
};
@@ -392,6 +388,17 @@ static bool isLoadFromStack(SILInstruction *i, AllocStackInst *asi) {
392
388
return true ;
393
389
}
394
390
391
+ // / Whether the storage is invalid after \p i.
392
+ // /
393
+ // / This is exactly when the instruction is a load [take].
394
+ static bool doesLoadInvalidateStorage (SILInstruction *i) {
395
+ auto *li = dyn_cast<LoadInst>(i);
396
+ if (!li) {
397
+ return false ;
398
+ }
399
+ return li->getOwnershipQualifier () == LoadOwnershipQualifier::Take;
400
+ }
401
+
395
402
// / Collects all load instructions which (transitively) use \p i as address.
396
403
static void collectLoads (SILInstruction *i,
397
404
SmallVectorImpl<SILInstruction *> &foundLoads) {
@@ -811,17 +818,15 @@ beginGuaranteedLexicalLifetimeAfterStore(AllocStackInst *asi,
811
818
// / it will already have been ended naturally by destroy_addrs (or equivalent)
812
819
// / of the alloc_stack.
813
820
void LiveValues::Owned::endLexicalLifetimeBeforeInst (
814
- AllocStackInst *asi, SILInstruction *beforeInstruction,
815
- SILBuilderContext &ctx) {
821
+ AllocStackInst *asi, SILInstruction *beforeInstruction) {
816
822
assert (lexicalLifetimeEnsured (asi));
817
823
assert (beforeInstruction);
818
824
}
819
825
820
826
// / End the lexical borrow scope for an @guaranteed stored value described by
821
827
// / the provided LiveValues struct before the specified instruction.
822
828
void LiveValues::Guaranteed::endLexicalLifetimeBeforeInst (
823
- AllocStackInst *asi, SILInstruction *beforeInstruction,
824
- SILBuilderContext &ctx) {
829
+ AllocStackInst *asi, SILInstruction *beforeInstruction) {
825
830
assert (lexicalLifetimeEnsured (asi));
826
831
assert (beforeInstruction);
827
832
assert (borrow);
@@ -831,8 +836,7 @@ void LiveValues::Guaranteed::endLexicalLifetimeBeforeInst(
831
836
}
832
837
833
838
void LiveValues::None::endLexicalLifetimeBeforeInst (
834
- AllocStackInst *asi, SILInstruction *beforeInstruction,
835
- SILBuilderContext &ctx) {
839
+ AllocStackInst *asi, SILInstruction *beforeInstruction) {
836
840
llvm::report_fatal_error (
837
841
" can't have lexical lifetime for ownership none value" );
838
842
}
@@ -1061,7 +1065,7 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1061
1065
if (runningVals && runningVals->value .canEndLexicalLifetime ()) {
1062
1066
// End it right now if we have enough information.
1063
1067
runningVals->value .getOwned ().endLexicalLifetimeBeforeInst (
1064
- asi, /* beforeInstruction=*/ li, ctx );
1068
+ asi, /* beforeInstruction=*/ li);
1065
1069
} else {
1066
1070
// If we don't have enough information, end it endLexicalLifetime.
1067
1071
assert (!deinitializationPoints[blockPromotingWithin]);
@@ -1088,7 +1092,7 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1088
1092
// StackAllocationPromoter::fixBranchesAndUses will later handle it.
1089
1093
LLVM_DEBUG (llvm::dbgs () << " *** First load: " << *li);
1090
1094
runningVals = {LiveValues::toReplace (asi, /* replacement=*/ li),
1091
- /* isStorageValid=*/ true };
1095
+ /* isStorageValid=*/ ! doesLoadInvalidateStorage (inst) };
1092
1096
}
1093
1097
continue ;
1094
1098
}
@@ -1143,7 +1147,7 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1143
1147
if (oldRunningVals && oldRunningVals->isStorageValid &&
1144
1148
oldRunningVals->value .canEndLexicalLifetime ()) {
1145
1149
oldRunningVals->value .getOwned ().endLexicalLifetimeBeforeInst (
1146
- asi, /* beforeInstruction=*/ si, ctx );
1150
+ asi, /* beforeInstruction=*/ si);
1147
1151
}
1148
1152
runningVals = beginOwnedLexicalLifetimeAfterStore (asi, si);
1149
1153
}
@@ -1175,9 +1179,6 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1175
1179
1176
1180
// End the lexical lifetime of the store_borrow source.
1177
1181
if (auto *ebi = dyn_cast<EndBorrowInst>(inst)) {
1178
- if (!lexicalLifetimeEnsured (asi, lastStoreInst)) {
1179
- continue ;
1180
- }
1181
1182
auto *sbi = dyn_cast<StoreBorrowInst>(ebi->getOperand ());
1182
1183
if (!sbi) {
1183
1184
continue ;
@@ -1196,8 +1197,10 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1196
1197
if (sbi->getSrc () != runningVals->value .getStored ()) {
1197
1198
continue ;
1198
1199
}
1199
- // Mark storage as invalid and mark end_borrow as a deinit point.
1200
1200
runningVals->isStorageValid = false ;
1201
+ if (!lexicalLifetimeEnsured (asi, lastStoreInst)) {
1202
+ continue ;
1203
+ }
1201
1204
runningVals->value .endLexicalLifetimeBeforeInstIfPossible (
1202
1205
asi, ebi->getNextInstruction (), ctx);
1203
1206
continue ;
@@ -1214,6 +1217,7 @@ SILInstruction *StackAllocationPromoter::promoteAllocationInBlock(
1214
1217
continue ;
1215
1218
}
1216
1219
if (runningVals) {
1220
+ assert (runningVals->isStorageValid );
1217
1221
replaceDestroy (dai, runningVals->value .replacement (asi, dai), ctx,
1218
1222
deleter, instructionsToDelete);
1219
1223
if (lexicalLifetimeEnsured (asi, lastStoreInst)) {
@@ -1968,9 +1972,8 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
1968
1972
LiveValues::toReplace (asi,
1969
1973
/* replacement=*/ createEmptyAndUndefValue (
1970
1974
asi->getElementType (), inst, ctx)),
1971
- /* isStorageValid=*/ true };
1975
+ /* isStorageValid=*/ ! doesLoadInvalidateStorage (inst) };
1972
1976
}
1973
- assert (runningVals && runningVals->isStorageValid );
1974
1977
auto *loadInst = dyn_cast<LoadInst>(inst);
1975
1978
if (loadInst &&
1976
1979
loadInst->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
@@ -2039,13 +2042,13 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
2039
2042
if (!runningVals.has_value ()) {
2040
2043
continue ;
2041
2044
}
2042
- if (!runningVals->value .isGuaranteed ()) {
2043
- continue ;
2044
- }
2045
2045
if (sbi->getSrc () != runningVals->value .getStored ()) {
2046
2046
continue ;
2047
2047
}
2048
2048
runningVals->isStorageValid = false ;
2049
+ if (!runningVals->value .isGuaranteed ()) {
2050
+ continue ;
2051
+ }
2049
2052
runningVals->value .endLexicalLifetimeBeforeInstIfPossible (
2050
2053
asi, ebi->getNextInstruction (), ctx);
2051
2054
continue ;
@@ -2094,24 +2097,32 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
2094
2097
}
2095
2098
}
2096
2099
2097
- if (lexicalLifetimeEnsured (asi) && runningVals &&
2098
- runningVals->isStorageValid &&
2099
- runningVals->value .getStored ()->getOwnershipKind ().isCompatibleWith (
2100
- OwnershipKind::Owned)) {
2101
- // There is still valid storage after visiting all instructions in this
2102
- // block which are the only instructions involving this alloc_stack.
2103
- // This can only happen if all paths from this block end in unreachable.
2104
- //
2105
- // We need to end the lexical lifetime at the last possible location, at the
2106
- // boundary blocks which are the predecessors of dominance frontier
2107
- // dominated by the alloc_stack.
2108
- SmallVector<SILBasicBlock *, 4 > boundary;
2109
- computeDominatedBoundaryBlocks (asi->getParent (), domInfo, boundary);
2110
- for (auto *block : boundary) {
2111
- auto *terminator = block->getTerminator ();
2112
- runningVals->value .endLexicalLifetimeBeforeInstIfPossible (
2113
- asi, /* beforeInstruction=*/ terminator, ctx);
2114
- }
2100
+ auto *function = asi->getFunction ();
2101
+ if (!function->hasOwnership () || !runningVals ||
2102
+ !runningVals->isStorageValid ||
2103
+ asi->getElementType ().isTrivial (function)) {
2104
+ return ;
2105
+ }
2106
+ // There is still valid storage after visiting all instructions in this
2107
+ // block which are the only instructions involving this alloc_stack.
2108
+ // That can happen if:
2109
+ // (1) this block is a dead-end. TODO: OSSACompleteLifetime: Complete such
2110
+ // lifetimes.
2111
+ // (2) a trivial case of a non-trivial enum was stored to the address
2112
+
2113
+ auto *deadEndBlocks = deadEndBlocksAnalysis->get (function);
2114
+
2115
+ if (!deadEndBlocks->isDeadEnd (parentBlock)) {
2116
+ // We may have incomplete lifetimes for enum locations on trivial paths.
2117
+ // After promoting them, complete lifetime here.
2118
+ ASSERT (asi->getElementType ().isOrHasEnum ());
2119
+ OSSACompleteLifetime completion (function, domInfo, *deadEndBlocks,
2120
+ OSSACompleteLifetime::IgnoreTrivialVariable,
2121
+ /* forceLivenessVerification=*/ false ,
2122
+ /* nonDestroyingEnd=*/ true );
2123
+ completion.completeOSSALifetime (
2124
+ runningVals->value .replacement (asi, nullptr ),
2125
+ OSSACompleteLifetime::Boundary::Liveness);
2115
2126
}
2116
2127
}
2117
2128
@@ -2211,7 +2222,8 @@ bool MemoryToRegisters::promoteAllocation(AllocStackInst *alloc,
2211
2222
}
2212
2223
2213
2224
// Remove write-only AllocStacks.
2214
- if (isWriteOnlyAllocation (alloc) && !lexicalLifetimeEnsured (alloc)) {
2225
+ if (isWriteOnlyAllocation (alloc) && !alloc->getType ().isOrHasEnum () &&
2226
+ !lexicalLifetimeEnsured (alloc)) {
2215
2227
LLVM_DEBUG (llvm::dbgs () << " *** Deleting store-only AllocStack: " << *alloc);
2216
2228
deleter.forceDeleteWithUsers (alloc);
2217
2229
return true ;
0 commit comments