Skip to content

Commit c3c78fa

Browse files
committed
DeadObjectElimination: Handle alloc_ref in ossa
1 parent f5c5c9e commit c3c78fa

File tree

1 file changed

+66
-35
lines changed

1 file changed

+66
-35
lines changed

lib/SILOptimizer/Transforms/DeadObjectElimination.cpp

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,22 @@ static DestructorEffects doesDestructorHaveSideEffects(AllocRefInstBase *ARI) {
177177
assert(RefInst->getNumOperands() == 1 &&
178178
"Make sure RefInst only has one argument.");
179179
LLVM_DEBUG(llvm::dbgs() << " SAFE! Ref count operation on "
180-
"Self.\n");
180+
"Self.\n");
181+
continue;
182+
}
183+
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! Ref count operation "
184+
"not on self.\n");
185+
return DestructorEffects::Unknown;
186+
}
187+
if (auto *destroy = dyn_cast<DestroyValueInst>(&I)) {
188+
if (stripCasts(destroy->getOperand()) == Self) {
189+
LLVM_DEBUG(llvm::dbgs() << " SAFE! Ref count operation on "
190+
"Self.\n");
181191
continue;
182-
} else {
183-
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! Ref count operation "
184-
"not on self.\n");
185-
return DestructorEffects::Unknown;
186192
}
193+
LLVM_DEBUG(llvm::dbgs() << " UNSAFE! Ref count operation "
194+
"not on self.\n");
195+
return DestructorEffects::Unknown;
187196
}
188197

189198
// dealloc_stack can be ignored.
@@ -246,7 +255,15 @@ static DestructorEffects doesDestructorHaveSideEffects(AllocRefInstBase *ARI) {
246255
/// alloc_ref alive.
247256
static bool canZapInstruction(SILInstruction *Inst, bool acceptRefCountInsts,
248257
bool onlyAcceptTrivialStores) {
249-
if (isa<SetDeallocatingInst>(Inst) || isa<FixLifetimeInst>(Inst))
258+
if (isa<DestroyValueInst>(Inst)) {
259+
return acceptRefCountInsts;
260+
}
261+
if (isa<CopyValueInst>(Inst) || isa<BeginBorrowInst>(Inst) ||
262+
isa<MoveValueInst>(Inst)) {
263+
return true;
264+
}
265+
if (isa<SetDeallocatingInst>(Inst) || isa<FixLifetimeInst>(Inst) ||
266+
isa<EndBorrowInst>(Inst))
250267
return true;
251268

252269
// It is ok to eliminate various retains/releases. We are either removing
@@ -384,6 +401,7 @@ hasUnremovableUsers(SILInstruction *allocation, UserList *Users,
384401
LLVM_DEBUG(llvm::dbgs() << " Analyzing Use Graph.");
385402

386403
SmallVector<RefElementAddrInst *, 8> refElementAddrs;
404+
387405
BuiltinInst *destroyArray = nullptr;
388406
auto *allocRef = dyn_cast<AllocRefInstBase>(allocation);
389407

@@ -397,11 +415,10 @@ hasUnremovableUsers(SILInstruction *allocation, UserList *Users,
397415
if (Users && !Users->insert(I)) {
398416
LLVM_DEBUG(llvm::dbgs() << " Already seen skipping...\n");
399417
continue;
400-
}
401-
if (auto *rea = dyn_cast<RefElementAddrInst>(I)) {
418+
} else if (auto *rea = dyn_cast<RefElementAddrInst>(I)) {
402419
if (rea != allocation && !rea->getType().isTrivial(*rea->getFunction()))
403420
refElementAddrs.push_back(rea);
404-
} else if (allocRef && Users && isDestroyArray(I)) {
421+
} else if (allocRef && isDestroyArray(I)) {
405422
if (destroyArray)
406423
return true;
407424
destroyArray = cast<BuiltinInst>(I);
@@ -434,20 +451,20 @@ hasUnremovableUsers(SILInstruction *allocation, UserList *Users,
434451
}
435452
}
436453

437-
// In OSSA, we don't have to do this check. We can always accept a
438-
// destroyArray and insert the compensating destroys right at the store
439-
// instructions.
440-
if (destroyArray)
441-
return !onlyStoresToTailObjects(destroyArray, *Users, allocRef);
442-
443-
// In non-OSSA we cannot reliably track the lifetime of non-trivial stored
444-
// properties. Removing the dead alloc_ref might leak a property value.
445-
// TODO: in OSSA we can replace stores to properties with a destroy_value.
446-
for (RefElementAddrInst *rea : refElementAddrs) {
447-
// Re-run the check with not accepting non-trivial stores.
448-
if (hasUnremovableUsers(rea, nullptr, acceptRefCountInsts,
449-
/*onlyAcceptTrivialStores*/ true))
450-
return true;
454+
if (!allocation->getFunction()->hasOwnership()) {
455+
// In non-ossa, if we found a destroy array builtin that destroys the tail
456+
// elements, ensure all stores are to the taile elems.
457+
if (destroyArray) {
458+
return !onlyStoresToTailObjects(destroyArray, *Users, allocRef);
459+
}
460+
// In non-OSSA we cannot reliably track the lifetime of non-trivial stored
461+
// properties. Removing the dead alloc_ref might leak a property value.
462+
for (RefElementAddrInst *rea : refElementAddrs) {
463+
// Re-run the check with not accepting non-trivial stores.
464+
if (hasUnremovableUsers(rea, nullptr, acceptRefCountInsts,
465+
/*onlyAcceptTrivialStores*/ true))
466+
return true;
467+
}
451468
}
452469

453470
return false;
@@ -820,21 +837,35 @@ bool DeadObjectElimination::processAllocRef(AllocRefInstBase *ARI) {
820837
return false;
821838
}
822839

823-
// Find the instruction which releases the object's tail elements.
824-
SILInstruction *releaseOfTailElems = nullptr;
825-
for (SILInstruction *user : UsersToRemove) {
826-
if (isDestroyArray(user) ||
827-
(destructorEffects == DestructorEffects::DestroysTailElems &&
828-
isa<RefCountingInst>(user) && user->mayRelease())) {
829-
// Bail if we find multiple such instructions.
830-
if (releaseOfTailElems)
840+
if (!ARI->getFunction()->hasOwnership()) {
841+
// Find the instruction which releases the object's tail elements.
842+
SILInstruction *releaseOfTailElems = nullptr;
843+
for (SILInstruction *user : UsersToRemove) {
844+
if (isDestroyArray(user) ||
845+
(destructorEffects == DestructorEffects::DestroysTailElems &&
846+
isa<RefCountingInst>(user) && user->mayRelease())) {
847+
// Bail if we find multiple such instructions.
848+
if (releaseOfTailElems)
849+
return false;
850+
releaseOfTailElems = user;
851+
}
852+
}
853+
if (releaseOfTailElems) {
854+
if (!insertCompensatingReleases(releaseOfTailElems, UsersToRemove)) {
831855
return false;
832-
releaseOfTailElems = user;
856+
}
833857
}
834858
}
835-
if (releaseOfTailElems) {
836-
if (!insertCompensatingReleases(releaseOfTailElems, UsersToRemove)) {
837-
return false;
859+
860+
if (ARI->getFunction()->hasOwnership()) {
861+
for (auto *user : UsersToRemove) {
862+
auto *store = dyn_cast<StoreInst>(user);
863+
if (!store ||
864+
store->getOwnershipQualifier() == StoreOwnershipQualifier::Trivial) {
865+
continue;
866+
}
867+
SILBuilderWithScope(store).createDestroyValue(store->getLoc(),
868+
store->getSrc());
838869
}
839870
}
840871

0 commit comments

Comments
 (0)